diff --git a/frontends/etiquette_flask/static/js/common.js b/frontends/etiquette_flask/static/js/common.js index 2a284f5..9818d2b 100644 --- a/frontends/etiquette_flask/static/js/common.js +++ b/frontends/etiquette_flask/static/js/common.js @@ -262,145 +262,6 @@ function init_button_with_confirm() }); } -common.spinner_button_index = 0; -common.button_spinner_groups = {}; -// When a group member is closing, it will call the closer on all other members -// in the group. Of course, this would recurse forever without some kind of -// flagging, so this dict will hold group_id:true if a close is in progress, -// and be empty otherwise. -common.spinner_group_closing = {}; - -common.add_to_spinner_group = -function add_to_spinner_group(group_id, button) -{ - if (!(group_id in common.button_spinner_groups)) - { - common.button_spinner_groups[group_id] = []; - } - common.button_spinner_groups[group_id].push(button); -} - -common.close_grouped_spinners = -function close_grouped_spinners(group_id) -{ - if (group_id && !(common.spinner_group_closing[group_id])) - { - common.spinner_group_closing[group_id] = true; - common.button_spinner_groups[group_id].forEach(function(button) - { - window[button.dataset.spinnerCloser](); - }); - delete common.spinner_group_closing[group_id]; - } -} - -common.open_grouped_spinners = -function open_grouped_spinners(group_id) -{ - common.button_spinner_groups[group_id].forEach(function(button) - { - window[button.dataset.spinnerOpener](); - }); -} - -common.init_button_with_spinner = -function init_button_with_spinner() -{ - /* - To create a button that has a spinner, and cannot be clicked again while - the action is running, assign it the class "button_with_spinner". - When you're ready for the spinner to disappear, call - window[button.dataset.spinnerCloser](). - - Required: - data-onclick: The string that would normally be the button's onclick. - - Optional: - data-spinner-id: If you want to use your own element as the spinner, - give its ID here. Otherwise a new one will be created. - - data-spinner-delay: The number of milliseconds to wait before the - spinner appears. For tasks that you expect to run very quickly, - this helps prevent a pointlessly short spinner. - - data-holder-class: CSS class for the new span that holds the menu. - - data-spinner-group: An opaque string. All button_with_spinner that have - the same group will go into spinner mode when any of them is - clicked. Useful if you want to have two copies of a button on the - page, or two buttons which do opposite things and you only want one - to run at a time. - */ - var buttons = Array.from(document.getElementsByClassName("button_with_spinner")); - buttons.forEach(function(button) - { - button.classList.remove("button_with_spinner"); - button.innerHTML = button.innerHTML.trim(); - - var holder = document.createElement("span"); - holder.classList.add("spinner_holder"); - holder.classList.add(button.dataset.holderClass || "spinner_holder"); - button.parentElement.insertBefore(holder, button); - button.parentElement.removeChild(button); - holder.appendChild(button); - - var spinner_element; - if (button.dataset.spinnerId) - { - spinner_element = document.getElementById(button.dataset.spinnerId); - } - else - { - spinner_element = document.createElement("span"); - spinner_element.innerText = "Working..."; - spinner_element.classList.add("hidden"); - holder.appendChild(spinner_element); - } - - if (button.dataset.spinnerGroup) - { - common.add_to_spinner_group(button.dataset.spinnerGroup, button); - } - - var spin = new spinner.Spinner(spinner_element); - var spin_delay = parseFloat(button.dataset.spinnerDelay) || 0; - - button.dataset.spinnerOpener = "spinner_opener_" + common.spinner_button_index; - window[button.dataset.spinnerOpener] = function spinner_opener() - { - spin.show(spin_delay); - button.disabled = true; - } - // It is expected that the function referenced by data-onclick will call - // window[button.dataset.spinnerCloser]() when appropriate, since from - // our perspective we cannot be sure when to close the spinner. - button.dataset.spinnerCloser = "spinner_closer_" + common.spinner_button_index; - window[button.dataset.spinnerCloser] = function spinner_closer() - { - common.close_grouped_spinners(button.dataset.spinnerGroup); - spin.hide(); - button.disabled = false; - } - - var wrapped_onclick = Function(button.dataset.onclick); - button.onclick = function() - { - if (button.dataset.spinnerGroup) - { - common.open_grouped_spinners(button.dataset.spinnerGroup); - } - else - { - window[button.dataset.spinnerOpener](); - } - return wrapped_onclick(); - } - delete button.dataset.onclick; - - common.spinner_button_index += 1; - }); -} - common.normalize_tagname = function normalize_tagname(tagname) { @@ -431,6 +292,5 @@ common.on_pageload = function on_pageload() { common.init_button_with_confirm(); - common.init_button_with_spinner(); } document.addEventListener("DOMContentLoaded", common.on_pageload); diff --git a/frontends/etiquette_flask/static/js/spinner.js b/frontends/etiquette_flask/static/js/spinner.js index e90ff54..45ddbed 100644 --- a/frontends/etiquette_flask/static/js/spinner.js +++ b/frontends/etiquette_flask/static/js/spinner.js @@ -29,3 +29,149 @@ function Spinner(element) this.delayed_showing_timeout = null; this.element = element; } + +spinner.spinner_button_index = 0; +spinner.button_spinner_groups = {}; +// When a group member is closing, it will call the closer on all other members +// in the group. Of course, this would recurse forever without some kind of +// flagging, so this dict will hold group_id:true if a close is in progress, +// and be empty otherwise. +spinner.spinner_group_closing = {}; + +spinner.add_to_spinner_group = +function add_to_spinner_group(group_id, button) +{ + if (!(group_id in spinner.button_spinner_groups)) + { + spinner.button_spinner_groups[group_id] = []; + } + spinner.button_spinner_groups[group_id].push(button); +} + +spinner.close_grouped_spinners = +function close_grouped_spinners(group_id) +{ + if (group_id && !(spinner.spinner_group_closing[group_id])) + { + spinner.spinner_group_closing[group_id] = true; + spinner.button_spinner_groups[group_id].forEach(function(button) + { + window[button.dataset.spinnerCloser](); + }); + delete spinner.spinner_group_closing[group_id]; + } +} + +spinner.open_grouped_spinners = +function open_grouped_spinners(group_id) +{ + spinner.button_spinner_groups[group_id].forEach(function(button) + { + window[button.dataset.spinnerOpener](); + }); +} + +spinner.init_button_with_spinner = +function init_button_with_spinner() +{ + /* + To create a button that has a spinner, and cannot be clicked again while + the action is running, assign it the class "button_with_spinner". + When you're ready for the spinner to disappear, call + window[button.dataset.spinnerCloser](). + + Required: + data-onclick: The string that would normally be the button's onclick. + + Optional: + data-spinner-id: If you want to use your own element as the spinner, + give its ID here. Otherwise a new one will be created. + + data-spinner-delay: The number of milliseconds to wait before the + spinner appears. For tasks that you expect to run very quickly, + this helps prevent a pointlessly short spinner. + + data-holder-class: CSS class for the new span that holds the menu. + + data-spinner-group: An opaque string. All button_with_spinner that have + the same group will go into spinner mode when any of them is + clicked. Useful if you want to have two copies of a button on the + page, or two buttons which do opposite things and you only want one + to run at a time. + */ + var buttons = Array.from(document.getElementsByClassName("button_with_spinner")); + buttons.forEach(function(button) + { + button.classList.remove("button_with_spinner"); + button.innerHTML = button.innerHTML.trim(); + + var holder = document.createElement("span"); + holder.classList.add("spinner_holder"); + holder.classList.add(button.dataset.holderClass || "spinner_holder"); + button.parentElement.insertBefore(holder, button); + button.parentElement.removeChild(button); + holder.appendChild(button); + + var spinner_element; + if (button.dataset.spinnerId) + { + spinner_element = document.getElementById(button.dataset.spinnerId); + } + else + { + spinner_element = document.createElement("span"); + spinner_element.innerText = "Working..."; + spinner_element.classList.add("hidden"); + holder.appendChild(spinner_element); + } + + if (button.dataset.spinnerGroup) + { + spinner.add_to_spinner_group(button.dataset.spinnerGroup, button); + } + + var spin = new spinner.Spinner(spinner_element); + var spin_delay = parseFloat(button.dataset.spinnerDelay) || 0; + + button.dataset.spinnerOpener = "spinner_opener_" + spinner.spinner_button_index; + window[button.dataset.spinnerOpener] = function spinner_opener() + { + spin.show(spin_delay); + button.disabled = true; + } + // It is expected that the function referenced by data-onclick will call + // window[button.dataset.spinnerCloser]() when appropriate, since from + // our perspective we cannot be sure when to close the spinner. + button.dataset.spinnerCloser = "spinner_closer_" + spinner.spinner_button_index; + window[button.dataset.spinnerCloser] = function spinner_closer() + { + spinner.close_grouped_spinners(button.dataset.spinnerGroup); + spin.hide(); + button.disabled = false; + } + + var wrapped_onclick = Function(button.dataset.onclick); + button.onclick = function() + { + if (button.dataset.spinnerGroup) + { + spinner.open_grouped_spinners(button.dataset.spinnerGroup); + } + else + { + window[button.dataset.spinnerOpener](); + } + return wrapped_onclick(); + } + delete button.dataset.onclick; + + spinner.spinner_button_index += 1; + }); +} + +spinner.on_pageload = +function on_pageload() +{ + spinner.init_button_with_spinner(); +} +document.addEventListener("DOMContentLoaded", spinner.on_pageload);