mirror of
https://github.com/kiwix/kiwix-js.git
synced 2025-09-08 14:49:34 -04:00
parent
cdcbc9f046
commit
3277f85d37
@ -24,14 +24,14 @@
|
|||||||
// DEV: Put your RequireJS definition in the rqDef array below, and any function exports in the function parenthesis of the define statement
|
// DEV: Put your RequireJS definition in the rqDef array below, and any function exports in the function parenthesis of the define statement
|
||||||
// We need to do it this way in order to load WebP polyfills conditionally. The WebP polyfills are only needed by a few old browsers, so loading them
|
// We need to do it this way in order to load WebP polyfills conditionally. The WebP polyfills are only needed by a few old browsers, so loading them
|
||||||
// only if needed saves approximately 1MB of memory.
|
// only if needed saves approximately 1MB of memory.
|
||||||
var rqDef = ['settingsStore'];
|
var rqDef = ['settingsStore', 'util'];
|
||||||
|
|
||||||
// Add WebP polyfill only if webpHero was loaded in init.js
|
// Add WebP polyfill only if webpHero was loaded in init.js
|
||||||
if (webpMachine) {
|
if (webpMachine) {
|
||||||
rqDef.push('webpHeroBundle');
|
rqDef.push('webpHeroBundle');
|
||||||
}
|
}
|
||||||
|
|
||||||
define(rqDef, function(settingsStore) {
|
define(rqDef, function(settingsStore, util) {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Displays a Bootstrap alert or confirm dialog box depending on the options provided
|
* Displays a Bootstrap alert or confirm dialog box depending on the options provided
|
||||||
@ -49,95 +49,97 @@ define(rqDef, function(settingsStore) {
|
|||||||
approveConfirmLabel = approveConfirmLabel || 'Confirm';
|
approveConfirmLabel = approveConfirmLabel || 'Confirm';
|
||||||
closeMessageLabel = closeMessageLabel || 'Okay';
|
closeMessageLabel = closeMessageLabel || 'Okay';
|
||||||
label = label || (isConfirm ? 'Confirmation' : 'Message');
|
label = label || (isConfirm ? 'Confirmation' : 'Message');
|
||||||
return new Promise(function (resolve, reject) {
|
return util.PromiseQueue.enqueue(function () {
|
||||||
if (!message) reject('Missing body message');
|
return new Promise(function (resolve, reject) {
|
||||||
// Set the text to the modal and its buttons
|
if (!message) reject('Missing body message');
|
||||||
document.getElementById('approveConfirm').textContent = approveConfirmLabel;
|
// Set the text to the modal and its buttons
|
||||||
document.getElementById('declineConfirm').textContent = declineConfirmLabel;
|
document.getElementById('approveConfirm').textContent = approveConfirmLabel;
|
||||||
document.getElementById('closeMessage').textContent = closeMessageLabel;
|
document.getElementById('declineConfirm').textContent = declineConfirmLabel;
|
||||||
document.getElementById('modalLabel').textContent = label;
|
document.getElementById('closeMessage').textContent = closeMessageLabel;
|
||||||
// Using innerHTML to set the message to allow HTML formatting
|
document.getElementById('modalLabel').textContent = label;
|
||||||
document.getElementById('modalText').innerHTML = message;
|
// Using innerHTML to set the message to allow HTML formatting
|
||||||
// Display buttons acc to the type of alert
|
document.getElementById('modalText').innerHTML = message;
|
||||||
document.getElementById('approveConfirm').style.display = isConfirm ? 'inline' : 'none';
|
// Display buttons acc to the type of alert
|
||||||
document.getElementById('declineConfirm').style.display = isConfirm ? 'inline' : 'none';
|
document.getElementById('approveConfirm').style.display = isConfirm ? 'inline' : 'none';
|
||||||
document.getElementById('closeMessage').style.display = isConfirm ? 'none' : 'inline';
|
document.getElementById('declineConfirm').style.display = isConfirm ? 'inline' : 'none';
|
||||||
// Display the modal
|
document.getElementById('closeMessage').style.display = isConfirm ? 'none' : 'inline';
|
||||||
const modal = document.querySelector('#alertModal');
|
// Display the modal
|
||||||
const backdrop = document.createElement('div');
|
const modal = document.querySelector('#alertModal');
|
||||||
backdrop.classList.add('modal-backdrop');
|
const backdrop = document.createElement('div');
|
||||||
document.body.appendChild(backdrop);
|
backdrop.classList.add('modal-backdrop');
|
||||||
|
document.body.appendChild(backdrop);
|
||||||
|
|
||||||
// Show the modal
|
// Show the modal
|
||||||
document.body.classList.add('modal-open');
|
document.body.classList.add('modal-open');
|
||||||
modal.classList.add('show');
|
modal.classList.add('show');
|
||||||
modal.style.display = 'block';
|
modal.style.display = 'block';
|
||||||
backdrop.classList.add('show');
|
backdrop.classList.add('show');
|
||||||
|
|
||||||
// Set the ARIA attributes for the modal
|
// Set the ARIA attributes for the modal
|
||||||
modal.setAttribute('aria-hidden', 'false');
|
modal.setAttribute('aria-hidden', 'false');
|
||||||
modal.setAttribute('aria-modal', 'true');
|
modal.setAttribute('aria-modal', 'true');
|
||||||
modal.setAttribute('role', 'dialog');
|
modal.setAttribute('role', 'dialog');
|
||||||
|
|
||||||
// Hide modal handlers
|
// Hide modal handlers
|
||||||
var closeModalHandler = function () {
|
var closeModalHandler = function () {
|
||||||
document.body.classList.remove('modal-open');
|
document.body.classList.remove('modal-open');
|
||||||
modal.classList.remove('show');
|
modal.classList.remove('show');
|
||||||
modal.style.display = 'none';
|
modal.style.display = 'none';
|
||||||
backdrop.classList.remove('show');
|
backdrop.classList.remove('show');
|
||||||
if(Array.from(document.body.children).indexOf(backdrop)>=0){
|
if(Array.from(document.body.children).indexOf(backdrop)>=0){
|
||||||
document.body.removeChild(backdrop);
|
document.body.removeChild(backdrop);
|
||||||
}
|
|
||||||
//remove event listeners
|
|
||||||
document.getElementById('modalCloseBtn').removeEventListener('click', close);
|
|
||||||
document.getElementById('declineConfirm').removeEventListener('click', close);
|
|
||||||
document.getElementById('closeMessage').removeEventListener('click', close);
|
|
||||||
document.getElementById('approveConfirm').removeEventListener('click', closeConfirm);
|
|
||||||
modal.removeEventListener('click', close);
|
|
||||||
document.getElementsByClassName('modal-dialog')[0].removeEventListener('click', stopOutsideModalClick);
|
|
||||||
modal.removeEventListener('keyup', keyHandler);
|
|
||||||
};
|
|
||||||
|
|
||||||
// function to call when modal is closed
|
|
||||||
var close = function () {
|
|
||||||
closeModalHandler();
|
|
||||||
resolve(false);
|
|
||||||
};
|
|
||||||
var closeConfirm = function () {
|
|
||||||
closeModalHandler();
|
|
||||||
resolve(true);
|
|
||||||
};
|
|
||||||
var stopOutsideModalClick = function (e) {
|
|
||||||
e.stopPropagation();
|
|
||||||
};
|
|
||||||
var keyHandler = function (e) {
|
|
||||||
if (/Enter/.test(e.key)) {
|
|
||||||
// We need to focus before clicking the button, because the handler above is based on document.activeElement
|
|
||||||
if (isConfirm) {
|
|
||||||
document.getElementById('approveConfirm').focus();
|
|
||||||
document.getElementById('approveConfirm').click();
|
|
||||||
} else {
|
|
||||||
document.getElementById('closeMessage').focus();
|
|
||||||
document.getElementById('closeMessage').click();
|
|
||||||
}
|
}
|
||||||
} else if (/Esc/.test(e.key)) {
|
//remove event listeners
|
||||||
document.getElementById('modalCloseBtn').focus();
|
document.getElementById('modalCloseBtn').removeEventListener('click', close);
|
||||||
document.getElementById('modalCloseBtn').click();
|
document.getElementById('declineConfirm').removeEventListener('click', close);
|
||||||
}
|
document.getElementById('closeMessage').removeEventListener('click', close);
|
||||||
};
|
document.getElementById('approveConfirm').removeEventListener('click', closeConfirm);
|
||||||
|
modal.removeEventListener('click', close);
|
||||||
|
document.getElementsByClassName('modal-dialog')[0].removeEventListener('click', stopOutsideModalClick);
|
||||||
|
modal.removeEventListener('keyup', keyHandler);
|
||||||
|
};
|
||||||
|
|
||||||
// When hide modal is called, resolve promise with true if hidden using approve button, false otherwise
|
// function to call when modal is closed
|
||||||
document.getElementById('modalCloseBtn').addEventListener('click', close);
|
var close = function () {
|
||||||
document.getElementById('declineConfirm').addEventListener('click', close);
|
closeModalHandler();
|
||||||
document.getElementById('closeMessage').addEventListener('click', close);
|
resolve(false);
|
||||||
document.getElementById('approveConfirm').addEventListener('click', closeConfirm);
|
};
|
||||||
|
var closeConfirm = function () {
|
||||||
modal.addEventListener('click', close);
|
closeModalHandler();
|
||||||
document.getElementsByClassName('modal-dialog')[0].addEventListener('click', stopOutsideModalClick);
|
resolve(true);
|
||||||
|
};
|
||||||
|
var stopOutsideModalClick = function (e) {
|
||||||
|
e.stopPropagation();
|
||||||
|
};
|
||||||
|
var keyHandler = function (e) {
|
||||||
|
if (/Enter/.test(e.key)) {
|
||||||
|
// We need to focus before clicking the button, because the handler above is based on document.activeElement
|
||||||
|
if (isConfirm) {
|
||||||
|
document.getElementById('approveConfirm').focus();
|
||||||
|
document.getElementById('approveConfirm').click();
|
||||||
|
} else {
|
||||||
|
document.getElementById('closeMessage').focus();
|
||||||
|
document.getElementById('closeMessage').click();
|
||||||
|
}
|
||||||
|
} else if (/Esc/.test(e.key)) {
|
||||||
|
document.getElementById('modalCloseBtn').focus();
|
||||||
|
document.getElementById('modalCloseBtn').click();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
modal.addEventListener('keyup', keyHandler);
|
// When hide modal is called, resolve promise with true if hidden using approve button, false otherwise
|
||||||
// Set focus to the first focusable element inside the modal
|
document.getElementById('modalCloseBtn').addEventListener('click', close);
|
||||||
modal.focus();
|
document.getElementById('declineConfirm').addEventListener('click', close);
|
||||||
|
document.getElementById('closeMessage').addEventListener('click', close);
|
||||||
|
document.getElementById('approveConfirm').addEventListener('click', closeConfirm);
|
||||||
|
|
||||||
|
modal.addEventListener('click', close);
|
||||||
|
document.getElementsByClassName('modal-dialog')[0].addEventListener('click', stopOutsideModalClick);
|
||||||
|
|
||||||
|
modal.addEventListener('keyup', keyHandler);
|
||||||
|
// Set focus to the first focusable element inside the modal
|
||||||
|
modal.focus();
|
||||||
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -194,6 +194,52 @@ define([], function() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
* Queues Promise Factories* to be resolved or rejected sequentially. This helps to avoid overlapping Promise functions.
|
||||||
|
* Primarily used by uiUtil.systemAlert, to prevent alerts showing while others are being displayed.
|
||||||
|
*
|
||||||
|
* *A Promise Factory is merely a Promise wrapped in a function to prevent it from executing immediately. E.g. to use
|
||||||
|
* this function with a Promise, call it like this (or, more likely, use your own pre-wrapped Promise):
|
||||||
|
*
|
||||||
|
* return util.PromiseQueue.enqueue(function () {
|
||||||
|
* return new Promise(function (resolve, reject) { ... });
|
||||||
|
* });
|
||||||
|
*
|
||||||
|
* Adapted from https://medium.com/@karenmarkosyan/how-to-manage-promises-into-dynamic-queue-with-vanilla-javascript-9d0d1f8d4df5
|
||||||
|
*
|
||||||
|
* @type {Object} PromiseQueue
|
||||||
|
* @property {Function} enqueue Queues a Promise Factory. Call this function repeatedly to queue Promises sequentially
|
||||||
|
* @param {Function<Promise>} promiseFactory A Promise wrapped in an ordinary function
|
||||||
|
* @returns {Promise} A Promise that resolves or rejects with the resolved/rejected value of the Promise Factory
|
||||||
|
*/
|
||||||
|
var PromiseQueue = {
|
||||||
|
_queue: [],
|
||||||
|
_working: false,
|
||||||
|
enqueue: function (promiseFactory) {
|
||||||
|
var that = this;
|
||||||
|
return new Promise(function (resolve, reject) {
|
||||||
|
that._queue.push({promise: promiseFactory, resolve: resolve, reject: reject});
|
||||||
|
if (!that._working) that._dequeue();
|
||||||
|
});
|
||||||
|
},
|
||||||
|
_dequeue: function () {
|
||||||
|
this._working = true;
|
||||||
|
var that = this;
|
||||||
|
var deferred = this._queue.shift();
|
||||||
|
if (!deferred) {
|
||||||
|
this._working = false;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return deferred.promise().then(function (val) {
|
||||||
|
deferred.resolve(val);
|
||||||
|
}).catch(function (err) {
|
||||||
|
deferred.reject(err);
|
||||||
|
}).finally(function () {
|
||||||
|
return that._dequeue();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
* Functions and classes exposed by this module
|
* Functions and classes exposed by this module
|
||||||
*/
|
*/
|
||||||
return {
|
return {
|
||||||
@ -203,6 +249,7 @@ define([], function() {
|
|||||||
readFloatFrom4Bytes: readFloatFrom4Bytes,
|
readFloatFrom4Bytes: readFloatFrom4Bytes,
|
||||||
readFileSlice: readFileSlice,
|
readFileSlice: readFileSlice,
|
||||||
binarySearch: binarySearch,
|
binarySearch: binarySearch,
|
||||||
leftShift: leftShift
|
leftShift: leftShift,
|
||||||
|
PromiseQueue: PromiseQueue
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
|
Loading…
x
Reference in New Issue
Block a user