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/modal.js | 371 ++++++++++++++++++++++++++++ 1 file changed, 371 insertions(+) create mode 100644 app/dispatch/static/materialize/js/modal.js (limited to 'app/dispatch/static/materialize/js/modal.js') diff --git a/app/dispatch/static/materialize/js/modal.js b/app/dispatch/static/materialize/js/modal.js new file mode 100644 index 0000000..fb182d7 --- /dev/null +++ b/app/dispatch/static/materialize/js/modal.js @@ -0,0 +1,371 @@ +(function($, Vel) { + 'use strict'; + + let _defaults = { + opacity: 0.5, + inDuration: 250, + outDuration: 250, + ready: undefined, + complete: undefined, + dismissible: true, + startingTop: '4%', + endingTop: '10%' + }; + + + /** + * @class + * + */ + class Modal { + /** + * Construct Modal instance and set up overlay + * @constructor + * @param {jQuery} $el + * @param {Object} options + */ + constructor($el, options) { + + // If exists, destroy and reinitialize + if (!!$el[0].M_Modal) { + $el[0].M_Modal.destroy(); + } + + /** + * The jQuery element + * @type {jQuery} + */ + this.$el = $el; + + /** + * Options for the modal + * @member Modal#options + * @prop {Number} [opacity=0.5] - Opacity of the modal overlay + * @prop {Number} [inDuration=250] - Length in ms of enter transition + * @prop {Number} [outDuration=250] - Length in ms of exit transition + * @prop {Function} ready - Callback function called when modal is finished entering + * @prop {Function} complete - Callback function called when modal is finished exiting + * @prop {Boolean} [dismissible=true] - Allow modal to be dismissed by keyboard or overlay click + * @prop {String} [startingTop='4%'] - startingTop + * @prop {String} [endingTop='10%'] - endingTop + */ + this.options = $.extend({}, Modal.defaults, options); + + /** + * Describes open/close state of modal + * @type {Boolean} + */ + this.isOpen = false; + + this.$el[0].M_Modal = this; + this.id = $el.attr('id'); + this.openingTrigger = undefined; + this.$overlay = $(''); + + Modal._increment++; + Modal._count++; + this.$overlay[0].style.zIndex = 1000 + Modal._increment * 2; + this.$el[0].style.zIndex = 1000 + Modal._increment * 2 + 1; + this.setupEventHandlers(); + } + + static get defaults() { + return _defaults; + } + + static init($els, options) { + let arr = []; + $els.each(function() { + arr.push(new Modal($(this), options)); + }); + return arr; + } + + /** + * Get Instance + */ + getInstance() { + return this; + } + + /** + * Teardown component + */ + destroy() { + this.removeEventHandlers(); + this.$el[0].removeAttribute('style') + if (!!this.$overlay[0].parentNode) { + this.$overlay[0].parentNode.removeChild(this.$overlay[0]); + } + this.$el[0].M_Modal = undefined; + Modal._count--; + } + + /** + * Setup Event Handlers + */ + setupEventHandlers() { + this.handleOverlayClickBound = this.handleOverlayClick.bind(this); + this.handleModalCloseClickBound = this.handleModalCloseClick.bind(this); + + if (Modal._count === 1) { + document.body.addEventListener('click', this.handleTriggerClick); + } + this.$overlay[0].addEventListener('click', this.handleOverlayClickBound); + this.$el[0].addEventListener('click', this.handleModalCloseClickBound); + } + + /** + * Remove Event Handlers + */ + removeEventHandlers() { + if (Modal._count === 0) { + document.body.removeEventListener('click', this.handleTriggerClick); + } + this.$overlay[0].removeEventListener('click', this.handleOverlayClickBound); + this.$el[0].removeEventListener('click', this.handleModalCloseClickBound); + } + + /** + * Handle Trigger Click + * @param {Event} e + */ + handleTriggerClick(e) { + let $trigger = $(e.target).closest('.modal-trigger'); + if (e.target && $trigger.length) { + let modalId = $trigger[0].getAttribute('href'); + if (modalId) { + modalId = modalId.slice(1); + } else { + modalId = $trigger[0].getAttribute('data-target'); + } + let modalInstance = document.getElementById(modalId).M_Modal; + if (modalInstance) { + modalInstance.open($trigger); + } + e.preventDefault(); + } + } + + /** + * Handle Overlay Click + */ + handleOverlayClick() { + if (this.options.dismissible) { + this.close(); + } + } + + /** + * Handle Modal Close Click + * @param {Event} e + */ + handleModalCloseClick(e) { + let $closeTrigger = $(e.target).closest('.modal-close'); + if (e.target && $closeTrigger.length) { + this.close(); + } + } + + /** + * Handle Keydown + * @param {Event} e + */ + handleKeydown(e) { + // ESC key + if (e.keyCode === 27 && this.options.dismissible) { + this.close(); + } + } + + /** + * Animate in modal + */ + animateIn() { + // Set initial styles + $.extend(this.$el[0].style, { + display: 'block', + opacity: 0 + }); + $.extend(this.$overlay[0].style, { + display: 'block', + opacity: 0 + }); + + // Animate overlay + Vel( + this.$overlay[0], + {opacity: this.options.opacity}, + {duration: this.options.inDuration, queue: false, ease: 'easeOutCubic'} + ); + + + // Define modal animation options + let enterVelocityOptions = { + duration: this.options.inDuration, + queue: false, + ease: 'easeOutCubic', + // Handle modal ready callback + complete: () => { + if (typeof(this.options.ready) === 'function') { + this.options.ready.call(this, this.$el, this.openingTrigger); + } + } + }; + + // Bottom sheet animation + if (this.$el[0].classList.contains('bottom-sheet')) { + Vel( + this.$el[0], + {bottom: 0, opacity: 1}, + enterVelocityOptions); + + // Normal modal animation + } else { + Vel.hook(this.$el[0], 'scaleX', 0.7); + this.$el[0].style.top = this.options.startingTop; + Vel( + this.$el[0], + {top: this.options.endingTop, opacity: 1, scaleX: 1}, + enterVelocityOptions + ); + } + } + + /** + * Animate out modal + */ + animateOut() { + // Animate overlay + Vel( + this.$overlay[0], + { opacity: 0}, + {duration: this.options.outDuration, queue: false, ease: 'easeOutQuart'} + ); + + // Define modal animation options + var exitVelocityOptions = { + duration: this.options.outDuration, + queue: false, + ease: 'easeOutCubic', + // Handle modal ready callback + complete: () => { + this.$el[0].style.display = 'none'; + // Call complete callback + if (typeof(this.options.complete) === 'function') { + this.options.complete.call(this, this.$el); + } + this.$overlay[0].parentNode.removeChild(this.$overlay[0]); + } + }; + + // Bottom sheet animation + if (this.$el[0].classList.contains('bottom-sheet')) { + Vel( + this.$el[0], + {bottom: '-100%', opacity: 0}, + exitVelocityOptions + ); + + // Normal modal animation + } else { + Vel( + this.$el[0], + {top: this.options.startingTop, opacity: 0, scaleX: 0.7}, + exitVelocityOptions + ); + } + } + + + /** + * Open Modal + * @param {jQuery} [$trigger] + */ + open($trigger) { + if (this.isOpen) { + return; + } + + this.isOpen = true; + let body = document.body; + body.style.overflow = 'hidden'; + this.$el[0].classList.add('open'); + body.appendChild(this.$overlay[0]); + + // Set opening trigger, undefined indicates modal was opened by javascript + this.openingTrigger = !!$trigger ? $trigger : undefined; + + + if (this.options.dismissible) { + this.handleKeydownBound = this.handleKeydown.bind(this); + document.addEventListener('keydown', this.handleKeydownBound); + } + + this.animateIn(); + + return this; + } + + /** + * Close Modal + */ + close() { + if (!this.isOpen) { + return; + } + + this.isOpen = false; + this.$el[0].classList.remove('open'); + document.body.style.overflow = ''; + + if (this.options.dismissible) { + document.removeEventListener('keydown', this.handleKeydownBound); + } + + this.animateOut(); + + return this; + } + } + + /** + * @static + * @memberof Modal + */ + Modal._increment = 0; + + /** + * @static + * @memberof Modal + */ + Modal._count = 0; + + Materialize.Modal = Modal; + + $.fn.modal = function(methodOrOptions) { + // Call plugin method if valid method name is passed in + if (Modal.prototype[methodOrOptions]) { + // Getter methods + if (methodOrOptions.slice(0,3) === 'get') { + return this.first()[0].M_Modal[methodOrOptions](); + + // Void methods + } else { + return this.each(function() { + this.M_Modal[methodOrOptions](); + }); + } + + // Initialize plugin if options or no argument is passed in + } else if ( typeof methodOrOptions === 'object' || ! methodOrOptions ) { + Modal.init(this, arguments[0]); + return this; + + // Return error if an unrecognized method name is passed in + } else { + $.error(`Method ${methodOrOptions} does not exist on jQuery.modal`); + } + }; + +})(jQuery, Materialize.Vel); -- cgit v1.2.3