migrate
This commit is contained in:
10
public/lib/cropper.min.js
vendored
Normal file
10
public/lib/cropper.min.js
vendored
Normal file
File diff suppressed because one or more lines are too long
37
public/lib/dialog-polyfill.css
Normal file
37
public/lib/dialog-polyfill.css
Normal file
@@ -0,0 +1,37 @@
|
||||
.poly_dialog {
|
||||
position: absolute;
|
||||
left: 0; right: 0;
|
||||
width: -moz-fit-content;
|
||||
width: -webkit-fit-content;
|
||||
width: fit-content;
|
||||
height: -moz-fit-content;
|
||||
height: -webkit-fit-content;
|
||||
height: fit-content;
|
||||
margin: auto;
|
||||
border: solid;
|
||||
padding: 1em;
|
||||
background: white;
|
||||
color: black;
|
||||
display: block;
|
||||
}
|
||||
|
||||
.poly_dialog:not([open]) {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.poly_dialog + .backdrop {
|
||||
position: fixed;
|
||||
top: 0; right: 0; bottom: 0; left: 0;
|
||||
background: rgba(0,0,0,0.1);
|
||||
}
|
||||
|
||||
._poly_dialog_overlay {
|
||||
position: fixed;
|
||||
top: 0; right: 0; bottom: 0; left: 0;
|
||||
}
|
||||
|
||||
.poly_dialog.fixed {
|
||||
position: fixed;
|
||||
top: 50%;
|
||||
transform: translate(0, -50%);
|
||||
}
|
858
public/lib/dialog-polyfill.esm.js
Normal file
858
public/lib/dialog-polyfill.esm.js
Normal file
@@ -0,0 +1,858 @@
|
||||
// nb. This is for IE10 and lower _only_.
|
||||
var supportCustomEvent = window.CustomEvent;
|
||||
if (!supportCustomEvent || typeof supportCustomEvent === 'object') {
|
||||
supportCustomEvent = function CustomEvent(event, x) {
|
||||
x = x || {};
|
||||
var ev = document.createEvent('CustomEvent');
|
||||
ev.initCustomEvent(event, !!x.bubbles, !!x.cancelable, x.detail || null);
|
||||
return ev;
|
||||
};
|
||||
supportCustomEvent.prototype = window.Event.prototype;
|
||||
}
|
||||
|
||||
/**
|
||||
* Dispatches the passed event to both an "on<type>" handler as well as via the
|
||||
* normal dispatch operation. Does not bubble.
|
||||
*
|
||||
* @param {!EventTarget} target
|
||||
* @param {!Event} event
|
||||
* @return {boolean}
|
||||
*/
|
||||
function safeDispatchEvent(target, event) {
|
||||
var check = 'on' + event.type.toLowerCase();
|
||||
if (typeof target[check] === 'function') {
|
||||
target[check](event);
|
||||
}
|
||||
return target.dispatchEvent(event);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {Element} el to check for stacking context
|
||||
* @return {boolean} whether this el or its parents creates a stacking context
|
||||
*/
|
||||
function createsStackingContext(el) {
|
||||
while (el && el !== document.body) {
|
||||
var s = window.getComputedStyle(el);
|
||||
var invalid = function(k, ok) {
|
||||
return !(s[k] === undefined || s[k] === ok);
|
||||
};
|
||||
|
||||
if (s.opacity < 1 ||
|
||||
invalid('zIndex', 'auto') ||
|
||||
invalid('transform', 'none') ||
|
||||
invalid('mixBlendMode', 'normal') ||
|
||||
invalid('filter', 'none') ||
|
||||
invalid('perspective', 'none') ||
|
||||
s['isolation'] === 'isolate' ||
|
||||
s.position === 'fixed' ||
|
||||
s.webkitOverflowScrolling === 'touch') {
|
||||
return true;
|
||||
}
|
||||
el = el.parentElement;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Finds the nearest <dialog> from the passed element.
|
||||
*
|
||||
* @param {Element} el to search from
|
||||
* @return {HTMLDialogElement} dialog found
|
||||
*/
|
||||
function findNearestDialog(el) {
|
||||
while (el) {
|
||||
if (el.localName === 'dialog') {
|
||||
return /** @type {HTMLDialogElement} */ (el);
|
||||
}
|
||||
if (el.parentElement) {
|
||||
el = el.parentElement;
|
||||
} else if (el.parentNode) {
|
||||
el = el.parentNode.host;
|
||||
} else {
|
||||
el = null;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Blur the specified element, as long as it's not the HTML body element.
|
||||
* This works around an IE9/10 bug - blurring the body causes Windows to
|
||||
* blur the whole application.
|
||||
*
|
||||
* @param {Element} el to blur
|
||||
*/
|
||||
function safeBlur(el) {
|
||||
// Find the actual focused element when the active element is inside a shadow root
|
||||
while (el && el.shadowRoot && el.shadowRoot.activeElement) {
|
||||
el = el.shadowRoot.activeElement;
|
||||
}
|
||||
|
||||
if (el && el.blur && el !== document.body) {
|
||||
el.blur();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {!NodeList} nodeList to search
|
||||
* @param {Node} node to find
|
||||
* @return {boolean} whether node is inside nodeList
|
||||
*/
|
||||
function inNodeList(nodeList, node) {
|
||||
for (var i = 0; i < nodeList.length; ++i) {
|
||||
if (nodeList[i] === node) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {HTMLFormElement} el to check
|
||||
* @return {boolean} whether this form has method="dialog"
|
||||
*/
|
||||
function isFormMethodDialog(el) {
|
||||
if (!el || !el.hasAttribute('method')) {
|
||||
return false;
|
||||
}
|
||||
return el.getAttribute('method').toLowerCase() === 'dialog';
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {!DocumentFragment|!Element} hostElement
|
||||
* @return {?Element}
|
||||
*/
|
||||
function findFocusableElementWithin(hostElement) {
|
||||
// Note that this is 'any focusable area'. This list is probably not exhaustive, but the
|
||||
// alternative involves stepping through and trying to focus everything.
|
||||
var opts = ['button', 'input', 'keygen', 'select', 'textarea'];
|
||||
var query = opts.map(function(el) {
|
||||
return el + ':not([disabled])';
|
||||
});
|
||||
// TODO(samthor): tabindex values that are not numeric are not focusable.
|
||||
query.push('[tabindex]:not([disabled]):not([tabindex=""])'); // tabindex != "", not disabled
|
||||
var target = hostElement.querySelector(query.join(', '));
|
||||
|
||||
if (!target && 'attachShadow' in Element.prototype) {
|
||||
// If we haven't found a focusable target, see if the host element contains an element
|
||||
// which has a shadowRoot.
|
||||
// Recursively search for the first focusable item in shadow roots.
|
||||
var elems = hostElement.querySelectorAll('*');
|
||||
for (var i = 0; i < elems.length; i++) {
|
||||
if (elems[i].tagName && elems[i].shadowRoot) {
|
||||
target = findFocusableElementWithin(elems[i].shadowRoot);
|
||||
if (target) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return target;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines if an element is attached to the DOM.
|
||||
* @param {Element} element to check
|
||||
* @return {boolean} whether the element is in DOM
|
||||
*/
|
||||
function isConnected(element) {
|
||||
return element.isConnected || document.body.contains(element);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {!Event} event
|
||||
* @return {?Element}
|
||||
*/
|
||||
function findFormSubmitter(event) {
|
||||
if (event.submitter) {
|
||||
return event.submitter;
|
||||
}
|
||||
|
||||
var form = event.target;
|
||||
if (!(form instanceof HTMLFormElement)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
var submitter = dialogPolyfill.formSubmitter;
|
||||
if (!submitter) {
|
||||
var target = event.target;
|
||||
var root = ('getRootNode' in target && target.getRootNode() || document);
|
||||
submitter = root.activeElement;
|
||||
}
|
||||
|
||||
if (!submitter || submitter.form !== form) {
|
||||
return null;
|
||||
}
|
||||
return submitter;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {!Event} event
|
||||
*/
|
||||
function maybeHandleSubmit(event) {
|
||||
if (event.defaultPrevented) {
|
||||
return;
|
||||
}
|
||||
var form = /** @type {!HTMLFormElement} */ (event.target);
|
||||
|
||||
// We'd have a value if we clicked on an imagemap.
|
||||
var value = dialogPolyfill.imagemapUseValue;
|
||||
var submitter = findFormSubmitter(event);
|
||||
if (value === null && submitter) {
|
||||
value = submitter.value;
|
||||
}
|
||||
|
||||
// There should always be a dialog as this handler is added specifically on them, but check just
|
||||
// in case.
|
||||
var dialog = findNearestDialog(form);
|
||||
if (!dialog) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Prefer formmethod on the button.
|
||||
var formmethod = submitter && submitter.getAttribute('formmethod') || form.getAttribute('method');
|
||||
if (formmethod !== 'dialog') {
|
||||
return;
|
||||
}
|
||||
event.preventDefault();
|
||||
|
||||
if (value != null) {
|
||||
// nb. we explicitly check against null/undefined
|
||||
dialog.close(value);
|
||||
} else {
|
||||
dialog.close();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {!HTMLDialogElement} dialog to upgrade
|
||||
* @constructor
|
||||
*/
|
||||
function dialogPolyfillInfo(dialog) {
|
||||
this.dialog_ = dialog;
|
||||
this.replacedStyleTop_ = false;
|
||||
this.openAsModal_ = false;
|
||||
|
||||
// Set a11y role. Browsers that support dialog implicitly know this already.
|
||||
if (!dialog.hasAttribute('role')) {
|
||||
dialog.setAttribute('role', 'dialog');
|
||||
}
|
||||
|
||||
dialog.show = this.show.bind(this);
|
||||
dialog.showModal = this.showModal.bind(this);
|
||||
dialog.close = this.close.bind(this);
|
||||
|
||||
dialog.addEventListener('submit', maybeHandleSubmit, false);
|
||||
|
||||
if (!('returnValue' in dialog)) {
|
||||
dialog.returnValue = '';
|
||||
}
|
||||
|
||||
if ('MutationObserver' in window) {
|
||||
var mo = new MutationObserver(this.maybeHideModal.bind(this));
|
||||
mo.observe(dialog, {attributes: true, attributeFilter: ['open']});
|
||||
} else {
|
||||
// IE10 and below support. Note that DOMNodeRemoved etc fire _before_ removal. They also
|
||||
// seem to fire even if the element was removed as part of a parent removal. Use the removed
|
||||
// events to force downgrade (useful if removed/immediately added).
|
||||
var removed = false;
|
||||
var cb = function() {
|
||||
removed ? this.downgradeModal() : this.maybeHideModal();
|
||||
removed = false;
|
||||
}.bind(this);
|
||||
var timeout;
|
||||
var delayModel = function(ev) {
|
||||
if (ev.target !== dialog) { return; } // not for a child element
|
||||
var cand = 'DOMNodeRemoved';
|
||||
removed |= (ev.type.substr(0, cand.length) === cand);
|
||||
window.clearTimeout(timeout);
|
||||
timeout = window.setTimeout(cb, 0);
|
||||
};
|
||||
['DOMAttrModified', 'DOMNodeRemoved', 'DOMNodeRemovedFromDocument'].forEach(function(name) {
|
||||
dialog.addEventListener(name, delayModel);
|
||||
});
|
||||
}
|
||||
// Note that the DOM is observed inside DialogManager while any dialog
|
||||
// is being displayed as a modal, to catch modal removal from the DOM.
|
||||
|
||||
Object.defineProperty(dialog, 'open', {
|
||||
set: this.setOpen.bind(this),
|
||||
get: dialog.hasAttribute.bind(dialog, 'open')
|
||||
});
|
||||
|
||||
this.backdrop_ = document.createElement('div');
|
||||
this.backdrop_.className = 'backdrop';
|
||||
this.backdrop_.addEventListener('mouseup' , this.backdropMouseEvent_.bind(this));
|
||||
this.backdrop_.addEventListener('mousedown', this.backdropMouseEvent_.bind(this));
|
||||
this.backdrop_.addEventListener('click' , this.backdropMouseEvent_.bind(this));
|
||||
}
|
||||
|
||||
dialogPolyfillInfo.prototype = /** @type {HTMLDialogElement.prototype} */ ({
|
||||
|
||||
get dialog() {
|
||||
return this.dialog_;
|
||||
},
|
||||
|
||||
/**
|
||||
* Maybe remove this dialog from the modal top layer. This is called when
|
||||
* a modal dialog may no longer be tenable, e.g., when the dialog is no
|
||||
* longer open or is no longer part of the DOM.
|
||||
*/
|
||||
maybeHideModal: function() {
|
||||
if (this.dialog_.hasAttribute('open') && isConnected(this.dialog_)) { return; }
|
||||
this.downgradeModal();
|
||||
},
|
||||
|
||||
/**
|
||||
* Remove this dialog from the modal top layer, leaving it as a non-modal.
|
||||
*/
|
||||
downgradeModal: function() {
|
||||
if (!this.openAsModal_) { return; }
|
||||
this.openAsModal_ = false;
|
||||
this.dialog_.style.zIndex = '';
|
||||
|
||||
// This won't match the native <dialog> exactly because if the user set top on a centered
|
||||
// polyfill dialog, that top gets thrown away when the dialog is closed. Not sure it's
|
||||
// possible to polyfill this perfectly.
|
||||
if (this.replacedStyleTop_) {
|
||||
this.dialog_.style.top = '';
|
||||
this.replacedStyleTop_ = false;
|
||||
}
|
||||
|
||||
// Clear the backdrop and remove from the manager.
|
||||
this.backdrop_.parentNode && this.backdrop_.parentNode.removeChild(this.backdrop_);
|
||||
dialogPolyfill.dm.removeDialog(this);
|
||||
},
|
||||
|
||||
/**
|
||||
* @param {boolean} value whether to open or close this dialog
|
||||
*/
|
||||
setOpen: function(value) {
|
||||
if (value) {
|
||||
this.dialog_.hasAttribute('open') || this.dialog_.setAttribute('open', '');
|
||||
} else {
|
||||
this.dialog_.removeAttribute('open');
|
||||
this.maybeHideModal(); // nb. redundant with MutationObserver
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Handles mouse events ('mouseup', 'mousedown', 'click') on the fake .backdrop element, redirecting them as if
|
||||
* they were on the dialog itself.
|
||||
*
|
||||
* @param {!Event} e to redirect
|
||||
*/
|
||||
backdropMouseEvent_: function(e) {
|
||||
if (!this.dialog_.hasAttribute('tabindex')) {
|
||||
// Clicking on the backdrop should move the implicit cursor, even if dialog cannot be
|
||||
// focused. Create a fake thing to focus on. If the backdrop was _before_ the dialog, this
|
||||
// would not be needed - clicks would move the implicit cursor there.
|
||||
var fake = document.createElement('div');
|
||||
this.dialog_.insertBefore(fake, this.dialog_.firstChild);
|
||||
fake.tabIndex = -1;
|
||||
fake.focus();
|
||||
this.dialog_.removeChild(fake);
|
||||
} else {
|
||||
this.dialog_.focus();
|
||||
}
|
||||
|
||||
var redirectedEvent = document.createEvent('MouseEvents');
|
||||
redirectedEvent.initMouseEvent(e.type, e.bubbles, e.cancelable, window,
|
||||
e.detail, e.screenX, e.screenY, e.clientX, e.clientY, e.ctrlKey,
|
||||
e.altKey, e.shiftKey, e.metaKey, e.button, e.relatedTarget);
|
||||
this.dialog_.dispatchEvent(redirectedEvent);
|
||||
e.stopPropagation();
|
||||
},
|
||||
|
||||
/**
|
||||
* Focuses on the first focusable element within the dialog. This will always blur the current
|
||||
* focus, even if nothing within the dialog is found.
|
||||
*/
|
||||
focus_: function() {
|
||||
// Find element with `autofocus` attribute, or fall back to the first form/tabindex control.
|
||||
var target = this.dialog_.querySelector('[autofocus]:not([disabled])');
|
||||
if (!target && this.dialog_.tabIndex >= 0) {
|
||||
target = this.dialog_;
|
||||
}
|
||||
if (!target) {
|
||||
target = findFocusableElementWithin(this.dialog_);
|
||||
}
|
||||
safeBlur(document.activeElement);
|
||||
target && target.focus();
|
||||
},
|
||||
|
||||
/**
|
||||
* Sets the zIndex for the backdrop and dialog.
|
||||
*
|
||||
* @param {number} dialogZ
|
||||
* @param {number} backdropZ
|
||||
*/
|
||||
updateZIndex: function(dialogZ, backdropZ) {
|
||||
if (dialogZ < backdropZ) {
|
||||
throw new Error('dialogZ should never be < backdropZ');
|
||||
}
|
||||
this.dialog_.style.zIndex = dialogZ;
|
||||
this.backdrop_.style.zIndex = backdropZ;
|
||||
},
|
||||
|
||||
/**
|
||||
* Shows the dialog. If the dialog is already open, this does nothing.
|
||||
*/
|
||||
show: function() {
|
||||
if (!this.dialog_.open) {
|
||||
this.setOpen(true);
|
||||
this.focus_();
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Show this dialog modally.
|
||||
*/
|
||||
showModal: function() {
|
||||
if (this.dialog_.hasAttribute('open')) {
|
||||
throw new Error('Failed to execute \'showModal\' on dialog: The element is already open, and therefore cannot be opened modally.');
|
||||
}
|
||||
if (!isConnected(this.dialog_)) {
|
||||
throw new Error('Failed to execute \'showModal\' on dialog: The element is not in a Document.');
|
||||
}
|
||||
if (!dialogPolyfill.dm.pushDialog(this)) {
|
||||
throw new Error('Failed to execute \'showModal\' on dialog: There are too many open modal dialogs.');
|
||||
}
|
||||
|
||||
if (createsStackingContext(this.dialog_.parentElement)) {
|
||||
console.warn('A dialog is being shown inside a stacking context. ' +
|
||||
'This may cause it to be unusable. For more information, see this link: ' +
|
||||
'https://github.com/GoogleChrome/dialog-polyfill/#stacking-context');
|
||||
}
|
||||
|
||||
this.setOpen(true);
|
||||
this.openAsModal_ = true;
|
||||
|
||||
// Optionally center vertically, relative to the current viewport.
|
||||
if (dialogPolyfill.needsCentering(this.dialog_)) {
|
||||
dialogPolyfill.reposition(this.dialog_);
|
||||
this.replacedStyleTop_ = true;
|
||||
} else {
|
||||
this.replacedStyleTop_ = false;
|
||||
}
|
||||
|
||||
// Insert backdrop.
|
||||
this.dialog_.parentNode.insertBefore(this.backdrop_, this.dialog_.nextSibling);
|
||||
|
||||
// Focus on whatever inside the dialog.
|
||||
this.focus_();
|
||||
},
|
||||
|
||||
/**
|
||||
* Closes this HTMLDialogElement. This is optional vs clearing the open
|
||||
* attribute, however this fires a 'close' event.
|
||||
*
|
||||
* @param {string=} opt_returnValue to use as the returnValue
|
||||
*/
|
||||
close: function(opt_returnValue) {
|
||||
if (!this.dialog_.hasAttribute('open')) {
|
||||
throw new Error('Failed to execute \'close\' on dialog: The element does not have an \'open\' attribute, and therefore cannot be closed.');
|
||||
}
|
||||
this.setOpen(false);
|
||||
|
||||
// Leave returnValue untouched in case it was set directly on the element
|
||||
if (opt_returnValue !== undefined) {
|
||||
this.dialog_.returnValue = opt_returnValue;
|
||||
}
|
||||
|
||||
// Triggering "close" event for any attached listeners on the <dialog>.
|
||||
var closeEvent = new supportCustomEvent('close', {
|
||||
bubbles: false,
|
||||
cancelable: false
|
||||
});
|
||||
safeDispatchEvent(this.dialog_, closeEvent);
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
var dialogPolyfill = {};
|
||||
|
||||
dialogPolyfill.reposition = function(element) {
|
||||
var scrollTop = document.body.scrollTop || document.documentElement.scrollTop;
|
||||
var topValue = scrollTop + (window.innerHeight - element.offsetHeight) / 2;
|
||||
element.style.top = Math.max(scrollTop, topValue) + 'px';
|
||||
};
|
||||
|
||||
dialogPolyfill.isInlinePositionSetByStylesheet = function(element) {
|
||||
for (var i = 0; i < document.styleSheets.length; ++i) {
|
||||
var styleSheet = document.styleSheets[i];
|
||||
var cssRules = null;
|
||||
// Some browsers throw on cssRules.
|
||||
try {
|
||||
cssRules = styleSheet.cssRules;
|
||||
} catch (e) {}
|
||||
if (!cssRules) { continue; }
|
||||
for (var j = 0; j < cssRules.length; ++j) {
|
||||
var rule = cssRules[j];
|
||||
var selectedNodes = null;
|
||||
// Ignore errors on invalid selector texts.
|
||||
try {
|
||||
selectedNodes = document.querySelectorAll(rule.selectorText);
|
||||
} catch(e) {}
|
||||
if (!selectedNodes || !inNodeList(selectedNodes, element)) {
|
||||
continue;
|
||||
}
|
||||
var cssTop = rule.style.getPropertyValue('top');
|
||||
var cssBottom = rule.style.getPropertyValue('bottom');
|
||||
if ((cssTop && cssTop !== 'auto') || (cssBottom && cssBottom !== 'auto')) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
};
|
||||
|
||||
dialogPolyfill.needsCentering = function(dialog) {
|
||||
var computedStyle = window.getComputedStyle(dialog);
|
||||
if (computedStyle.position !== 'absolute') {
|
||||
return false;
|
||||
}
|
||||
|
||||
// We must determine whether the top/bottom specified value is non-auto. In
|
||||
// WebKit/Blink, checking computedStyle.top == 'auto' is sufficient, but
|
||||
// Firefox returns the used value. So we do this crazy thing instead: check
|
||||
// the inline style and then go through CSS rules.
|
||||
if ((dialog.style.top !== 'auto' && dialog.style.top !== '') ||
|
||||
(dialog.style.bottom !== 'auto' && dialog.style.bottom !== '')) {
|
||||
return false;
|
||||
}
|
||||
return !dialogPolyfill.isInlinePositionSetByStylesheet(dialog);
|
||||
};
|
||||
|
||||
/**
|
||||
* @param {!Element} element to force upgrade
|
||||
*/
|
||||
dialogPolyfill.forceRegisterDialog = function(element) {
|
||||
if (window.HTMLDialogElement || element.showModal) {
|
||||
console.warn('This browser already supports <dialog>, the polyfill ' +
|
||||
'may not work correctly', element);
|
||||
}
|
||||
if (element.localName !== 'dialog') {
|
||||
throw new Error('Failed to register dialog: The element is not a dialog.');
|
||||
}
|
||||
new dialogPolyfillInfo(/** @type {!HTMLDialogElement} */ (element));
|
||||
};
|
||||
|
||||
/**
|
||||
* @param {!Element} element to upgrade, if necessary
|
||||
*/
|
||||
dialogPolyfill.registerDialog = function(element) {
|
||||
if (!element.showModal) {
|
||||
dialogPolyfill.forceRegisterDialog(element);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* @constructor
|
||||
*/
|
||||
dialogPolyfill.DialogManager = function() {
|
||||
/** @type {!Array<!dialogPolyfillInfo>} */
|
||||
this.pendingDialogStack = [];
|
||||
|
||||
var checkDOM = this.checkDOM_.bind(this);
|
||||
|
||||
// The overlay is used to simulate how a modal dialog blocks the document.
|
||||
// The blocking dialog is positioned on top of the overlay, and the rest of
|
||||
// the dialogs on the pending dialog stack are positioned below it. In the
|
||||
// actual implementation, the modal dialog stacking is controlled by the
|
||||
// top layer, where z-index has no effect.
|
||||
this.overlay = document.createElement('div');
|
||||
this.overlay.className = '_poly_dialog_overlay';
|
||||
this.overlay.addEventListener('click', function(e) {
|
||||
this.forwardTab_ = undefined;
|
||||
e.stopPropagation();
|
||||
checkDOM([]); // sanity-check DOM
|
||||
}.bind(this));
|
||||
|
||||
this.handleKey_ = this.handleKey_.bind(this);
|
||||
this.handleFocus_ = this.handleFocus_.bind(this);
|
||||
|
||||
this.zIndexLow_ = 100000;
|
||||
this.zIndexHigh_ = 100000 + 150;
|
||||
|
||||
this.forwardTab_ = undefined;
|
||||
|
||||
if ('MutationObserver' in window) {
|
||||
this.mo_ = new MutationObserver(function(records) {
|
||||
var removed = [];
|
||||
records.forEach(function(rec) {
|
||||
for (var i = 0, c; c = rec.removedNodes[i]; ++i) {
|
||||
if (!(c instanceof Element)) {
|
||||
continue;
|
||||
} else if (c.localName === 'dialog') {
|
||||
removed.push(c);
|
||||
}
|
||||
removed = removed.concat(c.querySelectorAll('dialog'));
|
||||
}
|
||||
});
|
||||
removed.length && checkDOM(removed);
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Called on the first modal dialog being shown. Adds the overlay and related
|
||||
* handlers.
|
||||
*/
|
||||
dialogPolyfill.DialogManager.prototype.blockDocument = function() {
|
||||
document.documentElement.addEventListener('focus', this.handleFocus_, true);
|
||||
document.addEventListener('keydown', this.handleKey_);
|
||||
this.mo_ && this.mo_.observe(document, {childList: true, subtree: true});
|
||||
};
|
||||
|
||||
/**
|
||||
* Called on the first modal dialog being removed, i.e., when no more modal
|
||||
* dialogs are visible.
|
||||
*/
|
||||
dialogPolyfill.DialogManager.prototype.unblockDocument = function() {
|
||||
document.documentElement.removeEventListener('focus', this.handleFocus_, true);
|
||||
document.removeEventListener('keydown', this.handleKey_);
|
||||
this.mo_ && this.mo_.disconnect();
|
||||
};
|
||||
|
||||
/**
|
||||
* Updates the stacking of all known dialogs.
|
||||
*/
|
||||
dialogPolyfill.DialogManager.prototype.updateStacking = function() {
|
||||
var zIndex = this.zIndexHigh_;
|
||||
|
||||
for (var i = 0, dpi; dpi = this.pendingDialogStack[i]; ++i) {
|
||||
dpi.updateZIndex(--zIndex, --zIndex);
|
||||
if (i === 0) {
|
||||
this.overlay.style.zIndex = --zIndex;
|
||||
}
|
||||
}
|
||||
|
||||
// Make the overlay a sibling of the dialog itself.
|
||||
var last = this.pendingDialogStack[0];
|
||||
if (last) {
|
||||
var p = last.dialog.parentNode || document.body;
|
||||
p.appendChild(this.overlay);
|
||||
} else if (this.overlay.parentNode) {
|
||||
this.overlay.parentNode.removeChild(this.overlay);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* @param {Element} candidate to check if contained or is the top-most modal dialog
|
||||
* @return {boolean} whether candidate is contained in top dialog
|
||||
*/
|
||||
dialogPolyfill.DialogManager.prototype.containedByTopDialog_ = function(candidate) {
|
||||
while (candidate = findNearestDialog(candidate)) {
|
||||
for (var i = 0, dpi; dpi = this.pendingDialogStack[i]; ++i) {
|
||||
if (dpi.dialog === candidate) {
|
||||
return i === 0; // only valid if top-most
|
||||
}
|
||||
}
|
||||
candidate = candidate.parentElement;
|
||||
}
|
||||
return false;
|
||||
};
|
||||
|
||||
dialogPolyfill.DialogManager.prototype.handleFocus_ = function(event) {
|
||||
var target = event.composedPath ? event.composedPath()[0] : event.target;
|
||||
|
||||
if (this.containedByTopDialog_(target)) { return; }
|
||||
|
||||
if (document.activeElement === document.documentElement) { return; }
|
||||
|
||||
event.preventDefault();
|
||||
event.stopPropagation();
|
||||
safeBlur(/** @type {Element} */ (target));
|
||||
|
||||
if (this.forwardTab_ === undefined) { return; } // move focus only from a tab key
|
||||
|
||||
var dpi = this.pendingDialogStack[0];
|
||||
var dialog = dpi.dialog;
|
||||
var position = dialog.compareDocumentPosition(target);
|
||||
if (position & Node.DOCUMENT_POSITION_PRECEDING) {
|
||||
if (this.forwardTab_) {
|
||||
// forward
|
||||
dpi.focus_();
|
||||
} else if (target !== document.documentElement) {
|
||||
// backwards if we're not already focused on <html>
|
||||
document.documentElement.focus();
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
};
|
||||
|
||||
dialogPolyfill.DialogManager.prototype.handleKey_ = function(event) {
|
||||
this.forwardTab_ = undefined;
|
||||
if (event.keyCode === 27) {
|
||||
event.preventDefault();
|
||||
event.stopPropagation();
|
||||
var cancelEvent = new supportCustomEvent('cancel', {
|
||||
bubbles: false,
|
||||
cancelable: true
|
||||
});
|
||||
var dpi = this.pendingDialogStack[0];
|
||||
if (dpi && safeDispatchEvent(dpi.dialog, cancelEvent)) {
|
||||
dpi.dialog.close();
|
||||
}
|
||||
} else if (event.keyCode === 9) {
|
||||
this.forwardTab_ = !event.shiftKey;
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Finds and downgrades any known modal dialogs that are no longer displayed. Dialogs that are
|
||||
* removed and immediately readded don't stay modal, they become normal.
|
||||
*
|
||||
* @param {!Array<!HTMLDialogElement>} removed that have definitely been removed
|
||||
*/
|
||||
dialogPolyfill.DialogManager.prototype.checkDOM_ = function(removed) {
|
||||
// This operates on a clone because it may cause it to change. Each change also calls
|
||||
// updateStacking, which only actually needs to happen once. But who removes many modal dialogs
|
||||
// at a time?!
|
||||
var clone = this.pendingDialogStack.slice();
|
||||
clone.forEach(function(dpi) {
|
||||
if (removed.indexOf(dpi.dialog) !== -1) {
|
||||
dpi.downgradeModal();
|
||||
} else {
|
||||
dpi.maybeHideModal();
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* @param {!dialogPolyfillInfo} dpi
|
||||
* @return {boolean} whether the dialog was allowed
|
||||
*/
|
||||
dialogPolyfill.DialogManager.prototype.pushDialog = function(dpi) {
|
||||
var allowed = (this.zIndexHigh_ - this.zIndexLow_) / 2 - 1;
|
||||
if (this.pendingDialogStack.length >= allowed) {
|
||||
return false;
|
||||
}
|
||||
if (this.pendingDialogStack.unshift(dpi) === 1) {
|
||||
this.blockDocument();
|
||||
}
|
||||
this.updateStacking();
|
||||
return true;
|
||||
};
|
||||
|
||||
/**
|
||||
* @param {!dialogPolyfillInfo} dpi
|
||||
*/
|
||||
dialogPolyfill.DialogManager.prototype.removeDialog = function(dpi) {
|
||||
var index = this.pendingDialogStack.indexOf(dpi);
|
||||
if (index === -1) { return; }
|
||||
|
||||
this.pendingDialogStack.splice(index, 1);
|
||||
if (this.pendingDialogStack.length === 0) {
|
||||
this.unblockDocument();
|
||||
}
|
||||
this.updateStacking();
|
||||
};
|
||||
|
||||
dialogPolyfill.dm = new dialogPolyfill.DialogManager();
|
||||
dialogPolyfill.formSubmitter = null;
|
||||
dialogPolyfill.imagemapUseValue = null;
|
||||
|
||||
/**
|
||||
* Installs global handlers, such as click listers and native method overrides. These are needed
|
||||
* even if a no dialog is registered, as they deal with <form method="dialog">.
|
||||
*/
|
||||
if (window.HTMLDialogElement === undefined) {
|
||||
|
||||
/**
|
||||
* If HTMLFormElement translates method="DIALOG" into 'get', then replace the descriptor with
|
||||
* one that returns the correct value.
|
||||
*/
|
||||
var testForm = document.createElement('form');
|
||||
testForm.setAttribute('method', 'dialog');
|
||||
if (testForm.method !== 'dialog') {
|
||||
var methodDescriptor = Object.getOwnPropertyDescriptor(HTMLFormElement.prototype, 'method');
|
||||
if (methodDescriptor) {
|
||||
// nb. Some older iOS and older PhantomJS fail to return the descriptor. Don't do anything
|
||||
// and don't bother to update the element.
|
||||
var realGet = methodDescriptor.get;
|
||||
methodDescriptor.get = function() {
|
||||
if (isFormMethodDialog(this)) {
|
||||
return 'dialog';
|
||||
}
|
||||
return realGet.call(this);
|
||||
};
|
||||
var realSet = methodDescriptor.set;
|
||||
/** @this {HTMLElement} */
|
||||
methodDescriptor.set = function(v) {
|
||||
if (typeof v === 'string' && v.toLowerCase() === 'dialog') {
|
||||
return this.setAttribute('method', v);
|
||||
}
|
||||
return realSet.call(this, v);
|
||||
};
|
||||
Object.defineProperty(HTMLFormElement.prototype, 'method', methodDescriptor);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Global 'click' handler, to capture the <input type="submit"> or <button> element which has
|
||||
* submitted a <form method="dialog">. Needed as Safari and others don't report this inside
|
||||
* document.activeElement.
|
||||
*/
|
||||
document.addEventListener('click', function(ev) {
|
||||
dialogPolyfill.formSubmitter = null;
|
||||
dialogPolyfill.imagemapUseValue = null;
|
||||
if (ev.defaultPrevented) { return; } // e.g. a submit which prevents default submission
|
||||
|
||||
var target = /** @type {Element} */ (ev.target);
|
||||
if ('composedPath' in ev) {
|
||||
var path = ev.composedPath();
|
||||
target = path.shift() || target;
|
||||
}
|
||||
if (!target || !isFormMethodDialog(target.form)) { return; }
|
||||
|
||||
var valid = (target.type === 'submit' && ['button', 'input'].indexOf(target.localName) > -1);
|
||||
if (!valid) {
|
||||
if (!(target.localName === 'input' && target.type === 'image')) { return; }
|
||||
// this is a <input type="image">, which can submit forms
|
||||
dialogPolyfill.imagemapUseValue = ev.offsetX + ',' + ev.offsetY;
|
||||
}
|
||||
|
||||
var dialog = findNearestDialog(target);
|
||||
if (!dialog) { return; }
|
||||
|
||||
dialogPolyfill.formSubmitter = target;
|
||||
|
||||
}, false);
|
||||
|
||||
/**
|
||||
* Global 'submit' handler. This handles submits of `method="dialog"` which are invalid, i.e.,
|
||||
* outside a dialog. They get prevented.
|
||||
*/
|
||||
document.addEventListener('submit', function(ev) {
|
||||
var form = ev.target;
|
||||
var dialog = findNearestDialog(form);
|
||||
if (dialog) {
|
||||
return; // ignore, handle there
|
||||
}
|
||||
|
||||
var submitter = findFormSubmitter(ev);
|
||||
var formmethod = submitter && submitter.getAttribute('formmethod') || form.getAttribute('method');
|
||||
if (formmethod === 'dialog') {
|
||||
ev.preventDefault();
|
||||
}
|
||||
});
|
||||
|
||||
/**
|
||||
* Replace the native HTMLFormElement.submit() method, as it won't fire the
|
||||
* submit event and give us a chance to respond.
|
||||
*/
|
||||
var nativeFormSubmit = HTMLFormElement.prototype.submit;
|
||||
var replacementFormSubmit = function () {
|
||||
if (!isFormMethodDialog(this)) {
|
||||
return nativeFormSubmit.call(this);
|
||||
}
|
||||
var dialog = findNearestDialog(this);
|
||||
dialog && dialog.close();
|
||||
};
|
||||
HTMLFormElement.prototype.submit = replacementFormSubmit;
|
||||
}
|
||||
|
||||
export default dialogPolyfill;
|
1
public/lib/epub.min.js
vendored
Normal file
1
public/lib/epub.min.js
vendored
Normal file
File diff suppressed because one or more lines are too long
197
public/lib/eventemitter.js
Normal file
197
public/lib/eventemitter.js
Normal file
@@ -0,0 +1,197 @@
|
||||
/* Polyfill indexOf. */
|
||||
var indexOf;
|
||||
|
||||
if (typeof Array.prototype.indexOf === 'function') {
|
||||
indexOf = function (haystack, needle) {
|
||||
return haystack.indexOf(needle);
|
||||
};
|
||||
} else {
|
||||
indexOf = function (haystack, needle) {
|
||||
var i = 0, length = haystack.length, idx = -1, found = false;
|
||||
|
||||
while (i < length && !found) {
|
||||
if (haystack[i] === needle) {
|
||||
idx = i;
|
||||
found = true;
|
||||
}
|
||||
|
||||
i++;
|
||||
}
|
||||
|
||||
return idx;
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
/* Polyfill EventEmitter. */
|
||||
/**
|
||||
* Creates an event emitter.
|
||||
* @param {string[]} autoFireAfterEmit Auto-fire event names
|
||||
*/
|
||||
var EventEmitter = function (autoFireAfterEmit = []) {
|
||||
this.events = {};
|
||||
this.autoFireLastArgs = new Map();
|
||||
this.autoFireAfterEmit = new Set(autoFireAfterEmit);
|
||||
};
|
||||
|
||||
/**
|
||||
* Adds a listener to an event.
|
||||
* @param {string} event Event name
|
||||
* @param {function} listener Event listener
|
||||
* @returns
|
||||
*/
|
||||
EventEmitter.prototype.on = function (event, listener) {
|
||||
// Unknown event used by external libraries?
|
||||
if (event === undefined) {
|
||||
console.trace('EventEmitter: Cannot listen to undefined event');
|
||||
return;
|
||||
}
|
||||
|
||||
if (typeof this.events[event] !== 'object') {
|
||||
this.events[event] = [];
|
||||
}
|
||||
|
||||
this.events[event].push(listener);
|
||||
|
||||
if (this.autoFireAfterEmit.has(event) && this.autoFireLastArgs.has(event)) {
|
||||
listener.apply(this, this.autoFireLastArgs.get(event));
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Makes the listener the last to be called when the event is emitted
|
||||
* @param {string} event Event name
|
||||
* @param {function} listener Event listener
|
||||
*/
|
||||
EventEmitter.prototype.makeLast = function (event, listener) {
|
||||
if (typeof this.events[event] !== 'object') {
|
||||
this.events[event] = [];
|
||||
}
|
||||
|
||||
const events = this.events[event];
|
||||
const idx = events.indexOf(listener);
|
||||
|
||||
if (idx > -1) {
|
||||
events.splice(idx, 1);
|
||||
}
|
||||
|
||||
events.push(listener);
|
||||
|
||||
if (this.autoFireAfterEmit.has(event) && this.autoFireLastArgs.has(event)) {
|
||||
listener.apply(this, this.autoFireLastArgs.get(event));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Makes the listener the first to be called when the event is emitted
|
||||
* @param {string} event Event name
|
||||
* @param {function} listener Event listener
|
||||
*/
|
||||
EventEmitter.prototype.makeFirst = function (event, listener) {
|
||||
if (typeof this.events[event] !== 'object') {
|
||||
this.events[event] = [];
|
||||
}
|
||||
|
||||
const events = this.events[event];
|
||||
const idx = events.indexOf(listener);
|
||||
|
||||
if (idx > -1) {
|
||||
events.splice(idx, 1);
|
||||
}
|
||||
|
||||
events.unshift(listener);
|
||||
|
||||
if (this.autoFireAfterEmit.has(event) && this.autoFireLastArgs.has(event)) {
|
||||
listener.apply(this, this.autoFireLastArgs.get(event));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes a listener from an event.
|
||||
* @param {string} event Event name
|
||||
* @param {function} listener Event listener
|
||||
*/
|
||||
EventEmitter.prototype.removeListener = function (event, listener) {
|
||||
var idx;
|
||||
|
||||
if (typeof this.events[event] === 'object') {
|
||||
idx = indexOf(this.events[event], listener);
|
||||
|
||||
if (idx > -1) {
|
||||
this.events[event].splice(idx, 1);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Emits an event with optional arguments.
|
||||
* @param {string} event Event name
|
||||
*/
|
||||
EventEmitter.prototype.emit = async function (event) {
|
||||
let args = [].slice.call(arguments, 1);
|
||||
if (localStorage.getItem('eventTracing') === 'true') {
|
||||
console.trace('Event emitted: ' + event, args);
|
||||
} else {
|
||||
console.debug('Event emitted: ' + event);
|
||||
}
|
||||
|
||||
let i, listeners, length;
|
||||
|
||||
if (typeof this.events[event] === 'object') {
|
||||
listeners = this.events[event].slice();
|
||||
length = listeners.length;
|
||||
|
||||
for (i = 0; i < length; i++) {
|
||||
try {
|
||||
await listeners[i].apply(this, args);
|
||||
}
|
||||
catch (err) {
|
||||
console.error(err);
|
||||
console.trace('Error in event listener');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (this.autoFireAfterEmit.has(event)) {
|
||||
this.autoFireLastArgs.set(event, args);
|
||||
}
|
||||
};
|
||||
|
||||
EventEmitter.prototype.emitAndWait = function (event) {
|
||||
let args = [].slice.call(arguments, 1);
|
||||
if (localStorage.getItem('eventTracing') === 'true') {
|
||||
console.trace('Event emitted: ' + event, args);
|
||||
} else {
|
||||
console.debug('Event emitted: ' + event);
|
||||
}
|
||||
|
||||
let i, listeners, length;
|
||||
|
||||
if (typeof this.events[event] === 'object') {
|
||||
listeners = this.events[event].slice();
|
||||
length = listeners.length;
|
||||
|
||||
for (i = 0; i < length; i++) {
|
||||
try {
|
||||
listeners[i].apply(this, args);
|
||||
}
|
||||
catch (err) {
|
||||
console.error(err);
|
||||
console.trace('Error in event listener');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (this.autoFireAfterEmit.has(event)) {
|
||||
this.autoFireLastArgs.set(event, args);
|
||||
}
|
||||
};
|
||||
|
||||
EventEmitter.prototype.once = function (event, listener) {
|
||||
this.on(event, function g() {
|
||||
this.removeListener(event, g);
|
||||
listener.apply(this, arguments);
|
||||
});
|
||||
};
|
||||
|
||||
export { EventEmitter }
|
2
public/lib/jquery-3.5.1.min.js
vendored
Normal file
2
public/lib/jquery-3.5.1.min.js
vendored
Normal file
File diff suppressed because one or more lines are too long
2
public/lib/jquery-cookie-1.4.1.min.js
vendored
Normal file
2
public/lib/jquery-cookie-1.4.1.min.js
vendored
Normal file
@@ -0,0 +1,2 @@
|
||||
/*! jquery.cookie v1.4.1 | MIT */
|
||||
!function(a){"function"==typeof define&&define.amd?define(["jquery"],a):"object"==typeof exports?a(require("jquery")):a(jQuery)}(function(a){function b(a){return h.raw?a:encodeURIComponent(a)}function c(a){return h.raw?a:decodeURIComponent(a)}function d(a){return b(h.json?JSON.stringify(a):String(a))}function e(a){0===a.indexOf('"')&&(a=a.slice(1,-1).replace(/\\"/g,'"').replace(/\\\\/g,"\\"));try{return a=decodeURIComponent(a.replace(g," ")),h.json?JSON.parse(a):a}catch(b){}}function f(b,c){var d=h.raw?b:e(b);return a.isFunction(c)?c(d):d}var g=/\+/g,h=a.cookie=function(e,g,i){if(void 0!==g&&!a.isFunction(g)){if(i=a.extend({},h.defaults,i),"number"==typeof i.expires){var j=i.expires,k=i.expires=new Date;k.setTime(+k+864e5*j)}return document.cookie=[b(e),"=",d(g),i.expires?"; expires="+i.expires.toUTCString():"",i.path?"; path="+i.path:"",i.domain?"; domain="+i.domain:"",i.secure?"; secure":""].join("")}for(var l=e?void 0:{},m=document.cookie?document.cookie.split("; "):[],n=0,o=m.length;o>n;n++){var p=m[n].split("="),q=c(p.shift()),r=p.join("=");if(e&&e===q){l=f(r,g);break}e||void 0===(r=f(r))||(l[q]=r)}return l};h.defaults={},a.removeCookie=function(b,c){return void 0===a.cookie(b)?!1:(a.cookie(b,"",a.extend({},c,{expires:-1})),!a.cookie(b))}});
|
10
public/lib/jquery-cropper.min.js
vendored
Normal file
10
public/lib/jquery-cropper.min.js
vendored
Normal file
@@ -0,0 +1,10 @@
|
||||
/*!
|
||||
* jQuery Cropper v1.0.1
|
||||
* https://fengyuanchen.github.io/jquery-cropper
|
||||
*
|
||||
* Copyright 2018-present Chen Fengyuan
|
||||
* Released under the MIT license
|
||||
*
|
||||
* Date: 2019-10-19T08:48:33.062Z
|
||||
*/
|
||||
!function(e,r){"object"==typeof exports&&"undefined"!=typeof module?r(require("jquery"),require("cropperjs")):"function"==typeof define&&define.amd?define(["jquery","cropperjs"],r):r((e=e||self).jQuery,e.Cropper)}(this,function(c,s){"use strict";if(c=c&&c.hasOwnProperty("default")?c.default:c,s=s&&s.hasOwnProperty("default")?s.default:s,c&&c.fn&&s){var e=c.fn.cropper,d="cropper";c.fn.cropper=function(p){for(var e=arguments.length,a=new Array(1<e?e-1:0),r=1;r<e;r++)a[r-1]=arguments[r];var u;return this.each(function(e,r){var t=c(r),n="destroy"===p,o=t.data(d);if(!o){if(n)return;var f=c.extend({},t.data(),c.isPlainObject(p)&&p);o=new s(r,f),t.data(d,o)}if("string"==typeof p){var i=o[p];c.isFunction(i)&&((u=i.apply(o,a))===o&&(u=void 0),n&&t.removeData(d))}}),void 0!==u?u:this},c.fn.cropper.Constructor=s,c.fn.cropper.setDefaults=s.setDefaults,c.fn.cropper.noConflict=function(){return c.fn.cropper=e,this}}});
|
6
public/lib/jquery-ui.min.js
vendored
Normal file
6
public/lib/jquery-ui.min.js
vendored
Normal file
File diff suppressed because one or more lines are too long
216
public/lib/jquery.izoomify.js
Normal file
216
public/lib/jquery.izoomify.js
Normal file
@@ -0,0 +1,216 @@
|
||||
/*!
|
||||
* @name: jquery-izoomify
|
||||
* @version: 1.0
|
||||
* @author: Carl Lomer Abia
|
||||
*/
|
||||
|
||||
(function ($) {
|
||||
var defaults = {
|
||||
callback: false,
|
||||
target: false,
|
||||
duration: 120,
|
||||
magnify: 1.2,
|
||||
touch: true,
|
||||
url: false
|
||||
};
|
||||
|
||||
var _izoomify = function (target, duration, magnify, url) {
|
||||
var xPos,
|
||||
yPos,
|
||||
$elTarget = $(target),
|
||||
$imgTarget = $elTarget.find('img:first'),
|
||||
imgOrigSrc = $imgTarget.attr('src'),
|
||||
imgSwapSrc,
|
||||
defaultOrigin = 'center top ' + 0 + 'px',
|
||||
resultOrigin,
|
||||
dUrl = 'data-izoomify-url',
|
||||
dMagnify = 'data-izoomify-magnify',
|
||||
dDuration = 'data-izoomify-duration',
|
||||
eClass = 'izoomify-in',
|
||||
eMagnify,
|
||||
eDuration;
|
||||
|
||||
function imageSource(imgSource) {
|
||||
var _img = new Image();
|
||||
_img.src = imgSource;
|
||||
return _img.src;
|
||||
}
|
||||
|
||||
function getImageAttribute($img, dataAttribute, defaultAttribute) {
|
||||
if ($img.attr(dataAttribute)) {
|
||||
return $img.attr(dataAttribute);
|
||||
}
|
||||
|
||||
return defaultAttribute;
|
||||
}
|
||||
|
||||
function getImageSource($img, dataImageSource, defaultImageSource) {
|
||||
if ($img.attr(dataImageSource)) {
|
||||
return imageSource($img.attr(dataImageSource));
|
||||
}
|
||||
|
||||
return defaultImageSource ? imageSource(defaultImageSource) : false;
|
||||
}
|
||||
|
||||
function getTouches(e) {
|
||||
return e.touches || e.originalEvent.touches;
|
||||
}
|
||||
|
||||
imgSwapSrc = getImageSource($imgTarget, dUrl, url);
|
||||
|
||||
eMagnify = getImageAttribute($imgTarget, dMagnify, magnify);
|
||||
|
||||
eDuration = getImageAttribute($imgTarget, dDuration, duration);
|
||||
|
||||
$elTarget
|
||||
.addClass(eClass)
|
||||
.css({
|
||||
'position': 'relative',
|
||||
'overflow': 'hidden'
|
||||
});
|
||||
|
||||
$imgTarget.css({
|
||||
'-webkit-transition-property': '-webkit-transform',
|
||||
'transition-property': '-webkit-transform',
|
||||
'-o-transition-property': 'transform',
|
||||
'transition-property': 'transform',
|
||||
'transition-property': 'transform, -webkit-transform',
|
||||
'-webkit-transition-timing-function': 'ease',
|
||||
'-o-transition-timing-function': 'ease',
|
||||
'transition-timing-function': 'ease',
|
||||
'-webkit-transition-duration': eDuration + 'ms',
|
||||
'-o-transition-duration': eDuration + 'ms',
|
||||
'transition-duration': eDuration + 'ms',
|
||||
'-webkit-transform': 'scale(1)',
|
||||
'-ms-transform': 'scale(1)',
|
||||
'transform': 'scale(1)',
|
||||
'-webkit-transform-origin': defaultOrigin,
|
||||
'-ms-transform-origin': defaultOrigin,
|
||||
'transform-origin': defaultOrigin
|
||||
});
|
||||
|
||||
return {
|
||||
moveStart: function (e, hasTouch) {
|
||||
var o = $(target).offset();
|
||||
|
||||
if (hasTouch) {
|
||||
e.preventDefault();
|
||||
xPos = getTouches(e)[0].clientX - o.left;
|
||||
yPos = getTouches(e)[0].clientY - o.top;
|
||||
} else {
|
||||
xPos = e.pageX - o.left;
|
||||
yPos = e.pageY - o.top;
|
||||
}
|
||||
|
||||
resultOrigin = xPos + 'px ' + yPos + 'px ' + 0 + 'px';
|
||||
|
||||
$imgTarget
|
||||
.css({
|
||||
'-webkit-transform': 'scale(' + eMagnify + ')',
|
||||
'-ms-transform': 'scale(' + eMagnify + ')',
|
||||
'transform': 'scale(' + eMagnify + ')',
|
||||
'-webkit-transform-origin': resultOrigin,
|
||||
'-ms-transform-origin': resultOrigin,
|
||||
'transform-origin': resultOrigin
|
||||
})
|
||||
.attr('src', imgSwapSrc || imgOrigSrc);
|
||||
},
|
||||
moveEnd: function () {
|
||||
this.reset();
|
||||
},
|
||||
reset: function () {
|
||||
resultOrigin = defaultOrigin;
|
||||
|
||||
$imgTarget
|
||||
.css({
|
||||
'-webkit-transform': 'scale(1)',
|
||||
'-ms-transform': 'scale(1)',
|
||||
'transform': 'scale(1)',
|
||||
'-webkit-transform-origin': resultOrigin,
|
||||
'-ms-transform-origin': resultOrigin,
|
||||
'transform-origin': resultOrigin
|
||||
})
|
||||
.attr('src', imgOrigSrc);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
$.fn.izoomify = function (options) {
|
||||
return this.each(function () {
|
||||
var settings = $.extend({}, defaults, options || {}),
|
||||
$target = settings.target && $(settings.target)[0] || this,
|
||||
src = this,
|
||||
$src = $(src),
|
||||
mouseStartEvents = 'mouseover.izoomify mousemove.izoomify',
|
||||
mouseEndEvents = 'mouseleave.izoomify mouseout.izoomify',
|
||||
touchStartEvents = 'touchstart.izoomify touchmove.izoomify',
|
||||
touchEndEvents = 'touchend.izoomify';
|
||||
|
||||
var izoomify = _izoomify($target, settings.duration, settings.magnify, settings.url);
|
||||
|
||||
function startEvent(e, hasTouch) {
|
||||
izoomify.moveStart(e, hasTouch);
|
||||
}
|
||||
|
||||
function endEvent($src) {
|
||||
izoomify.moveEnd();
|
||||
|
||||
if ($src) {
|
||||
$src
|
||||
.off(touchStartEvents)
|
||||
.off(touchEndEvents);
|
||||
}
|
||||
}
|
||||
|
||||
function resetImage() {
|
||||
izoomify.reset();
|
||||
}
|
||||
|
||||
$src.one('izoomify.destroy', function () {
|
||||
|
||||
$src.removeClass('izoomify-in');
|
||||
|
||||
resetImage();
|
||||
|
||||
$src
|
||||
.off(mouseStartEvents)
|
||||
.off(mouseEndEvents);
|
||||
|
||||
if (settings.touch) {
|
||||
$src
|
||||
.off(touchStartEvents)
|
||||
.off(touchStartEvents);
|
||||
}
|
||||
|
||||
$target.style.position = '';
|
||||
$target.style.overflow = '';
|
||||
|
||||
}.bind(this));
|
||||
|
||||
$src
|
||||
.on(mouseStartEvents, function (e) {
|
||||
startEvent(e);
|
||||
})
|
||||
.on(mouseEndEvents, function () {
|
||||
endEvent();
|
||||
});
|
||||
|
||||
if (settings.touch) {
|
||||
$src
|
||||
.on(touchStartEvents, function (e) {
|
||||
e.preventDefault();
|
||||
startEvent(e, true);
|
||||
})
|
||||
.on(touchEndEvents, function () {
|
||||
endEvent();
|
||||
});
|
||||
}
|
||||
|
||||
if ($.isFunction(settings.callback)) {
|
||||
settings.callback.call($src);
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
$.fn.izoomify.defaults = defaults;
|
||||
}(window.jQuery));
|
1
public/lib/jquery.transit.min.js
vendored
Normal file
1
public/lib/jquery.transit.min.js
vendored
Normal file
File diff suppressed because one or more lines are too long
249
public/lib/jquery.ui.touch-punch.min.js
vendored
Normal file
249
public/lib/jquery.ui.touch-punch.min.js
vendored
Normal file
@@ -0,0 +1,249 @@
|
||||
/*!
|
||||
* jQuery UI Touch Punch 1.0.9 as modified by RWAP Software
|
||||
* based on original touchpunch v0.2.3 which has not been updated since 2014
|
||||
*
|
||||
* Updates by RWAP Software to take account of various suggested changes on the original code issues
|
||||
*
|
||||
* Original: https://github.com/furf/jquery-ui-touch-punch
|
||||
* Copyright 2011–2014, Dave Furfero
|
||||
* Dual licensed under the MIT or GPL Version 2 licenses.
|
||||
*
|
||||
* Fork: https://github.com/RWAP/jquery-ui-touch-punch
|
||||
*
|
||||
* Depends:
|
||||
* jquery.ui.widget.js
|
||||
* jquery.ui.mouse.js
|
||||
*/
|
||||
|
||||
(function( factory ) {
|
||||
if ( typeof define === "function" && define.amd ) {
|
||||
|
||||
// AMD. Register as an anonymous module.
|
||||
define([ "jquery", "jquery-ui" ], factory );
|
||||
} else {
|
||||
|
||||
// Browser globals
|
||||
factory( jQuery );
|
||||
}
|
||||
}(function ($) {
|
||||
|
||||
// Detect touch support - Windows Surface devices and other touch devices
|
||||
$.mspointer = window.navigator.msPointerEnabled;
|
||||
$.touch = ( 'ontouchstart' in document
|
||||
|| 'ontouchstart' in window
|
||||
|| window.TouchEvent
|
||||
|| (window.DocumentTouch && document instanceof DocumentTouch)
|
||||
|| navigator.maxTouchPoints > 0
|
||||
|| navigator.msMaxTouchPoints > 0
|
||||
);
|
||||
|
||||
// Ignore browsers without touch or mouse support
|
||||
if ((!$.touch && !$.mspointer) || !$.ui.mouse) {
|
||||
return;
|
||||
}
|
||||
|
||||
let mouseProto = $.ui.mouse.prototype,
|
||||
_mouseInit = mouseProto._mouseInit,
|
||||
_mouseDestroy = mouseProto._mouseDestroy,
|
||||
touchHandled;
|
||||
|
||||
/**
|
||||
* Get the x,y position of a touch event
|
||||
* @param {Object} event A touch event
|
||||
*/
|
||||
function getTouchCoords (event) {
|
||||
return {
|
||||
x: event.originalEvent.changedTouches[0].pageX,
|
||||
y: event.originalEvent.changedTouches[0].pageY
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Simulate a mouse event based on a corresponding touch event
|
||||
* @param {Object} event A touch event
|
||||
* @param {String} simulatedType The corresponding mouse event
|
||||
*/
|
||||
function simulateMouseEvent (event, simulatedType) {
|
||||
|
||||
// Ignore multi-touch events
|
||||
if (event.originalEvent.touches.length > 1) {
|
||||
return;
|
||||
}
|
||||
|
||||
//Ignore input or textarea elements so user can still enter text
|
||||
if ($(event.target).is("input") || $(event.target).is("textarea")) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Prevent "Ignored attempt to cancel a touchmove event with cancelable=false" errors
|
||||
if (event.cancelable) {
|
||||
event.preventDefault();
|
||||
}
|
||||
|
||||
let touch = event.originalEvent.changedTouches[0],
|
||||
simulatedEvent = document.createEvent('MouseEvents');
|
||||
|
||||
// Initialize the simulated mouse event using the touch event's coordinates
|
||||
simulatedEvent.initMouseEvent(
|
||||
simulatedType, // type
|
||||
true, // bubbles
|
||||
true, // cancelable
|
||||
window, // view
|
||||
1, // detail
|
||||
touch.screenX, // screenX
|
||||
touch.screenY, // screenY
|
||||
touch.clientX, // clientX
|
||||
touch.clientY, // clientY
|
||||
false, // ctrlKey
|
||||
false, // altKey
|
||||
false, // shiftKey
|
||||
false, // metaKey
|
||||
0, // button
|
||||
null // relatedTarget
|
||||
);
|
||||
|
||||
// Dispatch the simulated event to the target element
|
||||
event.target.dispatchEvent(simulatedEvent);
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle the jQuery UI widget's touchstart events
|
||||
* @param {Object} event The widget element's touchstart event
|
||||
*/
|
||||
mouseProto._touchStart = function (event) {
|
||||
|
||||
let self = this;
|
||||
|
||||
// Interaction time
|
||||
this._startedMove = event.timeStamp;
|
||||
|
||||
// Track movement to determine if interaction was a click
|
||||
self._startPos = getTouchCoords(event);
|
||||
|
||||
// Ignore the event if another widget is already being handled
|
||||
if (touchHandled || !self._mouseCapture(event.originalEvent.changedTouches[0])) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Set the flag to prevent other widgets from inheriting the touch event
|
||||
touchHandled = true;
|
||||
|
||||
// Track movement to determine if interaction was a click
|
||||
self._touchMoved = false;
|
||||
|
||||
// Simulate the mouseover event
|
||||
simulateMouseEvent(event, 'mouseover');
|
||||
|
||||
// Simulate the mousemove event
|
||||
simulateMouseEvent(event, 'mousemove');
|
||||
|
||||
// Simulate the mousedown event
|
||||
simulateMouseEvent(event, 'mousedown');
|
||||
};
|
||||
|
||||
/**
|
||||
* Handle the jQuery UI widget's touchmove events
|
||||
* @param {Object} event The document's touchmove event
|
||||
*/
|
||||
mouseProto._touchMove = function (event) {
|
||||
|
||||
// Ignore event if not handled
|
||||
if (!touchHandled) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Interaction was moved
|
||||
this._touchMoved = true;
|
||||
|
||||
// Simulate the mousemove event
|
||||
simulateMouseEvent(event, 'mousemove');
|
||||
};
|
||||
|
||||
/**
|
||||
* Handle the jQuery UI widget's touchend events
|
||||
* @param {Object} event The document's touchend event
|
||||
*/
|
||||
mouseProto._touchEnd = function (event) {
|
||||
|
||||
// Ignore event if not handled
|
||||
if (!touchHandled) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Simulate the mouseup event
|
||||
simulateMouseEvent(event, 'mouseup');
|
||||
|
||||
// Simulate the mouseout event
|
||||
simulateMouseEvent(event, 'mouseout');
|
||||
|
||||
// If the touch interaction did not move, it should trigger a click
|
||||
// Check for this in two ways - length of time of simulation and distance moved
|
||||
// Allow for Apple Stylus to be used also
|
||||
let timeMoving = event.timeStamp - this._startedMove;
|
||||
if (!this._touchMoved || timeMoving < 500) {
|
||||
// Simulate the click event
|
||||
simulateMouseEvent(event, 'click');
|
||||
} else {
|
||||
let endPos = getTouchCoords(event);
|
||||
if ((Math.abs(endPos.x - this._startPos.x) < 10) && (Math.abs(endPos.y - this._startPos.y) < 10)) {
|
||||
|
||||
// If the touch interaction did not move, it should trigger a click
|
||||
if (!this._touchMoved || event.originalEvent.changedTouches[0].touchType === 'stylus') {
|
||||
// Simulate the click event
|
||||
simulateMouseEvent(event, 'click');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Unset the flag to determine the touch movement stopped
|
||||
this._touchMoved = false;
|
||||
|
||||
// Unset the flag to allow other widgets to inherit the touch event
|
||||
touchHandled = false;
|
||||
};
|
||||
|
||||
/**
|
||||
* A duck punch of the $.ui.mouse _mouseInit method to support touch events.
|
||||
* This method extends the widget with bound touch event handlers that
|
||||
* translate touch events to mouse events and pass them to the widget's
|
||||
* original mouse event handling methods.
|
||||
*/
|
||||
mouseProto._mouseInit = function () {
|
||||
|
||||
let self = this;
|
||||
|
||||
// Microsoft Surface Support = remove original touch Action
|
||||
if ($.support.mspointer) {
|
||||
self.element[0].style.msTouchAction = 'none';
|
||||
}
|
||||
|
||||
// Delegate the touch handlers to the widget's element
|
||||
self.element.on({
|
||||
touchstart: $.proxy(self, '_touchStart'),
|
||||
touchmove: $.proxy(self, '_touchMove'),
|
||||
touchend: $.proxy(self, '_touchEnd')
|
||||
});
|
||||
|
||||
// Call the original $.ui.mouse init method
|
||||
_mouseInit.call(self);
|
||||
};
|
||||
|
||||
/**
|
||||
* Remove the touch event handlers
|
||||
*/
|
||||
mouseProto._mouseDestroy = function () {
|
||||
|
||||
let self = this;
|
||||
|
||||
// Delegate the touch handlers to the widget's element
|
||||
self.element.off({
|
||||
touchstart: $.proxy(self, '_touchStart'),
|
||||
touchmove: $.proxy(self, '_touchMove'),
|
||||
touchend: $.proxy(self, '_touchEnd')
|
||||
});
|
||||
|
||||
// Call the original $.ui.mouse destroy method
|
||||
_mouseDestroy.call(self);
|
||||
};
|
||||
|
||||
}));
|
13
public/lib/jszip.min.js
vendored
Normal file
13
public/lib/jszip.min.js
vendored
Normal file
File diff suppressed because one or more lines are too long
1190
public/lib/pagination.js
Normal file
1190
public/lib/pagination.js
Normal file
File diff suppressed because it is too large
Load Diff
21
public/lib/pdf.min.mjs
Normal file
21
public/lib/pdf.min.mjs
Normal file
File diff suppressed because one or more lines are too long
21
public/lib/pdf.worker.min.mjs
Normal file
21
public/lib/pdf.worker.min.mjs
Normal file
File diff suppressed because one or more lines are too long
19
public/lib/polyfill.js
Normal file
19
public/lib/polyfill.js
Normal file
@@ -0,0 +1,19 @@
|
||||
// Polyfills for old Safari versions
|
||||
if (!Object.hasOwn) {
|
||||
Object.hasOwn = function (obj, prop) { return obj.hasOwnProperty(prop); }
|
||||
}
|
||||
|
||||
if (!Array.prototype.findLastIndex) {
|
||||
Array.prototype.findLastIndex = function (callback, thisArg) {
|
||||
for (let i = this.length - 1; i >= 0; i--) {
|
||||
if (callback.call(thisArg, this[i], i, this)) return i;
|
||||
}
|
||||
return -1;
|
||||
};
|
||||
}
|
||||
|
||||
if (!Array.prototype.toSorted) {
|
||||
Array.prototype.toSorted = function (compareFunction) {
|
||||
return this.slice().sort(compareFunction);
|
||||
};
|
||||
}
|
25
public/lib/select2-search-placeholder.js
Normal file
25
public/lib/select2-search-placeholder.js
Normal file
@@ -0,0 +1,25 @@
|
||||
(function($) {
|
||||
|
||||
var Defaults = $.fn.select2.amd.require('select2/defaults');
|
||||
|
||||
$.extend(Defaults.defaults, {
|
||||
searchInputPlaceholder: '',
|
||||
searchInputCssClass: '',
|
||||
});
|
||||
|
||||
var SearchDropdown = $.fn.select2.amd.require('select2/dropdown/search');
|
||||
|
||||
var _renderSearchDropdown = SearchDropdown.prototype.render;
|
||||
|
||||
SearchDropdown.prototype.render = function(decorated) {
|
||||
|
||||
// invoke parent method
|
||||
var $rendered = _renderSearchDropdown.apply(this, Array.prototype.slice.apply(arguments));
|
||||
|
||||
this.$search.attr('placeholder', this.options.get('searchInputPlaceholder'));
|
||||
this.$search.addClass(this.options.get('searchInputCssClass'));
|
||||
|
||||
return $rendered;
|
||||
};
|
||||
|
||||
})(window.jQuery);
|
2
public/lib/select2.min.js
vendored
Normal file
2
public/lib/select2.min.js
vendored
Normal file
File diff suppressed because one or more lines are too long
15
public/lib/structured-clone/LICENSE
Normal file
15
public/lib/structured-clone/LICENSE
Normal file
@@ -0,0 +1,15 @@
|
||||
ISC License
|
||||
|
||||
Copyright (c) 2021, Andrea Giammarchi, @WebReflection
|
||||
|
||||
Permission to use, copy, modify, and/or distribute this software for any
|
||||
purpose with or without fee is hereby granted, provided that the above
|
||||
copyright notice and this permission notice appear in all copies.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
|
||||
REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
|
||||
AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
|
||||
INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
|
||||
LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
|
||||
OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
|
||||
PERFORMANCE OF THIS SOFTWARE.
|
79
public/lib/structured-clone/deserialize.js
Normal file
79
public/lib/structured-clone/deserialize.js
Normal file
@@ -0,0 +1,79 @@
|
||||
import {
|
||||
VOID, PRIMITIVE,
|
||||
ARRAY, OBJECT,
|
||||
DATE, REGEXP, MAP, SET,
|
||||
ERROR, BIGINT
|
||||
} from './types.js';
|
||||
|
||||
const env = typeof self === 'object' ? self : globalThis;
|
||||
|
||||
const deserializer = ($, _) => {
|
||||
const as = (out, index) => {
|
||||
$.set(index, out);
|
||||
return out;
|
||||
};
|
||||
|
||||
const unpair = index => {
|
||||
if ($.has(index))
|
||||
return $.get(index);
|
||||
|
||||
const [type, value] = _[index];
|
||||
switch (type) {
|
||||
case PRIMITIVE:
|
||||
case VOID:
|
||||
return as(value, index);
|
||||
case ARRAY: {
|
||||
const arr = as([], index);
|
||||
for (const index of value)
|
||||
arr.push(unpair(index));
|
||||
return arr;
|
||||
}
|
||||
case OBJECT: {
|
||||
const object = as({}, index);
|
||||
for (const [key, index] of value)
|
||||
object[unpair(key)] = unpair(index);
|
||||
return object;
|
||||
}
|
||||
case DATE:
|
||||
return as(new Date(value), index);
|
||||
case REGEXP: {
|
||||
const {source, flags} = value;
|
||||
return as(new RegExp(source, flags), index);
|
||||
}
|
||||
case MAP: {
|
||||
const map = as(new Map, index);
|
||||
for (const [key, index] of value)
|
||||
map.set(unpair(key), unpair(index));
|
||||
return map;
|
||||
}
|
||||
case SET: {
|
||||
const set = as(new Set, index);
|
||||
for (const index of value)
|
||||
set.add(unpair(index));
|
||||
return set;
|
||||
}
|
||||
case ERROR: {
|
||||
const {name, message} = value;
|
||||
return as(new env[name](message), index);
|
||||
}
|
||||
case BIGINT:
|
||||
return as(BigInt(value), index);
|
||||
case 'BigInt':
|
||||
return as(Object(BigInt(value)), index);
|
||||
}
|
||||
return as(new env[type](value), index);
|
||||
};
|
||||
|
||||
return unpair;
|
||||
};
|
||||
|
||||
/**
|
||||
* @typedef {Array<string,any>} Record a type representation
|
||||
*/
|
||||
|
||||
/**
|
||||
* Returns a deserialized value from a serialized array of Records.
|
||||
* @param {Record[]} serialized a previously serialized value.
|
||||
* @returns {any}
|
||||
*/
|
||||
export const deserialize = serialized => deserializer(new Map, serialized)(0);
|
25
public/lib/structured-clone/index.js
Normal file
25
public/lib/structured-clone/index.js
Normal file
@@ -0,0 +1,25 @@
|
||||
import {deserialize} from './deserialize.js';
|
||||
import {serialize} from './serialize.js';
|
||||
|
||||
/**
|
||||
* @typedef {Array<string,any>} Record a type representation
|
||||
*/
|
||||
|
||||
/**
|
||||
* Returns an array of serialized Records.
|
||||
* @param {any} any a serializable value.
|
||||
* @param {{transfer?: any[], json?: boolean, lossy?: boolean}?} options an object with
|
||||
* a transfer option (ignored when polyfilled) and/or non standard fields that
|
||||
* fallback to the polyfill if present.
|
||||
* @returns {Record[]}
|
||||
*/
|
||||
export default typeof structuredClone === "function" ?
|
||||
/* c8 ignore start */
|
||||
(any, options) => (
|
||||
options && ('json' in options || 'lossy' in options) ?
|
||||
deserialize(serialize(any, options)) : structuredClone(any)
|
||||
) :
|
||||
(any, options) => deserialize(serialize(any, options));
|
||||
/* c8 ignore stop */
|
||||
|
||||
export {deserialize, serialize};
|
21
public/lib/structured-clone/json.js
Normal file
21
public/lib/structured-clone/json.js
Normal file
@@ -0,0 +1,21 @@
|
||||
/*! (c) Andrea Giammarchi - ISC */
|
||||
|
||||
import {deserialize} from './deserialize.js';
|
||||
import {serialize} from './serialize.js';
|
||||
|
||||
const {parse: $parse, stringify: $stringify} = JSON;
|
||||
const options = {json: true, lossy: true};
|
||||
|
||||
/**
|
||||
* Revive a previously stringified structured clone.
|
||||
* @param {string} str previously stringified data as string.
|
||||
* @returns {any} whatever was previously stringified as clone.
|
||||
*/
|
||||
export const parse = str => deserialize($parse(str));
|
||||
|
||||
/**
|
||||
* Represent a structured clone value as string.
|
||||
* @param {any} any some clone-able value to stringify.
|
||||
* @returns {string} the value stringified.
|
||||
*/
|
||||
export const stringify = any => $stringify(serialize(any, options));
|
6
public/lib/structured-clone/monkey-patch.js
Normal file
6
public/lib/structured-clone/monkey-patch.js
Normal file
@@ -0,0 +1,6 @@
|
||||
import structuredClone from './index.js';
|
||||
|
||||
if (!("structuredClone" in globalThis)) {
|
||||
console.debug("Monkey-patching structuredClone");
|
||||
globalThis.structuredClone = structuredClone;
|
||||
}
|
161
public/lib/structured-clone/serialize.js
Normal file
161
public/lib/structured-clone/serialize.js
Normal file
@@ -0,0 +1,161 @@
|
||||
import {
|
||||
VOID, PRIMITIVE,
|
||||
ARRAY, OBJECT,
|
||||
DATE, REGEXP, MAP, SET,
|
||||
ERROR, BIGINT
|
||||
} from './types.js';
|
||||
|
||||
const EMPTY = '';
|
||||
|
||||
const {toString} = {};
|
||||
const {keys} = Object;
|
||||
|
||||
const typeOf = value => {
|
||||
const type = typeof value;
|
||||
if (type !== 'object' || !value)
|
||||
return [PRIMITIVE, type];
|
||||
|
||||
const asString = toString.call(value).slice(8, -1);
|
||||
switch (asString) {
|
||||
case 'Array':
|
||||
return [ARRAY, EMPTY];
|
||||
case 'Object':
|
||||
return [OBJECT, EMPTY];
|
||||
case 'Date':
|
||||
return [DATE, EMPTY];
|
||||
case 'RegExp':
|
||||
return [REGEXP, EMPTY];
|
||||
case 'Map':
|
||||
return [MAP, EMPTY];
|
||||
case 'Set':
|
||||
return [SET, EMPTY];
|
||||
}
|
||||
|
||||
if (asString.includes('Array'))
|
||||
return [ARRAY, asString];
|
||||
|
||||
if (asString.includes('Error'))
|
||||
return [ERROR, asString];
|
||||
|
||||
return [OBJECT, asString];
|
||||
};
|
||||
|
||||
const shouldSkip = ([TYPE, type]) => (
|
||||
TYPE === PRIMITIVE &&
|
||||
(type === 'function' || type === 'symbol')
|
||||
);
|
||||
|
||||
const serializer = (strict, json, $, _) => {
|
||||
|
||||
const as = (out, value) => {
|
||||
const index = _.push(out) - 1;
|
||||
$.set(value, index);
|
||||
return index;
|
||||
};
|
||||
|
||||
const pair = value => {
|
||||
if ($.has(value))
|
||||
return $.get(value);
|
||||
|
||||
let [TYPE, type] = typeOf(value);
|
||||
switch (TYPE) {
|
||||
case PRIMITIVE: {
|
||||
let entry = value;
|
||||
switch (type) {
|
||||
case 'bigint':
|
||||
TYPE = BIGINT;
|
||||
entry = value.toString();
|
||||
break;
|
||||
case 'function':
|
||||
case 'symbol':
|
||||
if (strict)
|
||||
throw new TypeError('unable to serialize ' + type);
|
||||
entry = null;
|
||||
break;
|
||||
case 'undefined':
|
||||
return as([VOID], value);
|
||||
}
|
||||
return as([TYPE, entry], value);
|
||||
}
|
||||
case ARRAY: {
|
||||
if (type)
|
||||
return as([type, [...value]], value);
|
||||
|
||||
const arr = [];
|
||||
const index = as([TYPE, arr], value);
|
||||
for (const entry of value)
|
||||
arr.push(pair(entry));
|
||||
return index;
|
||||
}
|
||||
case OBJECT: {
|
||||
if (type) {
|
||||
switch (type) {
|
||||
case 'BigInt':
|
||||
return as([type, value.toString()], value);
|
||||
case 'Boolean':
|
||||
case 'Number':
|
||||
case 'String':
|
||||
return as([type, value.valueOf()], value);
|
||||
}
|
||||
}
|
||||
|
||||
if (json && ('toJSON' in value))
|
||||
return pair(value.toJSON());
|
||||
|
||||
const entries = [];
|
||||
const index = as([TYPE, entries], value);
|
||||
for (const key of keys(value)) {
|
||||
if (strict || !shouldSkip(typeOf(value[key])))
|
||||
entries.push([pair(key), pair(value[key])]);
|
||||
}
|
||||
return index;
|
||||
}
|
||||
case DATE:
|
||||
return as([TYPE, value.toISOString()], value);
|
||||
case REGEXP: {
|
||||
const {source, flags} = value;
|
||||
return as([TYPE, {source, flags}], value);
|
||||
}
|
||||
case MAP: {
|
||||
const entries = [];
|
||||
const index = as([TYPE, entries], value);
|
||||
for (const [key, entry] of value) {
|
||||
if (strict || !(shouldSkip(typeOf(key)) || shouldSkip(typeOf(entry))))
|
||||
entries.push([pair(key), pair(entry)]);
|
||||
}
|
||||
return index;
|
||||
}
|
||||
case SET: {
|
||||
const entries = [];
|
||||
const index = as([TYPE, entries], value);
|
||||
for (const entry of value) {
|
||||
if (strict || !shouldSkip(typeOf(entry)))
|
||||
entries.push(pair(entry));
|
||||
}
|
||||
return index;
|
||||
}
|
||||
}
|
||||
|
||||
const {message} = value;
|
||||
return as([TYPE, {name: type, message}], value);
|
||||
};
|
||||
|
||||
return pair;
|
||||
};
|
||||
|
||||
/**
|
||||
* @typedef {Array<string,any>} Record a type representation
|
||||
*/
|
||||
|
||||
/**
|
||||
* Returns an array of serialized Records.
|
||||
* @param {any} value a serializable value.
|
||||
* @param {{json?: boolean, lossy?: boolean}?} options an object with a `lossy` or `json` property that,
|
||||
* if `true`, will not throw errors on incompatible types, and behave more
|
||||
* like JSON stringify would behave. Symbol and Function will be discarded.
|
||||
* @returns {Record[]}
|
||||
*/
|
||||
export const serialize = (value, {json, lossy} = {}) => {
|
||||
const _ = [];
|
||||
return serializer(!(json || lossy), !!json, new Map, _)(value), _;
|
||||
};
|
11
public/lib/structured-clone/types.js
Normal file
11
public/lib/structured-clone/types.js
Normal file
@@ -0,0 +1,11 @@
|
||||
export const VOID = -1;
|
||||
export const PRIMITIVE = 0;
|
||||
export const ARRAY = 1;
|
||||
export const OBJECT = 2;
|
||||
export const DATE = 3;
|
||||
export const REGEXP = 4;
|
||||
export const MAP = 5;
|
||||
export const SET = 6;
|
||||
export const ERROR = 7;
|
||||
export const BIGINT = 8;
|
||||
// export const SYMBOL = 9;
|
165
public/lib/swiped-events.js
Normal file
165
public/lib/swiped-events.js
Normal file
@@ -0,0 +1,165 @@
|
||||
/*!
|
||||
* swiped-events.js - v@version@
|
||||
* Pure JavaScript swipe events
|
||||
* https://github.com/john-doherty/swiped-events
|
||||
* @inspiration https://stackoverflow.com/questions/16348031/disable-scrolling-when-touch-moving-certain-element
|
||||
* @author John Doherty <www.johndoherty.info>
|
||||
* @license MIT
|
||||
*/
|
||||
(function (window, document) {
|
||||
|
||||
'use strict';
|
||||
|
||||
// patch CustomEvent to allow constructor creation (IE/Chrome)
|
||||
if (typeof window.CustomEvent !== 'function') {
|
||||
|
||||
window.CustomEvent = function (event, params) {
|
||||
|
||||
params = params || { bubbles: false, cancelable: false, detail: undefined };
|
||||
|
||||
var evt = document.createEvent('CustomEvent');
|
||||
evt.initCustomEvent(event, params.bubbles, params.cancelable, params.detail);
|
||||
return evt;
|
||||
};
|
||||
|
||||
window.CustomEvent.prototype = window.Event.prototype;
|
||||
}
|
||||
|
||||
document.addEventListener('touchstart', handleTouchStart, false);
|
||||
document.addEventListener('touchmove', handleTouchMove, false);
|
||||
document.addEventListener('touchend', handleTouchEnd, false);
|
||||
|
||||
var xDown = null;
|
||||
var yDown = null;
|
||||
var xDiff = null;
|
||||
var yDiff = null;
|
||||
var timeDown = null;
|
||||
var startEl = null;
|
||||
|
||||
/**
|
||||
* Fires swiped event if swipe detected on touchend
|
||||
* @param {object} e - browser event object
|
||||
* @returns {void}
|
||||
*/
|
||||
function handleTouchEnd(e) {
|
||||
|
||||
// if the user released on a different target, cancel!
|
||||
if (startEl !== e.target) return;
|
||||
|
||||
var swipeThreshold = parseInt(getNearestAttribute(startEl, 'data-swipe-threshold', '20'), 10); // default 20 units
|
||||
var swipeUnit = getNearestAttribute(startEl, 'data-swipe-unit', 'px'); // default px
|
||||
var swipeTimeout = parseInt(getNearestAttribute(startEl, 'data-swipe-timeout', '500'), 10); // default 500ms
|
||||
var timeDiff = Date.now() - timeDown;
|
||||
var eventType = '';
|
||||
var changedTouches = e.changedTouches || e.touches || [];
|
||||
|
||||
if (swipeUnit === 'vh') {
|
||||
swipeThreshold = Math.round((swipeThreshold / 100) * document.documentElement.clientHeight); // get percentage of viewport height in pixels
|
||||
}
|
||||
if (swipeUnit === 'vw') {
|
||||
swipeThreshold = Math.round((swipeThreshold / 100) * document.documentElement.clientWidth); // get percentage of viewport height in pixels
|
||||
}
|
||||
|
||||
if (Math.abs(xDiff) > Math.abs(yDiff)) { // most significant
|
||||
if (Math.abs(xDiff) > swipeThreshold && timeDiff < swipeTimeout) {
|
||||
if (xDiff > 0) {
|
||||
eventType = 'swiped-left';
|
||||
}
|
||||
else {
|
||||
eventType = 'swiped-right';
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (Math.abs(yDiff) > swipeThreshold && timeDiff < swipeTimeout) {
|
||||
if (yDiff > 0) {
|
||||
eventType = 'swiped-up';
|
||||
}
|
||||
else {
|
||||
eventType = 'swiped-down';
|
||||
}
|
||||
}
|
||||
|
||||
if (eventType !== '') {
|
||||
|
||||
var eventData = {
|
||||
dir: eventType.replace(/swiped-/, ''),
|
||||
touchType: (changedTouches[0] || {}).touchType || 'direct',
|
||||
xStart: parseInt(xDown, 10),
|
||||
xEnd: parseInt((changedTouches[0] || {}).clientX || -1, 10),
|
||||
yStart: parseInt(yDown, 10),
|
||||
yEnd: parseInt((changedTouches[0] || {}).clientY || -1, 10)
|
||||
};
|
||||
|
||||
// fire `swiped` event event on the element that started the swipe
|
||||
startEl.dispatchEvent(new CustomEvent('swiped', { bubbles: true, cancelable: true, detail: eventData }));
|
||||
|
||||
// fire `swiped-dir` event on the element that started the swipe
|
||||
startEl.dispatchEvent(new CustomEvent(eventType, { bubbles: true, cancelable: true, detail: eventData }));
|
||||
}
|
||||
|
||||
// reset values
|
||||
xDown = null;
|
||||
yDown = null;
|
||||
timeDown = null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Records current location on touchstart event
|
||||
* @param {object} e - browser event object
|
||||
* @returns {void}
|
||||
*/
|
||||
function handleTouchStart(e) {
|
||||
|
||||
// if the element has data-swipe-ignore="true" we stop listening for swipe events
|
||||
if (e.target.getAttribute('data-swipe-ignore') === 'true') return;
|
||||
|
||||
startEl = e.target;
|
||||
|
||||
timeDown = Date.now();
|
||||
xDown = e.touches[0].clientX;
|
||||
yDown = e.touches[0].clientY;
|
||||
xDiff = 0;
|
||||
yDiff = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Records location diff in px on touchmove event
|
||||
* @param {object} e - browser event object
|
||||
* @returns {void}
|
||||
*/
|
||||
function handleTouchMove(e) {
|
||||
|
||||
if (!xDown || !yDown) return;
|
||||
|
||||
var xUp = e.touches[0].clientX;
|
||||
var yUp = e.touches[0].clientY;
|
||||
|
||||
xDiff = xDown - xUp;
|
||||
yDiff = yDown - yUp;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets attribute off HTML element or nearest parent
|
||||
* @param {object} el - HTML element to retrieve attribute from
|
||||
* @param {string} attributeName - name of the attribute
|
||||
* @param {any} defaultValue - default value to return if no match found
|
||||
* @returns {any} attribute value or defaultValue
|
||||
*/
|
||||
function getNearestAttribute(el, attributeName, defaultValue) {
|
||||
|
||||
// walk up the dom tree looking for attributeName
|
||||
while (el && el !== document.documentElement) {
|
||||
|
||||
var attributeValue = el.getAttribute(attributeName);
|
||||
|
||||
if (attributeValue) {
|
||||
return attributeValue;
|
||||
}
|
||||
|
||||
el = el.parentNode;
|
||||
}
|
||||
|
||||
return defaultValue;
|
||||
}
|
||||
|
||||
}(window, document));
|
1
public/lib/toastr.js.map
Normal file
1
public/lib/toastr.js.map
Normal file
File diff suppressed because one or more lines are too long
7
public/lib/toastr.min.js
vendored
Normal file
7
public/lib/toastr.min.js
vendored
Normal file
File diff suppressed because one or more lines are too long
87
public/lib/toolcool-color-picker.js
Normal file
87
public/lib/toolcool-color-picker.js
Normal file
File diff suppressed because one or more lines are too long
Reference in New Issue
Block a user