2016-08-15 4 views
-4

Я использую плагин, который использует этот блок инструкций для отображения меню. Теперь я использую его в угловых js.Как преобразовать функцию javascript в угловой js?

(function(window) { 
 

 
\t 'use strict'; 
 

 
\t var support = { animations : Modernizr.cssanimations }, 
 
\t \t animEndEventNames = { 'WebkitAnimation' : 'webkitAnimationEnd', 'OAnimation' : 'oAnimationEnd', 'msAnimation' : 'MSAnimationEnd', 'animation' : 'animationend' }, 
 
\t \t animEndEventName = animEndEventNames[ Modernizr.prefixed('animation') ], 
 
\t \t onEndAnimation = function(el, callback) { 
 
\t \t \t var onEndCallbackFn = function(ev) { 
 
\t \t \t \t if(support.animations) { 
 
\t \t \t \t \t if(ev.target != this) return; 
 
\t \t \t \t \t this.removeEventListener(animEndEventName, onEndCallbackFn); 
 
\t \t \t \t } 
 
\t \t \t \t if(callback && typeof callback === 'function') { callback.call(); } 
 
\t \t \t }; 
 
\t \t \t if(support.animations) { 
 
\t \t \t \t el.addEventListener(animEndEventName, onEndCallbackFn); 
 
\t \t \t } 
 
\t \t \t else { 
 
\t \t \t \t onEndCallbackFn(); 
 
\t \t \t } 
 
\t \t }; 
 

 
\t function extend(a, b) { 
 
\t \t for(var key in b) { 
 
\t \t \t if(b.hasOwnProperty(key)) { 
 
\t \t \t \t a[key] = b[key]; 
 
\t \t \t } 
 
\t \t } 
 
\t \t return a; 
 
\t } 
 

 
\t function MLMenu(el, options) { 
 
\t \t this.el = el; 
 
\t \t this.options = extend({}, this.options); 
 
\t \t extend(this.options, options); 
 
\t \t 
 
\t \t // the menus (<ul>´s) 
 
\t \t this.menus = [].slice.call(this.el.querySelectorAll('.menu__level')); 
 
\t \t // index of current menu 
 
\t \t this.current = 0; 
 

 
\t \t this._init(); 
 
\t } 
 

 
\t MLMenu.prototype.options = { 
 
\t \t // show breadcrumbs 
 
\t \t breadcrumbsCtrl : true, 
 
\t \t // initial breadcrumb text 
 
\t \t initialBreadcrumb : 'all', 
 
\t \t // show back button 
 
\t \t backCtrl : true, 
 
\t \t // delay between each menu item sliding animation 
 
\t \t itemsDelayInterval : 60, 
 
\t \t // direction 
 
\t \t direction : 'r2l', 
 
\t \t // callback: item that doesn´t have a submenu gets clicked 
 
\t \t // onItemClick([event], [inner HTML of the clicked item]) 
 
\t \t onItemClick : function(ev, itemName) { return false; } 
 
\t }; 
 

 
\t MLMenu.prototype._init = function() { 
 
\t \t // iterate the existing menus and create an array of menus, more specifically an array of objects where each one holds the info of each menu element and its menu items 
 
\t \t this.menusArr = []; 
 
\t \t var self = this; 
 
\t \t this.menus.forEach(function(menuEl, pos) { 
 
\t \t \t var menu = {menuEl : menuEl, menuItems : [].slice.call(menuEl.querySelectorAll('.menu__item'))}; 
 
\t \t \t self.menusArr.push(menu); 
 

 
\t \t \t // set current menu class 
 
\t \t \t if(pos === self.current) { 
 
\t \t \t \t classie.add(menuEl, 'menu__level--current'); 
 
\t \t \t } 
 
\t \t }); 
 

 
\t \t // create back button 
 
\t \t if(this.options.backCtrl) { 
 
\t \t \t this.backCtrl = document.createElement('button'); 
 
\t \t \t this.backCtrl.className = 'menu__back menu__back--hidden'; 
 
\t \t \t this.backCtrl.setAttribute('aria-label', 'Go back'); 
 
\t \t \t this.backCtrl.innerHTML = '<span class="icon icon--arrow-left"></span>'; 
 
\t \t \t this.el.insertBefore(this.backCtrl, this.el.firstChild); 
 
\t \t } 
 
\t \t 
 
\t \t 
 
\t \t // create breadcrumbs 
 
\t \t if(self.options.breadcrumbsCtrl) { 
 
\t \t \t this.breadcrumbsCtrl = document.createElement('nav'); 
 
\t \t \t this.breadcrumbsCtrl.className = 'menu__breadcrumbs'; 
 
\t \t \t this.el.insertBefore(this.breadcrumbsCtrl, this.el.firstChild); 
 
\t \t \t // add initial breadcrumb 
 
\t \t \t this._addBreadcrumb(0); 
 
\t \t } 
 

 
\t \t // event binding 
 
\t \t this._initEvents(); 
 
\t }; 
 

 
\t MLMenu.prototype._initEvents = function() { 
 
\t \t var self = this; 
 

 
\t \t for(var i = 0, len = this.menusArr.length; i < len; ++i) { 
 
\t \t \t this.menusArr[i].menuItems.forEach(function(item, pos) { 
 
\t \t \t \t item.querySelector('a').addEventListener('click', function(ev) { 
 
\t \t \t \t \t var submenu = ev.target.getAttribute('data-submenu'), 
 
\t \t \t \t \t \t itemName = ev.target.innerHTML, 
 
\t \t \t \t \t \t subMenuEl = self.el.querySelector('ul[data-menu="' + submenu + '"]'); 
 

 
\t \t \t \t \t // check if there's a sub menu for this item 
 
\t \t \t \t \t if(submenu && subMenuEl) { 
 
\t \t \t \t \t \t ev.preventDefault(); 
 
\t \t \t \t \t \t // open it 
 
\t \t \t \t \t \t self._openSubMenu(subMenuEl, pos, itemName); 
 
\t \t \t \t \t } 
 
\t \t \t \t \t else { 
 
\t \t \t \t \t \t // add class current 
 
\t \t \t \t \t \t var currentlink = self.el.querySelector('.menu__link--current'); 
 
\t \t \t \t \t \t if(currentlink) { 
 
\t \t \t \t \t \t \t classie.remove(self.el.querySelector('.menu__link--current'), 'menu__link--current'); 
 
\t \t \t \t \t \t } 
 
\t \t \t \t \t \t classie.add(ev.target, 'menu__link--current'); 
 
\t \t \t \t \t \t 
 
\t \t \t \t \t \t // callback 
 
\t \t \t \t \t \t self.options.onItemClick(ev, itemName); 
 
\t \t \t \t \t } 
 
\t \t \t \t }); 
 
\t \t \t }); 
 
\t \t } 
 
\t \t 
 
\t \t // back navigation 
 
\t \t if(this.options.backCtrl) { 
 
\t \t \t this.backCtrl.addEventListener('click', function() { 
 
\t \t \t \t self._back(); 
 
\t \t \t }); 
 
\t \t } 
 
\t }; 
 

 
\t MLMenu.prototype._openSubMenu = function(subMenuEl, clickPosition, subMenuName) { 
 
\t \t if(this.isAnimating) { 
 
\t \t \t return false; 
 
\t \t } 
 
\t \t this.isAnimating = true; 
 
\t \t 
 
\t \t // save "parent" menu index for back navigation 
 
\t \t this.menusArr[this.menus.indexOf(subMenuEl)].backIdx = this.current; 
 
\t \t // save "parent" menu´s name 
 
\t \t this.menusArr[this.menus.indexOf(subMenuEl)].name = subMenuName; 
 
\t \t // current menu slides out 
 
\t \t this._menuOut(clickPosition); 
 
\t \t // next menu (submenu) slides in 
 
\t \t this._menuIn(subMenuEl, clickPosition); 
 
\t }; 
 

 
\t MLMenu.prototype._back = function() { 
 
\t \t if(this.isAnimating) { 
 
\t \t \t return false; 
 
\t \t } 
 
\t \t this.isAnimating = true; 
 

 
\t \t // current menu slides out 
 
\t \t this._menuOut(); 
 
\t \t // next menu (previous menu) slides in 
 
\t \t var backMenu = this.menusArr[this.menusArr[this.current].backIdx].menuEl; 
 
\t \t this._menuIn(backMenu); 
 

 
\t \t // remove last breadcrumb 
 
\t \t if(this.options.breadcrumbsCtrl) { 
 
\t \t \t this.breadcrumbsCtrl.removeChild(this.breadcrumbsCtrl.lastElementChild); 
 
\t \t } 
 
\t }; 
 

 
\t MLMenu.prototype._menuOut = function(clickPosition) { 
 
\t \t // the current menu 
 
\t \t var self = this, 
 
\t \t \t currentMenu = this.menusArr[this.current].menuEl, 
 
\t \t \t isBackNavigation = typeof clickPosition == 'undefined' ? true : false; 
 

 
\t \t // slide out current menu items - first, set the delays for the items 
 
\t \t this.menusArr[this.current].menuItems.forEach(function(item, pos) { 
 
\t \t \t item.style.WebkitAnimationDelay = item.style.animationDelay = isBackNavigation ? parseInt(pos * self.options.itemsDelayInterval) + 'ms' : parseInt(Math.abs(clickPosition - pos) * self.options.itemsDelayInterval) + 'ms'; 
 
\t \t }); 
 
\t \t // animation class 
 
\t \t if(this.options.direction === 'r2l') { 
 
\t \t \t classie.add(currentMenu, !isBackNavigation ? 'animate-outToLeft' : 'animate-outToRight'); 
 
\t \t } 
 
\t \t else { 
 
\t \t \t classie.add(currentMenu, isBackNavigation ? 'animate-outToLeft' : 'animate-outToRight'); \t 
 
\t \t } 
 
\t }; 
 

 
\t MLMenu.prototype._menuIn = function(nextMenuEl, clickPosition) { 
 
\t \t var self = this, 
 
\t \t \t // the current menu 
 
\t \t \t currentMenu = this.menusArr[this.current].menuEl, 
 
\t \t \t isBackNavigation = typeof clickPosition == 'undefined' ? true : false, 
 
\t \t \t // index of the nextMenuEl 
 
\t \t \t nextMenuIdx = this.menus.indexOf(nextMenuEl), 
 

 
\t \t \t nextMenuItems = this.menusArr[nextMenuIdx].menuItems, 
 
\t \t \t nextMenuItemsTotal = nextMenuItems.length; 
 

 
\t \t // slide in next menu items - first, set the delays for the items 
 
\t \t nextMenuItems.forEach(function(item, pos) { 
 
\t \t \t item.style.WebkitAnimationDelay = item.style.animationDelay = isBackNavigation ? parseInt(pos * self.options.itemsDelayInterval) + 'ms' : parseInt(Math.abs(clickPosition - pos) * self.options.itemsDelayInterval) + 'ms'; 
 

 
\t \t \t // we need to reset the classes once the last item animates in 
 
\t \t \t // the "last item" is the farthest from the clicked item 
 
\t \t \t // let's calculate the index of the farthest item 
 
\t \t \t var farthestIdx = clickPosition <= nextMenuItemsTotal/2 || isBackNavigation ? nextMenuItemsTotal - 1 : 0; 
 

 
\t \t \t if(pos === farthestIdx) { 
 
\t \t \t \t onEndAnimation(item, function() { 
 
\t \t \t \t \t // reset classes 
 
\t \t \t \t \t if(self.options.direction === 'r2l') { 
 
\t \t \t \t \t \t classie.remove(currentMenu, !isBackNavigation ? 'animate-outToLeft' : 'animate-outToRight'); 
 
\t \t \t \t \t \t classie.remove(nextMenuEl, !isBackNavigation ? 'animate-inFromRight' : 'animate-inFromLeft'); 
 
\t \t \t \t \t } 
 
\t \t \t \t \t else { 
 
\t \t \t \t \t \t classie.remove(currentMenu, isBackNavigation ? 'animate-outToLeft' : 'animate-outToRight'); 
 
\t \t \t \t \t \t classie.remove(nextMenuEl, isBackNavigation ? 'animate-inFromRight' : 'animate-inFromLeft'); 
 
\t \t \t \t \t } 
 
\t \t \t \t \t classie.remove(currentMenu, 'menu__level--current'); 
 
\t \t \t \t \t classie.add(nextMenuEl, 'menu__level--current'); 
 

 
\t \t \t \t \t //reset current 
 
\t \t \t \t \t self.current = nextMenuIdx; 
 

 
\t \t \t \t \t // control back button and breadcrumbs navigation elements 
 
\t \t \t \t \t if(!isBackNavigation) { 
 
\t \t \t \t \t \t // show back button 
 
\t \t \t \t \t \t if(self.options.backCtrl) { 
 
\t \t \t \t \t \t \t classie.remove(self.backCtrl, 'menu__back--hidden'); 
 
\t \t \t \t \t \t } 
 
\t \t \t \t \t \t 
 
\t \t \t \t \t \t // add breadcrumb 
 
\t \t \t \t \t \t self._addBreadcrumb(nextMenuIdx); 
 
\t \t \t \t \t } 
 
\t \t \t \t \t else if(self.current === 0 && self.options.backCtrl) { 
 
\t \t \t \t \t \t // hide back button 
 
\t \t \t \t \t \t classie.add(self.backCtrl, 'menu__back--hidden'); 
 
\t \t \t \t \t } 
 

 
\t \t \t \t \t // we can navigate again.. 
 
\t \t \t \t \t self.isAnimating = false; 
 
\t \t \t \t }); 
 
\t \t \t } 
 
\t \t }); \t 
 
\t \t 
 
\t \t // animation class 
 
\t \t if(this.options.direction === 'r2l') { 
 
\t \t \t classie.add(nextMenuEl, !isBackNavigation ? 'animate-inFromRight' : 'animate-inFromLeft'); 
 
\t \t } 
 
\t \t else { 
 
\t \t \t classie.add(nextMenuEl, isBackNavigation ? 'animate-inFromRight' : 'animate-inFromLeft'); 
 
\t \t } 
 
\t }; 
 

 
\t MLMenu.prototype._addBreadcrumb = function(idx) { 
 
\t \t if(!this.options.breadcrumbsCtrl) { 
 
\t \t \t return false; 
 
\t \t } 
 

 
\t \t var bc = document.createElement('a'); 
 
\t \t bc.innerHTML = idx ? this.menusArr[idx].name : this.options.initialBreadcrumb; 
 
\t \t this.breadcrumbsCtrl.appendChild(bc); 
 

 
\t \t var self = this; 
 
\t \t bc.addEventListener('click', function(ev) { 
 
\t \t \t ev.preventDefault(); 
 

 
\t \t \t // do nothing if this breadcrumb is the last one in the list of breadcrumbs 
 
\t \t \t if(!bc.nextSibling || self.isAnimating) { 
 
\t \t \t \t return false; 
 
\t \t \t } 
 
\t \t \t self.isAnimating = true; 
 
\t \t \t 
 
\t \t \t // current menu slides out 
 
\t \t \t self._menuOut(); 
 
\t \t \t // next menu slides in 
 
\t \t \t var nextMenu = self.menusArr[idx].menuEl; 
 
\t \t \t self._menuIn(nextMenu); 
 

 
\t \t \t // remove breadcrumbs that are ahead 
 
\t \t \t var siblingNode; 
 
\t \t \t while (siblingNode = bc.nextSibling) { 
 
\t \t \t \t self.breadcrumbsCtrl.removeChild(siblingNode); 
 
\t \t \t } 
 
\t \t }); 
 
\t }; 
 

 
\t window.MLMenu = MLMenu; 
 

 
})(window);

и настроить Java Script:

(function() { 
 
\t  var menuEl = document.getElementById('ml-menu'); 
 
\t \t \t mlmenu = new MLMenu(menuEl, { 
 
\t \t \t \t // breadcrumbsCtrl : true, // show breadcrumbs 
 
\t \t \t \t // initialBreadcrumb : 'all', // initial breadcrumb text 
 
\t \t \t \t backCtrl : false, // show back button 
 
\t \t \t \t // itemsDelayInterval : 60, // delay between each menu item sliding animation 
 
\t \t \t \t onItemClick: loadDummyData // callback: item that doesn´t have a submenu gets clicked - onItemClick([event], [inner HTML of the clicked item]) 
 
\t \t \t }); 
 

 
\t \t //mobile menu toggle 
 
\t \t var openMenuCtrl = document.querySelector('.action--open'), 
 
\t \t \t closeMenuCtrl = document.querySelector('.action--close'); 
 

 
\t \t openMenuCtrl.addEventListener('click', openMenu); 
 
\t \t closeMenuCtrl.addEventListener('click', closeMenu); 
 

 
\t \t function openMenu() { 
 
\t \t \t classie.add(menuEl, 'menu--open'); 
 
\t \t } 
 

 
\t \t function closeMenu() { 
 
\t \t \t classie.remove(menuEl, 'menu--open'); 
 
\t \t } 
 

 
\t \t // simulate grid content loading 
 
\t \t var gridWrapper = document.querySelector('.content'); 
 

 
\t \t function loadDummyData(ev, itemName) { 
 
\t \t \t ev.preventDefault(); 
 

 
\t \t \t closeMenu(); 
 
\t \t \t gridWrapper.innerHTML = ''; 
 
\t \t \t classie.add(gridWrapper, 'content--loading'); 
 
\t \t \t setTimeout(function() { 
 
\t \t \t \t classie.remove(gridWrapper, 'content--loading'); 
 
\t \t \t \t gridWrapper.innerHTML = '<ul class="products">' + dummyData[itemName] + '<ul>'; 
 
\t \t \t }, 700); 
 
\t \t } 
 
\t })();

Я хочу, чтобы преобразовать часть этого ниже заказной сценарий для угловых JS.

mlmenu = new MLMenu(menuEl, { 
 
\t \t \t \t // breadcrumbsCtrl : true, // show breadcrumbs 
 
\t \t \t \t // initialBreadcrumb : 'all', // initial breadcrumb text 
 
\t \t \t \t backCtrl : false, // show back button 
 
\t \t \t \t // itemsDelayInterval : 60, // delay between each menu item sliding animation 
 
\t \t \t \t onItemClick: loadDummyData // callback: item that doesn´t have a submenu gets clicked - onItemClick([event], [inner HTML of the clicked item]) 
 
\t \t \t });

Я использую его, как это в угловой, но у него есть ошибки.

$scope.menuEl = document.getElementById('ml-menu'); 
 
    var menuEl = document.getElementById('ml-menu'), 
 
    mlmenu = new MLMenu(menuEl, { 
 
       
 
       // breadcrumbsCtrl : true, // show breadcrumbs 
 
       // initialBreadcrumb : 'all', // initial breadcrumb text 
 
       backCtrl: false, // show back button 
 
       // itemsDelayInterval : 60, // delay between each menu item sliding animation 
 
       onItemClick: $scope.loadDummyData // callback: item that doesn´t have a submenu gets clicked - onItemClick([event], [inner HTML of the clicked item]) 
 
    });

Как я могу это сделать?

ответ

0

Я думаю, вы должны обернуть ваш плагин с AngularJS директивы https://docs.angularjs.org/guide/directive

И.Э. создайте директиву, которая использует ваш плагин и инициализирует его на отмеченной DOM.

angular.module('yourModule') 
.directive('mlMenu', function() { 
    return { 
    restrict: 'A', 
    link: function (scope, element) { 
     var mlmenu = new MLMenu(element, 
     ... 
    } 
    }; 
}); 

чем в HTML

<div data-ml-menu></div> 

И если вы собираетесь изменить масштаб в плагин слушателей не забудьте использовать scope.$apply() обертку.