vendor/assets/js/foundation.drilldown.js.es6 in foundation-rails-6.2.4.0 vs vendor/assets/js/foundation.drilldown.js.es6 in foundation-rails-6.3.0.0

- old
+ new

@@ -45,12 +45,14 @@ */ _init() { this.$submenuAnchors = this.$element.find('li.is-drilldown-submenu-parent').children('a'); this.$submenus = this.$submenuAnchors.parent('li').children('[data-submenu]'); this.$menuItems = this.$element.find('li').not('.js-drilldown-back').attr('role', 'menuitem').find('a'); + this.$element.attr('data-mutate', (this.$element.attr('data-drilldown') || Foundation.GetYoDigits(6, 'drilldown'))); this._prepareMenu(); + this._registerEvents(); this._keyboardEvents(); } /** @@ -82,20 +84,41 @@ }); this.$submenus.each(function(){ var $menu = $(this), $back = $menu.find('.js-drilldown-back'); if(!$back.length){ - $menu.prepend(_this.options.backButton); + switch (_this.options.backButtonPosition) { + case "bottom": + $menu.append(_this.options.backButton); + break; + case "top": + $menu.prepend(_this.options.backButton); + break; + default: + console.error("Unsupported backButtonPosition value '" + _this.options.backButtonPosition + "'"); + } } _this._back($menu); }); + + if(!this.options.autoHeight) { + this.$submenus.addClass('drilldown-submenu-cover-previous'); + } + if(!this.$element.parent().hasClass('is-drilldown')){ this.$wrapper = $(this.options.wrapper).addClass('is-drilldown'); + if(this.options.animateHeight) this.$wrapper.addClass('animate-height'); this.$wrapper = this.$element.wrap(this.$wrapper).parent().css(this._getMaxDims()); } } + _resize() { + this.$wrapper.css({'max-width': 'none', 'min-height': 'none'}); + // _getMaxDims has side effects (boo) but calling it should update all other necessary heights & widths + this.$wrapper.css(this._getMaxDims()); + } + /** * Adds event handlers to elements in the menu. * @function * @private * @param {jQuery} $elem - the current menu item to add handlers to. @@ -123,21 +146,51 @@ _this._hideAll(); $body.off('.zf.drilldown'); }); } }); + this.$element.on('mutateme.zf.trigger', this._resize.bind(this)); } /** + * Adds event handlers to the menu element. + * @function + * @private + */ + _registerEvents() { + if(this.options.scrollTop){ + this._bindHandler = this._scrollTop.bind(this); + this.$element.on('open.zf.drilldown hide.zf.drilldown closed.zf.drilldown',this._bindHandler); + } + } + + /** + * Scroll to Top of Element or data-scroll-top-element + * @function + * @fires Drilldown#scrollme + */ + _scrollTop() { + var _this = this; + var $scrollTopElement = _this.options.scrollTopElement!=''?$(_this.options.scrollTopElement):_this.$element, + scrollPos = parseInt($scrollTopElement.offset().top+_this.options.scrollTopOffset); + $('html, body').stop(true).animate({ scrollTop: scrollPos }, _this.options.animationDuration, _this.options.animationEasing,function(){ + /** + * Fires after the menu has scrolled + * @event Drilldown#scrollme + */ + if(this===$('html')[0])_this.$element.trigger('scrollme.zf.drilldown'); + }); + } + + /** * Adds keydown event listener to `li`'s in the menu. * @private */ _keyboardEvents() { var _this = this; - this.$menuItems.add(this.$element.find('.js-drilldown-back > a')).on('keydown.zf.drilldown', function(e){ - + this.$menuItems.add(this.$element.find('.js-drilldown-back > a, .is-submenu-parent-item > a')).on('keydown.zf.drilldown', function(e){ var $element = $(this), $elements = $element.parent('li').parent('ul').children('li').children('a'), $prevElement, $nextElement; @@ -186,11 +239,11 @@ $element.parent('li').parent('ul').one(Foundation.transitionend($element), function(){ setTimeout(function() { $element.parent('li').parent('ul').parent('li').children('a').first().focus(); }, 1); }); - return true; + return true; } else if ($element.is(_this.$submenuAnchors)) { _this._show($element.parent('li')); $element.parent('li').one(Foundation.transitionend($element), function(){ $element.parent('li').find('ul li a').filter(_this.$menuItems).first().focus(); }); @@ -212,10 +265,11 @@ * @function * @fires Drilldown#closed */ _hideAll() { var $elem = this.$element.find('.is-drilldown-submenu.is-active').addClass('is-closing'); + if(this.options.autoHeight) this.$wrapper.css({height:$elem.parent().closest('ul').data('calcHeight')}); $elem.one(Foundation.transitionend($elem), function(e){ $elem.removeClass('is-active is-closing'); }); /** * Fires when the menu is fully closed. @@ -239,11 +293,11 @@ // console.log('mouseup on back'); _this._hide($elem); // If there is a parent submenu, call show let parentSubMenu = $elem.parent('li').parent('ul').parent('li'); - if (parentSubMenu.length) { + if (parentSubMenu.length) { _this._show(parentSubMenu); } }); } @@ -269,10 +323,11 @@ * @function * @fires Drilldown#open * @param {jQuery} $elem - the current element with a submenu to open, i.e. the `li` tag. */ _show($elem) { + if(this.options.autoHeight) this.$wrapper.css({height:$elem.children('[data-submenu]').data('calcHeight')}); $elem.attr('aria-expanded', true); $elem.children('[data-submenu]').addClass('is-active').attr('aria-hidden', false); /** * Fires when the submenu has opened. * @event Drilldown#open @@ -285,13 +340,15 @@ * @function * @fires Drilldown#hide * @param {jQuery} $elem - the current sub-menu to hide, i.e. the `ul` tag. */ _hide($elem) { + if(this.options.autoHeight) this.$wrapper.css({height:$elem.parent().closest('ul').data('calcHeight')}); var _this = this; $elem.parent('li').attr('aria-expanded', false); $elem.attr('aria-hidden', true).addClass('is-closing') + $elem.addClass('is-closing') .one(Foundation.transitionend($elem), function(){ $elem.removeClass('is-active is-closing'); $elem.blur(); }); /** @@ -306,38 +363,47 @@ * Prevents content jumping. * @function * @private */ _getMaxDims() { - var biggest = 0 - var result = {}; - - this.$submenus.add(this.$element).each((i, elem) => { - var height = elem.getBoundingClientRect().height; - if (height > biggest) biggest = height; + var maxHeight = 0, result = {}, _this = this; + this.$submenus.add(this.$element).each(function(){ + var numOfElems = $(this).children('li').length; + var height = Foundation.Box.GetDimensions(this).height; + maxHeight = height > maxHeight ? height : maxHeight; + if(_this.options.autoHeight) { + $(this).data('calcHeight',height); + if (!$(this).hasClass('is-drilldown-submenu')) result['height'] = height; + } }); - result['min-height'] = `${biggest}px`; + if(!this.options.autoHeight) result['min-height'] = `${maxHeight}px`; + result['max-width'] = `${this.$element[0].getBoundingClientRect().width}px`; return result; } /** * Destroys the Drilldown Menu * @function */ destroy() { + if(this.options.scrollTop) this.$element.off('.zf.drilldown',this._bindHandler); this._hideAll(); + this.$element.off('mutateme.zf.trigger'); Foundation.Nest.Burn(this.$element, 'drilldown'); this.$element.unwrap() .find('.js-drilldown-back, .is-submenu-parent-item').remove() .end().find('.is-active, .is-closing, .is-drilldown-submenu').removeClass('is-active is-closing is-drilldown-submenu') .end().find('[data-submenu]').removeAttr('aria-hidden tabindex role'); this.$submenuAnchors.each(function() { $(this).off('.zf.drilldown'); }); + + this.$submenus.removeClass('drilldown-submenu-cover-previous'); + this.$element.find('a').each(function(){ var $link = $(this); $link.removeAttr('tabindex'); if($link.data('savedHref')){ $link.attr('href', $link.data('savedHref')).removeData('savedHref'); @@ -347,16 +413,22 @@ }; } Drilldown.defaults = { /** - * Markup used for JS generated back button. Prepended to submenu lists and deleted on `destroy` method, 'js-drilldown-back' class required. Remove the backslash (`\`) if copy and pasting. + * Markup used for JS generated back button. Prepended or appended (see backButtonPosition) to submenu lists and deleted on `destroy` method, 'js-drilldown-back' class required. Remove the backslash (`\`) if copy and pasting. * @option * @example '<\li><\a>Back<\/a><\/li>' */ backButton: '<li class="js-drilldown-back"><a tabindex="0">Back</a></li>', /** + * Position the back button either at the top or bottom of drilldown submenus. + * @option + * @example bottom + */ + backButtonPosition: 'top', + /** * Markup used to wrap drilldown menu. Use a class name for independent styling; the JS applied class: `is-drilldown` is required. Remove the backslash (`\`) if copy and pasting. * @option * @example '<\div class="is-drilldown"><\/div>' */ wrapper: '<div></div>', @@ -369,10 +441,52 @@ /** * Allow the menu to return to root list on body click. * @option * @example false */ - closeOnClick: false + closeOnClick: false, + /** + * Allow the menu to auto adjust height. + * @option + * @example false + */ + autoHeight: false, + /** + * Animate the auto adjust height. + * @option + * @example false + */ + animateHeight: false, + /** + * Scroll to the top of the menu after opening a submenu or navigating back using the menu back button + * @option + * @example false + */ + scrollTop: false, + /** + * String jquery selector (for example 'body') of element to take offset().top from, if empty string the drilldown menu offset().top is taken + * @option + * @example '' + */ + scrollTopElement: '', + /** + * ScrollTop offset + * @option + * @example 100 + */ + scrollTopOffset: 0, + /** + * Scroll animation duration + * @option + * @example 500 + */ + animationDuration: 500, + /** + * Scroll animation easing + * @option + * @example 'swing' + */ + animationEasing: 'swing' // holdOpen: false }; // Window exports Foundation.plugin(Drilldown, 'Drilldown');