Move all spinner related functions from common.js to spinner.js.

This commit is contained in:
voussoir 2020-06-17 12:41:13 -07:00
parent 91ac2315e6
commit fdfc7308b0
2 changed files with 146 additions and 140 deletions

View file

@ -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 = common.normalize_tagname =
function normalize_tagname(tagname) function normalize_tagname(tagname)
{ {
@ -431,6 +292,5 @@ common.on_pageload =
function on_pageload() function on_pageload()
{ {
common.init_button_with_confirm(); common.init_button_with_confirm();
common.init_button_with_spinner();
} }
document.addEventListener("DOMContentLoaded", common.on_pageload); document.addEventListener("DOMContentLoaded", common.on_pageload);

View file

@ -29,3 +29,149 @@ function Spinner(element)
this.delayed_showing_timeout = null; this.delayed_showing_timeout = null;
this.element = element; 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);