834 lines
		
	
	
		
			29 KiB
		
	
	
	
		
			JavaScript
		
	
	
		
			Executable File
		
	
	
			
		
		
	
	
			834 lines
		
	
	
		
			29 KiB
		
	
	
	
		
			JavaScript
		
	
	
		
			Executable File
		
	
	
| /**
 | |
|  * Copyright © Magento, Inc. All rights reserved.
 | |
|  * See COPYING.txt for license details.
 | |
|  */
 | |
| 
 | |
| define([
 | |
|     'jquery',
 | |
|     'matchMedia',
 | |
|     'jquery-ui-modules/menu',
 | |
|     'mage/translate'
 | |
| ], function ($, mediaCheck) {
 | |
|     'use strict';
 | |
| 
 | |
|     /**
 | |
|      * Menu Widget - this widget is a wrapper for the jQuery UI Menu
 | |
|      */
 | |
|     $.widget('mage.menu', $.ui.menu, {
 | |
|         options: {
 | |
|             responsive: false,
 | |
|             expanded: false,
 | |
|             showDelay: 42,
 | |
|             hideDelay: 300,
 | |
|             delay: 0,
 | |
|             mediaBreakpoint: '(max-width: 768px)'
 | |
|         },
 | |
| 
 | |
|         /**
 | |
|          * @private
 | |
|          */
 | |
|         _create: function () {
 | |
|             var self = this;
 | |
| 
 | |
|             this.delay = this.options.delay;
 | |
| 
 | |
|             this._super();
 | |
|             $(window).on('resize', function () {
 | |
|                 self.element.find('.submenu-reverse').removeClass('submenu-reverse');
 | |
|             });
 | |
|         },
 | |
| 
 | |
|         /**
 | |
|          * @private
 | |
|          */
 | |
|         _init: function () {
 | |
|             this._super();
 | |
| 
 | |
|             if (this.options.expanded === true) {
 | |
|                 this.isExpanded();
 | |
|             }
 | |
| 
 | |
|             if (this.options.responsive === true) {
 | |
|                 mediaCheck({
 | |
|                     media: this.options.mediaBreakpoint,
 | |
|                     entry: $.proxy(function () {
 | |
|                         this._toggleMobileMode();
 | |
|                     }, this),
 | |
|                     exit: $.proxy(function () {
 | |
|                         this._toggleDesktopMode();
 | |
|                     }, this)
 | |
|                 });
 | |
|             }
 | |
| 
 | |
|             this._assignControls()._listen();
 | |
|             this._setActiveMenu();
 | |
|         },
 | |
| 
 | |
|         /**
 | |
|          * @return {Object}
 | |
|          * @private
 | |
|          */
 | |
|         _assignControls: function () {
 | |
|             this.controls = {
 | |
|                 toggleBtn: $('[data-action="toggle-nav"]')
 | |
|             };
 | |
| 
 | |
|             return this;
 | |
|         },
 | |
| 
 | |
|         /**
 | |
|          * @private
 | |
|          */
 | |
|         _listen: function () {
 | |
|             var controls = this.controls,
 | |
|                 toggle = this.toggle;
 | |
| 
 | |
|             controls.toggleBtn.off('click');
 | |
|             controls.toggleBtn.on('click', toggle.bind(this));
 | |
|         },
 | |
| 
 | |
|         /**
 | |
|          * Toggle.
 | |
|          */
 | |
|         toggle: function () {
 | |
|             var html = $('html');
 | |
| 
 | |
|             if (html.hasClass('nav-open')) {
 | |
|                 html.removeClass('nav-open');
 | |
|                 setTimeout(function () {
 | |
|                     html.removeClass('nav-before-open');
 | |
|                 }, this.options.hideDelay);
 | |
|             } else {
 | |
|                 html.addClass('nav-before-open');
 | |
|                 setTimeout(function () {
 | |
|                     html.addClass('nav-open');
 | |
|                 }, this.options.showDelay);
 | |
|             }
 | |
|         },
 | |
| 
 | |
|         /**
 | |
|          * Tries to figure out the active category for current page and add appropriate classes:
 | |
|          *  - 'active' class for active category
 | |
|          *  - 'has-active' class for all parents of active category
 | |
|          *
 | |
|          *  First, checks whether current URL is URL of category page,
 | |
|          *  otherwise tries to retrieve category URL in case of current URL is product view page URL
 | |
|          *  which has category tree path in it.
 | |
|          *
 | |
|          * @return void
 | |
|          * @private
 | |
|          */
 | |
|         _setActiveMenu: function () {
 | |
|             var currentUrl = window.location.href.split('?')[0];
 | |
| 
 | |
|             if (!this._setActiveMenuForCategory(currentUrl)) {
 | |
|                 this._setActiveMenuForProduct(currentUrl);
 | |
|             }
 | |
|         },
 | |
| 
 | |
|         /**
 | |
|          * Looks for category with provided URL and adds 'active' CSS class to it if it was not set before.
 | |
|          * If menu item has parent categories, sets 'has-active' class to all af them.
 | |
|          *
 | |
|          * @param {String} url - possible category URL
 | |
|          * @returns {Boolean} - true if active category was founded by provided URL, otherwise return false
 | |
|          * @private
 | |
|          */
 | |
|         _setActiveMenuForCategory: function (url) {
 | |
|             var activeCategoryLink = this.element.find('a[href="' + url + '"]'),
 | |
|                 classes,
 | |
|                 classNav;
 | |
| 
 | |
|             if (!activeCategoryLink || !activeCategoryLink.hasClass('ui-menu-item-wrapper')) {
 | |
| 
 | |
|                 //category was not found by provided URL
 | |
|                 return false;
 | |
|             } else if (!activeCategoryLink.parent().hasClass('active')) {
 | |
|                 activeCategoryLink.parent().addClass('active');
 | |
|                 classes = activeCategoryLink.parent().attr('class');
 | |
|                 classNav = classes.match(/(nav\-)[0-9]+(\-[0-9]+)+/gi);
 | |
| 
 | |
|                 if (classNav) {
 | |
|                     this._setActiveParent(classNav[0]);
 | |
|                 }
 | |
|             }
 | |
| 
 | |
|             return true;
 | |
|         },
 | |
| 
 | |
|         /**
 | |
|          * Sets 'has-active' CSS class to all parent categories which have part of provided class in childClassName
 | |
|          *
 | |
|          * @example
 | |
|          *  childClassName - 'nav-1-2-3'
 | |
|          *  CSS class 'has-active' will be added to categories have 'nav-1-2' and 'nav-1' classes
 | |
|          *
 | |
|          * @param {String} childClassName - Class name of active category <li> element
 | |
|          * @return void
 | |
|          * @private
 | |
|          */
 | |
|         _setActiveParent: function (childClassName) {
 | |
|             var parentElement,
 | |
|                 parentClass = childClassName.substr(0, childClassName.lastIndexOf('-'));
 | |
| 
 | |
|             if (parentClass.lastIndexOf('-') !== -1) {
 | |
|                 parentElement = this.element.find('.' + parentClass);
 | |
| 
 | |
|                 if (parentElement) {
 | |
|                     parentElement.addClass('has-active');
 | |
|                 }
 | |
|                 this._setActiveParent(parentClass);
 | |
|             }
 | |
|         },
 | |
| 
 | |
|         /**
 | |
|          * Tries to retrieve category URL from current URL and mark this category as active
 | |
|          * @see _setActiveMenuForCategory(url)
 | |
|          *
 | |
|          * @example
 | |
|          *  currentUrl - http://magento.com/category1/category12/product.html,
 | |
|          *  category URLs has extensions .phtml - http://magento.com/category1.phtml
 | |
|          *  method sets active category which has URL http://magento.com/category1/category12.phtml
 | |
|          *
 | |
|          * @param {String} currentUrl - current page URL without parameters
 | |
|          * @return void
 | |
|          * @private
 | |
|          */
 | |
|         _setActiveMenuForProduct: function (currentUrl) {
 | |
|             var categoryUrlExtension,
 | |
|                 lastUrlSection,
 | |
|                 possibleCategoryUrl,
 | |
|                 //retrieve first category URL to know what extension is used for category URLs
 | |
|                 firstCategoryUrl = this.element.find('> li a').attr('href');
 | |
| 
 | |
|             if (firstCategoryUrl) {
 | |
|                 lastUrlSection = firstCategoryUrl.substr(firstCategoryUrl.lastIndexOf('/'));
 | |
|                 categoryUrlExtension = lastUrlSection.lastIndexOf('.') !== -1 ?
 | |
|                     lastUrlSection.substr(lastUrlSection.lastIndexOf('.')) : '';
 | |
| 
 | |
|                 possibleCategoryUrl = currentUrl.substr(0, currentUrl.lastIndexOf('/')) + categoryUrlExtension;
 | |
|                 this._setActiveMenuForCategory(possibleCategoryUrl);
 | |
|             }
 | |
|         },
 | |
| 
 | |
|         /**
 | |
|          * Add class for expanded option.
 | |
|          */
 | |
|         isExpanded: function () {
 | |
|             var subMenus = this.element.find(this.options.menus),
 | |
|                 expandedMenus = subMenus.find(this.options.menus);
 | |
| 
 | |
|             expandedMenus.addClass('expanded');
 | |
|         },
 | |
| 
 | |
|         /**
 | |
|          * @param {jQuery.Event} event
 | |
|          * @private
 | |
|          */
 | |
|         _activate: function (event) {
 | |
|             window.location.href = this.active.find('> a').attr('href');
 | |
|             this.collapseAll(event);
 | |
|         },
 | |
| 
 | |
|         /**
 | |
|          * @param {jQuery.Event} event
 | |
|          * @private
 | |
|          */
 | |
|         _keydown: function (event) {
 | |
|             var match, prev, character, skip, regex,
 | |
|                 preventDefault = true;
 | |
| 
 | |
|             /* eslint-disable max-depth */
 | |
|             /**
 | |
|              * @param {String} value
 | |
|              */
 | |
|             function escape(value) {
 | |
|                 return value.replace(/[\-\[\]{}()*+?.,\\\^$|#\s]/g, '\\$&');
 | |
|             }
 | |
| 
 | |
|             if (this.active.closest(this.options.menus).attr('aria-expanded') != 'true') { //eslint-disable-line eqeqeq
 | |
| 
 | |
|                 switch (event.keyCode) {
 | |
|                     case $.ui.keyCode.PAGE_UP:
 | |
|                         this.previousPage(event);
 | |
|                         break;
 | |
| 
 | |
|                     case $.ui.keyCode.PAGE_DOWN:
 | |
|                         this.nextPage(event);
 | |
|                         break;
 | |
| 
 | |
|                     case $.ui.keyCode.HOME:
 | |
|                         this._move('first', 'first', event);
 | |
|                         break;
 | |
| 
 | |
|                     case $.ui.keyCode.END:
 | |
|                         this._move('last', 'last', event);
 | |
|                         break;
 | |
| 
 | |
|                     case $.ui.keyCode.UP:
 | |
|                         this.previous(event);
 | |
|                         break;
 | |
| 
 | |
|                     case $.ui.keyCode.DOWN:
 | |
|                         if (this.active && !this.active.is('.ui-state-disabled')) {
 | |
|                             this.expand(event);
 | |
|                         }
 | |
|                         break;
 | |
| 
 | |
|                     case $.ui.keyCode.LEFT:
 | |
|                         this.previous(event);
 | |
|                         break;
 | |
| 
 | |
|                     case $.ui.keyCode.RIGHT:
 | |
|                         this.next(event);
 | |
|                         break;
 | |
| 
 | |
|                     case $.ui.keyCode.ENTER:
 | |
|                     case $.ui.keyCode.SPACE:
 | |
|                         this._activate(event);
 | |
|                         break;
 | |
| 
 | |
|                     case $.ui.keyCode.ESCAPE:
 | |
|                         this.collapse(event);
 | |
|                         break;
 | |
|                     default:
 | |
|                         preventDefault = false;
 | |
|                         prev = this.previousFilter || '';
 | |
|                         character = String.fromCharCode(event.keyCode);
 | |
|                         skip = false;
 | |
| 
 | |
|                         clearTimeout(this.filterTimer);
 | |
| 
 | |
|                         if (character === prev) {
 | |
|                             skip = true;
 | |
|                         } else {
 | |
|                             character = prev + character;
 | |
|                         }
 | |
| 
 | |
|                         regex = new RegExp('^' + escape(character), 'i');
 | |
|                         match = this.activeMenu.children('.ui-menu-item').filter(function () {
 | |
|                             return regex.test($(this).children('a').text());
 | |
|                         });
 | |
|                         match = skip && match.index(this.active.next()) !== -1 ?
 | |
|                             this.active.nextAll('.ui-menu-item') :
 | |
|                             match;
 | |
| 
 | |
|                         // If no matches on the current filter, reset to the last character pressed
 | |
|                         // to move down the menu to the first item that starts with that character
 | |
|                         if (!match.length) {
 | |
|                             character = String.fromCharCode(event.keyCode);
 | |
|                             regex = new RegExp('^' + escape(character), 'i');
 | |
|                             match = this.activeMenu.children('.ui-menu-item').filter(function () {
 | |
|                                 return regex.test($(this).children('a').text());
 | |
|                             });
 | |
|                         }
 | |
| 
 | |
|                         if (match.length) {
 | |
|                             this.focus(event, match);
 | |
| 
 | |
|                             if (match.length > 1) {
 | |
|                                 this.previousFilter = character;
 | |
|                                 this.filterTimer = this._delay(function () {
 | |
|                                     delete this.previousFilter;
 | |
|                                 }, 1000);
 | |
|                             } else {
 | |
|                                 delete this.previousFilter;
 | |
|                             }
 | |
|                         } else {
 | |
|                             delete this.previousFilter;
 | |
|                         }
 | |
|                 }
 | |
|             } else {
 | |
|                 switch (event.keyCode) {
 | |
|                     case $.ui.keyCode.DOWN:
 | |
|                         this.next(event);
 | |
|                         break;
 | |
| 
 | |
|                     case $.ui.keyCode.UP:
 | |
|                         this.previous(event);
 | |
|                         break;
 | |
| 
 | |
|                     case $.ui.keyCode.RIGHT:
 | |
|                         if (this.active && !this.active.is('.ui-state-disabled')) {
 | |
|                             this.expand(event);
 | |
|                         }
 | |
|                         break;
 | |
| 
 | |
|                     case $.ui.keyCode.ENTER:
 | |
|                     case $.ui.keyCode.SPACE:
 | |
|                         this._activate(event);
 | |
|                         break;
 | |
| 
 | |
|                     case $.ui.keyCode.LEFT:
 | |
|                     case $.ui.keyCode.ESCAPE:
 | |
|                         this.collapse(event);
 | |
|                         break;
 | |
|                     default:
 | |
|                         preventDefault = false;
 | |
|                         prev = this.previousFilter || '';
 | |
|                         character = String.fromCharCode(event.keyCode);
 | |
|                         skip = false;
 | |
| 
 | |
|                         clearTimeout(this.filterTimer);
 | |
| 
 | |
|                         if (character === prev) {
 | |
|                             skip = true;
 | |
|                         } else {
 | |
|                             character = prev + character;
 | |
|                         }
 | |
| 
 | |
|                         regex = new RegExp('^' + escape(character), 'i');
 | |
|                         match = this.activeMenu.children('.ui-menu-item').filter(function () {
 | |
|                             return regex.test($(this).children('a').text());
 | |
|                         });
 | |
|                         match = skip && match.index(this.active.next()) !== -1 ?
 | |
|                             this.active.nextAll('.ui-menu-item') :
 | |
|                             match;
 | |
| 
 | |
|                         // If no matches on the current filter, reset to the last character pressed
 | |
|                         // to move down the menu to the first item that starts with that character
 | |
|                         if (!match.length) {
 | |
|                             character = String.fromCharCode(event.keyCode);
 | |
|                             regex = new RegExp('^' + escape(character), 'i');
 | |
|                             match = this.activeMenu.children('.ui-menu-item').filter(function () {
 | |
|                                 return regex.test($(this).children('a').text());
 | |
|                             });
 | |
|                         }
 | |
| 
 | |
|                         if (match.length) {
 | |
|                             this.focus(event, match);
 | |
| 
 | |
|                             if (match.length > 1) {
 | |
|                                 this.previousFilter = character;
 | |
|                                 this.filterTimer = this._delay(function () {
 | |
|                                     delete this.previousFilter;
 | |
|                                 }, 1000);
 | |
|                             } else {
 | |
|                                 delete this.previousFilter;
 | |
|                             }
 | |
|                         } else {
 | |
|                             delete this.previousFilter;
 | |
|                         }
 | |
|                 }
 | |
|             }
 | |
| 
 | |
|             /* eslint-enable max-depth */
 | |
|             if (preventDefault) {
 | |
|                 event.preventDefault();
 | |
|             }
 | |
|         },
 | |
| 
 | |
|         /**
 | |
|          * @private
 | |
|          */
 | |
|         _toggleMobileMode: function () {
 | |
|             var subMenus;
 | |
| 
 | |
|             $(this.element).off('mouseenter mouseleave');
 | |
|             this._on({
 | |
| 
 | |
|                 /**
 | |
|                  * @param {jQuery.Event} event
 | |
|                  */
 | |
|                 'click .ui-menu-item:has(a)': function (event) {
 | |
|                     var target;
 | |
| 
 | |
|                     event.preventDefault();
 | |
|                     target = $(event.target).closest('.ui-menu-item');
 | |
|                     target.get(0).scrollIntoView();
 | |
| 
 | |
|                     // Open submenu on click
 | |
|                     if (target.has('.ui-menu').length) {
 | |
|                         this.expand(event);
 | |
|                     } else if (!this.element.is(':focus') &&
 | |
|                         $(this.document[0].activeElement).closest('.ui-menu').length
 | |
|                     ) {
 | |
|                         // Redirect focus to the menu
 | |
|                         this.element.trigger('focus', [true]);
 | |
| 
 | |
|                         // If the active item is on the top level, let it stay active.
 | |
|                         // Otherwise, blur the active item since it is no longer visible.
 | |
|                         if (this.active && this.active.parents('.ui-menu').length === 1) { //eslint-disable-line
 | |
|                             clearTimeout(this.timer);
 | |
|                         }
 | |
|                     }
 | |
| 
 | |
|                     if (!target.hasClass('level-top') || !target.has('.ui-menu').length) {
 | |
|                         window.location.href = target.find('> a').attr('href');
 | |
|                     }
 | |
|                 },
 | |
| 
 | |
|                 /**
 | |
|                  * @param {jQuery.Event} event
 | |
|                  */
 | |
|                 'click .ui-menu-item:has(.ui-state-active)': function (event) {
 | |
|                     this.collapseAll(event, true);
 | |
|                 }
 | |
|             });
 | |
| 
 | |
|             subMenus = this.element.find('.level-top');
 | |
|             $.each(subMenus, $.proxy(function (index, item) {
 | |
|                 var category = $(item).find('> a span').not('.ui-menu-icon').text(),
 | |
|                     categoryUrl = $(item).find('> a').attr('href'),
 | |
|                     menu = $(item).find('> .ui-menu');
 | |
| 
 | |
|                 this.categoryLink = $('<a>')
 | |
|                     .attr('href', categoryUrl)
 | |
|                     .text($.mage.__('All %1').replace('%1', category));
 | |
| 
 | |
|                 this.categoryParent = $('<li>')
 | |
|                     .addClass('ui-menu-item all-category')
 | |
|                     .html(this.categoryLink);
 | |
| 
 | |
|                 if (menu.find('.all-category').length === 0) {
 | |
|                     menu.prepend(this.categoryParent);
 | |
|                 }
 | |
| 
 | |
|             }, this));
 | |
|         },
 | |
| 
 | |
|         /**
 | |
|          * @private
 | |
|          */
 | |
|         _toggleDesktopMode: function () {
 | |
|             var categoryParent, html;
 | |
| 
 | |
|             $(this.element).off('click mousedown mouseenter mouseleave');
 | |
|             this._on({
 | |
| 
 | |
|                 /**
 | |
|                  * Prevent focus from sticking to links inside menu after clicking
 | |
|                  * them (focus should always stay on UL during navigation).
 | |
|                  */
 | |
|                 'mousedown .ui-menu-item > a': function (event) {
 | |
|                     event.preventDefault();
 | |
|                 },
 | |
| 
 | |
|                 /**
 | |
|                  * Prevent focus from sticking to links inside menu after clicking
 | |
|                  * them (focus should always stay on UL during navigation).
 | |
|                  */
 | |
|                 'click .ui-state-disabled > a': function (event) {
 | |
|                     event.preventDefault();
 | |
|                 },
 | |
| 
 | |
|                 /**
 | |
|                  * @param {jQuer.Event} event
 | |
|                  */
 | |
|                 'click .ui-menu-item:has(a)': function (event) {
 | |
|                     var target = $(event.target).closest('.ui-menu-item');
 | |
| 
 | |
|                     if (!this.mouseHandled && target.not('.ui-state-disabled').length) {
 | |
|                         this.select(event);
 | |
| 
 | |
|                         // Only set the mouseHandled flag if the event will bubble, see #9469.
 | |
|                         if (!event.isPropagationStopped()) {
 | |
|                             this.mouseHandled = true;
 | |
|                         }
 | |
| 
 | |
|                         // Open submenu on click
 | |
|                         if (target.has('.ui-menu').length) {
 | |
|                             this.expand(event);
 | |
|                         } else if (!this.element.is(':focus') &&
 | |
|                             $(this.document[0].activeElement).closest('.ui-menu').length
 | |
|                         ) {
 | |
|                             // Redirect focus to the menu
 | |
|                             this.element.trigger('focus', [true]);
 | |
| 
 | |
|                             // If the active item is on the top level, let it stay active.
 | |
|                             // Otherwise, blur the active item since it is no longer visible.
 | |
|                             if (this.active && this.active.parents('.ui-menu').length === 1) { //eslint-disable-line
 | |
|                                 clearTimeout(this.timer);
 | |
|                             }
 | |
|                         }
 | |
|                     }
 | |
|                 },
 | |
| 
 | |
|                 /**
 | |
|                  * @param {jQuery.Event} event
 | |
|                  */
 | |
|                 'mouseenter .ui-menu-item': function (event) {
 | |
|                     var target = $(event.currentTarget),
 | |
|                         submenu = this.options.menus,
 | |
|                         ulElement,
 | |
|                         ulElementWidth,
 | |
|                         width,
 | |
|                         targetPageX,
 | |
|                         rightBound;
 | |
| 
 | |
|                     if (target.has(submenu)) {
 | |
|                         ulElement = target.find(submenu);
 | |
|                         ulElementWidth = ulElement.outerWidth(true);
 | |
|                         width = target.outerWidth() * 2;
 | |
|                         targetPageX = target.offset().left;
 | |
|                         rightBound = $(window).width();
 | |
| 
 | |
|                         if (ulElementWidth + width + targetPageX > rightBound) {
 | |
|                             ulElement.addClass('submenu-reverse');
 | |
|                         }
 | |
| 
 | |
|                         if (targetPageX - ulElementWidth < 0) {
 | |
|                             ulElement.removeClass('submenu-reverse');
 | |
|                         }
 | |
|                     }
 | |
| 
 | |
|                     // Remove ui-state-active class from siblings of the newly focused menu item
 | |
|                     // to avoid a jump caused by adjacent elements both having a class with a border
 | |
|                     target.siblings().children('.ui-state-active').removeClass('ui-state-active');
 | |
|                     this.focus(event, target);
 | |
|                 },
 | |
| 
 | |
|                 /**
 | |
|                  * @param {jQuery.Event} event
 | |
|                  */
 | |
|                 'mouseleave': function (event) {
 | |
|                     this.collapseAll(event, true);
 | |
|                 },
 | |
| 
 | |
|                 /**
 | |
|                  * Mouse leave.
 | |
|                  */
 | |
|                 'mouseleave .ui-menu': 'collapseAll'
 | |
|             });
 | |
| 
 | |
|             categoryParent = this.element.find('.all-category');
 | |
|             html = $('html');
 | |
| 
 | |
|             categoryParent.remove();
 | |
| 
 | |
|             if (html.hasClass('nav-open')) {
 | |
|                 html.removeClass('nav-open');
 | |
|                 setTimeout(function () {
 | |
|                     html.removeClass('nav-before-open');
 | |
|                 }, this.options.hideDelay);
 | |
|             }
 | |
|         },
 | |
| 
 | |
|         /**
 | |
|          * @param {*} handler
 | |
|          * @param {Number} delay
 | |
|          * @return {Number}
 | |
|          * @private
 | |
|          */
 | |
|         _delay: function (handler, delay) {
 | |
|             var instance = this,
 | |
| 
 | |
|                 /**
 | |
|                  * @return {*}
 | |
|                  */
 | |
|                 handlerProxy = function () {
 | |
|                     return (typeof handler === 'string' ? instance[handler] : handler).apply(instance, arguments);
 | |
|                 };
 | |
| 
 | |
|             return setTimeout(handlerProxy, delay || 0);
 | |
|         },
 | |
| 
 | |
|         /**
 | |
|          * @param {jQuery.Event} event
 | |
|          */
 | |
|         expand: function (event) {
 | |
|             var newItem = this.active &&
 | |
|                 this.active
 | |
|                     .children('.ui-menu')
 | |
|                     .children('.ui-menu-item')
 | |
|                     .first();
 | |
| 
 | |
|             if (newItem && newItem.length) {
 | |
|                 if (newItem.closest('.ui-menu').is(':visible') &&
 | |
|                     newItem.closest('.ui-menu').has('.all-categories')
 | |
|                 ) {
 | |
|                     return;
 | |
|                 }
 | |
| 
 | |
|                 // remove the active state class from the siblings
 | |
|                 this.active.siblings().children('.ui-state-active').removeClass('ui-state-active');
 | |
| 
 | |
|                 this._open(newItem.parent());
 | |
| 
 | |
|                 // Delay so Firefox will not hide activedescendant change in expanding submenu from AT
 | |
|                 this._delay(function () {
 | |
|                     this.focus(event, newItem);
 | |
|                 });
 | |
|             }
 | |
|         },
 | |
| 
 | |
|         /**
 | |
|          * @param {jQuery.Event} event
 | |
|          */
 | |
|         select: function (event) {
 | |
|             var ui;
 | |
| 
 | |
|             this.active = this.active || $(event.target).closest('.ui-menu-item');
 | |
| 
 | |
|             if (this.active.is('.all-category')) {
 | |
|                 this.active = $(event.target).closest('.ui-menu-item');
 | |
|             }
 | |
|             ui = {
 | |
|                 item: this.active
 | |
|             };
 | |
| 
 | |
|             if (!this.active.has('.ui-menu').length) {
 | |
|                 this.collapseAll(event, true);
 | |
|             }
 | |
|             this._trigger('select', event, ui);
 | |
|         }
 | |
|     });
 | |
| 
 | |
|     $.widget('mage.navigation', $.mage.menu, {
 | |
|         options: {
 | |
|             responsiveAction: 'wrap', //option for responsive handling
 | |
|             maxItems: null, //option to set max number of menu items
 | |
|             container: '#menu', //container to check against navigation length
 | |
|             moreText: $.mage.__('more'),
 | |
|             breakpoint: 768
 | |
|         },
 | |
| 
 | |
|         /**
 | |
|          * @private
 | |
|          */
 | |
|         _init: function () {
 | |
|             var that, responsive;
 | |
| 
 | |
|             this._super();
 | |
| 
 | |
|             that = this;
 | |
|             responsive = this.options.responsiveAction;
 | |
| 
 | |
|             this.element
 | |
|                 .addClass('ui-menu-responsive')
 | |
|                 .attr('responsive', 'main');
 | |
| 
 | |
|             this.setupMoreMenu();
 | |
|             this.setMaxItems();
 | |
| 
 | |
|             //check responsive option
 | |
|             if (responsive == 'onResize') { //eslint-disable-line eqeqeq
 | |
|                 $(window).on('resize', function () {
 | |
|                     if ($(window).width() > that.options.breakpoint) {
 | |
|                         that._responsive();
 | |
|                         $('[responsive=more]').show();
 | |
|                     } else {
 | |
|                         that.element.children().show();
 | |
|                         $('[responsive=more]').hide();
 | |
|                     }
 | |
|                 });
 | |
|             } else if (responsive == 'onReload') { //eslint-disable-line eqeqeq
 | |
|                 this._responsive();
 | |
|             }
 | |
|         },
 | |
| 
 | |
|         /**
 | |
|          * Setup more menu.
 | |
|          */
 | |
|         setupMoreMenu: function () {
 | |
|             var moreListItems = this.element.children().clone(),
 | |
|                 moreLink = $('<a>' + this.options.moreText + '</a>');
 | |
| 
 | |
|             moreListItems.hide();
 | |
| 
 | |
|             moreLink.attr('href', '#');
 | |
| 
 | |
|             this.moreItemsList = $('<ul>')
 | |
|                 .append(moreListItems);
 | |
| 
 | |
|             this.moreListContainer = $('<li>')
 | |
|                 .append(moreLink)
 | |
|                 .append(this.moreItemsList);
 | |
| 
 | |
|             this.responsiveMenu = $('<ul>')
 | |
|                 .addClass('ui-menu-more')
 | |
|                 .attr('responsive', 'more')
 | |
|                 .append(this.moreListContainer)
 | |
|                 .menu({
 | |
|                     position: {
 | |
|                         my: 'right top',
 | |
|                         at: 'right bottom'
 | |
|                     }
 | |
|                 })
 | |
|                 .insertAfter(this.element);
 | |
|         },
 | |
| 
 | |
|         /**
 | |
|          * @private
 | |
|          */
 | |
|         _responsive: function () {
 | |
|             var container = $(this.options.container),
 | |
|                 containerSize = container.width(),
 | |
|                 width = 0,
 | |
|                 items = this.element.children('li'),
 | |
|                 more = $('.ui-menu-more > li > ul > li a');
 | |
| 
 | |
|             items = items.map(function () {
 | |
|                 var item = {};
 | |
| 
 | |
|                 item.item = $(this);
 | |
|                 item.itemSize = $(this).outerWidth();
 | |
| 
 | |
|                 return item;
 | |
|             });
 | |
| 
 | |
|             $.each(items, function (index) {
 | |
|                 var itemText = items[index].item
 | |
|                     .find('a:first')
 | |
|                     .text();
 | |
| 
 | |
|                 width += parseInt(items[index].itemSize, null); //eslint-disable-line radix
 | |
| 
 | |
|                 if (width < containerSize) {
 | |
|                     items[index].item.show();
 | |
| 
 | |
|                     more.each(function () {
 | |
|                         var text = $(this).text();
 | |
| 
 | |
|                         if (text === itemText) {
 | |
|                             $(this).parent().hide();
 | |
|                         }
 | |
|                     });
 | |
|                 } else if (width > containerSize) {
 | |
|                     items[index].item.hide();
 | |
| 
 | |
|                     more.each(function () {
 | |
|                         var text = $(this).text();
 | |
| 
 | |
|                         if (text === itemText) {
 | |
|                             $(this).parent().show();
 | |
|                         }
 | |
|                     });
 | |
|                 }
 | |
|             });
 | |
|         },
 | |
| 
 | |
|         /**
 | |
|          * Set max items.
 | |
|          */
 | |
|         setMaxItems: function () {
 | |
|             var items = this.element.children('li'),
 | |
|                 itemsCount = items.length,
 | |
|                 maxItems = this.options.maxItems,
 | |
|                 overflow = itemsCount - maxItems,
 | |
|                 overflowItems = items.slice(overflow);
 | |
| 
 | |
|             overflowItems.hide();
 | |
| 
 | |
|             overflowItems.each(function () {
 | |
|                 var itemText = $(this).find('a:first').text();
 | |
| 
 | |
|                 $(this).hide();
 | |
| 
 | |
|                 $('.ui-menu-more > li > ul > li a').each(function () {
 | |
|                     var text = $(this).text();
 | |
| 
 | |
|                     if (text === itemText) {
 | |
|                         $(this).parent().show();
 | |
|                     }
 | |
|                 });
 | |
|             });
 | |
|         }
 | |
|     });
 | |
| 
 | |
|     return {
 | |
|         menu: $.mage.menu,
 | |
|         navigation: $.mage.navigation
 | |
|     };
 | |
| });
 |