(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);