diff --git a/static/js/anime.min.js b/static/js/anime.min.js deleted file mode 100644 index fb578584..00000000 --- a/static/js/anime.min.js +++ /dev/null @@ -1,34 +0,0 @@ -/* - v2.2.0 - 2017 Julian Garnier - Released under the MIT license -*/ -var $jscomp={scope:{}};$jscomp.defineProperty="function"==typeof Object.defineProperties?Object.defineProperty:function(e,r,p){if(p.get||p.set)throw new TypeError("ES3 does not support getters and setters.");e!=Array.prototype&&e!=Object.prototype&&(e[r]=p.value)};$jscomp.getGlobal=function(e){return"undefined"!=typeof window&&window===e?e:"undefined"!=typeof global&&null!=global?global:e};$jscomp.global=$jscomp.getGlobal(this);$jscomp.SYMBOL_PREFIX="jscomp_symbol_"; -$jscomp.initSymbol=function(){$jscomp.initSymbol=function(){};$jscomp.global.Symbol||($jscomp.global.Symbol=$jscomp.Symbol)};$jscomp.symbolCounter_=0;$jscomp.Symbol=function(e){return $jscomp.SYMBOL_PREFIX+(e||"")+$jscomp.symbolCounter_++}; -$jscomp.initSymbolIterator=function(){$jscomp.initSymbol();var e=$jscomp.global.Symbol.iterator;e||(e=$jscomp.global.Symbol.iterator=$jscomp.global.Symbol("iterator"));"function"!=typeof Array.prototype[e]&&$jscomp.defineProperty(Array.prototype,e,{configurable:!0,writable:!0,value:function(){return $jscomp.arrayIterator(this)}});$jscomp.initSymbolIterator=function(){}};$jscomp.arrayIterator=function(e){var r=0;return $jscomp.iteratorPrototype(function(){return rb&&(b+=1);1b?c:b<2/3?a+(c-a)*(2/3-b)*6:a}var d=/hsl\((\d+),\s*([\d.]+)%,\s*([\d.]+)%\)/g.exec(a)||/hsla\((\d+),\s*([\d.]+)%,\s*([\d.]+)%,\s*([\d.]+)\)/g.exec(a);a=parseInt(d[1])/360;var b=parseInt(d[2])/100,f=parseInt(d[3])/100,d=d[4]||1;if(0==b)f=b=a=f;else{var n=.5>f?f*(1+b):f+b-f*b,k=2*f-n,f=c(k,n,a+1/3),b=c(k,n,a);a=c(k,n,a-1/3)}return"rgba("+ -255*f+","+255*b+","+255*a+","+d+")"}function y(a){if(a=/([\+\-]?[0-9#\.]+)(%|px|pt|em|rem|in|cm|mm|ex|ch|pc|vw|vh|vmin|vmax|deg|rad|turn)?$/.exec(a))return a[2]}function V(a){if(-1=g.currentTime)for(var G=0;G=w||!k)g.began||(g.began=!0,f("begin")),f("run");if(q>n&&q=k&&r!==k||!k)b(k),x||e();f("update");a>=k&&(g.remaining?(t=h,"alternate"===g.direction&&(g.reversed=!g.reversed)):(g.pause(),g.completed||(g.completed=!0,f("complete"),"Promise"in window&&(p(),m=c()))),l=0)}a=void 0===a?{}:a;var h,t,l=0,p=null,m=c(),g=fa(a);g.reset=function(){var a=g.direction,c=g.loop;g.currentTime= -0;g.progress=0;g.paused=!0;g.began=!1;g.completed=!1;g.reversed="reverse"===a;g.remaining="alternate"===a&&1===c?2:c;b(0);for(a=g.children.length;a--;)g.children[a].reset()};g.tick=function(a){h=a;t||(t=h);k((l+h-t)*q.speed)};g.seek=function(a){k(d(a))};g.pause=function(){var a=v.indexOf(g);-1=c&&0<=b&&1>=b){var e=new Float32Array(11);if(c!==d||b!==f)for(var k=0;11>k;++k)e[k]=a(.1*k,c,b);return function(k){if(c===d&&b===f)return k;if(0===k)return 0;if(1===k)return 1;for(var h=0,l=1;10!==l&&e[l]<=k;++l)h+=.1;--l;var l=h+(k-e[l])/(e[l+1]-e[l])*.1,n=3*(1-3*b+3*c)*l*l+2*(3*b-6*c)*l+3*c;if(.001<=n){for(h=0;4>h;++h){n=3*(1-3*b+3*c)*l*l+2*(3*b-6*c)*l+3*c;if(0===n)break;var m=a(l,c,b)-k,l=l-m/n}k=l}else if(0=== -n)k=l;else{var l=h,h=h+.1,g=0;do m=l+(h-l)/2,n=a(m,c,b)-k,0++g);k=m}return a(k,d,f)}}}}(),Q=function(){function a(a,b){return 0===a||1===a?a:-Math.pow(2,10*(a-1))*Math.sin(2*(a-1-b/(2*Math.PI)*Math.asin(1))*Math.PI/b)}var c="Quad Cubic Quart Quint Sine Expo Circ Back Elastic".split(" "),d={In:[[.55,.085,.68,.53],[.55,.055,.675,.19],[.895,.03,.685,.22],[.755,.05,.855,.06],[.47,0,.745,.715],[.95,.05,.795,.035],[.6,.04,.98,.335],[.6,-.28,.735,.045],a],Out:[[.25, -.46,.45,.94],[.215,.61,.355,1],[.165,.84,.44,1],[.23,1,.32,1],[.39,.575,.565,1],[.19,1,.22,1],[.075,.82,.165,1],[.175,.885,.32,1.275],function(b,c){return 1-a(1-b,c)}],InOut:[[.455,.03,.515,.955],[.645,.045,.355,1],[.77,0,.175,1],[.86,0,.07,1],[.445,.05,.55,.95],[1,0,0,1],[.785,.135,.15,.86],[.68,-.55,.265,1.55],function(b,c){return.5>b?a(2*b,c)/2:1-a(-2*b+2,c)/2}]},b={linear:A(.25,.25,.75,.75)},f={},e;for(e in d)f.type=e,d[f.type].forEach(function(a){return function(d,f){b["ease"+a.type+c[f]]=h.fnc(d)? -d:A.apply($jscomp$this,d)}}(f)),f={type:f.type};return b}(),ha={css:function(a,c,d){return a.style[c]=d},attribute:function(a,c,d){return a.setAttribute(c,d)},object:function(a,c,d){return a[c]=d},transform:function(a,c,d,b,f){b[f]||(b[f]=[]);b[f].push(c+"("+d+")")}},v=[],B=0,ia=function(){function a(){B=requestAnimationFrame(c)}function c(c){var b=v.length;if(b){for(var d=0;db&&(c.duration=d.duration);c.children.push(d)});c.seek(0);c.reset();c.autoplay&&c.restart();return c};return c};q.random=function(a,c){return Math.floor(Math.random()*(c-a+1))+a};return q}); diff --git a/static/js/autocomplete.js b/static/js/autocomplete.js deleted file mode 100644 index 6366736c..00000000 --- a/static/js/autocomplete.js +++ /dev/null @@ -1,450 +0,0 @@ -(function($) { - 'use strict'; - - let _defaults = { - data: {}, // Autocomplete data set - limit: Infinity, // Limit of results the autocomplete shows - onAutocomplete: null, // Callback for when autocompleted - minLength: 1, // Min characters before autocomplete starts - sortFunction: function(a, b, inputString) { - // Sort function for sorting autocomplete results - return a.indexOf(inputString) - b.indexOf(inputString); - } - }; - - /** - * @class - * - */ - class Autocomplete extends Component { - /** - * Construct Autocomplete instance - * @constructor - * @param {Element} el - * @param {Object} options - */ - constructor(el, options) { - super(Autocomplete, el, options); - - this.el.M_Autocomplete = this; - - /** - * Options for the autocomplete - * @member Autocomplete#options - * @prop {Number} duration - * @prop {Number} dist - * @prop {number} shift - * @prop {number} padding - * @prop {Boolean} fullWidth - * @prop {Boolean} indicators - * @prop {Boolean} noWrap - * @prop {Function} onCycleTo - */ - this.options = $.extend({}, Autocomplete.defaults, options); - - // Setup - this.isOpen = false; - this.count = 0; - this.activeIndex = -1; - this.oldVal; - this.$inputField = this.$el.closest('.input-field'); - this.$active = $(); - this._mousedown = false; - this._setupDropdown(); - - this._setupEventHandlers(); - } - - static get defaults() { - return _defaults; - } - - static init(els, options) { - return super.init(this, els, options); - } - - /** - * Get Instance - */ - static getInstance(el) { - let domElem = !!el.jquery ? el[0] : el; - return domElem.M_Autocomplete; - } - - /** - * Teardown component - */ - destroy() { - this._removeEventHandlers(); - this._removeDropdown(); - this.el.M_Autocomplete = undefined; - } - - /** - * Setup Event Handlers - */ - _setupEventHandlers() { - this._handleInputBlurBound = this._handleInputBlur.bind(this); - this._handleInputKeyupAndFocusBound = this._handleInputKeyupAndFocus.bind(this); - this._handleInputKeydownBound = this._handleInputKeydown.bind(this); - this._handleInputClickBound = this._handleInputClick.bind(this); - this._handleContainerMousedownAndTouchstartBound = this._handleContainerMousedownAndTouchstart.bind( - this - ); - this._handleContainerMouseupAndTouchendBound = this._handleContainerMouseupAndTouchend.bind( - this - ); - - this.el.addEventListener('blur', this._handleInputBlurBound); - this.el.addEventListener('keyup', this._handleInputKeyupAndFocusBound); - this.el.addEventListener('focus', this._handleInputKeyupAndFocusBound); - this.el.addEventListener('keydown', this._handleInputKeydownBound); - this.el.addEventListener('click', this._handleInputClickBound); - this.container.addEventListener( - 'mousedown', - this._handleContainerMousedownAndTouchstartBound - ); - this.container.addEventListener('mouseup', this._handleContainerMouseupAndTouchendBound); - - if (typeof window.ontouchstart !== 'undefined') { - this.container.addEventListener( - 'touchstart', - this._handleContainerMousedownAndTouchstartBound - ); - this.container.addEventListener('touchend', this._handleContainerMouseupAndTouchendBound); - } - } - - /** - * Remove Event Handlers - */ - _removeEventHandlers() { - this.el.removeEventListener('blur', this._handleInputBlurBound); - this.el.removeEventListener('keyup', this._handleInputKeyupAndFocusBound); - this.el.removeEventListener('focus', this._handleInputKeyupAndFocusBound); - this.el.removeEventListener('keydown', this._handleInputKeydownBound); - this.el.removeEventListener('click', this._handleInputClickBound); - this.container.removeEventListener( - 'mousedown', - this._handleContainerMousedownAndTouchstartBound - ); - this.container.removeEventListener('mouseup', this._handleContainerMouseupAndTouchendBound); - - if (typeof window.ontouchstart !== 'undefined') { - this.container.removeEventListener( - 'touchstart', - this._handleContainerMousedownAndTouchstartBound - ); - this.container.removeEventListener( - 'touchend', - this._handleContainerMouseupAndTouchendBound - ); - } - } - - /** - * Setup dropdown - */ - _setupDropdown() { - this.container = document.createElement('ul'); - this.container.id = `autocomplete-options-${M.guid()}`; - $(this.container).addClass('autocomplete-content dropdown-content'); - this.$inputField.append(this.container); - this.el.setAttribute('data-target', this.container.id); - - this.dropdown = M.Dropdown.init(this.el, { - autoFocus: false, - closeOnClick: false, - coverTrigger: false, - onItemClick: (itemEl) => { - this.selectOption($(itemEl)); - } - }); - - // Sketchy removal of dropdown click handler - this.el.removeEventListener('click', this.dropdown._handleClickBound); - } - - /** - * Remove dropdown - */ - _removeDropdown() { - this.container.parentNode.removeChild(this.container); - } - - /** - * Handle Input Blur - */ - _handleInputBlur() { - if (!this._mousedown) { - this.close(); - this._resetAutocomplete(); - } - } - - /** - * Handle Input Keyup and Focus - * @param {Event} e - */ - _handleInputKeyupAndFocus(e) { - if (e.type === 'keyup') { - Autocomplete._keydown = false; - } - - this.count = 0; - let val = this.el.value.toLowerCase(); - - // Don't capture enter or arrow key usage. - if (e.keyCode === 13 || e.keyCode === 38 || e.keyCode === 40) { - return; - } - - // Check if the input isn't empty - // Check if focus triggered by tab - if (this.oldVal !== val && (M.tabPressed || e.type !== 'focus')) { - this.open(); - } - - // Update oldVal - this.oldVal = val; - } - - /** - * Handle Input Keydown - * @param {Event} e - */ - _handleInputKeydown(e) { - Autocomplete._keydown = true; - - // Arrow keys and enter key usage - let keyCode = e.keyCode, - liElement, - numItems = $(this.container).children('li').length; - - // select element on Enter - if (keyCode === M.keys.ENTER && this.activeIndex >= 0) { - liElement = $(this.container) - .children('li') - .eq(this.activeIndex); - if (liElement.length) { - this.selectOption(liElement); - e.preventDefault(); - } - return; - } - - // Capture up and down key - if (keyCode === M.keys.ARROW_UP || keyCode === M.keys.ARROW_DOWN) { - e.preventDefault(); - - if (keyCode === M.keys.ARROW_UP && this.activeIndex > 0) { - this.activeIndex--; - } - - if (keyCode === M.keys.ARROW_DOWN && this.activeIndex < numItems - 1) { - this.activeIndex++; - } - - this.$active.removeClass('active'); - if (this.activeIndex >= 0) { - this.$active = $(this.container) - .children('li') - .eq(this.activeIndex); - this.$active.addClass('active'); - } - } - } - - /** - * Handle Input Click - * @param {Event} e - */ - _handleInputClick(e) { - this.open(); - } - - /** - * Handle Container Mousedown and Touchstart - * @param {Event} e - */ - _handleContainerMousedownAndTouchstart(e) { - this._mousedown = true; - } - - /** - * Handle Container Mouseup and Touchend - * @param {Event} e - */ - _handleContainerMouseupAndTouchend(e) { - this._mousedown = false; - } - - /** - * Highlight partial match - */ - _highlight(string, $el) { - let img = $el.find('img'); - let matchStart = $el - .text() - .toLowerCase() - .indexOf('' + string.toLowerCase() + ''), - matchEnd = matchStart + string.length - 1, - beforeMatch = $el.text().slice(0, matchStart), - matchText = $el.text().slice(matchStart, matchEnd + 1), - afterMatch = $el.text().slice(matchEnd + 1); - $el.html( - `${beforeMatch}${matchText}${afterMatch}` - ); - if (img.length) { - $el.prepend(img); - } - } - - /** - * Reset current element position - */ - _resetCurrentElement() { - this.activeIndex = -1; - this.$active.removeClass('active'); - } - - /** - * Reset autocomplete elements - */ - _resetAutocomplete() { - $(this.container).empty(); - this._resetCurrentElement(); - this.oldVal = null; - this.isOpen = false; - this._mousedown = false; - } - - /** - * Select autocomplete option - * @param {Element} el Autocomplete option list item element - */ - selectOption(el) { - let text = el.text().trim(); - this.el.value = text; - this.$el.trigger('change'); - this._resetAutocomplete(); - this.close(); - - // Handle onAutocomplete callback. - if (typeof this.options.onAutocomplete === 'function') { - this.options.onAutocomplete.call(this, text); - } - } - - /** - * Render dropdown content - * @param {Object} data data set - * @param {String} val current input value - */ - _renderDropdown(data, val) { - this._resetAutocomplete(); - - let matchingData = []; - - // Gather all matching data - for (let key in data) { - if (data.hasOwnProperty(key) && key.toLowerCase().indexOf(val) !== -1) { - // Break if past limit - if (this.count >= this.options.limit) { - break; - } - - let entry = { - data: data[key], - key: key - }; - matchingData.push(entry); - - this.count++; - } - } - - // Sort - if (this.options.sortFunction) { - let sortFunctionBound = (a, b) => { - return this.options.sortFunction( - a.key.toLowerCase(), - b.key.toLowerCase(), - val.toLowerCase() - ); - }; - matchingData.sort(sortFunctionBound); - } - - // Render - for (let i = 0; i < matchingData.length; i++) { - let entry = matchingData[i]; - let $autocompleteOption = $('
  • '); - if (!!entry.data) { - $autocompleteOption.append( - `${entry.key}` - ); - } else { - $autocompleteOption.append('' + entry.key + ''); - } - - $(this.container).append($autocompleteOption); - this._highlight(val, $autocompleteOption); - } - } - - /** - * Open Autocomplete Dropdown - */ - open() { - let val = this.el.value.toLowerCase(); - - this._resetAutocomplete(); - - if (val.length >= this.options.minLength) { - this.isOpen = true; - this._renderDropdown(this.options.data, val); - } - - // Open dropdown - if (!this.dropdown.isOpen) { - this.dropdown.open(); - } else { - // Recalculate dropdown when its already open - this.dropdown.recalculateDimensions(); - } - } - - /** - * Close Autocomplete Dropdown - */ - close() { - this.dropdown.close(); - } - - /** - * Update Data - * @param {Object} data - */ - updateData(data) { - let val = this.el.value.toLowerCase(); - this.options.data = data; - - if (this.isOpen) { - this._renderDropdown(data, val); - } - } - } - - /** - * @static - * @memberof Autocomplete - */ - Autocomplete._keydown = false; - - M.Autocomplete = Autocomplete; - - if (M.jQueryLoaded) { - M.initializeJqueryWrapper(Autocomplete, 'autocomplete', 'M_Autocomplete'); - } -})(cash); diff --git a/static/js/buttons.js b/static/js/buttons.js deleted file mode 100644 index fb2ba286..00000000 --- a/static/js/buttons.js +++ /dev/null @@ -1,354 +0,0 @@ -(function($, anim) { - 'use strict'; - - let _defaults = { - direction: 'top', - hoverEnabled: true, - toolbarEnabled: false - }; - - $.fn.reverse = [].reverse; - - /** - * @class - * - */ - class FloatingActionButton extends Component { - /** - * Construct FloatingActionButton instance - * @constructor - * @param {Element} el - * @param {Object} options - */ - constructor(el, options) { - super(FloatingActionButton, el, options); - - this.el.M_FloatingActionButton = this; - - /** - * Options for the fab - * @member FloatingActionButton#options - * @prop {Boolean} [direction] - Direction fab menu opens - * @prop {Boolean} [hoverEnabled=true] - Enable hover vs click - * @prop {Boolean} [toolbarEnabled=false] - Enable toolbar transition - */ - this.options = $.extend({}, FloatingActionButton.defaults, options); - - this.isOpen = false; - this.$anchor = this.$el.children('a').first(); - this.$menu = this.$el.children('ul').first(); - this.$floatingBtns = this.$el.find('ul .btn-floating'); - this.$floatingBtnsReverse = this.$el.find('ul .btn-floating').reverse(); - this.offsetY = 0; - this.offsetX = 0; - - this.$el.addClass(`direction-${this.options.direction}`); - if (this.options.direction === 'top') { - this.offsetY = 40; - } else if (this.options.direction === 'right') { - this.offsetX = -40; - } else if (this.options.direction === 'bottom') { - this.offsetY = -40; - } else { - this.offsetX = 40; - } - this._setupEventHandlers(); - } - - static get defaults() { - return _defaults; - } - - static init(els, options) { - return super.init(this, els, options); - } - - /** - * Get Instance - */ - static getInstance(el) { - let domElem = !!el.jquery ? el[0] : el; - return domElem.M_FloatingActionButton; - } - - /** - * Teardown component - */ - destroy() { - this._removeEventHandlers(); - this.el.M_FloatingActionButton = undefined; - } - - /** - * Setup Event Handlers - */ - _setupEventHandlers() { - this._handleFABClickBound = this._handleFABClick.bind(this); - this._handleOpenBound = this.open.bind(this); - this._handleCloseBound = this.close.bind(this); - - if (this.options.hoverEnabled && !this.options.toolbarEnabled) { - this.el.addEventListener('mouseenter', this._handleOpenBound); - this.el.addEventListener('mouseleave', this._handleCloseBound); - } else { - this.el.addEventListener('click', this._handleFABClickBound); - } - } - - /** - * Remove Event Handlers - */ - _removeEventHandlers() { - if (this.options.hoverEnabled && !this.options.toolbarEnabled) { - this.el.removeEventListener('mouseenter', this._handleOpenBound); - this.el.removeEventListener('mouseleave', this._handleCloseBound); - } else { - this.el.removeEventListener('click', this._handleFABClickBound); - } - } - - /** - * Handle FAB Click - */ - _handleFABClick() { - if (this.isOpen) { - this.close(); - } else { - this.open(); - } - } - - /** - * Handle Document Click - * @param {Event} e - */ - _handleDocumentClick(e) { - if (!$(e.target).closest(this.$menu).length) { - this.close(); - } - } - - /** - * Open FAB - */ - open() { - if (this.isOpen) { - return; - } - - if (this.options.toolbarEnabled) { - this._animateInToolbar(); - } else { - this._animateInFAB(); - } - this.isOpen = true; - } - - /** - * Close FAB - */ - close() { - if (!this.isOpen) { - return; - } - - if (this.options.toolbarEnabled) { - window.removeEventListener('scroll', this._handleCloseBound, true); - document.body.removeEventListener('click', this._handleDocumentClickBound, true); - this._animateOutToolbar(); - } else { - this._animateOutFAB(); - } - this.isOpen = false; - } - - /** - * Classic FAB Menu open - */ - _animateInFAB() { - this.$el.addClass('active'); - - let time = 0; - this.$floatingBtnsReverse.each((el) => { - anim({ - targets: el, - opacity: 1, - scale: [0.4, 1], - translateY: [this.offsetY, 0], - translateX: [this.offsetX, 0], - duration: 275, - delay: time, - easing: 'easeInOutQuad' - }); - time += 40; - }); - } - - /** - * Classic FAB Menu close - */ - _animateOutFAB() { - this.$floatingBtnsReverse.each((el) => { - anim.remove(el); - anim({ - targets: el, - opacity: 0, - scale: 0.4, - translateY: this.offsetY, - translateX: this.offsetX, - duration: 175, - easing: 'easeOutQuad', - complete: () => { - this.$el.removeClass('active'); - } - }); - }); - } - - /** - * Toolbar transition Menu open - */ - _animateInToolbar() { - let scaleFactor; - let windowWidth = window.innerWidth; - let windowHeight = window.innerHeight; - let btnRect = this.el.getBoundingClientRect(); - let backdrop = $('
    '); - let fabColor = this.$anchor.css('background-color'); - this.$anchor.append(backdrop); - - this.offsetX = btnRect.left - windowWidth / 2 + btnRect.width / 2; - this.offsetY = windowHeight - btnRect.bottom; - scaleFactor = windowWidth / backdrop[0].clientWidth; - this.btnBottom = btnRect.bottom; - this.btnLeft = btnRect.left; - this.btnWidth = btnRect.width; - - // Set initial state - this.$el.addClass('active'); - this.$el.css({ - 'text-align': 'center', - width: '100%', - bottom: 0, - left: 0, - transform: 'translateX(' + this.offsetX + 'px)', - transition: 'none' - }); - this.$anchor.css({ - transform: 'translateY(' + -this.offsetY + 'px)', - transition: 'none' - }); - backdrop.css({ - 'background-color': fabColor - }); - - setTimeout(() => { - this.$el.css({ - transform: '', - transition: - 'transform .2s cubic-bezier(0.550, 0.085, 0.680, 0.530), background-color 0s linear .2s' - }); - this.$anchor.css({ - overflow: 'visible', - transform: '', - transition: 'transform .2s' - }); - - setTimeout(() => { - this.$el.css({ - overflow: 'hidden', - 'background-color': fabColor - }); - backdrop.css({ - transform: 'scale(' + scaleFactor + ')', - transition: 'transform .2s cubic-bezier(0.550, 0.055, 0.675, 0.190)' - }); - this.$menu - .children('li') - .children('a') - .css({ - opacity: 1 - }); - - // Scroll to close. - this._handleDocumentClickBound = this._handleDocumentClick.bind(this); - window.addEventListener('scroll', this._handleCloseBound, true); - document.body.addEventListener('click', this._handleDocumentClickBound, true); - }, 100); - }, 0); - } - - /** - * Toolbar transition Menu close - */ - _animateOutToolbar() { - let windowWidth = window.innerWidth; - let windowHeight = window.innerHeight; - let backdrop = this.$el.find('.fab-backdrop'); - let fabColor = this.$anchor.css('background-color'); - - this.offsetX = this.btnLeft - windowWidth / 2 + this.btnWidth / 2; - this.offsetY = windowHeight - this.btnBottom; - - // Hide backdrop - this.$el.removeClass('active'); - this.$el.css({ - 'background-color': 'transparent', - transition: 'none' - }); - this.$anchor.css({ - transition: 'none' - }); - backdrop.css({ - transform: 'scale(0)', - 'background-color': fabColor - }); - this.$menu - .children('li') - .children('a') - .css({ - opacity: '' - }); - - setTimeout(() => { - backdrop.remove(); - - // Set initial state. - this.$el.css({ - 'text-align': '', - width: '', - bottom: '', - left: '', - overflow: '', - 'background-color': '', - transform: 'translate3d(' + -this.offsetX + 'px,0,0)' - }); - this.$anchor.css({ - overflow: '', - transform: 'translate3d(0,' + this.offsetY + 'px,0)' - }); - - setTimeout(() => { - this.$el.css({ - transform: 'translate3d(0,0,0)', - transition: 'transform .2s' - }); - this.$anchor.css({ - transform: 'translate3d(0,0,0)', - transition: 'transform .2s cubic-bezier(0.550, 0.055, 0.675, 0.190)' - }); - }, 20); - }, 200); - } - } - - M.FloatingActionButton = FloatingActionButton; - - if (M.jQueryLoaded) { - M.initializeJqueryWrapper( - FloatingActionButton, - 'floatingActionButton', - 'M_FloatingActionButton' - ); - } -})(cash, M.anime); diff --git a/static/js/cards.js b/static/js/cards.js deleted file mode 100644 index 0c1ad737..00000000 --- a/static/js/cards.js +++ /dev/null @@ -1,40 +0,0 @@ -(function($, anim) { - $(document).on('click', '.card', function(e) { - if ($(this).children('.card-reveal').length) { - var $card = $(e.target).closest('.card'); - if ($card.data('initialOverflow') === undefined) { - $card.data( - 'initialOverflow', - $card.css('overflow') === undefined ? '' : $card.css('overflow') - ); - } - let $cardReveal = $(this).find('.card-reveal'); - if ( - $(e.target).is($('.card-reveal .card-title')) || - $(e.target).is($('.card-reveal .card-title i')) - ) { - // Make Reveal animate down and display none - anim({ - targets: $cardReveal[0], - translateY: 0, - duration: 225, - easing: 'easeInOutQuad', - complete: function(anim) { - let el = anim.animatables[0].target; - $(el).css({ display: 'none' }); - $card.css('overflow', $card.data('initialOverflow')); - } - }); - } else if ($(e.target).is($('.card .activator')) || $(e.target).is($('.card .activator i'))) { - $card.css('overflow', 'hidden'); - $cardReveal.css({ display: 'block' }); - anim({ - targets: $cardReveal[0], - translateY: '-100%', - duration: 300, - easing: 'easeInOutQuad' - }); - } - } - }); -})(cash, M.anime); diff --git a/static/js/carousel.js b/static/js/carousel.js deleted file mode 100644 index be98dc88..00000000 --- a/static/js/carousel.js +++ /dev/null @@ -1,717 +0,0 @@ -(function($) { - 'use strict'; - - let _defaults = { - duration: 200, // ms - dist: -100, // zoom scale TODO: make this more intuitive as an option - shift: 0, // spacing for center image - padding: 0, // Padding between non center items - numVisible: 5, // Number of visible items in carousel - fullWidth: false, // Change to full width styles - indicators: false, // Toggle indicators - noWrap: false, // Don't wrap around and cycle through items. - onCycleTo: null // Callback for when a new slide is cycled to. - }; - - /** - * @class - * - */ - class Carousel extends Component { - /** - * Construct Carousel instance - * @constructor - * @param {Element} el - * @param {Object} options - */ - constructor(el, options) { - super(Carousel, el, options); - - this.el.M_Carousel = this; - - /** - * Options for the carousel - * @member Carousel#options - * @prop {Number} duration - * @prop {Number} dist - * @prop {Number} shift - * @prop {Number} padding - * @prop {Number} numVisible - * @prop {Boolean} fullWidth - * @prop {Boolean} indicators - * @prop {Boolean} noWrap - * @prop {Function} onCycleTo - */ - this.options = $.extend({}, Carousel.defaults, options); - - // Setup - this.hasMultipleSlides = this.$el.find('.carousel-item').length > 1; - this.showIndicators = this.options.indicators && this.hasMultipleSlides; - this.noWrap = this.options.noWrap || !this.hasMultipleSlides; - this.pressed = false; - this.dragged = false; - this.offset = this.target = 0; - this.images = []; - this.itemWidth = this.$el - .find('.carousel-item') - .first() - .innerWidth(); - this.itemHeight = this.$el - .find('.carousel-item') - .first() - .innerHeight(); - this.dim = this.itemWidth * 2 + this.options.padding || 1; // Make sure dim is non zero for divisions. - this._autoScrollBound = this._autoScroll.bind(this); - this._trackBound = this._track.bind(this); - - // Full Width carousel setup - if (this.options.fullWidth) { - this.options.dist = 0; - this._setCarouselHeight(); - - // Offset fixed items when indicators. - if (this.showIndicators) { - this.$el.find('.carousel-fixed-item').addClass('with-indicators'); - } - } - - // Iterate through slides - this.$indicators = $('
      '); - this.$el.find('.carousel-item').each((el, i) => { - this.images.push(el); - if (this.showIndicators) { - let $indicator = $('
    • '); - - // Add active to first by default. - if (i === 0) { - $indicator[0].classList.add('active'); - } - - this.$indicators.append($indicator); - } - }); - if (this.showIndicators) { - this.$el.append(this.$indicators); - } - this.count = this.images.length; - - // Cap numVisible at count - this.options.numVisible = Math.min(this.count, this.options.numVisible); - - // Setup cross browser string - this.xform = 'transform'; - ['webkit', 'Moz', 'O', 'ms'].every((prefix) => { - var e = prefix + 'Transform'; - if (typeof document.body.style[e] !== 'undefined') { - this.xform = e; - return false; - } - return true; - }); - - this._setupEventHandlers(); - this._scroll(this.offset); - } - - static get defaults() { - return _defaults; - } - - static init(els, options) { - return super.init(this, els, options); - } - - /** - * Get Instance - */ - static getInstance(el) { - let domElem = !!el.jquery ? el[0] : el; - return domElem.M_Carousel; - } - - /** - * Teardown component - */ - destroy() { - this._removeEventHandlers(); - this.el.M_Carousel = undefined; - } - - /** - * Setup Event Handlers - */ - _setupEventHandlers() { - this._handleCarouselTapBound = this._handleCarouselTap.bind(this); - this._handleCarouselDragBound = this._handleCarouselDrag.bind(this); - this._handleCarouselReleaseBound = this._handleCarouselRelease.bind(this); - this._handleCarouselClickBound = this._handleCarouselClick.bind(this); - - if (typeof window.ontouchstart !== 'undefined') { - this.el.addEventListener('touchstart', this._handleCarouselTapBound); - this.el.addEventListener('touchmove', this._handleCarouselDragBound); - this.el.addEventListener('touchend', this._handleCarouselReleaseBound); - } - - this.el.addEventListener('mousedown', this._handleCarouselTapBound); - this.el.addEventListener('mousemove', this._handleCarouselDragBound); - this.el.addEventListener('mouseup', this._handleCarouselReleaseBound); - this.el.addEventListener('mouseleave', this._handleCarouselReleaseBound); - this.el.addEventListener('click', this._handleCarouselClickBound); - - if (this.showIndicators && this.$indicators) { - this._handleIndicatorClickBound = this._handleIndicatorClick.bind(this); - this.$indicators.find('.indicator-item').each((el, i) => { - el.addEventListener('click', this._handleIndicatorClickBound); - }); - } - - // Resize - let throttledResize = M.throttle(this._handleResize, 200); - this._handleThrottledResizeBound = throttledResize.bind(this); - - window.addEventListener('resize', this._handleThrottledResizeBound); - } - - /** - * Remove Event Handlers - */ - _removeEventHandlers() { - if (typeof window.ontouchstart !== 'undefined') { - this.el.removeEventListener('touchstart', this._handleCarouselTapBound); - this.el.removeEventListener('touchmove', this._handleCarouselDragBound); - this.el.removeEventListener('touchend', this._handleCarouselReleaseBound); - } - this.el.removeEventListener('mousedown', this._handleCarouselTapBound); - this.el.removeEventListener('mousemove', this._handleCarouselDragBound); - this.el.removeEventListener('mouseup', this._handleCarouselReleaseBound); - this.el.removeEventListener('mouseleave', this._handleCarouselReleaseBound); - this.el.removeEventListener('click', this._handleCarouselClickBound); - - if (this.showIndicators && this.$indicators) { - this.$indicators.find('.indicator-item').each((el, i) => { - el.removeEventListener('click', this._handleIndicatorClickBound); - }); - } - - window.removeEventListener('resize', this._handleThrottledResizeBound); - } - - /** - * Handle Carousel Tap - * @param {Event} e - */ - _handleCarouselTap(e) { - // Fixes firefox draggable image bug - if (e.type === 'mousedown' && $(e.target).is('img')) { - e.preventDefault(); - } - this.pressed = true; - this.dragged = false; - this.verticalDragged = false; - this.reference = this._xpos(e); - this.referenceY = this._ypos(e); - - this.velocity = this.amplitude = 0; - this.frame = this.offset; - this.timestamp = Date.now(); - clearInterval(this.ticker); - this.ticker = setInterval(this._trackBound, 100); - } - - /** - * Handle Carousel Drag - * @param {Event} e - */ - _handleCarouselDrag(e) { - let x, y, delta, deltaY; - if (this.pressed) { - x = this._xpos(e); - y = this._ypos(e); - delta = this.reference - x; - deltaY = Math.abs(this.referenceY - y); - if (deltaY < 30 && !this.verticalDragged) { - // If vertical scrolling don't allow dragging. - if (delta > 2 || delta < -2) { - this.dragged = true; - this.reference = x; - this._scroll(this.offset + delta); - } - } else if (this.dragged) { - // If dragging don't allow vertical scroll. - e.preventDefault(); - e.stopPropagation(); - return false; - } else { - // Vertical scrolling. - this.verticalDragged = true; - } - } - - if (this.dragged) { - // If dragging don't allow vertical scroll. - e.preventDefault(); - e.stopPropagation(); - return false; - } - } - - /** - * Handle Carousel Release - * @param {Event} e - */ - _handleCarouselRelease(e) { - if (this.pressed) { - this.pressed = false; - } else { - return; - } - - clearInterval(this.ticker); - this.target = this.offset; - if (this.velocity > 10 || this.velocity < -10) { - this.amplitude = 0.9 * this.velocity; - this.target = this.offset + this.amplitude; - } - this.target = Math.round(this.target / this.dim) * this.dim; - - // No wrap of items. - if (this.noWrap) { - if (this.target >= this.dim * (this.count - 1)) { - this.target = this.dim * (this.count - 1); - } else if (this.target < 0) { - this.target = 0; - } - } - this.amplitude = this.target - this.offset; - this.timestamp = Date.now(); - requestAnimationFrame(this._autoScrollBound); - - if (this.dragged) { - e.preventDefault(); - e.stopPropagation(); - } - return false; - } - - /** - * Handle Carousel CLick - * @param {Event} e - */ - _handleCarouselClick(e) { - // Disable clicks if carousel was dragged. - if (this.dragged) { - e.preventDefault(); - e.stopPropagation(); - return false; - } else if (!this.options.fullWidth) { - let clickedIndex = $(e.target) - .closest('.carousel-item') - .index(); - let diff = this._wrap(this.center) - clickedIndex; - - // Disable clicks if carousel was shifted by click - if (diff !== 0) { - e.preventDefault(); - e.stopPropagation(); - } - this._cycleTo(clickedIndex); - } - } - - /** - * Handle Indicator CLick - * @param {Event} e - */ - _handleIndicatorClick(e) { - e.stopPropagation(); - - let indicator = $(e.target).closest('.indicator-item'); - if (indicator.length) { - this._cycleTo(indicator.index()); - } - } - - /** - * Handle Throttle Resize - * @param {Event} e - */ - _handleResize(e) { - if (this.options.fullWidth) { - this.itemWidth = this.$el - .find('.carousel-item') - .first() - .innerWidth(); - this.imageHeight = this.$el.find('.carousel-item.active').height(); - this.dim = this.itemWidth * 2 + this.options.padding; - this.offset = this.center * 2 * this.itemWidth; - this.target = this.offset; - this._setCarouselHeight(true); - } else { - this._scroll(); - } - } - - /** - * Set carousel height based on first slide - * @param {Booleam} imageOnly - true for image slides - */ - _setCarouselHeight(imageOnly) { - let firstSlide = this.$el.find('.carousel-item.active').length - ? this.$el.find('.carousel-item.active').first() - : this.$el.find('.carousel-item').first(); - let firstImage = firstSlide.find('img').first(); - if (firstImage.length) { - if (firstImage[0].complete) { - // If image won't trigger the load event - let imageHeight = firstImage.height(); - if (imageHeight > 0) { - this.$el.css('height', imageHeight + 'px'); - } else { - // If image still has no height, use the natural dimensions to calculate - let naturalWidth = firstImage[0].naturalWidth; - let naturalHeight = firstImage[0].naturalHeight; - let adjustedHeight = this.$el.width() / naturalWidth * naturalHeight; - this.$el.css('height', adjustedHeight + 'px'); - } - } else { - // Get height when image is loaded normally - firstImage.one('load', (el, i) => { - this.$el.css('height', el.offsetHeight + 'px'); - }); - } - } else if (!imageOnly) { - let slideHeight = firstSlide.height(); - this.$el.css('height', slideHeight + 'px'); - } - } - - /** - * Get x position from event - * @param {Event} e - */ - _xpos(e) { - // touch event - if (e.targetTouches && e.targetTouches.length >= 1) { - return e.targetTouches[0].clientX; - } - - // mouse event - return e.clientX; - } - - /** - * Get y position from event - * @param {Event} e - */ - _ypos(e) { - // touch event - if (e.targetTouches && e.targetTouches.length >= 1) { - return e.targetTouches[0].clientY; - } - - // mouse event - return e.clientY; - } - - /** - * Wrap index - * @param {Number} x - */ - _wrap(x) { - return x >= this.count ? x % this.count : x < 0 ? this._wrap(this.count + x % this.count) : x; - } - - /** - * Tracks scrolling information - */ - _track() { - let now, elapsed, delta, v; - - now = Date.now(); - elapsed = now - this.timestamp; - this.timestamp = now; - delta = this.offset - this.frame; - this.frame = this.offset; - - v = 1000 * delta / (1 + elapsed); - this.velocity = 0.8 * v + 0.2 * this.velocity; - } - - /** - * Auto scrolls to nearest carousel item. - */ - _autoScroll() { - let elapsed, delta; - - if (this.amplitude) { - elapsed = Date.now() - this.timestamp; - delta = this.amplitude * Math.exp(-elapsed / this.options.duration); - if (delta > 2 || delta < -2) { - this._scroll(this.target - delta); - requestAnimationFrame(this._autoScrollBound); - } else { - this._scroll(this.target); - } - } - } - - /** - * Scroll to target - * @param {Number} x - */ - _scroll(x) { - // Track scrolling state - if (!this.$el.hasClass('scrolling')) { - this.el.classList.add('scrolling'); - } - if (this.scrollingTimeout != null) { - window.clearTimeout(this.scrollingTimeout); - } - this.scrollingTimeout = window.setTimeout(() => { - this.$el.removeClass('scrolling'); - }, this.options.duration); - - // Start actual scroll - let i, - half, - delta, - dir, - tween, - el, - alignment, - zTranslation, - tweenedOpacity, - centerTweenedOpacity; - let lastCenter = this.center; - let numVisibleOffset = 1 / this.options.numVisible; - - this.offset = typeof x === 'number' ? x : this.offset; - this.center = Math.floor((this.offset + this.dim / 2) / this.dim); - delta = this.offset - this.center * this.dim; - dir = delta < 0 ? 1 : -1; - tween = -dir * delta * 2 / this.dim; - half = this.count >> 1; - - if (this.options.fullWidth) { - alignment = 'translateX(0)'; - centerTweenedOpacity = 1; - } else { - alignment = 'translateX(' + (this.el.clientWidth - this.itemWidth) / 2 + 'px) '; - alignment += 'translateY(' + (this.el.clientHeight - this.itemHeight) / 2 + 'px)'; - centerTweenedOpacity = 1 - numVisibleOffset * tween; - } - - // Set indicator active - if (this.showIndicators) { - let diff = this.center % this.count; - let activeIndicator = this.$indicators.find('.indicator-item.active'); - if (activeIndicator.index() !== diff) { - activeIndicator.removeClass('active'); - this.$indicators - .find('.indicator-item') - .eq(diff)[0] - .classList.add('active'); - } - } - - // center - // Don't show wrapped items. - if (!this.noWrap || (this.center >= 0 && this.center < this.count)) { - el = this.images[this._wrap(this.center)]; - - // Add active class to center item. - if (!$(el).hasClass('active')) { - this.$el.find('.carousel-item').removeClass('active'); - el.classList.add('active'); - } - let transformString = `${alignment} translateX(${-delta / 2}px) translateX(${dir * - this.options.shift * - tween * - i}px) translateZ(${this.options.dist * tween}px)`; - this._updateItemStyle(el, centerTweenedOpacity, 0, transformString); - } - - for (i = 1; i <= half; ++i) { - // right side - if (this.options.fullWidth) { - zTranslation = this.options.dist; - tweenedOpacity = i === half && delta < 0 ? 1 - tween : 1; - } else { - zTranslation = this.options.dist * (i * 2 + tween * dir); - tweenedOpacity = 1 - numVisibleOffset * (i * 2 + tween * dir); - } - // Don't show wrapped items. - if (!this.noWrap || this.center + i < this.count) { - el = this.images[this._wrap(this.center + i)]; - let transformString = `${alignment} translateX(${this.options.shift + - (this.dim * i - delta) / 2}px) translateZ(${zTranslation}px)`; - this._updateItemStyle(el, tweenedOpacity, -i, transformString); - } - - // left side - if (this.options.fullWidth) { - zTranslation = this.options.dist; - tweenedOpacity = i === half && delta > 0 ? 1 - tween : 1; - } else { - zTranslation = this.options.dist * (i * 2 - tween * dir); - tweenedOpacity = 1 - numVisibleOffset * (i * 2 - tween * dir); - } - // Don't show wrapped items. - if (!this.noWrap || this.center - i >= 0) { - el = this.images[this._wrap(this.center - i)]; - let transformString = `${alignment} translateX(${-this.options.shift + - (-this.dim * i - delta) / 2}px) translateZ(${zTranslation}px)`; - this._updateItemStyle(el, tweenedOpacity, -i, transformString); - } - } - - // center - // Don't show wrapped items. - if (!this.noWrap || (this.center >= 0 && this.center < this.count)) { - el = this.images[this._wrap(this.center)]; - let transformString = `${alignment} translateX(${-delta / 2}px) translateX(${dir * - this.options.shift * - tween}px) translateZ(${this.options.dist * tween}px)`; - this._updateItemStyle(el, centerTweenedOpacity, 0, transformString); - } - - // onCycleTo callback - let $currItem = this.$el.find('.carousel-item').eq(this._wrap(this.center)); - if (lastCenter !== this.center && typeof this.options.onCycleTo === 'function') { - this.options.onCycleTo.call(this, $currItem[0], this.dragged); - } - - // One time callback - if (typeof this.oneTimeCallback === 'function') { - this.oneTimeCallback.call(this, $currItem[0], this.dragged); - this.oneTimeCallback = null; - } - } - - /** - * Cycle to target - * @param {Element} el - * @param {Number} opacity - * @param {Number} zIndex - * @param {String} transform - */ - _updateItemStyle(el, opacity, zIndex, transform) { - el.style[this.xform] = transform; - el.style.zIndex = zIndex; - el.style.opacity = opacity; - el.style.visibility = 'visible'; - } - - /** - * Cycle to target - * @param {Number} n - * @param {Function} callback - */ - _cycleTo(n, callback) { - let diff = this.center % this.count - n; - - // Account for wraparound. - if (!this.noWrap) { - if (diff < 0) { - if (Math.abs(diff + this.count) < Math.abs(diff)) { - diff += this.count; - } - } else if (diff > 0) { - if (Math.abs(diff - this.count) < diff) { - diff -= this.count; - } - } - } - - this.target = this.dim * Math.round(this.offset / this.dim); - // Next - if (diff < 0) { - this.target += this.dim * Math.abs(diff); - - // Prev - } else if (diff > 0) { - this.target -= this.dim * diff; - } - - // Set one time callback - if (typeof callback === 'function') { - this.oneTimeCallback = callback; - } - - // Scroll - if (this.offset !== this.target) { - this.amplitude = this.target - this.offset; - this.timestamp = Date.now(); - requestAnimationFrame(this._autoScrollBound); - } - } - - /** - * Cycle to next item - * @param {Number} [n] - */ - next(n) { - if (n === undefined || isNaN(n)) { - n = 1; - } - - let index = this.center + n; - if (index >= this.count || index < 0) { - if (this.noWrap) { - return; - } - - index = this._wrap(index); - } - this._cycleTo(index); - } - - /** - * Cycle to previous item - * @param {Number} [n] - */ - prev(n) { - if (n === undefined || isNaN(n)) { - n = 1; - } - - let index = this.center - n; - if (index >= this.count || index < 0) { - if (this.noWrap) { - return; - } - - index = this._wrap(index); - } - - this._cycleTo(index); - } - - /** - * Cycle to nth item - * @param {Number} [n] - * @param {Function} callback - */ - set(n, callback) { - if (n === undefined || isNaN(n)) { - n = 0; - } - - if (n > this.count || n < 0) { - if (this.noWrap) { - return; - } - - n = this._wrap(n); - } - - this._cycleTo(n, callback); - } - } - - M.Carousel = Carousel; - - if (M.jQueryLoaded) { - M.initializeJqueryWrapper(Carousel, 'carousel', 'M_Carousel'); - } -})(cash); diff --git a/static/js/cash.js b/static/js/cash.js deleted file mode 100644 index 17d95acd..00000000 --- a/static/js/cash.js +++ /dev/null @@ -1,960 +0,0 @@ -/*! cash-dom 1.3.5, https://github.com/kenwheeler/cash @license MIT */ -(function (factory) { - window.cash = factory(); -})(function () { - var doc = document, win = window, ArrayProto = Array.prototype, slice = ArrayProto.slice, filter = ArrayProto.filter, push = ArrayProto.push; - - var noop = function () {}, isFunction = function (item) { - // @see https://crbug.com/568448 - return typeof item === typeof noop && item.call; - }, isString = function (item) { - return typeof item === typeof ""; - }; - - var idMatch = /^#[\w-]*$/, classMatch = /^\.[\w-]*$/, htmlMatch = /<.+>/, singlet = /^\w+$/; - - function find(selector, context) { - context = context || doc; - var elems = (classMatch.test(selector) ? context.getElementsByClassName(selector.slice(1)) : singlet.test(selector) ? context.getElementsByTagName(selector) : context.querySelectorAll(selector)); - return elems; - } - - var frag; - function parseHTML(str) { - if (!frag) { - frag = doc.implementation.createHTMLDocument(null); - var base = frag.createElement("base"); - base.href = doc.location.href; - frag.head.appendChild(base); - } - - frag.body.innerHTML = str; - - return frag.body.childNodes; - } - - function onReady(fn) { - if (doc.readyState !== "loading") { - fn(); - } else { - doc.addEventListener("DOMContentLoaded", fn); - } - } - - function Init(selector, context) { - if (!selector) { - return this; - } - - // If already a cash collection, don't do any further processing - if (selector.cash && selector !== win) { - return selector; - } - - var elems = selector, i = 0, length; - - if (isString(selector)) { - elems = (idMatch.test(selector) ? - // If an ID use the faster getElementById check - doc.getElementById(selector.slice(1)) : htmlMatch.test(selector) ? - // If HTML, parse it into real elements - parseHTML(selector) : - // else use `find` - find(selector, context)); - - // If function, use as shortcut for DOM ready - } else if (isFunction(selector)) { - onReady(selector);return this; - } - - if (!elems) { - return this; - } - - // If a single DOM element is passed in or received via ID, return the single element - if (elems.nodeType || elems === win) { - this[0] = elems; - this.length = 1; - } else { - // Treat like an array and loop through each item. - length = this.length = elems.length; - for (; i < length; i++) { - this[i] = elems[i]; - } - } - - return this; - } - - function cash(selector, context) { - return new Init(selector, context); - } - - var fn = cash.fn = cash.prototype = Init.prototype = { // jshint ignore:line - cash: true, - length: 0, - push: push, - splice: ArrayProto.splice, - map: ArrayProto.map, - init: Init - }; - - Object.defineProperty(fn, "constructor", { value: cash }); - - cash.parseHTML = parseHTML; - cash.noop = noop; - cash.isFunction = isFunction; - cash.isString = isString; - - cash.extend = fn.extend = function (target) { - target = target || {}; - - var args = slice.call(arguments), length = args.length, i = 1; - - if (args.length === 1) { - target = this; - i = 0; - } - - for (; i < length; i++) { - if (!args[i]) { - continue; - } - for (var key in args[i]) { - if (args[i].hasOwnProperty(key)) { - target[key] = args[i][key]; - } - } - } - - return target; - }; - - function each(collection, callback) { - var l = collection.length, i = 0; - - for (; i < l; i++) { - if (callback.call(collection[i], collection[i], i, collection) === false) { - break; - } - } - } - - function matches(el, selector) { - var m = el && (el.matches || el.webkitMatchesSelector || el.mozMatchesSelector || el.msMatchesSelector || el.oMatchesSelector); - return !!m && m.call(el, selector); - } - - function getCompareFunction(selector) { - return ( - /* Use browser's `matches` function if string */ - isString(selector) ? matches : - /* Match a cash element */ - selector.cash ? function (el) { - return selector.is(el); - } : - /* Direct comparison */ - function (el, selector) { - return el === selector; - }); - } - - function unique(collection) { - return cash(slice.call(collection).filter(function (item, index, self) { - return self.indexOf(item) === index; - })); - } - - cash.extend({ - merge: function (first, second) { - var len = +second.length, i = first.length, j = 0; - - for (; j < len; i++, j++) { - first[i] = second[j]; - } - - first.length = i; - return first; - }, - - each: each, - matches: matches, - unique: unique, - isArray: Array.isArray, - isNumeric: function (n) { - return !isNaN(parseFloat(n)) && isFinite(n); - } - - }); - - var uid = cash.uid = "_cash" + Date.now(); - - function getDataCache(node) { - return (node[uid] = node[uid] || {}); - } - - function setData(node, key, value) { - return (getDataCache(node)[key] = value); - } - - function getData(node, key) { - var c = getDataCache(node); - if (c[key] === undefined) { - c[key] = node.dataset ? node.dataset[key] : cash(node).attr("data-" + key); - } - return c[key]; - } - - function removeData(node, key) { - var c = getDataCache(node); - if (c) { - delete c[key]; - } else if (node.dataset) { - delete node.dataset[key]; - } else { - cash(node).removeAttr("data-" + name); - } - } - - fn.extend({ - data: function (name, value) { - if (isString(name)) { - return (value === undefined ? getData(this[0], name) : this.each(function (v) { - return setData(v, name, value); - })); - } - - for (var key in name) { - this.data(key, name[key]); - } - - return this; - }, - - removeData: function (key) { - return this.each(function (v) { - return removeData(v, key); - }); - } - - }); - - var notWhiteMatch = /\S+/g; - - function getClasses(c) { - return isString(c) && c.match(notWhiteMatch); - } - - function hasClass(v, c) { - return (v.classList ? v.classList.contains(c) : new RegExp("(^| )" + c + "( |$)", "gi").test(v.className)); - } - - function addClass(v, c, spacedName) { - if (v.classList) { - v.classList.add(c); - } else if (spacedName.indexOf(" " + c + " ")) { - v.className += " " + c; - } - } - - function removeClass(v, c) { - if (v.classList) { - v.classList.remove(c); - } else { - v.className = v.className.replace(c, ""); - } - } - - fn.extend({ - addClass: function (c) { - var classes = getClasses(c); - - return (classes ? this.each(function (v) { - var spacedName = " " + v.className + " "; - each(classes, function (c) { - addClass(v, c, spacedName); - }); - }) : this); - }, - - attr: function (name, value) { - if (!name) { - return undefined; - } - - if (isString(name)) { - if (value === undefined) { - return this[0] ? this[0].getAttribute ? this[0].getAttribute(name) : this[0][name] : undefined; - } - - return this.each(function (v) { - if (v.setAttribute) { - v.setAttribute(name, value); - } else { - v[name] = value; - } - }); - } - - for (var key in name) { - this.attr(key, name[key]); - } - - return this; - }, - - hasClass: function (c) { - var check = false, classes = getClasses(c); - if (classes && classes.length) { - this.each(function (v) { - check = hasClass(v, classes[0]); - return !check; - }); - } - return check; - }, - - prop: function (name, value) { - if (isString(name)) { - return (value === undefined ? this[0][name] : this.each(function (v) { - v[name] = value; - })); - } - - for (var key in name) { - this.prop(key, name[key]); - } - - return this; - }, - - removeAttr: function (name) { - return this.each(function (v) { - if (v.removeAttribute) { - v.removeAttribute(name); - } else { - delete v[name]; - } - }); - }, - - removeClass: function (c) { - if (!arguments.length) { - return this.attr("class", ""); - } - var classes = getClasses(c); - return (classes ? this.each(function (v) { - each(classes, function (c) { - removeClass(v, c); - }); - }) : this); - }, - - removeProp: function (name) { - return this.each(function (v) { - delete v[name]; - }); - }, - - toggleClass: function (c, state) { - if (state !== undefined) { - return this[state ? "addClass" : "removeClass"](c); - } - var classes = getClasses(c); - return (classes ? this.each(function (v) { - var spacedName = " " + v.className + " "; - each(classes, function (c) { - if (hasClass(v, c)) { - removeClass(v, c); - } else { - addClass(v, c, spacedName); - } - }); - }) : this); - } }); - - fn.extend({ - add: function (selector, context) { - return unique(cash.merge(this, cash(selector, context))); - }, - - each: function (callback) { - each(this, callback); - return this; - }, - - eq: function (index) { - return cash(this.get(index)); - }, - - filter: function (selector) { - if (!selector) { - return this; - } - - var comparator = (isFunction(selector) ? selector : getCompareFunction(selector)); - - return cash(filter.call(this, function (e) { - return comparator(e, selector); - })); - }, - - first: function () { - return this.eq(0); - }, - - get: function (index) { - if (index === undefined) { - return slice.call(this); - } - return (index < 0 ? this[index + this.length] : this[index]); - }, - - index: function (elem) { - var child = elem ? cash(elem)[0] : this[0], collection = elem ? this : cash(child).parent().children(); - return slice.call(collection).indexOf(child); - }, - - last: function () { - return this.eq(-1); - } - - }); - - var camelCase = (function () { - var camelRegex = /(?:^\w|[A-Z]|\b\w)/g, whiteSpace = /[\s-_]+/g; - return function (str) { - return str.replace(camelRegex, function (letter, index) { - return letter[index === 0 ? "toLowerCase" : "toUpperCase"](); - }).replace(whiteSpace, ""); - }; - }()); - - var getPrefixedProp = (function () { - var cache = {}, doc = document, div = doc.createElement("div"), style = div.style; - - return function (prop) { - prop = camelCase(prop); - if (cache[prop]) { - return cache[prop]; - } - - var ucProp = prop.charAt(0).toUpperCase() + prop.slice(1), prefixes = ["webkit", "moz", "ms", "o"], props = (prop + " " + (prefixes).join(ucProp + " ") + ucProp).split(" "); - - each(props, function (p) { - if (p in style) { - cache[p] = prop = cache[prop] = p; - return false; - } - }); - - return cache[prop]; - }; - }()); - - cash.prefixedProp = getPrefixedProp; - cash.camelCase = camelCase; - - fn.extend({ - css: function (prop, value) { - if (isString(prop)) { - prop = getPrefixedProp(prop); - return (arguments.length > 1 ? this.each(function (v) { - return v.style[prop] = value; - }) : win.getComputedStyle(this[0])[prop]); - } - - for (var key in prop) { - this.css(key, prop[key]); - } - - return this; - } - - }); - - function compute(el, prop) { - return parseInt(win.getComputedStyle(el[0], null)[prop], 10) || 0; - } - - each(["Width", "Height"], function (v) { - var lower = v.toLowerCase(); - - fn[lower] = function () { - return this[0].getBoundingClientRect()[lower]; - }; - - fn["inner" + v] = function () { - return this[0]["client" + v]; - }; - - fn["outer" + v] = function (margins) { - return this[0]["offset" + v] + (margins ? compute(this, "margin" + (v === "Width" ? "Left" : "Top")) + compute(this, "margin" + (v === "Width" ? "Right" : "Bottom")) : 0); - }; - }); - - function registerEvent(node, eventName, callback) { - var eventCache = getData(node, "_cashEvents") || setData(node, "_cashEvents", {}); - eventCache[eventName] = eventCache[eventName] || []; - eventCache[eventName].push(callback); - node.addEventListener(eventName, callback); - } - - function removeEvent(node, eventName, callback) { - var events = getData(node, "_cashEvents"), eventCache = (events && events[eventName]), index; - - if (!eventCache) { - return; - } - - if (callback) { - node.removeEventListener(eventName, callback); - index = eventCache.indexOf(callback); - if (index >= 0) { - eventCache.splice(index, 1); - } - } else { - each(eventCache, function (event) { - node.removeEventListener(eventName, event); - }); - eventCache = []; - } - } - - fn.extend({ - off: function (eventName, callback) { - return this.each(function (v) { - return removeEvent(v, eventName, callback); - }); - }, - - on: function (eventName, delegate, callback, runOnce) { - // jshint ignore:line - var originalCallback; - if (!isString(eventName)) { - for (var key in eventName) { - this.on(key, delegate, eventName[key]); - } - return this; - } - - if (isFunction(delegate)) { - callback = delegate; - delegate = null; - } - - if (eventName === "ready") { - onReady(callback); - return this; - } - - if (delegate) { - originalCallback = callback; - callback = function (e) { - var t = e.target; - while (!matches(t, delegate)) { - if (t === this || t === null) { - return (t = false); - } - - t = t.parentNode; - } - - if (t) { - originalCallback.call(t, e); - } - }; - } - - return this.each(function (v) { - var finalCallback = callback; - if (runOnce) { - finalCallback = function () { - callback.apply(this, arguments); - removeEvent(v, eventName, finalCallback); - }; - } - registerEvent(v, eventName, finalCallback); - }); - }, - - one: function (eventName, delegate, callback) { - return this.on(eventName, delegate, callback, true); - }, - - ready: onReady, - - /** - * Modified - * Triggers browser event - * @param String eventName - * @param Object data - Add properties to event object - */ - trigger: function (eventName, data) { - if (document.createEvent) { - let evt = document.createEvent('HTMLEvents'); - evt.initEvent(eventName, true, false); - evt = this.extend(evt, data); - return this.each(function (v) { - return v.dispatchEvent(evt); - }); - } - } - - }); - - function encode(name, value) { - return "&" + encodeURIComponent(name) + "=" + encodeURIComponent(value).replace(/%20/g, "+"); - } - - function getSelectMultiple_(el) { - var values = []; - each(el.options, function (o) { - if (o.selected) { - values.push(o.value); - } - }); - return values.length ? values : null; - } - - function getSelectSingle_(el) { - var selectedIndex = el.selectedIndex; - return selectedIndex >= 0 ? el.options[selectedIndex].value : null; - } - - function getValue(el) { - var type = el.type; - if (!type) { - return null; - } - switch (type.toLowerCase()) { - case "select-one": - return getSelectSingle_(el); - case "select-multiple": - return getSelectMultiple_(el); - case "radio": - return (el.checked) ? el.value : null; - case "checkbox": - return (el.checked) ? el.value : null; - default: - return el.value ? el.value : null; - } - } - - fn.extend({ - serialize: function () { - var query = ""; - - each(this[0].elements || this, function (el) { - if (el.disabled || el.tagName === "FIELDSET") { - return; - } - var name = el.name; - switch (el.type.toLowerCase()) { - case "file": - case "reset": - case "submit": - case "button": - break; - case "select-multiple": - var values = getValue(el); - if (values !== null) { - each(values, function (value) { - query += encode(name, value); - }); - } - break; - default: - var value = getValue(el); - if (value !== null) { - query += encode(name, value); - } - } - }); - - return query.substr(1); - }, - - val: function (value) { - if (value === undefined) { - return getValue(this[0]); - } - - return this.each(function (v) { - return v.value = value; - }); - } - - }); - - function insertElement(el, child, prepend) { - if (prepend) { - var first = el.childNodes[0]; - el.insertBefore(child, first); - } else { - el.appendChild(child); - } - } - - function insertContent(parent, child, prepend) { - var str = isString(child); - - if (!str && child.length) { - each(child, function (v) { - return insertContent(parent, v, prepend); - }); - return; - } - - each(parent, str ? function (v) { - return v.insertAdjacentHTML(prepend ? "afterbegin" : "beforeend", child); - } : function (v, i) { - return insertElement(v, (i === 0 ? child : child.cloneNode(true)), prepend); - }); - } - - fn.extend({ - after: function (selector) { - cash(selector).insertAfter(this); - return this; - }, - - append: function (content) { - insertContent(this, content); - return this; - }, - - appendTo: function (parent) { - insertContent(cash(parent), this); - return this; - }, - - before: function (selector) { - cash(selector).insertBefore(this); - return this; - }, - - clone: function () { - return cash(this.map(function (v) { - return v.cloneNode(true); - })); - }, - - empty: function () { - this.html(""); - return this; - }, - - html: function (content) { - if (content === undefined) { - return this[0].innerHTML; - } - var source = (content.nodeType ? content[0].outerHTML : content); - return this.each(function (v) { - return v.innerHTML = source; - }); - }, - - insertAfter: function (selector) { - var _this = this; - - - cash(selector).each(function (el, i) { - var parent = el.parentNode, sibling = el.nextSibling; - _this.each(function (v) { - parent.insertBefore((i === 0 ? v : v.cloneNode(true)), sibling); - }); - }); - - return this; - }, - - insertBefore: function (selector) { - var _this2 = this; - cash(selector).each(function (el, i) { - var parent = el.parentNode; - _this2.each(function (v) { - parent.insertBefore((i === 0 ? v : v.cloneNode(true)), el); - }); - }); - return this; - }, - - prepend: function (content) { - insertContent(this, content, true); - return this; - }, - - prependTo: function (parent) { - insertContent(cash(parent), this, true); - return this; - }, - - remove: function () { - return this.each(function (v) { - if (!!v.parentNode) { - return v.parentNode.removeChild(v); - } - }); - }, - - text: function (content) { - if (content === undefined) { - return this[0].textContent; - } - return this.each(function (v) { - return v.textContent = content; - }); - } - - }); - - var docEl = doc.documentElement; - - fn.extend({ - position: function () { - var el = this[0]; - return { - left: el.offsetLeft, - top: el.offsetTop - }; - }, - - offset: function () { - var rect = this[0].getBoundingClientRect(); - return { - top: rect.top + win.pageYOffset - docEl.clientTop, - left: rect.left + win.pageXOffset - docEl.clientLeft - }; - }, - - offsetParent: function () { - return cash(this[0].offsetParent); - } - - }); - - fn.extend({ - children: function (selector) { - var elems = []; - this.each(function (el) { - push.apply(elems, el.children); - }); - elems = unique(elems); - - return (!selector ? elems : elems.filter(function (v) { - return matches(v, selector); - })); - }, - - closest: function (selector) { - if (!selector || this.length < 1) { - return cash(); - } - if (this.is(selector)) { - return this.filter(selector); - } - return this.parent().closest(selector); - }, - - is: function (selector) { - if (!selector) { - return false; - } - - var match = false, comparator = getCompareFunction(selector); - - this.each(function (el) { - match = comparator(el, selector); - return !match; - }); - - return match; - }, - - find: function (selector) { - if (!selector || selector.nodeType) { - return cash(selector && this.has(selector).length ? selector : null); - } - - var elems = []; - this.each(function (el) { - push.apply(elems, find(selector, el)); - }); - - return unique(elems); - }, - - has: function (selector) { - var comparator = (isString(selector) ? function (el) { - return find(selector, el).length !== 0; - } : function (el) { - return el.contains(selector); - }); - - return this.filter(comparator); - }, - - next: function () { - return cash(this[0].nextElementSibling); - }, - - not: function (selector) { - if (!selector) { - return this; - } - - var comparator = getCompareFunction(selector); - - return this.filter(function (el) { - return !comparator(el, selector); - }); - }, - - parent: function () { - var result = []; - - this.each(function (item) { - if (item && item.parentNode) { - result.push(item.parentNode); - } - }); - - return unique(result); - }, - - parents: function (selector) { - var last, result = []; - - this.each(function (item) { - last = item; - - while (last && last.parentNode && last !== doc.body.parentNode) { - last = last.parentNode; - - if (!selector || (selector && matches(last, selector))) { - result.push(last); - } - } - }); - - return unique(result); - }, - - prev: function () { - return cash(this[0].previousElementSibling); - }, - - siblings: function (selector) { - var collection = this.parent().children(selector), el = this[0]; - - return collection.filter(function (i) { - return i !== el; - }); - } - - }); - - - return cash; -}); diff --git a/static/js/characterCounter.js b/static/js/characterCounter.js deleted file mode 100644 index 761d1bfc..00000000 --- a/static/js/characterCounter.js +++ /dev/null @@ -1,136 +0,0 @@ -(function($) { - 'use strict'; - - let _defaults = {}; - - /** - * @class - * - */ - class CharacterCounter extends Component { - /** - * Construct CharacterCounter instance - * @constructor - * @param {Element} el - * @param {Object} options - */ - constructor(el, options) { - super(CharacterCounter, el, options); - - this.el.M_CharacterCounter = this; - - /** - * Options for the character counter - */ - this.options = $.extend({}, CharacterCounter.defaults, options); - - this.isInvalid = false; - this.isValidLength = false; - this._setupCounter(); - this._setupEventHandlers(); - } - - static get defaults() { - return _defaults; - } - - static init(els, options) { - return super.init(this, els, options); - } - - /** - * Get Instance - */ - static getInstance(el) { - let domElem = !!el.jquery ? el[0] : el; - return domElem.M_CharacterCounter; - } - - /** - * Teardown component - */ - destroy() { - this._removeEventHandlers(); - this.el.CharacterCounter = undefined; - this._removeCounter(); - } - - /** - * Setup Event Handlers - */ - _setupEventHandlers() { - this._handleUpdateCounterBound = this.updateCounter.bind(this); - - this.el.addEventListener('focus', this._handleUpdateCounterBound, true); - this.el.addEventListener('input', this._handleUpdateCounterBound, true); - } - - /** - * Remove Event Handlers - */ - _removeEventHandlers() { - this.el.removeEventListener('focus', this._handleUpdateCounterBound, true); - this.el.removeEventListener('input', this._handleUpdateCounterBound, true); - } - - /** - * Setup counter element - */ - _setupCounter() { - this.counterEl = document.createElement('span'); - $(this.counterEl) - .addClass('character-counter') - .css({ - float: 'right', - 'font-size': '12px', - height: 1 - }); - - this.$el.parent().append(this.counterEl); - } - - /** - * Remove counter element - */ - _removeCounter() { - $(this.counterEl).remove(); - } - - /** - * Update counter - */ - updateCounter() { - let maxLength = +this.$el.attr('data-length'), - actualLength = this.el.value.length; - this.isValidLength = actualLength <= maxLength; - let counterString = actualLength; - - if (maxLength) { - counterString += '/' + maxLength; - this._validateInput(); - } - - $(this.counterEl).html(counterString); - } - - /** - * Add validation classes - */ - _validateInput() { - if (this.isValidLength && this.isInvalid) { - this.isInvalid = false; - this.$el.removeClass('invalid'); - } else if (!this.isValidLength && !this.isInvalid) { - this.isInvalid = true; - this.$el.removeClass('valid'); - this.$el.addClass('invalid'); - } - } - } - - M.CharacterCounter = CharacterCounter; - - if (M.jQueryLoaded) { - M.initializeJqueryWrapper(CharacterCounter, 'characterCounter', 'M_CharacterCounter'); - } -})(cash); diff --git a/static/js/chips.js b/static/js/chips.js deleted file mode 100644 index 84fd9341..00000000 --- a/static/js/chips.js +++ /dev/null @@ -1,481 +0,0 @@ -(function($) { - 'use strict'; - - let _defaults = { - data: [], - placeholder: '', - secondaryPlaceholder: '', - autocompleteOptions: {}, - limit: Infinity, - onChipAdd: null, - onChipSelect: null, - onChipDelete: null - }; - - /** - * @typedef {Object} chip - * @property {String} tag chip tag string - * @property {String} [image] chip avatar image string - */ - - /** - * @class - * - */ - class Chips extends Component { - /** - * Construct Chips instance and set up overlay - * @constructor - * @param {Element} el - * @param {Object} options - */ - constructor(el, options) { - super(Chips, el, options); - - this.el.M_Chips = this; - - /** - * Options for the modal - * @member Chips#options - * @prop {Array} data - * @prop {String} placeholder - * @prop {String} secondaryPlaceholder - * @prop {Object} autocompleteOptions - */ - this.options = $.extend({}, Chips.defaults, options); - - this.$el.addClass('chips input-field'); - this.chipsData = []; - this.$chips = $(); - this._setupInput(); - this.hasAutocomplete = Object.keys(this.options.autocompleteOptions).length > 0; - - // Set input id - if (!this.$input.attr('id')) { - this.$input.attr('id', M.guid()); - } - - // Render initial chips - if (this.options.data.length) { - this.chipsData = this.options.data; - this._renderChips(this.chipsData); - } - - // Setup autocomplete if needed - if (this.hasAutocomplete) { - this._setupAutocomplete(); - } - - this._setPlaceholder(); - this._setupLabel(); - this._setupEventHandlers(); - } - - static get defaults() { - return _defaults; - } - - static init(els, options) { - return super.init(this, els, options); - } - - /** - * Get Instance - */ - static getInstance(el) { - let domElem = !!el.jquery ? el[0] : el; - return domElem.M_Chips; - } - - /** - * Get Chips Data - */ - getData() { - return this.chipsData; - } - - /** - * Teardown component - */ - destroy() { - this._removeEventHandlers(); - this.$chips.remove(); - this.el.M_Chips = undefined; - } - - /** - * Setup Event Handlers - */ - _setupEventHandlers() { - this._handleChipClickBound = this._handleChipClick.bind(this); - this._handleInputKeydownBound = this._handleInputKeydown.bind(this); - this._handleInputFocusBound = this._handleInputFocus.bind(this); - this._handleInputBlurBound = this._handleInputBlur.bind(this); - - this.el.addEventListener('click', this._handleChipClickBound); - document.addEventListener('keydown', Chips._handleChipsKeydown); - document.addEventListener('keyup', Chips._handleChipsKeyup); - this.el.addEventListener('blur', Chips._handleChipsBlur, true); - this.$input[0].addEventListener('focus', this._handleInputFocusBound); - this.$input[0].addEventListener('blur', this._handleInputBlurBound); - this.$input[0].addEventListener('keydown', this._handleInputKeydownBound); - } - - /** - * Remove Event Handlers - */ - _removeEventHandlers() { - this.el.removeEventListener('click', this._handleChipClickBound); - document.removeEventListener('keydown', Chips._handleChipsKeydown); - document.removeEventListener('keyup', Chips._handleChipsKeyup); - this.el.removeEventListener('blur', Chips._handleChipsBlur, true); - this.$input[0].removeEventListener('focus', this._handleInputFocusBound); - this.$input[0].removeEventListener('blur', this._handleInputBlurBound); - this.$input[0].removeEventListener('keydown', this._handleInputKeydownBound); - } - - /** - * Handle Chip Click - * @param {Event} e - */ - _handleChipClick(e) { - let $chip = $(e.target).closest('.chip'); - let clickedClose = $(e.target).is('.close'); - if ($chip.length) { - let index = $chip.index(); - if (clickedClose) { - // delete chip - this.deleteChip(index); - this.$input[0].focus(); - } else { - // select chip - this.selectChip(index); - } - - // Default handle click to focus on input - } else { - this.$input[0].focus(); - } - } - - /** - * Handle Chips Keydown - * @param {Event} e - */ - static _handleChipsKeydown(e) { - Chips._keydown = true; - - let $chips = $(e.target).closest('.chips'); - let chipsKeydown = e.target && $chips.length; - - // Don't handle keydown inputs on input and textarea - if ($(e.target).is('input, textarea') || !chipsKeydown) { - return; - } - - let currChips = $chips[0].M_Chips; - - // backspace and delete - if (e.keyCode === 8 || e.keyCode === 46) { - e.preventDefault(); - - let selectIndex = currChips.chipsData.length; - if (currChips._selectedChip) { - let index = currChips._selectedChip.index(); - currChips.deleteChip(index); - currChips._selectedChip = null; - - // Make sure selectIndex doesn't go negative - selectIndex = Math.max(index - 1, 0); - } - - if (currChips.chipsData.length) { - currChips.selectChip(selectIndex); - } - - // left arrow key - } else if (e.keyCode === 37) { - if (currChips._selectedChip) { - let selectIndex = currChips._selectedChip.index() - 1; - if (selectIndex < 0) { - return; - } - currChips.selectChip(selectIndex); - } - - // right arrow key - } else if (e.keyCode === 39) { - if (currChips._selectedChip) { - let selectIndex = currChips._selectedChip.index() + 1; - - if (selectIndex >= currChips.chipsData.length) { - currChips.$input[0].focus(); - } else { - currChips.selectChip(selectIndex); - } - } - } - } - - /** - * Handle Chips Keyup - * @param {Event} e - */ - static _handleChipsKeyup(e) { - Chips._keydown = false; - } - - /** - * Handle Chips Blur - * @param {Event} e - */ - static _handleChipsBlur(e) { - if (!Chips._keydown) { - let $chips = $(e.target).closest('.chips'); - let currChips = $chips[0].M_Chips; - - currChips._selectedChip = null; - } - } - - /** - * Handle Input Focus - */ - _handleInputFocus() { - this.$el.addClass('focus'); - } - - /** - * Handle Input Blur - */ - _handleInputBlur() { - this.$el.removeClass('focus'); - } - - /** - * Handle Input Keydown - * @param {Event} e - */ - _handleInputKeydown(e) { - Chips._keydown = true; - - // enter - if (e.keyCode === 13) { - // Override enter if autocompleting. - if (this.hasAutocomplete && this.autocomplete && this.autocomplete.isOpen) { - return; - } - - e.preventDefault(); - this.addChip({ - tag: this.$input[0].value - }); - this.$input[0].value = ''; - - // delete or left - } else if ( - (e.keyCode === 8 || e.keyCode === 37) && - this.$input[0].value === '' && - this.chipsData.length - ) { - e.preventDefault(); - this.selectChip(this.chipsData.length - 1); - } - } - - /** - * Render Chip - * @param {chip} chip - * @return {Element} - */ - _renderChip(chip) { - if (!chip.tag) { - return; - } - - let renderedChip = document.createElement('div'); - let closeIcon = document.createElement('i'); - renderedChip.classList.add('chip'); - renderedChip.textContent = chip.tag; - renderedChip.setAttribute('tabindex', 0); - $(closeIcon).addClass('material-icons close'); - closeIcon.textContent = 'close'; - - // attach image if needed - if (chip.image) { - let img = document.createElement('img'); - img.setAttribute('src', chip.image); - renderedChip.insertBefore(img, renderedChip.firstChild); - } - - renderedChip.appendChild(closeIcon); - return renderedChip; - } - - /** - * Render Chips - */ - _renderChips() { - this.$chips.remove(); - for (let i = 0; i < this.chipsData.length; i++) { - let chipEl = this._renderChip(this.chipsData[i]); - this.$el.append(chipEl); - this.$chips.add(chipEl); - } - - // move input to end - this.$el.append(this.$input[0]); - } - - /** - * Setup Autocomplete - */ - _setupAutocomplete() { - this.options.autocompleteOptions.onAutocomplete = (val) => { - this.addChip({ - tag: val - }); - this.$input[0].value = ''; - this.$input[0].focus(); - }; - - this.autocomplete = M.Autocomplete.init(this.$input[0], this.options.autocompleteOptions); - } - - /** - * Setup Input - */ - _setupInput() { - this.$input = this.$el.find('input'); - if (!this.$input.length) { - this.$input = $(''); - this.$el.append(this.$input); - } - - this.$input.addClass('input'); - } - - /** - * Setup Label - */ - _setupLabel() { - this.$label = this.$el.find('label'); - if (this.$label.length) { - this.$label.setAttribute('for', this.$input.attr('id')); - } - } - - /** - * Set placeholder - */ - _setPlaceholder() { - if (this.chipsData !== undefined && !this.chipsData.length && this.options.placeholder) { - $(this.$input).prop('placeholder', this.options.placeholder); - } else if ( - (this.chipsData === undefined || !!this.chipsData.length) && - this.options.secondaryPlaceholder - ) { - $(this.$input).prop('placeholder', this.options.secondaryPlaceholder); - } - } - - /** - * Check if chip is valid - * @param {chip} chip - */ - _isValid(chip) { - if (chip.hasOwnProperty('tag') && chip.tag !== '') { - let exists = false; - for (let i = 0; i < this.chipsData.length; i++) { - if (this.chipsData[i].tag === chip.tag) { - exists = true; - break; - } - } - return !exists; - } - - return false; - } - - /** - * Add chip - * @param {chip} chip - */ - addChip(chip) { - if (!this._isValid(chip) || this.chipsData.length >= this.options.limit) { - return; - } - - let renderedChip = this._renderChip(chip); - this.$chips.add(renderedChip); - this.chipsData.push(chip); - $(this.$input).before(renderedChip); - this._setPlaceholder(); - - // fire chipAdd callback - if (typeof this.options.onChipAdd === 'function') { - this.options.onChipAdd.call(this, this.$el, renderedChip); - } - } - - /** - * Delete chip - * @param {Number} chip - */ - deleteChip(chipIndex) { - let $chip = this.$chips.eq(chipIndex); - this.$chips.eq(chipIndex).remove(); - this.$chips = this.$chips.filter(function(el) { - return $(el).index() >= 0; - }); - this.chipsData.splice(chipIndex, 1); - this._setPlaceholder(); - - // fire chipDelete callback - if (typeof this.options.onChipDelete === 'function') { - this.options.onChipDelete.call(this, this.$el, $chip[0]); - } - } - - /** - * Select chip - * @param {Number} chip - */ - selectChip(chipIndex) { - let $chip = this.$chips.eq(chipIndex); - this._selectedChip = $chip; - $chip[0].focus(); - - // fire chipSelect callback - if (typeof this.options.onChipSelect === 'function') { - this.options.onChipSelect.call(this, this.$el, $chip[0]); - } - } - } - - /** - * @static - * @memberof Chips - */ - Chips._keydown = false; - - M.Chips = Chips; - - if (M.jQueryLoaded) { - M.initializeJqueryWrapper(Chips, 'chips', 'M_Chips'); - } - - $(document).ready(function() { - // Handle removal of static chips. - $(document.body).on('click', '.chip .close', function() { - let $chips = $(this).closest('.chips'); - if ($chips.length && $chips[0].M_Chips) { - return; - } - $(this) - .closest('.chip') - .remove(); - }); - }); -})(cash); diff --git a/static/js/collapsible.js b/static/js/collapsible.js deleted file mode 100644 index 6c491261..00000000 --- a/static/js/collapsible.js +++ /dev/null @@ -1,275 +0,0 @@ -(function($, anim) { - 'use strict'; - - let _defaults = { - accordion: true, - onOpenStart: undefined, - onOpenEnd: undefined, - onCloseStart: undefined, - onCloseEnd: undefined, - inDuration: 300, - outDuration: 300 - }; - - /** - * @class - * - */ - class Collapsible extends Component { - /** - * Construct Collapsible instance - * @constructor - * @param {Element} el - * @param {Object} options - */ - constructor(el, options) { - super(Collapsible, el, options); - - this.el.M_Collapsible = this; - - /** - * Options for the collapsible - * @member Collapsible#options - * @prop {Boolean} [accordion=false] - Type of the collapsible - * @prop {Function} onOpenStart - Callback function called before collapsible is opened - * @prop {Function} onOpenEnd - Callback function called after collapsible is opened - * @prop {Function} onCloseStart - Callback function called before collapsible is closed - * @prop {Function} onCloseEnd - Callback function called after collapsible is closed - * @prop {Number} inDuration - Transition in duration in milliseconds. - * @prop {Number} outDuration - Transition duration in milliseconds. - */ - this.options = $.extend({}, Collapsible.defaults, options); - - // Setup tab indices - this.$headers = this.$el.children('li').children('.collapsible-header'); - this.$headers.attr('tabindex', 0); - - this._setupEventHandlers(); - - // Open first active - let $activeBodies = this.$el.children('li.active').children('.collapsible-body'); - if (this.options.accordion) { - // Handle Accordion - $activeBodies.first().css('display', 'block'); - } else { - // Handle Expandables - $activeBodies.css('display', 'block'); - } - } - - static get defaults() { - return _defaults; - } - - static init(els, options) { - return super.init(this, els, options); - } - - /** - * Get Instance - */ - static getInstance(el) { - let domElem = !!el.jquery ? el[0] : el; - return domElem.M_Collapsible; - } - - /** - * Teardown component - */ - destroy() { - this._removeEventHandlers(); - this.el.M_Collapsible = undefined; - } - - /** - * Setup Event Handlers - */ - _setupEventHandlers() { - this._handleCollapsibleClickBound = this._handleCollapsibleClick.bind(this); - this._handleCollapsibleKeydownBound = this._handleCollapsibleKeydown.bind(this); - this.el.addEventListener('click', this._handleCollapsibleClickBound); - this.$headers.each((header) => { - header.addEventListener('keydown', this._handleCollapsibleKeydownBound); - }); - } - - /** - * Remove Event Handlers - */ - _removeEventHandlers() { - this.el.removeEventListener('click', this._handleCollapsibleClickBound); - this.$headers.each((header) => { - header.removeEventListener('keydown', this._handleCollapsibleKeydownBound); - }); - } - - /** - * Handle Collapsible Click - * @param {Event} e - */ - _handleCollapsibleClick(e) { - let $header = $(e.target).closest('.collapsible-header'); - if (e.target && $header.length) { - let $collapsible = $header.closest('.collapsible'); - if ($collapsible[0] === this.el) { - let $collapsibleLi = $header.closest('li'); - let $collapsibleLis = $collapsible.children('li'); - let isActive = $collapsibleLi[0].classList.contains('active'); - let index = $collapsibleLis.index($collapsibleLi); - - if (isActive) { - this.close(index); - } else { - this.open(index); - } - } - } - } - - /** - * Handle Collapsible Keydown - * @param {Event} e - */ - _handleCollapsibleKeydown(e) { - if (e.keyCode === 13) { - this._handleCollapsibleClickBound(e); - } - } - - /** - * Animate in collapsible slide - * @param {Number} index - 0th index of slide - */ - _animateIn(index) { - let $collapsibleLi = this.$el.children('li').eq(index); - if ($collapsibleLi.length) { - let $body = $collapsibleLi.children('.collapsible-body'); - - anim.remove($body[0]); - $body.css({ - display: 'block', - overflow: 'hidden', - height: 0, - paddingTop: '', - paddingBottom: '' - }); - - let pTop = $body.css('padding-top'); - let pBottom = $body.css('padding-bottom'); - let finalHeight = $body[0].scrollHeight; - $body.css({ - paddingTop: 0, - paddingBottom: 0 - }); - - anim({ - targets: $body[0], - height: finalHeight, - paddingTop: pTop, - paddingBottom: pBottom, - duration: this.options.inDuration, - easing: 'easeInOutCubic', - complete: (anim) => { - $body.css({ - overflow: '', - paddingTop: '', - paddingBottom: '', - height: '' - }); - - // onOpenEnd callback - if (typeof this.options.onOpenEnd === 'function') { - this.options.onOpenEnd.call(this, $collapsibleLi[0]); - } - } - }); - } - } - - /** - * Animate out collapsible slide - * @param {Number} index - 0th index of slide to open - */ - _animateOut(index) { - let $collapsibleLi = this.$el.children('li').eq(index); - if ($collapsibleLi.length) { - let $body = $collapsibleLi.children('.collapsible-body'); - anim.remove($body[0]); - $body.css('overflow', 'hidden'); - anim({ - targets: $body[0], - height: 0, - paddingTop: 0, - paddingBottom: 0, - duration: this.options.outDuration, - easing: 'easeInOutCubic', - complete: () => { - $body.css({ - height: '', - overflow: '', - padding: '', - display: '' - }); - - // onCloseEnd callback - if (typeof this.options.onCloseEnd === 'function') { - this.options.onCloseEnd.call(this, $collapsibleLi[0]); - } - } - }); - } - } - - /** - * Open Collapsible - * @param {Number} index - 0th index of slide - */ - open(index) { - let $collapsibleLi = this.$el.children('li').eq(index); - if ($collapsibleLi.length && !$collapsibleLi[0].classList.contains('active')) { - // onOpenStart callback - if (typeof this.options.onOpenStart === 'function') { - this.options.onOpenStart.call(this, $collapsibleLi[0]); - } - - // Handle accordion behavior - if (this.options.accordion) { - let $collapsibleLis = this.$el.children('li'); - let $activeLis = this.$el.children('li.active'); - $activeLis.each((el) => { - let index = $collapsibleLis.index($(el)); - this.close(index); - }); - } - - // Animate in - $collapsibleLi[0].classList.add('active'); - this._animateIn(index); - } - } - - /** - * Close Collapsible - * @param {Number} index - 0th index of slide - */ - close(index) { - let $collapsibleLi = this.$el.children('li').eq(index); - if ($collapsibleLi.length && $collapsibleLi[0].classList.contains('active')) { - // onCloseStart callback - if (typeof this.options.onCloseStart === 'function') { - this.options.onCloseStart.call(this, $collapsibleLi[0]); - } - - // Animate out - $collapsibleLi[0].classList.remove('active'); - this._animateOut(index); - } - } - } - - M.Collapsible = Collapsible; - - if (M.jQueryLoaded) { - M.initializeJqueryWrapper(Collapsible, 'collapsible', 'M_Collapsible'); - } -})(cash, M.anime); diff --git a/static/js/component.js b/static/js/component.js deleted file mode 100644 index 19eea9fd..00000000 --- a/static/js/component.js +++ /dev/null @@ -1,44 +0,0 @@ -class Component { - /** - * Generic constructor for all components - * @constructor - * @param {Element} el - * @param {Object} options - */ - constructor(classDef, el, options) { - // Display error if el is valid HTML Element - if (!(el instanceof Element)) { - console.error(Error(el + ' is not an HTML Element')); - } - - // If exists, destroy and reinitialize in child - let ins = classDef.getInstance(el); - if (!!ins) { - ins.destroy(); - } - - this.el = el; - this.$el = cash(el); - } - - /** - * Initializes components - * @param {class} classDef - * @param {Element | NodeList | jQuery} els - * @param {Object} options - */ - static init(classDef, els, options) { - let instances = null; - if (els instanceof Element) { - instances = new classDef(els, options); - } else if (!!els && (els.jquery || els.cash || els instanceof NodeList)) { - let instancesArr = []; - for (let i = 0; i < els.length; i++) { - instancesArr.push(new classDef(els[i], options)); - } - instances = instancesArr; - } - - return instances; - } -} diff --git a/static/js/datepicker.js b/static/js/datepicker.js deleted file mode 100644 index 7199dd27..00000000 --- a/static/js/datepicker.js +++ /dev/null @@ -1,975 +0,0 @@ -(function($) { - 'use strict'; - - let _defaults = { - // Close when date is selected - autoClose: false, - - // the default output format for the input field value - format: 'mmm dd, yyyy', - - // Used to create date object from current input string - parse: null, - - // The initial date to view when first opened - defaultDate: null, - - // Make the `defaultDate` the initial selected value - setDefaultDate: false, - - disableWeekends: false, - - disableDayFn: null, - - // First day of week (0: Sunday, 1: Monday etc) - firstDay: 0, - - // The earliest date that can be selected - minDate: null, - // Thelatest date that can be selected - maxDate: null, - - // Number of years either side, or array of upper/lower range - yearRange: 10, - - // used internally (don't config outside) - minYear: 0, - maxYear: 9999, - minMonth: undefined, - maxMonth: undefined, - - startRange: null, - endRange: null, - - isRTL: false, - - // Render the month after year in the calendar title - showMonthAfterYear: false, - - // Render days of the calendar grid that fall in the next or previous month - showDaysInNextAndPreviousMonths: false, - - // Specify a DOM element to render the calendar in - container: null, - - // Show clear button - showClearBtn: false, - - // internationalization - i18n: { - cancel: 'Cancel', - clear: 'Clear', - done: 'Ok', - previousMonth: '‹', - nextMonth: '›', - months: [ - 'January', - 'February', - 'March', - 'April', - 'May', - 'June', - 'July', - 'August', - 'September', - 'October', - 'November', - 'December' - ], - monthsShort: [ - 'Jan', - 'Feb', - 'Mar', - 'Apr', - 'May', - 'Jun', - 'Jul', - 'Aug', - 'Sep', - 'Oct', - 'Nov', - 'Dec' - ], - weekdays: ['Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday'], - weekdaysShort: ['Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat'], - weekdaysAbbrev: ['S', 'M', 'T', 'W', 'T', 'F', 'S'] - }, - - // events array - events: [], - - // callback function - onSelect: null, - onOpen: null, - onClose: null, - onDraw: null - }; - - /** - * @class - * - */ - class Datepicker extends Component { - /** - * Construct Datepicker instance and set up overlay - * @constructor - * @param {Element} el - * @param {Object} options - */ - constructor(el, options) { - super(Datepicker, el, options); - - this.el.M_Datepicker = this; - - this.options = $.extend({}, Datepicker.defaults, options); - - // make sure i18n defaults are not lost when only few i18n option properties are passed - if (!!options && options.hasOwnProperty('i18n') && typeof options.i18n === 'object') { - this.options.i18n = $.extend({}, Datepicker.defaults.i18n, options.i18n); - } - - // Remove time component from minDate and maxDate options - if (this.options.minDate) this.options.minDate.setHours(0, 0, 0, 0); - if (this.options.maxDate) this.options.maxDate.setHours(0, 0, 0, 0); - - this.id = M.guid(); - - this._setupVariables(); - this._insertHTMLIntoDOM(); - this._setupModal(); - - this._setupEventHandlers(); - - if (!this.options.defaultDate) { - this.options.defaultDate = new Date(Date.parse(this.el.value)); - } - - let defDate = this.options.defaultDate; - if (Datepicker._isDate(defDate)) { - if (this.options.setDefaultDate) { - this.setDate(defDate, true); - this.setInputValue(); - } else { - this.gotoDate(defDate); - } - } else { - this.gotoDate(new Date()); - } - - /** - * Describes open/close state of datepicker - * @type {Boolean} - */ - this.isOpen = false; - } - - static get defaults() { - return _defaults; - } - - static init(els, options) { - return super.init(this, els, options); - } - - static _isDate(obj) { - return /Date/.test(Object.prototype.toString.call(obj)) && !isNaN(obj.getTime()); - } - - static _isWeekend(date) { - let day = date.getDay(); - return day === 0 || day === 6; - } - - static _setToStartOfDay(date) { - if (Datepicker._isDate(date)) date.setHours(0, 0, 0, 0); - } - - static _getDaysInMonth(year, month) { - return [31, Datepicker._isLeapYear(year) ? 29 : 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31][ - month - ]; - } - - static _isLeapYear(year) { - // solution by Matti Virkkunen: http://stackoverflow.com/a/4881951 - return (year % 4 === 0 && year % 100 !== 0) || year % 400 === 0; - } - - static _compareDates(a, b) { - // weak date comparison (use setToStartOfDay(date) to ensure correct result) - return a.getTime() === b.getTime(); - } - - static _setToStartOfDay(date) { - if (Datepicker._isDate(date)) date.setHours(0, 0, 0, 0); - } - - /** - * Get Instance - */ - static getInstance(el) { - let domElem = !!el.jquery ? el[0] : el; - return domElem.M_Datepicker; - } - - /** - * Teardown component - */ - destroy() { - this._removeEventHandlers(); - this.modal.destroy(); - $(this.modalEl).remove(); - this.destroySelects(); - this.el.M_Datepicker = undefined; - } - - destroySelects() { - let oldYearSelect = this.calendarEl.querySelector('.orig-select-year'); - if (oldYearSelect) { - M.FormSelect.getInstance(oldYearSelect).destroy(); - } - let oldMonthSelect = this.calendarEl.querySelector('.orig-select-month'); - if (oldMonthSelect) { - M.FormSelect.getInstance(oldMonthSelect).destroy(); - } - } - - _insertHTMLIntoDOM() { - if (this.options.showClearBtn) { - $(this.clearBtn).css({ visibility: '' }); - this.clearBtn.innerHTML = this.options.i18n.clear; - } - - this.doneBtn.innerHTML = this.options.i18n.done; - this.cancelBtn.innerHTML = this.options.i18n.cancel; - - if (this.options.container) { - this.$modalEl.appendTo(this.options.container); - } else { - this.$modalEl.insertBefore(this.el); - } - } - - _setupModal() { - this.modalEl.id = 'modal-' + this.id; - this.modal = M.Modal.init(this.modalEl, { - onCloseEnd: () => { - this.isOpen = false; - } - }); - } - - toString(format) { - format = format || this.options.format; - if (!Datepicker._isDate(this.date)) { - return ''; - } - - let formatArray = format.split(/(d{1,4}|m{1,4}|y{4}|yy|!.)/g); - let formattedDate = formatArray - .map((label) => { - if (this.formats[label]) { - return this.formats[label](); - } - - return label; - }) - .join(''); - return formattedDate; - } - - setDate(date, preventOnSelect) { - if (!date) { - this.date = null; - this._renderDateDisplay(); - return this.draw(); - } - if (typeof date === 'string') { - date = new Date(Date.parse(date)); - } - if (!Datepicker._isDate(date)) { - return; - } - - let min = this.options.minDate, - max = this.options.maxDate; - - if (Datepicker._isDate(min) && date < min) { - date = min; - } else if (Datepicker._isDate(max) && date > max) { - date = max; - } - - this.date = new Date(date.getTime()); - - this._renderDateDisplay(); - - Datepicker._setToStartOfDay(this.date); - this.gotoDate(this.date); - - if (!preventOnSelect && typeof this.options.onSelect === 'function') { - this.options.onSelect.call(this, this.date); - } - } - - setInputValue() { - this.el.value = this.toString(); - this.$el.trigger('change', { firedBy: this }); - } - - _renderDateDisplay() { - let displayDate = Datepicker._isDate(this.date) ? this.date : new Date(); - let i18n = this.options.i18n; - let day = i18n.weekdaysShort[displayDate.getDay()]; - let month = i18n.monthsShort[displayDate.getMonth()]; - let date = displayDate.getDate(); - this.yearTextEl.innerHTML = displayDate.getFullYear(); - this.dateTextEl.innerHTML = `${day}, ${month} ${date}`; - } - - /** - * change view to a specific date - */ - gotoDate(date) { - let newCalendar = true; - - if (!Datepicker._isDate(date)) { - return; - } - - if (this.calendars) { - let firstVisibleDate = new Date(this.calendars[0].year, this.calendars[0].month, 1), - lastVisibleDate = new Date( - this.calendars[this.calendars.length - 1].year, - this.calendars[this.calendars.length - 1].month, - 1 - ), - visibleDate = date.getTime(); - // get the end of the month - lastVisibleDate.setMonth(lastVisibleDate.getMonth() + 1); - lastVisibleDate.setDate(lastVisibleDate.getDate() - 1); - newCalendar = - visibleDate < firstVisibleDate.getTime() || lastVisibleDate.getTime() < visibleDate; - } - - if (newCalendar) { - this.calendars = [ - { - month: date.getMonth(), - year: date.getFullYear() - } - ]; - } - - this.adjustCalendars(); - } - - adjustCalendars() { - this.calendars[0] = this.adjustCalendar(this.calendars[0]); - this.draw(); - } - - adjustCalendar(calendar) { - if (calendar.month < 0) { - calendar.year -= Math.ceil(Math.abs(calendar.month) / 12); - calendar.month += 12; - } - if (calendar.month > 11) { - calendar.year += Math.floor(Math.abs(calendar.month) / 12); - calendar.month -= 12; - } - return calendar; - } - - nextMonth() { - this.calendars[0].month++; - this.adjustCalendars(); - } - - prevMonth() { - this.calendars[0].month--; - this.adjustCalendars(); - } - - render(year, month, randId) { - let opts = this.options, - now = new Date(), - days = Datepicker._getDaysInMonth(year, month), - before = new Date(year, month, 1).getDay(), - data = [], - row = []; - Datepicker._setToStartOfDay(now); - if (opts.firstDay > 0) { - before -= opts.firstDay; - if (before < 0) { - before += 7; - } - } - let previousMonth = month === 0 ? 11 : month - 1, - nextMonth = month === 11 ? 0 : month + 1, - yearOfPreviousMonth = month === 0 ? year - 1 : year, - yearOfNextMonth = month === 11 ? year + 1 : year, - daysInPreviousMonth = Datepicker._getDaysInMonth(yearOfPreviousMonth, previousMonth); - let cells = days + before, - after = cells; - while (after > 7) { - after -= 7; - } - cells += 7 - after; - let isWeekSelected = false; - for (let i = 0, r = 0; i < cells; i++) { - let day = new Date(year, month, 1 + (i - before)), - isSelected = Datepicker._isDate(this.date) - ? Datepicker._compareDates(day, this.date) - : false, - isToday = Datepicker._compareDates(day, now), - hasEvent = opts.events.indexOf(day.toDateString()) !== -1 ? true : false, - isEmpty = i < before || i >= days + before, - dayNumber = 1 + (i - before), - monthNumber = month, - yearNumber = year, - isStartRange = opts.startRange && Datepicker._compareDates(opts.startRange, day), - isEndRange = opts.endRange && Datepicker._compareDates(opts.endRange, day), - isInRange = - opts.startRange && opts.endRange && opts.startRange < day && day < opts.endRange, - isDisabled = - (opts.minDate && day < opts.minDate) || - (opts.maxDate && day > opts.maxDate) || - (opts.disableWeekends && Datepicker._isWeekend(day)) || - (opts.disableDayFn && opts.disableDayFn(day)); - - if (isEmpty) { - if (i < before) { - dayNumber = daysInPreviousMonth + dayNumber; - monthNumber = previousMonth; - yearNumber = yearOfPreviousMonth; - } else { - dayNumber = dayNumber - days; - monthNumber = nextMonth; - yearNumber = yearOfNextMonth; - } - } - - let dayConfig = { - day: dayNumber, - month: monthNumber, - year: yearNumber, - hasEvent: hasEvent, - isSelected: isSelected, - isToday: isToday, - isDisabled: isDisabled, - isEmpty: isEmpty, - isStartRange: isStartRange, - isEndRange: isEndRange, - isInRange: isInRange, - showDaysInNextAndPreviousMonths: opts.showDaysInNextAndPreviousMonths - }; - - row.push(this.renderDay(dayConfig)); - - if (++r === 7) { - data.push(this.renderRow(row, opts.isRTL, isWeekSelected)); - row = []; - r = 0; - isWeekSelected = false; - } - } - return this.renderTable(opts, data, randId); - } - - renderDay(opts) { - let arr = []; - let ariaSelected = 'false'; - if (opts.isEmpty) { - if (opts.showDaysInNextAndPreviousMonths) { - arr.push('is-outside-current-month'); - arr.push('is-selection-disabled'); - } else { - return ''; - } - } - if (opts.isDisabled) { - arr.push('is-disabled'); - } - - if (opts.isToday) { - arr.push('is-today'); - } - if (opts.isSelected) { - arr.push('is-selected'); - ariaSelected = 'true'; - } - if (opts.hasEvent) { - arr.push('has-event'); - } - if (opts.isInRange) { - arr.push('is-inrange'); - } - if (opts.isStartRange) { - arr.push('is-startrange'); - } - if (opts.isEndRange) { - arr.push('is-endrange'); - } - return ( - `` + - `` + - '' - ); - } - - renderRow(days, isRTL, isRowSelected) { - return ( - '' + - (isRTL ? days.reverse() : days).join('') + - '' - ); - } - - renderTable(opts, data, randId) { - return ( - '
      ' + - this.renderHead(opts) + - this.renderBody(data) + - '
      ' - ); - } - - renderHead(opts) { - let i, - arr = []; - for (i = 0; i < 7; i++) { - arr.push( - `${this.renderDayName( - opts, - i, - true - )}` - ); - } - return '' + (opts.isRTL ? arr.reverse() : arr).join('') + ''; - } - - renderBody(rows) { - return '' + rows.join('') + ''; - } - - renderTitle(instance, c, year, month, refYear, randId) { - let i, - j, - arr, - opts = this.options, - isMinYear = year === opts.minYear, - isMaxYear = year === opts.maxYear, - html = - '
      ', - monthHtml, - yearHtml, - prev = true, - next = true; - - for (arr = [], i = 0; i < 12; i++) { - arr.push( - '' - ); - } - - monthHtml = - ''; - - if ($.isArray(opts.yearRange)) { - i = opts.yearRange[0]; - j = opts.yearRange[1] + 1; - } else { - i = year - opts.yearRange; - j = 1 + year + opts.yearRange; - } - - for (arr = []; i < j && i <= opts.maxYear; i++) { - if (i >= opts.minYear) { - arr.push(``); - } - } - - yearHtml = ``; - - let leftArrow = - ''; - html += ``; - - html += '
      '; - if (opts.showMonthAfterYear) { - html += yearHtml + monthHtml; - } else { - html += monthHtml + yearHtml; - } - html += '
      '; - - if (isMinYear && (month === 0 || opts.minMonth >= month)) { - prev = false; - } - - if (isMaxYear && (month === 11 || opts.maxMonth <= month)) { - next = false; - } - - let rightArrow = - ''; - html += ``; - - return (html += '
      '); - } - - /** - * refresh the HTML - */ - draw(force) { - if (!this.isOpen && !force) { - return; - } - let opts = this.options, - minYear = opts.minYear, - maxYear = opts.maxYear, - minMonth = opts.minMonth, - maxMonth = opts.maxMonth, - html = '', - randId; - - if (this._y <= minYear) { - this._y = minYear; - if (!isNaN(minMonth) && this._m < minMonth) { - this._m = minMonth; - } - } - if (this._y >= maxYear) { - this._y = maxYear; - if (!isNaN(maxMonth) && this._m > maxMonth) { - this._m = maxMonth; - } - } - - randId = - 'datepicker-title-' + - Math.random() - .toString(36) - .replace(/[^a-z]+/g, '') - .substr(0, 2); - - for (let c = 0; c < 1; c++) { - this._renderDateDisplay(); - html += - this.renderTitle( - this, - c, - this.calendars[c].year, - this.calendars[c].month, - this.calendars[0].year, - randId - ) + this.render(this.calendars[c].year, this.calendars[c].month, randId); - } - - this.destroySelects(); - - this.calendarEl.innerHTML = html; - - // Init Materialize Select - let yearSelect = this.calendarEl.querySelector('.orig-select-year'); - let monthSelect = this.calendarEl.querySelector('.orig-select-month'); - M.FormSelect.init(yearSelect, { - classes: 'select-year', - dropdownOptions: { container: document.body, constrainWidth: false } - }); - M.FormSelect.init(monthSelect, { - classes: 'select-month', - dropdownOptions: { container: document.body, constrainWidth: false } - }); - - // Add change handlers for select - yearSelect.addEventListener('change', this._handleYearChange.bind(this)); - monthSelect.addEventListener('change', this._handleMonthChange.bind(this)); - - if (typeof this.options.onDraw === 'function') { - this.options.onDraw(this); - } - } - - /** - * Setup Event Handlers - */ - _setupEventHandlers() { - this._handleInputKeydownBound = this._handleInputKeydown.bind(this); - this._handleInputClickBound = this._handleInputClick.bind(this); - this._handleInputChangeBound = this._handleInputChange.bind(this); - this._handleCalendarClickBound = this._handleCalendarClick.bind(this); - this._finishSelectionBound = this._finishSelection.bind(this); - this._handleMonthChange = this._handleMonthChange.bind(this); - this._closeBound = this.close.bind(this); - - this.el.addEventListener('click', this._handleInputClickBound); - this.el.addEventListener('keydown', this._handleInputKeydownBound); - this.el.addEventListener('change', this._handleInputChangeBound); - this.calendarEl.addEventListener('click', this._handleCalendarClickBound); - this.doneBtn.addEventListener('click', this._finishSelectionBound); - this.cancelBtn.addEventListener('click', this._closeBound); - - if (this.options.showClearBtn) { - this._handleClearClickBound = this._handleClearClick.bind(this); - this.clearBtn.addEventListener('click', this._handleClearClickBound); - } - } - - _setupVariables() { - this.$modalEl = $(Datepicker._template); - this.modalEl = this.$modalEl[0]; - - this.calendarEl = this.modalEl.querySelector('.datepicker-calendar'); - - this.yearTextEl = this.modalEl.querySelector('.year-text'); - this.dateTextEl = this.modalEl.querySelector('.date-text'); - if (this.options.showClearBtn) { - this.clearBtn = this.modalEl.querySelector('.datepicker-clear'); - } - this.doneBtn = this.modalEl.querySelector('.datepicker-done'); - this.cancelBtn = this.modalEl.querySelector('.datepicker-cancel'); - - this.formats = { - d: () => { - return this.date.getDate(); - }, - dd: () => { - let d = this.date.getDate(); - return (d < 10 ? '0' : '') + d; - }, - ddd: () => { - return this.options.i18n.weekdaysShort[this.date.getDay()]; - }, - dddd: () => { - return this.options.i18n.weekdays[this.date.getDay()]; - }, - m: () => { - return this.date.getMonth() + 1; - }, - mm: () => { - let m = this.date.getMonth() + 1; - return (m < 10 ? '0' : '') + m; - }, - mmm: () => { - return this.options.i18n.monthsShort[this.date.getMonth()]; - }, - mmmm: () => { - return this.options.i18n.months[this.date.getMonth()]; - }, - yy: () => { - return ('' + this.date.getFullYear()).slice(2); - }, - yyyy: () => { - return this.date.getFullYear(); - } - }; - } - - /** - * Remove Event Handlers - */ - _removeEventHandlers() { - this.el.removeEventListener('click', this._handleInputClickBound); - this.el.removeEventListener('keydown', this._handleInputKeydownBound); - this.el.removeEventListener('change', this._handleInputChangeBound); - this.calendarEl.removeEventListener('click', this._handleCalendarClickBound); - } - - _handleInputClick() { - this.open(); - } - - _handleInputKeydown(e) { - if (e.which === M.keys.ENTER) { - e.preventDefault(); - this.open(); - } - } - - _handleCalendarClick(e) { - if (!this.isOpen) { - return; - } - - let $target = $(e.target); - if (!$target.hasClass('is-disabled')) { - if ( - $target.hasClass('datepicker-day-button') && - !$target.hasClass('is-empty') && - !$target.parent().hasClass('is-disabled') - ) { - this.setDate( - new Date( - e.target.getAttribute('data-year'), - e.target.getAttribute('data-month'), - e.target.getAttribute('data-day') - ) - ); - if (this.options.autoClose) { - this._finishSelection(); - } - } else if ($target.closest('.month-prev').length) { - this.prevMonth(); - } else if ($target.closest('.month-next').length) { - this.nextMonth(); - } - } - } - - _handleClearClick() { - this.date = null; - this.setInputValue(); - this.close(); - } - - _handleMonthChange(e) { - this.gotoMonth(e.target.value); - } - - _handleYearChange(e) { - this.gotoYear(e.target.value); - } - - /** - * change view to a specific month (zero-index, e.g. 0: January) - */ - gotoMonth(month) { - if (!isNaN(month)) { - this.calendars[0].month = parseInt(month, 10); - this.adjustCalendars(); - } - } - - /** - * change view to a specific full year (e.g. "2012") - */ - gotoYear(year) { - if (!isNaN(year)) { - this.calendars[0].year = parseInt(year, 10); - this.adjustCalendars(); - } - } - - _handleInputChange(e) { - let date; - - // Prevent change event from being fired when triggered by the plugin - if (e.firedBy === this) { - return; - } - if (this.options.parse) { - date = this.options.parse(this.el.value, this.options.format); - } else { - date = new Date(Date.parse(this.el.value)); - } - - if (Datepicker._isDate(date)) { - this.setDate(date); - } - } - - renderDayName(opts, day, abbr) { - day += opts.firstDay; - while (day >= 7) { - day -= 7; - } - return abbr ? opts.i18n.weekdaysAbbrev[day] : opts.i18n.weekdays[day]; - } - - /** - * Set input value to the selected date and close Datepicker - */ - _finishSelection() { - this.setInputValue(); - this.close(); - } - - /** - * Open Datepicker - */ - open() { - if (this.isOpen) { - return; - } - - this.isOpen = true; - if (typeof this.options.onOpen === 'function') { - this.options.onOpen.call(this); - } - this.draw(); - this.modal.open(); - return this; - } - - /** - * Close Datepicker - */ - close() { - if (!this.isOpen) { - return; - } - - this.isOpen = false; - if (typeof this.options.onClose === 'function') { - this.options.onClose.call(this); - } - this.modal.close(); - return this; - } - } - - Datepicker._template = [ - '' - ].join(''); - - M.Datepicker = Datepicker; - - if (M.jQueryLoaded) { - M.initializeJqueryWrapper(Datepicker, 'datepicker', 'M_Datepicker'); - } -})(cash); diff --git a/static/js/dropdown.js b/static/js/dropdown.js deleted file mode 100644 index 201c18e1..00000000 --- a/static/js/dropdown.js +++ /dev/null @@ -1,615 +0,0 @@ -(function($, anim) { - 'use strict'; - - let _defaults = { - alignment: 'left', - autoFocus: true, - constrainWidth: true, - container: null, - coverTrigger: true, - closeOnClick: true, - hover: false, - inDuration: 150, - outDuration: 250, - onOpenStart: null, - onOpenEnd: null, - onCloseStart: null, - onCloseEnd: null, - onItemClick: null - }; - - /** - * @class - */ - class Dropdown extends Component { - constructor(el, options) { - super(Dropdown, el, options); - - this.el.M_Dropdown = this; - Dropdown._dropdowns.push(this); - - this.id = M.getIdFromTrigger(el); - this.dropdownEl = document.getElementById(this.id); - this.$dropdownEl = $(this.dropdownEl); - - /** - * Options for the dropdown - * @member Dropdown#options - * @prop {String} [alignment='left'] - Edge which the dropdown is aligned to - * @prop {Boolean} [autoFocus=true] - Automatically focus dropdown el for keyboard - * @prop {Boolean} [constrainWidth=true] - Constrain width to width of the button - * @prop {Element} container - Container element to attach dropdown to (optional) - * @prop {Boolean} [coverTrigger=true] - Place dropdown over trigger - * @prop {Boolean} [closeOnClick=true] - Close on click of dropdown item - * @prop {Boolean} [hover=false] - Open dropdown on hover - * @prop {Number} [inDuration=150] - Duration of open animation in ms - * @prop {Number} [outDuration=250] - Duration of close animation in ms - * @prop {Function} onOpenStart - Function called when dropdown starts opening - * @prop {Function} onOpenEnd - Function called when dropdown finishes opening - * @prop {Function} onCloseStart - Function called when dropdown starts closing - * @prop {Function} onCloseEnd - Function called when dropdown finishes closing - */ - this.options = $.extend({}, Dropdown.defaults, options); - - /** - * Describes open/close state of dropdown - * @type {Boolean} - */ - this.isOpen = false; - - /** - * Describes if dropdown content is scrollable - * @type {Boolean} - */ - this.isScrollable = false; - - /** - * Describes if touch moving on dropdown content - * @type {Boolean} - */ - this.isTouchMoving = false; - - this.focusedIndex = -1; - this.filterQuery = []; - - // Move dropdown-content after dropdown-trigger - if (!!this.options.container) { - $(this.options.container).append(this.dropdownEl); - } else { - this.$el.after(this.dropdownEl); - } - - this._makeDropdownFocusable(); - this._resetFilterQueryBound = this._resetFilterQuery.bind(this); - this._handleDocumentClickBound = this._handleDocumentClick.bind(this); - this._handleDocumentTouchmoveBound = this._handleDocumentTouchmove.bind(this); - this._handleDropdownClickBound = this._handleDropdownClick.bind(this); - this._handleDropdownKeydownBound = this._handleDropdownKeydown.bind(this); - this._handleTriggerKeydownBound = this._handleTriggerKeydown.bind(this); - this._setupEventHandlers(); - } - - static get defaults() { - return _defaults; - } - - static init(els, options) { - return super.init(this, els, options); - } - - /** - * Get Instance - */ - static getInstance(el) { - let domElem = !!el.jquery ? el[0] : el; - return domElem.M_Dropdown; - } - - /** - * Teardown component - */ - destroy() { - this._resetDropdownStyles(); - this._removeEventHandlers(); - Dropdown._dropdowns.splice(Dropdown._dropdowns.indexOf(this), 1); - this.el.M_Dropdown = undefined; - } - - /** - * Setup Event Handlers - */ - _setupEventHandlers() { - // Trigger keydown handler - this.el.addEventListener('keydown', this._handleTriggerKeydownBound); - - // Item click handler - this.dropdownEl.addEventListener('click', this._handleDropdownClickBound); - - // Hover event handlers - if (this.options.hover) { - this._handleMouseEnterBound = this._handleMouseEnter.bind(this); - this.el.addEventListener('mouseenter', this._handleMouseEnterBound); - this._handleMouseLeaveBound = this._handleMouseLeave.bind(this); - this.el.addEventListener('mouseleave', this._handleMouseLeaveBound); - this.dropdownEl.addEventListener('mouseleave', this._handleMouseLeaveBound); - - // Click event handlers - } else { - this._handleClickBound = this._handleClick.bind(this); - this.el.addEventListener('click', this._handleClickBound); - } - } - - /** - * Remove Event Handlers - */ - _removeEventHandlers() { - this.el.removeEventListener('keydown', this._handleTriggerKeydownBound); - this.dropdownEl.removeEventListener('click', this._handleDropdownClickBound); - - if (this.options.hover) { - this.el.removeEventListener('mouseenter', this._handleMouseEnterBound); - this.el.removeEventListener('mouseleave', this._handleMouseLeaveBound); - this.dropdownEl.removeEventListener('mouseleave', this._handleMouseLeaveBound); - } else { - this.el.removeEventListener('click', this._handleClickBound); - } - } - - _setupTemporaryEventHandlers() { - // Use capture phase event handler to prevent click - document.body.addEventListener('click', this._handleDocumentClickBound, true); - document.body.addEventListener('touchend', this._handleDocumentClickBound); - document.body.addEventListener('touchmove', this._handleDocumentTouchmoveBound); - this.dropdownEl.addEventListener('keydown', this._handleDropdownKeydownBound); - } - - _removeTemporaryEventHandlers() { - // Use capture phase event handler to prevent click - document.body.removeEventListener('click', this._handleDocumentClickBound, true); - document.body.removeEventListener('touchend', this._handleDocumentClickBound); - document.body.removeEventListener('touchmove', this._handleDocumentTouchmoveBound); - this.dropdownEl.removeEventListener('keydown', this._handleDropdownKeydownBound); - } - - _handleClick(e) { - e.preventDefault(); - this.open(); - } - - _handleMouseEnter() { - this.open(); - } - - _handleMouseLeave(e) { - let toEl = e.toElement || e.relatedTarget; - let leaveToDropdownContent = !!$(toEl).closest('.dropdown-content').length; - let leaveToActiveDropdownTrigger = false; - - let $closestTrigger = $(toEl).closest('.dropdown-trigger'); - if ( - $closestTrigger.length && - !!$closestTrigger[0].M_Dropdown && - $closestTrigger[0].M_Dropdown.isOpen - ) { - leaveToActiveDropdownTrigger = true; - } - - // Close hover dropdown if mouse did not leave to either active dropdown-trigger or dropdown-content - if (!leaveToActiveDropdownTrigger && !leaveToDropdownContent) { - this.close(); - } - } - - _handleDocumentClick(e) { - let $target = $(e.target); - if ( - this.options.closeOnClick && - $target.closest('.dropdown-content').length && - !this.isTouchMoving - ) { - // isTouchMoving to check if scrolling on mobile. - setTimeout(() => { - this.close(); - }, 0); - } else if ( - $target.closest('.dropdown-trigger').length || - !$target.closest('.dropdown-content').length - ) { - setTimeout(() => { - this.close(); - }, 0); - } - this.isTouchMoving = false; - } - - _handleTriggerKeydown(e) { - // ARROW DOWN OR ENTER WHEN SELECT IS CLOSED - open Dropdown - if ((e.which === M.keys.ARROW_DOWN || e.which === M.keys.ENTER) && !this.isOpen) { - e.preventDefault(); - this.open(); - } - } - - /** - * Handle Document Touchmove - * @param {Event} e - */ - _handleDocumentTouchmove(e) { - let $target = $(e.target); - if ($target.closest('.dropdown-content').length) { - this.isTouchMoving = true; - } - } - - /** - * Handle Dropdown Click - * @param {Event} e - */ - _handleDropdownClick(e) { - // onItemClick callback - if (typeof this.options.onItemClick === 'function') { - let itemEl = $(e.target).closest('li')[0]; - this.options.onItemClick.call(this, itemEl); - } - } - - /** - * Handle Dropdown Keydown - * @param {Event} e - */ - _handleDropdownKeydown(e) { - if (e.which === M.keys.TAB) { - e.preventDefault(); - this.close(); - - // Navigate down dropdown list - } else if ((e.which === M.keys.ARROW_DOWN || e.which === M.keys.ARROW_UP) && this.isOpen) { - e.preventDefault(); - let direction = e.which === M.keys.ARROW_DOWN ? 1 : -1; - let newFocusedIndex = this.focusedIndex; - let foundNewIndex = false; - do { - newFocusedIndex = newFocusedIndex + direction; - - if ( - !!this.dropdownEl.children[newFocusedIndex] && - this.dropdownEl.children[newFocusedIndex].tabIndex !== -1 - ) { - foundNewIndex = true; - break; - } - } while (newFocusedIndex < this.dropdownEl.children.length && newFocusedIndex >= 0); - - if (foundNewIndex) { - this.focusedIndex = newFocusedIndex; - this._focusFocusedItem(); - } - - // ENTER selects choice on focused item - } else if (e.which === M.keys.ENTER && this.isOpen) { - // Search for and ` - ) - .appendTo(this.footer) - .on('click', this.clear.bind(this)); - if (this.options.showClearBtn) { - $clearBtn.css({ visibility: '' }); - } - - let confirmationBtnsContainer = $('
      '); - $( - '' - ) - .appendTo(confirmationBtnsContainer) - .on('click', this.close.bind(this)); - $( - '' - ) - .appendTo(confirmationBtnsContainer) - .on('click', this.done.bind(this)); - confirmationBtnsContainer.appendTo(this.footer); - } - - _clockSetup() { - if (this.options.twelveHour) { - this.$amBtn = $('
      AM
      '); - this.$pmBtn = $('
      PM
      '); - this.$amBtn.on('click', this._handleAmPmClick.bind(this)).appendTo(this.spanAmPm); - this.$pmBtn.on('click', this._handleAmPmClick.bind(this)).appendTo(this.spanAmPm); - } - - this._buildHoursView(); - this._buildMinutesView(); - this._buildSVGClock(); - } - - _buildSVGClock() { - // Draw clock hands and others - let dialRadius = this.options.dialRadius; - let tickRadius = this.options.tickRadius; - let diameter = dialRadius * 2; - - let svg = Timepicker._createSVGEl('svg'); - svg.setAttribute('class', 'timepicker-svg'); - svg.setAttribute('width', diameter); - svg.setAttribute('height', diameter); - let g = Timepicker._createSVGEl('g'); - g.setAttribute('transform', 'translate(' + dialRadius + ',' + dialRadius + ')'); - let bearing = Timepicker._createSVGEl('circle'); - bearing.setAttribute('class', 'timepicker-canvas-bearing'); - bearing.setAttribute('cx', 0); - bearing.setAttribute('cy', 0); - bearing.setAttribute('r', 4); - let hand = Timepicker._createSVGEl('line'); - hand.setAttribute('x1', 0); - hand.setAttribute('y1', 0); - let bg = Timepicker._createSVGEl('circle'); - bg.setAttribute('class', 'timepicker-canvas-bg'); - bg.setAttribute('r', tickRadius); - g.appendChild(hand); - g.appendChild(bg); - g.appendChild(bearing); - svg.appendChild(g); - this._canvas.appendChild(svg); - - this.hand = hand; - this.bg = bg; - this.bearing = bearing; - this.g = g; - } - - _buildHoursView() { - let $tick = $('
      '); - // Hours view - if (this.options.twelveHour) { - for (let i = 1; i < 13; i += 1) { - let tick = $tick.clone(); - let radian = i / 6 * Math.PI; - let radius = this.options.outerRadius; - tick.css({ - left: - this.options.dialRadius + Math.sin(radian) * radius - this.options.tickRadius + 'px', - top: - this.options.dialRadius - Math.cos(radian) * radius - this.options.tickRadius + 'px' - }); - tick.html(i === 0 ? '00' : i); - this.hoursView.appendChild(tick[0]); - // tick.on(mousedownEvent, mousedown); - } - } else { - for (let i = 0; i < 24; i += 1) { - let tick = $tick.clone(); - let radian = i / 6 * Math.PI; - let inner = i > 0 && i < 13; - let radius = inner ? this.options.innerRadius : this.options.outerRadius; - tick.css({ - left: - this.options.dialRadius + Math.sin(radian) * radius - this.options.tickRadius + 'px', - top: - this.options.dialRadius - Math.cos(radian) * radius - this.options.tickRadius + 'px' - }); - tick.html(i === 0 ? '00' : i); - this.hoursView.appendChild(tick[0]); - // tick.on(mousedownEvent, mousedown); - } - } - } - - _buildMinutesView() { - let $tick = $('
      '); - // Minutes view - for (let i = 0; i < 60; i += 5) { - let tick = $tick.clone(); - let radian = i / 30 * Math.PI; - tick.css({ - left: - this.options.dialRadius + - Math.sin(radian) * this.options.outerRadius - - this.options.tickRadius + - 'px', - top: - this.options.dialRadius - - Math.cos(radian) * this.options.outerRadius - - this.options.tickRadius + - 'px' - }); - tick.html(Timepicker._addLeadingZero(i)); - this.minutesView.appendChild(tick[0]); - } - } - - _handleAmPmClick(e) { - let $btnClicked = $(e.target); - this.amOrPm = $btnClicked.hasClass('am-btn') ? 'AM' : 'PM'; - this._updateAmPmView(); - } - - _updateAmPmView() { - if (this.options.twelveHour) { - this.$amBtn.toggleClass('text-primary', this.amOrPm === 'AM'); - this.$pmBtn.toggleClass('text-primary', this.amOrPm === 'PM'); - } - } - - _updateTimeFromInput() { - // Get the time - let value = ((this.el.value || this.options.defaultTime || '') + '').split(':'); - if (this.options.twelveHour && !(typeof value[1] === 'undefined')) { - if (value[1].toUpperCase().indexOf('AM') > 0) { - this.amOrPm = 'AM'; - } else { - this.amOrPm = 'PM'; - } - value[1] = value[1].replace('AM', '').replace('PM', ''); - } - if (value[0] === 'now') { - let now = new Date(+new Date() + this.options.fromNow); - value = [now.getHours(), now.getMinutes()]; - if (this.options.twelveHour) { - this.amOrPm = value[0] >= 12 && value[0] < 24 ? 'PM' : 'AM'; - } - } - this.hours = +value[0] || 0; - this.minutes = +value[1] || 0; - this.spanHours.innerHTML = this.hours; - this.spanMinutes.innerHTML = Timepicker._addLeadingZero(this.minutes); - - this._updateAmPmView(); - } - - showView(view, delay) { - if (view === 'minutes' && $(this.hoursView).css('visibility') === 'visible') { - // raiseCallback(this.options.beforeHourSelect); - } - let isHours = view === 'hours', - nextView = isHours ? this.hoursView : this.minutesView, - hideView = isHours ? this.minutesView : this.hoursView; - this.currentView = view; - - $(this.spanHours).toggleClass('text-primary', isHours); - $(this.spanMinutes).toggleClass('text-primary', !isHours); - - // Transition view - hideView.classList.add('timepicker-dial-out'); - $(nextView) - .css('visibility', 'visible') - .removeClass('timepicker-dial-out'); - - // Reset clock hand - this.resetClock(delay); - - // After transitions ended - clearTimeout(this.toggleViewTimer); - this.toggleViewTimer = setTimeout(() => { - $(hideView).css('visibility', 'hidden'); - }, this.options.duration); - } - - resetClock(delay) { - let view = this.currentView, - value = this[view], - isHours = view === 'hours', - unit = Math.PI / (isHours ? 6 : 30), - radian = value * unit, - radius = - isHours && value > 0 && value < 13 ? this.options.innerRadius : this.options.outerRadius, - x = Math.sin(radian) * radius, - y = -Math.cos(radian) * radius, - self = this; - - if (delay) { - $(this.canvas).addClass('timepicker-canvas-out'); - setTimeout(() => { - $(self.canvas).removeClass('timepicker-canvas-out'); - self.setHand(x, y); - }, delay); - } else { - this.setHand(x, y); - } - } - - setHand(x, y, roundBy5) { - let radian = Math.atan2(x, -y), - isHours = this.currentView === 'hours', - unit = Math.PI / (isHours || roundBy5 ? 6 : 30), - z = Math.sqrt(x * x + y * y), - inner = isHours && z < (this.options.outerRadius + this.options.innerRadius) / 2, - radius = inner ? this.options.innerRadius : this.options.outerRadius; - - if (this.options.twelveHour) { - radius = this.options.outerRadius; - } - - // Radian should in range [0, 2PI] - if (radian < 0) { - radian = Math.PI * 2 + radian; - } - - // Get the round value - let value = Math.round(radian / unit); - - // Get the round radian - radian = value * unit; - - // Correct the hours or minutes - if (this.options.twelveHour) { - if (isHours) { - if (value === 0) value = 12; - } else { - if (roundBy5) value *= 5; - if (value === 60) value = 0; - } - } else { - if (isHours) { - if (value === 12) { - value = 0; - } - value = inner ? (value === 0 ? 12 : value) : value === 0 ? 0 : value + 12; - } else { - if (roundBy5) { - value *= 5; - } - if (value === 60) { - value = 0; - } - } - } - - // Once hours or minutes changed, vibrate the device - if (this[this.currentView] !== value) { - if (this.vibrate && this.options.vibrate) { - // Do not vibrate too frequently - if (!this.vibrateTimer) { - navigator[this.vibrate](10); - this.vibrateTimer = setTimeout(() => { - this.vibrateTimer = null; - }, 100); - } - } - } - - this[this.currentView] = value; - if (isHours) { - this['spanHours'].innerHTML = value; - } else { - this['spanMinutes'].innerHTML = Timepicker._addLeadingZero(value); - } - - // Set clock hand and others' position - let cx1 = Math.sin(radian) * (radius - this.options.tickRadius), - cy1 = -Math.cos(radian) * (radius - this.options.tickRadius), - cx2 = Math.sin(radian) * radius, - cy2 = -Math.cos(radian) * radius; - this.hand.setAttribute('x2', cx1); - this.hand.setAttribute('y2', cy1); - this.bg.setAttribute('cx', cx2); - this.bg.setAttribute('cy', cy2); - } - - open() { - if (this.isOpen) { - return; - } - - this.isOpen = true; - this._updateTimeFromInput(); - this.showView('hours'); - - this.modal.open(); - } - - close() { - if (!this.isOpen) { - return; - } - - this.isOpen = false; - this.modal.close(); - } - - /** - * Finish timepicker selection. - */ - done(e, clearValue) { - // Set input value - let last = this.el.value; - let value = clearValue - ? '' - : Timepicker._addLeadingZero(this.hours) + ':' + Timepicker._addLeadingZero(this.minutes); - this.time = value; - if (!clearValue && this.options.twelveHour) { - value = `${value} ${this.amOrPm}`; - } - this.el.value = value; - - // Trigger change event - if (value !== last) { - this.$el.trigger('change'); - } - - this.close(); - this.el.focus(); - } - - clear() { - this.done(null, true); - } - } - - Timepicker._template = [ - '' - ].join(''); - - M.Timepicker = Timepicker; - - if (M.jQueryLoaded) { - M.initializeJqueryWrapper(Timepicker, 'timepicker', 'M_Timepicker'); - } -})(cash); diff --git a/static/js/toasts.js b/static/js/toasts.js deleted file mode 100644 index b0e4b83a..00000000 --- a/static/js/toasts.js +++ /dev/null @@ -1,310 +0,0 @@ -(function($, anim) { - 'use strict'; - - let _defaults = { - html: '', - displayLength: 4000, - inDuration: 300, - outDuration: 375, - classes: '', - completeCallback: null, - activationPercent: 0.8 - }; - - class Toast { - constructor(options) { - /** - * Options for the toast - * @member Toast#options - */ - this.options = $.extend({}, Toast.defaults, options); - this.message = this.options.html; - - /** - * 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.$el = $(toastElement); - this._animateIn(); - this._setTimer(); - } - - static get defaults() { - return _defaults; - } - - /** - * Get Instance - */ - static getInstance(el) { - let domElem = !!el.jquery ? el[0] : el; - return domElem.M_Toast; - } - - /** - * 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).remove(); - 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 - */ - static _onDragEnd() { - 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.dismiss(); - - // 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 dismissAll() { - for (let toastIndex in Toast._toasts) { - Toast._toasts[toastIndex].dismiss(); - } - } - - /** - * 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.classes.length) { - $(toast).addClass(this.options.classes); - } - - // 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.jquery) { - $(toast).append(this.message[0]); - - // Insert as html; - } else { - toast.innerHTML = this.message; - } - - // Append toasft - Toast._container.appendChild(toast); - return toast; - } - - /** - * Animate in toast - */ - _animateIn() { - // Animate toast in - anim({ - targets: this.el, - top: 0, - opacity: 1, - duration: this.options.inDuration, - easing: 'easeOutCubic' - }); - } - - /** - * 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.dismiss(); - } - }, 20); - } - } - - /** - * Dismiss toast with animation - */ - dismiss() { - 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; - } - - anim({ - targets: this.el, - opacity: 0, - marginTop: -40, - duration: this.options.outDuration, - easing: 'easeOutExpo', - complete: () => { - // Call the optional callback - if (typeof this.options.completeCallback === 'function') { - this.options.completeCallback(); - } - // Remove toast from DOM - this.$el.remove(); - 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; - - M.Toast = Toast; - M.toast = function(options) { - return new Toast(options); - }; -})(cash, M.anime); diff --git a/static/js/tooltip.js b/static/js/tooltip.js deleted file mode 100644 index b30dce2b..00000000 --- a/static/js/tooltip.js +++ /dev/null @@ -1,303 +0,0 @@ -(function($, anim) { - 'use strict'; - - let _defaults = { - exitDelay: 200, - enterDelay: 0, - html: null, - margin: 5, - inDuration: 250, - outDuration: 200, - position: 'bottom', - transitionMovement: 10 - }; - - /** - * @class - * - */ - class Tooltip extends Component { - /** - * Construct Tooltip instance - * @constructor - * @param {Element} el - * @param {Object} options - */ - constructor(el, options) { - super(Tooltip, el, options); - - this.el.M_Tooltip = this; - this.options = $.extend({}, Tooltip.defaults, options); - - this.isOpen = false; - this.isHovered = false; - this.isFocused = false; - this._appendTooltipEl(); - this._setupEventHandlers(); - } - - static get defaults() { - return _defaults; - } - - static init(els, options) { - return super.init(this, els, options); - } - - /** - * Get Instance - */ - static getInstance(el) { - let domElem = !!el.jquery ? el[0] : el; - return domElem.M_Tooltip; - } - - /** - * Teardown component - */ - destroy() { - $(this.tooltipEl).remove(); - this._removeEventHandlers(); - this.el.M_Tooltip = undefined; - } - - _appendTooltipEl() { - let tooltipEl = document.createElement('div'); - tooltipEl.classList.add('material-tooltip'); - this.tooltipEl = tooltipEl; - - let tooltipContentEl = document.createElement('div'); - tooltipContentEl.classList.add('tooltip-content'); - tooltipContentEl.innerHTML = this.options.html; - tooltipEl.appendChild(tooltipContentEl); - document.body.appendChild(tooltipEl); - } - - _updateTooltipContent() { - this.tooltipEl.querySelector('.tooltip-content').innerHTML = this.options.html; - } - - _setupEventHandlers() { - this._handleMouseEnterBound = this._handleMouseEnter.bind(this); - this._handleMouseLeaveBound = this._handleMouseLeave.bind(this); - this._handleFocusBound = this._handleFocus.bind(this); - this._handleBlurBound = this._handleBlur.bind(this); - this.el.addEventListener('mouseenter', this._handleMouseEnterBound); - this.el.addEventListener('mouseleave', this._handleMouseLeaveBound); - this.el.addEventListener('focus', this._handleFocusBound, true); - this.el.addEventListener('blur', this._handleBlurBound, true); - } - - _removeEventHandlers() { - this.el.removeEventListener('mouseenter', this._handleMouseEnterBound); - this.el.removeEventListener('mouseleave', this._handleMouseLeaveBound); - this.el.removeEventListener('focus', this._handleFocusBound, true); - this.el.removeEventListener('blur', this._handleBlurBound, true); - } - - open(isManual) { - if (this.isOpen) { - return; - } - isManual = isManual === undefined ? true : undefined; // Default value true - this.isOpen = true; - // Update tooltip content with HTML attribute options - this.options = $.extend({}, this.options, this._getAttributeOptions()); - this._updateTooltipContent(); - this._setEnterDelayTimeout(isManual); - } - - close() { - if (!this.isOpen) { - return; - } - - this.isHovered = false; - this.isFocused = false; - this.isOpen = false; - this._setExitDelayTimeout(); - } - - /** - * Create timeout which delays when the tooltip closes - */ - _setExitDelayTimeout() { - clearTimeout(this._exitDelayTimeout); - - this._exitDelayTimeout = setTimeout(() => { - if (this.isHovered || this.isFocused) { - return; - } - - this._animateOut(); - }, this.options.exitDelay); - } - - /** - * Create timeout which delays when the toast closes - */ - _setEnterDelayTimeout(isManual) { - clearTimeout(this._enterDelayTimeout); - - this._enterDelayTimeout = setTimeout(() => { - if (!this.isHovered && !this.isFocused && !isManual) { - return; - } - - this._animateIn(); - }, this.options.enterDelay); - } - - _positionTooltip() { - let origin = this.el, - tooltip = this.tooltipEl, - originHeight = origin.offsetHeight, - originWidth = origin.offsetWidth, - tooltipHeight = tooltip.offsetHeight, - tooltipWidth = tooltip.offsetWidth, - newCoordinates, - margin = this.options.margin, - targetTop, - targetLeft; - - (this.xMovement = 0), (this.yMovement = 0); - - targetTop = origin.getBoundingClientRect().top + M.getDocumentScrollTop(); - targetLeft = origin.getBoundingClientRect().left + M.getDocumentScrollLeft(); - - if (this.options.position === 'top') { - targetTop += -tooltipHeight - margin; - targetLeft += originWidth / 2 - tooltipWidth / 2; - this.yMovement = -this.options.transitionMovement; - } else if (this.options.position === 'right') { - targetTop += originHeight / 2 - tooltipHeight / 2; - targetLeft += originWidth + margin; - this.xMovement = this.options.transitionMovement; - } else if (this.options.position === 'left') { - targetTop += originHeight / 2 - tooltipHeight / 2; - targetLeft += -tooltipWidth - margin; - this.xMovement = -this.options.transitionMovement; - } else { - targetTop += originHeight + margin; - targetLeft += originWidth / 2 - tooltipWidth / 2; - this.yMovement = this.options.transitionMovement; - } - - newCoordinates = this._repositionWithinScreen( - targetLeft, - targetTop, - tooltipWidth, - tooltipHeight - ); - $(tooltip).css({ - top: newCoordinates.y + 'px', - left: newCoordinates.x + 'px' - }); - } - - _repositionWithinScreen(x, y, width, height) { - let scrollLeft = M.getDocumentScrollLeft(); - let scrollTop = M.getDocumentScrollTop(); - let newX = x - scrollLeft; - let newY = y - scrollTop; - - let bounding = { - left: newX, - top: newY, - width: width, - height: height - }; - - let offset = this.options.margin + this.options.transitionMovement; - let edges = M.checkWithinContainer(document.body, bounding, offset); - - if (edges.left) { - newX = offset; - } else if (edges.right) { - newX -= newX + width - window.innerWidth; - } - - if (edges.top) { - newY = offset; - } else if (edges.bottom) { - newY -= newY + height - window.innerHeight; - } - - return { - x: newX + scrollLeft, - y: newY + scrollTop - }; - } - - _animateIn() { - this._positionTooltip(); - this.tooltipEl.style.visibility = 'visible'; - anim.remove(this.tooltipEl); - anim({ - targets: this.tooltipEl, - opacity: 1, - translateX: this.xMovement, - translateY: this.yMovement, - duration: this.options.inDuration, - easing: 'easeOutCubic' - }); - } - - _animateOut() { - anim.remove(this.tooltipEl); - anim({ - targets: this.tooltipEl, - opacity: 0, - translateX: 0, - translateY: 0, - duration: this.options.outDuration, - easing: 'easeOutCubic' - }); - } - - _handleMouseEnter() { - this.isHovered = true; - this.isFocused = false; // Allows close of tooltip when opened by focus. - this.open(false); - } - - _handleMouseLeave() { - this.isHovered = false; - this.isFocused = false; // Allows close of tooltip when opened by focus. - this.close(); - } - - _handleFocus() { - if (M.tabPressed) { - this.isFocused = true; - this.open(false); - } - } - - _handleBlur() { - this.isFocused = false; - this.close(); - } - - _getAttributeOptions() { - let attributeOptions = {}; - let tooltipTextOption = this.el.getAttribute('data-tooltip'); - let positionOption = this.el.getAttribute('data-position'); - - if (tooltipTextOption) { - attributeOptions.html = tooltipTextOption; - } - - if (positionOption) { - attributeOptions.position = positionOption; - } - return attributeOptions; - } - } - - M.Tooltip = Tooltip; - - if (M.jQueryLoaded) { - M.initializeJqueryWrapper(Tooltip, 'tooltip', 'M_Tooltip'); - } -})(cash, M.anime); diff --git a/static/js/waves.js b/static/js/waves.js deleted file mode 100644 index b56cc2cb..00000000 --- a/static/js/waves.js +++ /dev/null @@ -1,335 +0,0 @@ -/*! - * Waves v0.6.4 - * http://fian.my.id/Waves - * - * Copyright 2014 Alfiana E. Sibuea and other contributors - * Released under the MIT license - * https://github.com/fians/Waves/blob/master/LICENSE - */ - -;(function(window) { - 'use strict'; - - var Waves = Waves || {}; - var $$ = document.querySelectorAll.bind(document); - - // Find exact position of element - function isWindow(obj) { - return obj !== null && obj === obj.window; - } - - function getWindow(elem) { - return isWindow(elem) ? elem : elem.nodeType === 9 && elem.defaultView; - } - - function offset(elem) { - var docElem, win, - box = {top: 0, left: 0}, - doc = elem && elem.ownerDocument; - - docElem = doc.documentElement; - - if (typeof elem.getBoundingClientRect !== typeof undefined) { - box = elem.getBoundingClientRect(); - } - win = getWindow(doc); - return { - top: box.top + win.pageYOffset - docElem.clientTop, - left: box.left + win.pageXOffset - docElem.clientLeft - }; - } - - function convertStyle(obj) { - var style = ''; - - for (var a in obj) { - if (obj.hasOwnProperty(a)) { - style += (a + ':' + obj[a] + ';'); - } - } - - return style; - } - - var Effect = { - - // Effect delay - duration: 750, - - show: function(e, element) { - - // Disable right click - if (e.button === 2) { - return false; - } - - var el = element || this; - - // Create ripple - var ripple = document.createElement('div'); - ripple.className = 'waves-ripple'; - el.appendChild(ripple); - - // Get click coordinate and element witdh - var pos = offset(el); - var relativeY = (e.pageY - pos.top); - var relativeX = (e.pageX - pos.left); - var scale = 'scale('+((el.clientWidth / 100) * 10)+')'; - - // Support for touch devices - if ('touches' in e) { - relativeY = (e.touches[0].pageY - pos.top); - relativeX = (e.touches[0].pageX - pos.left); - } - - // Attach data to element - ripple.setAttribute('data-hold', Date.now()); - ripple.setAttribute('data-scale', scale); - ripple.setAttribute('data-x', relativeX); - ripple.setAttribute('data-y', relativeY); - - // Set ripple position - var rippleStyle = { - 'top': relativeY+'px', - 'left': relativeX+'px' - }; - - ripple.className = ripple.className + ' waves-notransition'; - ripple.setAttribute('style', convertStyle(rippleStyle)); - ripple.className = ripple.className.replace('waves-notransition', ''); - - // Scale the ripple - rippleStyle['-webkit-transform'] = scale; - rippleStyle['-moz-transform'] = scale; - rippleStyle['-ms-transform'] = scale; - rippleStyle['-o-transform'] = scale; - rippleStyle.transform = scale; - rippleStyle.opacity = '1'; - - rippleStyle['-webkit-transition-duration'] = Effect.duration + 'ms'; - rippleStyle['-moz-transition-duration'] = Effect.duration + 'ms'; - rippleStyle['-o-transition-duration'] = Effect.duration + 'ms'; - rippleStyle['transition-duration'] = Effect.duration + 'ms'; - - rippleStyle['-webkit-transition-timing-function'] = 'cubic-bezier(0.250, 0.460, 0.450, 0.940)'; - rippleStyle['-moz-transition-timing-function'] = 'cubic-bezier(0.250, 0.460, 0.450, 0.940)'; - rippleStyle['-o-transition-timing-function'] = 'cubic-bezier(0.250, 0.460, 0.450, 0.940)'; - rippleStyle['transition-timing-function'] = 'cubic-bezier(0.250, 0.460, 0.450, 0.940)'; - - ripple.setAttribute('style', convertStyle(rippleStyle)); - }, - - hide: function(e) { - TouchHandler.touchup(e); - - var el = this; - var width = el.clientWidth * 1.4; - - // Get first ripple - var ripple = null; - var ripples = el.getElementsByClassName('waves-ripple'); - if (ripples.length > 0) { - ripple = ripples[ripples.length - 1]; - } else { - return false; - } - - var relativeX = ripple.getAttribute('data-x'); - var relativeY = ripple.getAttribute('data-y'); - var scale = ripple.getAttribute('data-scale'); - - // Get delay beetween mousedown and mouse leave - var diff = Date.now() - Number(ripple.getAttribute('data-hold')); - var delay = 350 - diff; - - if (delay < 0) { - delay = 0; - } - - // Fade out ripple after delay - setTimeout(function() { - var style = { - 'top': relativeY+'px', - 'left': relativeX+'px', - 'opacity': '0', - - // Duration - '-webkit-transition-duration': Effect.duration + 'ms', - '-moz-transition-duration': Effect.duration + 'ms', - '-o-transition-duration': Effect.duration + 'ms', - 'transition-duration': Effect.duration + 'ms', - '-webkit-transform': scale, - '-moz-transform': scale, - '-ms-transform': scale, - '-o-transform': scale, - 'transform': scale, - }; - - ripple.setAttribute('style', convertStyle(style)); - - setTimeout(function() { - try { - el.removeChild(ripple); - } catch(e) { - return false; - } - }, Effect.duration); - }, delay); - }, - - // Little hack to make can perform waves effect - wrapInput: function(elements) { - for (var a = 0; a < elements.length; a++) { - var el = elements[a]; - - if (el.tagName.toLowerCase() === 'input') { - var parent = el.parentNode; - - // If input already have parent just pass through - if (parent.tagName.toLowerCase() === 'i' && parent.className.indexOf('waves-effect') !== -1) { - continue; - } - - // Put element class and style to the specified parent - var wrapper = document.createElement('i'); - wrapper.className = el.className + ' waves-input-wrapper'; - - var elementStyle = el.getAttribute('style'); - - if (!elementStyle) { - elementStyle = ''; - } - - wrapper.setAttribute('style', elementStyle); - - el.className = 'waves-button-input'; - el.removeAttribute('style'); - - // Put element as child - parent.replaceChild(wrapper, el); - wrapper.appendChild(el); - } - } - } - }; - - - /** - * Disable mousedown event for 500ms during and after touch - */ - var TouchHandler = { - /* uses an integer rather than bool so there's no issues with - * needing to clear timeouts if another touch event occurred - * within the 500ms. Cannot mouseup between touchstart and - * touchend, nor in the 500ms after touchend. */ - touches: 0, - allowEvent: function(e) { - var allow = true; - - if (e.type === 'touchstart') { - TouchHandler.touches += 1; //push - } else if (e.type === 'touchend' || e.type === 'touchcancel') { - setTimeout(function() { - if (TouchHandler.touches > 0) { - TouchHandler.touches -= 1; //pop after 500ms - } - }, 500); - } else if (e.type === 'mousedown' && TouchHandler.touches > 0) { - allow = false; - } - - return allow; - }, - touchup: function(e) { - TouchHandler.allowEvent(e); - } - }; - - - /** - * Delegated click handler for .waves-effect element. - * returns null when .waves-effect element not in "click tree" - */ - function getWavesEffectElement(e) { - if (TouchHandler.allowEvent(e) === false) { - return null; - } - - var element = null; - var target = e.target || e.srcElement; - - while (target.parentNode !== null) { - if (!(target instanceof SVGElement) && target.className.indexOf('waves-effect') !== -1) { - element = target; - break; - } - target = target.parentNode; - } - return element; - } - - /** - * Bubble the click and show effect if .waves-effect elem was found - */ - function showEffect(e) { - var element = getWavesEffectElement(e); - - if (element !== null) { - Effect.show(e, element); - - if ('ontouchstart' in window) { - element.addEventListener('touchend', Effect.hide, false); - element.addEventListener('touchcancel', Effect.hide, false); - } - - element.addEventListener('mouseup', Effect.hide, false); - element.addEventListener('mouseleave', Effect.hide, false); - element.addEventListener('dragend', Effect.hide, false); - } - } - - Waves.displayEffect = function(options) { - options = options || {}; - - if ('duration' in options) { - Effect.duration = options.duration; - } - - //Wrap input inside tag - Effect.wrapInput($$('.waves-effect')); - - if ('ontouchstart' in window) { - document.body.addEventListener('touchstart', showEffect, false); - } - - document.body.addEventListener('mousedown', showEffect, false); - }; - - /** - * Attach Waves to an input element (or any element which doesn't - * bubble mouseup/mousedown events). - * Intended to be used with dynamically loaded forms/inputs, or - * where the user doesn't want a delegated click handler. - */ - Waves.attach = function(element) { - //FUTURE: automatically add waves classes and allow users - // to specify them with an options param? Eg. light/classic/button - if (element.tagName.toLowerCase() === 'input') { - Effect.wrapInput([element]); - element = element.parentNode; - } - - if ('ontouchstart' in window) { - element.addEventListener('touchstart', showEffect, false); - } - - element.addEventListener('mousedown', showEffect, false); - }; - - window.Waves = Waves; - - document.addEventListener('DOMContentLoaded', function() { - Waves.displayEffect(); - }, false); - -})(window);