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