Generic modal window
Dieses Skript sollte nicht direkt installiert werden. Es handelt sich hier um eine Bibliothek für andere Skripte, welche über folgenden Befehl in den Metadaten eines Skriptes eingebunden wird // @require https://update.greasyfork.org/scripts/384230/704110/Modal.js
// ==UserScript==
// @name Modal
// @name:en Modal
// @description Generic modal window
// @description:en Generic modal window
// @namespace https://greasyfork.org/users/174399
// @version 0.1.0
// @include *://*.mozilla.org/*
// @grant none
// ==/UserScript==
(function(window, undefined) {
// const btn = document.body.appendChild(createSElement(`
// <div style="position: fixed; bottom: 0; right: 0; width: 10%; height: 10%; background: green; z-index: 99999; display: flex;">
// <label for="modal-cbox" style="flex: 1"></label>
// </div>
// `));
// setTimeout(() => querySelector('label', btn).click(), 2000);
function Modal({
content: {
css: contentCSS = {},
} = {},
header: {
html: headerHTML = '',
css: headerCSS = {},
onClick: onClickHeader,
} = {},
body: {
html: bodyHTML = '',
css: bodyCSS = {},
onClick: onClickBody,
} = {},
footer: {
html: footerHTML = '',
css: footerCSS = {},
onClick: onClickFooter,
} = {},
withClose = true,
} = {}) {
const wrapper = querySelector('.modal-wrapper') || Modal.create();
const content = querySelector('.modal-content', wrapper);
const mheader = querySelector('.modal-header', wrapper);
const mfooter = querySelector('.modal-footer', wrapper);
const mbody = querySelector('.modal-body', wrapper);
// html
mheader.appendChild(createSElement(headerHTML));
mfooter.innerHTML = footerHTML;
mbody.innerHTML = bodyHTML;
// style
setStyle(content, contentCSS);
setStyle(mheader, headerCSS);
setStyle(mfooter, footerCSS);
setStyle(mbody, bodyCSS);
// onclick
addEventListener(mheader, 'click', onClickHeader);
addEventListener(mfooter, 'click', onClickFooter);
addEventListener(mbody, 'click', onClickBody);
// return object
this.wrapper = wrapper;
this.content = content;
this.header = mheader;
this.footer = mfooter;
this.body = mbody;
this.onClickHeader = onClickHeader;
this.onClickFooter = onClickFooter;
this.onClickBody = onClickBody;
}
Modal.toggle = function() {
const btn = querySelector('.modal-wrapper .modal-close-background');
return btn && btn.click();
};
Modal._open = function(visible = true) {
(querySelector('.modal-wrapper #modal-cbox') || {}).checked = visible;
};
Modal.close = function() { Modal._open(false); };
Modal.open = function() { Modal._open(true); };
Modal.WRAPPER_HTML = `
<div class="modal-wrapper">
<input type="checkbox" checked style="display: none" id="modal-cbox" />
<div class="modal-container">
<label for="modal-cbox" class="modal-close-background" ></label>
<div class="modal-content">
<div class="modal-header">
<label for="modal-cbox" title="close" class="modal-close-x"><div></div></label>
</div>
<div class="modal-body"></div>
<div class="modal-footer"></div>
</div>
</div>
</div>`.replace(/\s+/g, ' ').replace(/\n/g, ' ').trim();
Modal.WRAPPER_CSS = `
.modal-container {
opacity: 0;
visibility: hidden;
}
#modal-cbox:checked + .modal-container {
position: fixed;
z-index: 9999999;
visibility: visible;
opacity: 1;
top: 0;
right: 0;
bottom: 0;
left: 0;
transition: opacity .25s;
}
#modal-cbox:checked + .modal-container .modal-content {
bottom: 0;
}
.modal-content {
position: absolute;
background-color: gray;
min-width: 400px;
min-height: 100px;
opacity: 1;
display: flex;
flex-direction: column;
align-items: center;
right: 0;
bottom: -20%;
transition: all .25s;
}
.modal-header {
display: flex;
flex-direction: row;
position: relative;
align-items: center;
width: 100%;
height: 40px;
}
.modal-close-x {
position: absolute;
right: 10px;
}
.modal-close-x div {
display: flex;
flex-direction: row;
justify-content: center;
}
.modal-close-x,
.modal-close-x div {
width: 24px;
height: 24px;
}
.modal-close-x div:after,
.modal-close-x div:before {
content: "";
position: absolute;
background: #ccc;
width: 2px;
height: 24px;
display: block;
transform: rotate(45deg);
}
.modal-close-x div:before {
transform: rotate(-45deg);
}
.modal-close-background {
position: absolute;
background-color: black;
width: 100%;
height: 100%;
opacity: 0.4;
}
`.replace(/\s+/g, ' ').replace(/\n/g, ' ').trim();
Modal.create = function() {
let wrapper = querySelector('.modal-wrapper');
if (wrapper) {
return wrapper;
}
if (document.readyState === 'loading') {
throw new Error('you can\'t insert HTMLElement to DOMTree while document is loading');
}
const {
body = querySelector('body'),
head = querySelector('head'),
} = document;
if (!body) {
throw new Error('document.body not found');
}
if (!head) {
throw new Error('document.head not found');
}
wrapper = createSElement(Modal.WRAPPER_HTML);
const style = createElement('style', Modal.WRAPPER_CSS);
head.appendChild(style);
return body.appendChild(wrapper);
};
function createSElement(html) {
return createElement('div', html).firstElementChild;
}
function createElement(tag, html) {
const elem = document.createElement(tag);
if (typeof html !== 'undefined') {
elem.innerHTML = html;
}
return elem;
}
function querySelector(selector, context) {
return (context || document).querySelector(selector);
}
function querySelectorAll(selector, context = document) {
return (context || document).querySelectorAll(selector);
}
function setStyle(elem, css, val) {
if (!elem) {
return;
}
switch (typeof css) {
case 'object':
Object.keys(css).map(toCamelCase).forEach(key => setStyle(elem, key, css[key]));
break;
case 'string':
elem.style[css] = val;
break;
}
}
function toCamelCase(str) {
return str.replace(/\-([a-z])/g, (match, p1) => p1.toUpperCase());
}
function addEventListener(elem, event, callback) {
if (!elem || typeof event !== 'string' || typeof callback !== 'function') {
return;
}
return elem.addEventListener(event, callback);
}
const { ESModules = {} } = window;
ESModules.Modal = Modal;
window.ESModules = ESModules;
// Modal.create();
// setTimeout(Modal.toggle, 4000);
})(window);