CanvasBlocker/lib/modal.js

158 lines
4.2 KiB
JavaScript

/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
(function(){
"use strict";
let scope;
if ((typeof exports) !== "undefined"){
scope = exports;
}
else {
scope = require.register("./modal", {});
}
const extension = require("./extension");
function getGlobalOffsetTop(node){
if (node){
return node.offsetTop + getGlobalOffsetTop(node.offsetParent);
}
else {
return 0;
}
}
function getGlobalScrollTop(node){
if (node && node.scrollTop){
return node.scrollTop + getGlobalScrollTop(node.parentNode);
}
else {
return window.scrollY;
}
}
function openDialog(text, buttons, parent = document.body){
if (!(parent instanceof Node)){
const parentSelector = parent.selector;
parent = parent.node;
while (parent && !parent.matches(parentSelector)){
parent = parent.parentNode;
}
if (!parent){
parent = document.body;
}
}
const container = document.createElement("div");
container.className = "modal";
parent.appendChild(container);
const overlay = document.createElement("div");
overlay.className = "overlay";
container.appendChild(overlay);
const dialogPosition = document.createElement("div");
dialogPosition.className = "dialogPosition";
container.appendChild(dialogPosition);
const dialog = document.createElement("div");
dialog.className = "dialog";
dialogPosition.appendChild(dialog);
const textNode = document.createElement("span");
textNode.className = "text";
textNode.textContent = text;
dialog.appendChild(textNode);
const buttonsNode = document.createElement("div");
buttonsNode.className = "buttons";
dialog.appendChild(buttonsNode);
let defaultButton;
buttons.forEach(function(button){
const buttonNode = document.createElement("button");
buttonNode.textContent = button.text;
buttonNode.addEventListener("click", function(){
close();
button.callback();
});
buttonsNode.appendChild(buttonNode);
if (button.focused){
buttonNode.focus();
}
if (button.default){
defaultButton = button;
}
});
function closeOnEscape(event){
if (event.keyCode === 27){
close();
if (defaultButton){
defaultButton.callback();
}
}
}
function positionDialog(){
const parentTop = getGlobalOffsetTop(parent) - getGlobalScrollTop(parent);
const parentHeight = parent.offsetHeight;
const height = dialog.offsetHeight;
const top = Math.max(0,
Math.min(
container.offsetHeight - height,
parentTop + parentHeight / 2 - height / 2
)
);
dialogPosition.style.top = top + "px";
}
function close(){
window.removeEventListener("keydown", closeOnEscape);
window.removeEventListener("scroll", positionDialog);
window.removeEventListener("resize", positionDialog);
parent.removeChild(container);
}
window.addEventListener("keydown", closeOnEscape);
if (parent !== document.body){
positionDialog();
window.addEventListener("scroll", positionDialog);
window.addEventListener("resize", positionDialog);
}
return container;
}
scope.confirm = function(text, parent){
return new Promise(function(resolve){
openDialog(text, [
{text: extension.getTranslation("cancel"), default: true, callback: ()=>resolve(false)},
{text: extension.getTranslation("OK"), focused: true, callback: ()=>resolve(true)}
], parent);
});
};
scope.select = function(text, options, parent){
return new Promise(function(resolve, reject){
const select = document.createElement("select");
options.forEach(function(option){
const optionNode = document.createElement("option");
optionNode.text = option.name;
optionNode.object = option.object;
select.appendChild(optionNode);
});
const container = openDialog(text, [
{
text: extension.getTranslation("cancel"),
default: true,
callback: () => reject(false)
},
{
text: extension.getTranslation("OK"),
focused: true,
callback: () => resolve(select.options[select.selectedIndex].object)
}
], parent);
container.querySelector(".text").insertAdjacentElement("afterend", select);
});
};
}());