diff options
Diffstat (limited to 'node_modules/materialize-css/js/collapsible.js')
-rw-r--r-- | node_modules/materialize-css/js/collapsible.js | 275 |
1 files changed, 275 insertions, 0 deletions
diff --git a/node_modules/materialize-css/js/collapsible.js b/node_modules/materialize-css/js/collapsible.js new file mode 100644 index 0000000000..6c4912612d --- /dev/null +++ b/node_modules/materialize-css/js/collapsible.js @@ -0,0 +1,275 @@ +(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); |