mirror of
https://github.com/TriliumNext/Notes.git
synced 2025-07-27 10:02:59 +08:00

git-subtree-dir: apps/web-clipper git-subtree-mainline: b0e519071893ce9434dd3bb3a568b3e41332c718 git-subtree-split: 786d249a6effe0262859d05e6cb1737e5fc8bdd8
266 lines
7.1 KiB
JavaScript
266 lines
7.1 KiB
JavaScript
/***********************************************
|
|
|
|
"toast.js"
|
|
|
|
Created by Michael Cheng on 05/31/2015 22:34
|
|
http://michaelcheng.us/
|
|
michael@michaelcheng.us
|
|
--All Rights Reserved--
|
|
|
|
***********************************************/
|
|
|
|
'use strict';
|
|
|
|
/**
|
|
* The Toast animation speed; how long the Toast takes to move to and from the screen
|
|
* @type {Number}
|
|
*/
|
|
const TOAST_ANIMATION_SPEED = 400;
|
|
|
|
const Transitions = {
|
|
SHOW: {
|
|
'-webkit-transition': 'opacity ' + TOAST_ANIMATION_SPEED + 'ms, -webkit-transform ' + TOAST_ANIMATION_SPEED + 'ms',
|
|
'transition': 'opacity ' + TOAST_ANIMATION_SPEED + 'ms, transform ' + TOAST_ANIMATION_SPEED + 'ms',
|
|
'opacity': '1',
|
|
'-webkit-transform': 'translateY(-100%) translateZ(0)',
|
|
'transform': 'translateY(-100%) translateZ(0)'
|
|
},
|
|
|
|
HIDE: {
|
|
'opacity': '0',
|
|
'-webkit-transform': 'translateY(150%) translateZ(0)',
|
|
'transform': 'translateY(150%) translateZ(0)'
|
|
}
|
|
};
|
|
|
|
/**
|
|
* The main Toast object
|
|
* @param {String} text The text to put inside the Toast
|
|
* @param {Object} options Optional; the Toast options. See Toast.prototype.DEFAULT_SETTINGS for more information
|
|
* @param {Object} transitions Optional; the Transitions object. This should not be used unless you know what you're doing
|
|
*/
|
|
function Toast(text, options, transitions) {
|
|
if(getToastStage() !== null) {
|
|
// If there is already a Toast being shown, put this Toast in the queue to show later
|
|
Toast.prototype.toastQueue.push({
|
|
text: text,
|
|
options: options,
|
|
transitions: transitions
|
|
});
|
|
} else {
|
|
Toast.prototype.Transitions = transitions || Transitions;
|
|
var _options = options || {};
|
|
_options = Toast.prototype.mergeOptions(Toast.prototype.DEFAULT_SETTINGS, _options);
|
|
|
|
Toast.prototype.show(text, _options);
|
|
|
|
_options = null;
|
|
}
|
|
}
|
|
|
|
|
|
/**
|
|
* The toastStage. This is the HTML element in which the toast resides
|
|
* Getter and setter methods are available privately
|
|
* @type {Element}
|
|
*/
|
|
var _toastStage = null;
|
|
function getToastStage() {
|
|
return _toastStage;
|
|
}
|
|
function setToastStage(toastStage) {
|
|
_toastStage = toastStage;
|
|
}
|
|
|
|
|
|
|
|
|
|
// define some Toast constants
|
|
|
|
/**
|
|
* The default Toast settings
|
|
* @type {Object}
|
|
*/
|
|
Toast.prototype.DEFAULT_SETTINGS = {
|
|
style: {
|
|
main: {
|
|
'background': 'rgba(0, 0, 0, .8)',
|
|
'box-shadow': '0 0 10px rgba(0, 0, 0, .8)',
|
|
|
|
'border-radius': '3px',
|
|
|
|
'z-index': '99999',
|
|
|
|
'color': 'rgba(255, 255, 255, .9)',
|
|
|
|
'padding': '10px 15px',
|
|
'max-width': '60%',
|
|
'width': '100%',
|
|
'word-break': 'keep-all',
|
|
'margin': '0 auto',
|
|
'text-align': 'center',
|
|
|
|
'position': 'fixed',
|
|
'left': '0',
|
|
'right': '0',
|
|
'bottom': '0',
|
|
|
|
'-webkit-transform': 'translateY(150%) translateZ(0)',
|
|
'transform': 'translateY(150%) translateZ(0)',
|
|
'-webkit-filter': 'blur(0)',
|
|
'opacity': '0'
|
|
}
|
|
},
|
|
|
|
settings: {
|
|
duration: 4000
|
|
}
|
|
};
|
|
|
|
Toast.prototype.Transitions = {};
|
|
|
|
|
|
/**
|
|
* The queue of Toasts waiting to be shown
|
|
* @type {Array}
|
|
*/
|
|
Toast.prototype.toastQueue = [];
|
|
|
|
|
|
/**
|
|
* The Timeout object for animations.
|
|
* This should be shared among the Toasts, because timeouts may be cancelled e.g. on explicit call of hide()
|
|
* @type {Object}
|
|
*/
|
|
Toast.prototype.timeout = null;
|
|
|
|
|
|
/**
|
|
* Merge the DEFAULT_SETTINGS with the user defined options if specified
|
|
* @param {Object} options The user defined options
|
|
*/
|
|
Toast.prototype.mergeOptions = function(initialOptions, customOptions) {
|
|
var merged = customOptions;
|
|
for(var prop in initialOptions) {
|
|
if(merged.hasOwnProperty(prop)) {
|
|
if(initialOptions[prop] !== null && initialOptions[prop].constructor === Object) {
|
|
merged[prop] = Toast.prototype.mergeOptions(initialOptions[prop], merged[prop]);
|
|
}
|
|
} else {
|
|
merged[prop] = initialOptions[prop];
|
|
}
|
|
}
|
|
return merged;
|
|
};
|
|
|
|
|
|
/**
|
|
* Generate the Toast with the specified text.
|
|
* @param {String|Object} text The text to show inside the Toast, can be an HTML element or plain text
|
|
* @param {Object} style The style to set for the Toast
|
|
*/
|
|
Toast.prototype.generate = function(text, style) {
|
|
var toastStage = document.createElement('div');
|
|
|
|
|
|
/**
|
|
* If the text is a String, create a textNode for appending
|
|
*/
|
|
if(typeof text === 'string') {
|
|
text = document.createTextNode(text);
|
|
}
|
|
toastStage.appendChild(text);
|
|
|
|
|
|
setToastStage(toastStage);
|
|
toastStage = null;
|
|
|
|
Toast.prototype.stylize(getToastStage(), style);
|
|
};
|
|
|
|
/**
|
|
* Stylize the Toast.
|
|
* @param {Element} element The HTML element to stylize
|
|
* @param {Object} styles An object containing the style to apply
|
|
* @return Returns nothing
|
|
*/
|
|
Toast.prototype.stylize = function(element, styles) {
|
|
Object.keys(styles).forEach(function(style) {
|
|
element.style[style] = styles[style];
|
|
});
|
|
};
|
|
|
|
|
|
/**
|
|
* Show the Toast
|
|
* @param {String} text The text to show inside the Toast
|
|
* @param {Object} options The object containing the options for the Toast
|
|
*/
|
|
Toast.prototype.show = function(text, options) {
|
|
this.generate(text, options.style.main);
|
|
|
|
var toastStage = getToastStage();
|
|
document.body.insertBefore(toastStage, document.body.firstChild);
|
|
|
|
|
|
|
|
// This is a hack to get animations started. Apparently without explicitly redrawing, it'll just attach the class and no animations would be done
|
|
toastStage.offsetHeight;
|
|
|
|
|
|
Toast.prototype.stylize(toastStage, Toast.prototype.Transitions.SHOW);
|
|
|
|
|
|
toastStage = null;
|
|
|
|
|
|
// Hide the Toast after the specified time
|
|
clearTimeout(Toast.prototype.timeout);
|
|
Toast.prototype.timeout = setTimeout(Toast.prototype.hide, options.settings.duration);
|
|
};
|
|
|
|
|
|
/**
|
|
* Hide the Toast that's currently shown
|
|
*/
|
|
Toast.prototype.hide = function() {
|
|
var toastStage = getToastStage();
|
|
Toast.prototype.stylize(toastStage, Toast.prototype.Transitions.HIDE);
|
|
|
|
// Destroy the Toast element after animations end
|
|
clearTimeout(Toast.prototype.timeout);
|
|
toastStage.addEventListener('transitionend', Toast.prototype.animationListener);
|
|
toastStage = null;
|
|
};
|
|
|
|
Toast.prototype.animationListener = function() {
|
|
getToastStage().removeEventListener('transitionend', Toast.prototype.animationListener);
|
|
Toast.prototype.destroy.call(this);
|
|
};
|
|
|
|
|
|
/**
|
|
* Clean up after the Toast slides away. Namely, removing the Toast from the DOM. After the Toast is cleaned up, display the next Toast in the queue if any exists
|
|
*/
|
|
Toast.prototype.destroy = function() {
|
|
var toastStage = getToastStage();
|
|
document.body.removeChild(toastStage);
|
|
|
|
toastStage = null;
|
|
setToastStage(null);
|
|
|
|
|
|
if(Toast.prototype.toastQueue.length > 0) {
|
|
// Show the rest of the Toasts in the queue if they exist
|
|
|
|
var toast = Toast.prototype.toastQueue.shift();
|
|
Toast(toast.text, toast.options, toast.transitions);
|
|
|
|
// clean up
|
|
toast = null;
|
|
}
|
|
};
|
|
|
|
window.showToast = Toast;
|
|
|
|
"END OF FILE"; // to avoid "result is non-structured-clonable data"
|