From 3e8b34be2fdeccf16c8b46f1ee518f970853768d Mon Sep 17 00:00:00 2001 From: Mitch Riedstra Date: Tue, 24 Oct 2017 16:59:48 -0400 Subject: Adding in materialize source and templates --- app/dispatch/static/materialize/js/toasts.js | 320 +++++++++++++++++++++++++++ 1 file changed, 320 insertions(+) create mode 100644 app/dispatch/static/materialize/js/toasts.js (limited to 'app/dispatch/static/materialize/js/toasts.js') 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._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); -- cgit v1.2.3