diff options
Diffstat (limited to 'app/dispatch/static/materialize/js/toasts.js')
| -rw-r--r-- | app/dispatch/static/materialize/js/toasts.js | 320 |
1 files changed, 320 insertions, 0 deletions
diff --git a/app/dispatch/static/materialize/js/toasts.js b/app/dispatch/static/materialize/js/toasts.js new file mode 100644 index 0000000..70abed8 --- /dev/null +++ b/app/dispatch/static/materialize/js/toasts.js @@ -0,0 +1,320 @@ +(function($, Vel) {
+ 'use strict';
+
+ let _defaults = {
+ displayLength: Infinity,
+ inDuration: 300,
+ outDuration: 375,
+ className: undefined,
+ completeCallback: undefined,
+ activationPercent: 0.8
+ };
+
+ class Toast {
+ constructor(message, displayLength, className, completeCallback) {
+ if (!message) {
+ return;
+ }
+
+
+ /**
+ * Options for the toast
+ * @member Toast#options
+ */
+ this.options = {
+ displayLength: displayLength,
+ className: className,
+ completeCallback: completeCallback
+ };
+
+ this.options = $.extend({}, Toast.defaults, this.options);
+ this.message = message;
+
+ /**
+ * Describes current pan state toast
+ * @type {Boolean}
+ */
+ this.panning = false;
+
+ /**
+ * Time remaining until toast is removed
+ */
+ this.timeRemaining = this.options.displayLength;
+
+ if (Toast._toasts.length === 0) {
+ Toast._createContainer();
+ }
+
+ // Create new toast
+ Toast._toasts.push(this);
+ let toastElement = this.createToast();
+ toastElement.M_Toast = this;
+ this.el = toastElement;
+ this._animateIn();
+ this.setTimer();
+ }
+
+ static get defaults() {
+ return _defaults;
+ }
+
+ /**
+ * Append toast container and add event handlers
+ */
+ static _createContainer() {
+ let container = document.createElement('div');
+ container.setAttribute('id', 'toast-container');
+
+ // Add event handler
+ container.addEventListener('touchstart', Toast._onDragStart);
+ container.addEventListener('touchmove', Toast._onDragMove);
+ container.addEventListener('touchend', Toast._onDragEnd);
+
+ container.addEventListener('mousedown', Toast._onDragStart);
+ document.addEventListener('mousemove', Toast._onDragMove);
+ document.addEventListener('mouseup', Toast._onDragEnd);
+
+ document.body.appendChild(container);
+ Toast._container = container;
+ }
+
+ /**
+ * Remove toast container and event handlers
+ */
+ static _removeContainer() {
+ // Add event handler
+ document.removeEventListener('mousemove', Toast._onDragMove);
+ document.removeEventListener('mouseup', Toast._onDragEnd);
+
+ Toast._container.parentNode.removeChild(Toast._container);
+ Toast._container = null;
+ }
+
+ /**
+ * Begin drag handler
+ * @param {Event} e
+ */
+ static _onDragStart(e) {
+ if (e.target && $(e.target).closest('.toast').length) {
+ let $toast = $(e.target).closest('.toast');
+ let toast = $toast[0].M_Toast;
+ toast.panning = true;
+ Toast._draggedToast = toast;
+ toast.el.classList.add('panning');
+ toast.el.style.transition = '';
+ toast.startingXPos = Toast._xPos(e);
+ toast.time = Date.now();
+ toast.xPos = Toast._xPos(e);
+ }
+ }
+
+ /**
+ * Drag move handler
+ * @param {Event} e
+ */
+ static _onDragMove(e) {
+ if (!!Toast._draggedToast) {
+ e.preventDefault();
+ let toast = Toast._draggedToast;
+ toast.deltaX = Math.abs(toast.xPos - Toast._xPos(e));
+ toast.xPos = Toast._xPos(e);
+ toast.velocityX = toast.deltaX / (Date.now() - toast.time);
+ toast.time = Date.now();
+
+ let totalDeltaX = toast.xPos - toast.startingXPos;
+ let activationDistance =
+ toast.el.offsetWidth * toast.options.activationPercent;
+ toast.el.style.transform = `translateX(${totalDeltaX}px)`;
+ toast.el.style.opacity = 1-Math.abs(totalDeltaX / activationDistance);
+ }
+ }
+
+ /**
+ * End drag handler
+ * @param {Event} e
+ */
+ static _onDragEnd(e) {
+ if (!!Toast._draggedToast) {
+ let toast = Toast._draggedToast;
+ toast.panning = false;
+ toast.el.classList.remove('panning');
+
+ let totalDeltaX = toast.xPos - toast.startingXPos;
+ let activationDistance =
+ toast.el.offsetWidth * toast.options.activationPercent;
+ let shouldBeDismissed = Math.abs(totalDeltaX) > activationDistance ||
+ toast.velocityX > 1;
+
+ // Remove toast
+ if (shouldBeDismissed) {
+ toast.wasSwiped = true;
+ toast.remove();
+
+ // Animate toast back to original position
+ } else {
+ toast.el.style.transition = 'transform .2s, opacity .2s';
+ toast.el.style.transform = '';
+ toast.el.style.opacity = '';
+ }
+ Toast._draggedToast = null;
+ }
+ }
+
+ /**
+ * Get x position of mouse or touch event
+ * @param {Event} e
+ */
+ static _xPos(e) {
+ if (e.targetTouches && (e.targetTouches.length >= 1)) {
+ return e.targetTouches[0].clientX;
+ }
+ // mouse event
+ return e.clientX;
+ }
+
+ /**
+ * Remove all toasts
+ */
+ static removeAll() {
+ for(let toastIndex in Toast._toasts) {
+ Toast._toasts[toastIndex].remove();
+ }
+ }
+
+
+ /**
+ * Create toast and append it to toast container
+ */
+ createToast() {
+ let toast = document.createElement('div');
+ toast.classList.add('toast');
+
+ // Add custom classes onto toast
+ if (this.options.className) {
+ let classes = this.options.className.split(' ');
+ let i, count;
+ for (i = 0, count = classes.length; i < count; i++) {
+ toast.classList.add(classes[i]);
+ }
+ }
+
+ // Set content
+ if ( typeof HTMLElement === 'object' ?
+ this.message instanceof HTMLElement :
+ this.message && typeof this.message === 'object' &&
+ this.message !== null && this.message.nodeType === 1 &&
+ typeof this.message.nodeName==='string'
+ ) {
+ toast.appendChild(this.message);
+
+ // Check if it is jQuery object
+ } else if (this.message instanceof jQuery) {
+ $(toast).append(this.message);
+
+ // Insert as text;
+ } else {
+ toast.innerHTML = this.message;
+ }
+
+ // Append toasft
+ Toast._container.appendChild(toast);
+ return toast;
+ }
+
+ /**
+ * Animate in toast
+ */
+ _animateIn() {
+ // Animate toast in
+ Vel(this.el, {top: 0, opacity: 1 }, {
+ duration: 300,
+ easing: 'easeOutCubic',
+ queue: false
+ });
+ }
+
+
+ /**
+ * Create setInterval which automatically removes toast when timeRemaining >= 0
+ * has been reached
+ */
+ setTimer() {
+ if (this.timeRemaining !== Infinity) {
+ this.counterInterval = setInterval(() => {
+ // If toast is not being dragged, decrease its time remaining
+ if (!this.panning) {
+ this.timeRemaining -= 20;
+ }
+
+ // Animate toast out
+ if (this.timeRemaining <= 0) {
+ this.remove();
+ }
+ }, 20);
+ }
+ }
+
+
+ /**
+ * Dismiss toast with animation
+ */
+ remove() {
+ window.clearInterval(this.counterInterval);
+ let activationDistance =
+ this.el.offsetWidth * this.options.activationPercent;
+
+ if(this.wasSwiped) {
+ this.el.style.transition = 'transform .05s, opacity .05s';
+ this.el.style.transform = `translateX(${activationDistance}px)`;
+ this.el.style.opacity = 0;
+ }
+
+ Vel(
+ this.el,
+ {opacity: 0, marginTop: '-40px'},
+ {
+ duration: this.options.outDuration,
+ easing: 'easeOutExpo',
+ queue: false,
+ complete: () => {
+ // Call the optional callback
+ if(typeof(this.options.completeCallback) === 'function') {
+ this.options.completeCallback();
+ }
+ // Remove toast from DOM
+ this.el.parentNode.removeChild(this.el);
+ Toast._toasts.splice(Toast._toasts.indexOf(this), 1);
+ if (Toast._toasts.length === 0) {
+ Toast._removeContainer();
+ }
+ }
+ }
+ );
+ }
+ }
+
+ /**
+ * @static
+ * @memberof Toast
+ * @type {Array.<Toast>}
+ */
+ Toast._toasts = [];
+
+ /**
+ * @static
+ * @memberof Toast
+ */
+ Toast._container = null;
+
+ /**
+ * @static
+ * @memberof Toast
+ * @type {Toast}
+ */
+ Toast._draggedToast = null;
+
+ Materialize.Toast = Toast;
+ Materialize.toast = function(message, displayLength, className, completeCallback) {
+ return new Toast(message, displayLength, className, completeCallback);
+ };
+})(jQuery, Materialize.Vel);
|
