/** * Menu.js * * A menu object. This is the container to which you may add {@link Common.UI.MenuItem menu items}. * * Created by Alexander Yuzhin on 1/28/14 * Copyright (c) 2014 Ascensio System SIA. All rights reserved. * */ /** * Default template * *
* * A useful classes of menu position * * - `'pull-right'` using for layout menu by right side of a parent * * * Example usage: * * new Common.UI.Menu({ * items: [ * { caption: 'item 1', value: 1 }, * { caption: 'item 1', value: 2 }, * { caption: '--' }, * { caption: 'item 1', value: 3 }, * ] * }) * * @property {Object} itemTemplate * * Default template for items * * * @property {Array} items * * Arrow of the {Common.UI.MenuItem} menu items * * */ if (Common === undefined) var Common = {}; define([ 'common/main/lib/extend/Bootstrap', 'common/main/lib/component/BaseView', 'common/main/lib/component/MenuItem', 'common/main/lib/component/Scroller' ], function () { 'use strict'; Common.UI.Menu = (function(){ var manager = (function(){ var active = [], menus = {}; return { register: function(menu) { menus[menu.id] = menu; menu .on('show:after', function(m) { active.push(m); }) .on('hide:after', function(m) { var index = active.indexOf(m); if (index > -1) active.splice(index, 1); }); }, unregister: function(menu) { var index = active.indexOf(menu); delete menus[menu.id]; if (index > -1) active.splice(index, 1); menu.off('show:after').off('hide:after'); }, hideAll: function() { Common.NotificationCenter.trigger('menumanager:hideall'); if (active && active.length > 0) { _.each(active, function(menu) { menu.hide(); }); return true; } return false; } } })(); return _.extend(Common.UI.BaseView.extend({ options : { cls : '', style : '', itemTemplate: null, items : [], menuAlign : 'tl-bl', menuAlignEl : null, offset : [0, 0], cyclic : true }, template: _.template([ ' ' ].join('')), initialize : function(options) { Common.UI.BaseView.prototype.initialize.call(this, options); var me = this; this.id = this.options.id || Common.UI.getId(); this.itemTemplate = this.options.itemTemplate || Common.UI.MenuItem.prototype.template; this.rendered = false; this.items = []; this.offset = [0, 0]; this.menuAlign = this.options.menuAlign; this.menuAlignEl = this.options.menuAlignEl; if (!this.options.cyclic) this.options.cls += ' no-cyclic'; _.each(this.options.items, function(item) { if (item instanceof Common.UI.MenuItem) { me.items.push(item) } else { me.items.push( new Common.UI.MenuItem(_.extend({ tagName : 'li', template: me.itemTemplate }, item)) ); } }); if (this.options.el) this.render(); manager.register(this); }, remove: function() { manager.unregister(this); Common.UI.BaseView.prototype.remove.call(this); }, render: function(parentEl) { var me = this; this.trigger('render:before', this); this.cmpEl = $(this.el); if (parentEl) { this.setElement(parentEl, false); if (!me.rendered) { this.cmpEl = $(this.template({ options : me.options })); parentEl.append(this.cmpEl); } } else { if (!me.rendered) { this.cmpEl = this.template({ options : me.options }); $(this.el).append(this.cmpEl); } } var rootEl = this.cmpEl.parent(), menuRoot = (rootEl.attr('role') === 'menu') ? rootEl : rootEl.find('[role=menu]'); if (menuRoot) { if (!me.rendered) { _.each(me.items || [], function(item) { menuRoot.append(item.render().el); item.on('click', _.bind(me.onItemClick, me)); item.on('toggle', _.bind(me.onItemToggle, me)); }); } menuRoot.css({ 'max-height': me.options.maxHeight||'none', position : 'fixed', right : 'auto', left : -1000, top : -1000 }); this.parentEl = menuRoot.parent(); this.parentEl.on('show.bs.dropdown', _.bind(me.onBeforeShowMenu, me)); this.parentEl.on('shown.bs.dropdown', _.bind(me.onAfterShowMenu, me)); this.parentEl.on('hide.bs.dropdown', _.bind(me.onBeforeHideMenu, me)); this.parentEl.on('hidden.bs.dropdown', _.bind(me.onAfterHideMenu, me)); this.parentEl.on('keydown.after.bs.dropdown', _.bind(me.onAfterKeydownMenu, me)); menuRoot.on('scroll', _.bind(me.onScroll, me)); menuRoot.hover( function(e) { me.isOver = true;}, function(e) { me.isOver = false; } ); } this.rendered = true; this.trigger('render:after', this); return this; }, isVisible: function() { return this.rendered && (this.cmpEl.is(':visible')); }, show: function() { if (this.rendered && this.parentEl && !this.parentEl.hasClass('open')) { this.cmpEl.dropdown('toggle'); } }, hide: function() { if (this.rendered && this.parentEl) { if ( this.parentEl.hasClass('open') ) this.cmpEl.dropdown('toggle'); else if (this.parentEl.hasClass('over')) this.parentEl.removeClass('over'); } }, insertItem: function(index, item) { var me = this, el = this.cmpEl; if (!(item instanceof Common.UI.MenuItem)) { item = new Common.UI.MenuItem(_.extend({ tagName : 'li', template: me.itemTemplate }, item)); } if (index < 0 || index >= me.items.length) me.items.push(item); else me.items.splice(index, 0, item); if (this.rendered) { var menuRoot = (el.attr('role') === 'menu') ? el : el.find('[role=menu]'); if (menuRoot) { if (index < 0) { menuRoot.append(item.render().el); } else if (index === 0) { menuRoot.prepend(item.render().el); } else { $('li:nth-child(' + (index+1) + ')', menuRoot).before(item.render().el); } item.on('click', _.bind(me.onItemClick, me)); item.on('toggle', _.bind(me.onItemToggle, me)); } } }, doLayout: function() { if (this.options.maxHeight > 0) { if (!this.rendered) { this.mustLayout = true; return; } var me = this, el = this.cmpEl; var menuRoot = (el.attr('role') === 'menu') ? el : el.find('[role=menu]'); if (!menuRoot.is(':visible')) { var pos = [menuRoot.css('left'), menuRoot.css('top')]; menuRoot.css({ left : '-1000px', top : '-1000px', display : 'block' }); } var $items = menuRoot.find('li'); if ($items.height() * $items.length > this.options.maxHeight) { var scroll = ''; menuRoot.prepend(scroll); scroll = ''; menuRoot.append(scroll); menuRoot.css({ 'box-shadow' : 'none', 'overflow-y' : 'hidden', 'padding-top' : '18px' // 'padding-bottom' : '18px' }); menuRoot.find('> li:last-of-type').css('margin-bottom',18); var addEvent = function( elem, type, fn ) { elem.addEventListener ? elem.addEventListener( type, fn, false ) : elem.attachEvent( "on" + type, fn ); }; var eventname=(/Firefox/i.test(navigator.userAgent))? 'DOMMouseScroll' : 'mousewheel'; addEvent(menuRoot[0], eventname, _.bind(this.onMouseWheel,this)); menuRoot.find('.menu-scroll').on('click', _.bind(this.onScrollClick, this)); } if (pos) { menuRoot.css({ display : '', left : pos[0], top : pos[1] }); } } }, addItem: function(item) { this.insertItem(-1, item); }, removeItem: function(item) { var me = this, index = me.items.indexOf(item); if (index > -1) { me.items.splice(index, 1); item.off('click').off('toggle'); item.remove(); } }, removeItems: function(from, len) { if (from > this.items.length-1) return; if (from+len>this.items.length) len = this.items.length - from; for (var i=from; i