Ext.namespace('Zarafa.core.ui'); /** * @class Zarafa.core.ui.MainToolbar * @extends Zarafa.core.ui.Toolbar * @xtype zarafa.maintoolbar */ Zarafa.core.ui.MainToolbar = Ext.extend(Zarafa.core.ui.Toolbar, { // Insertion points for this class /** * @insert main.maintoolbar.new.item * Insertion point for populating the "New item" menu. It will be placed in the item part of the * list. Each item inserted to this list is accessible from all contexts. * @param {Zarafa.core.ui.MainToolbar} toolbar This toolbar */ /** * @insert main.maintoolbar.new.folder * Insertion point for populating the "New item" menu. It will be placed in the folder part of * the list. Each item inserted to this list is accessible from all contexts. * @param {Zarafa.core.ui.MainToolbar} toolbar This toolbar */ /** * @insert main.toolbar.actions * Insertion point for populating the main toolbar with buttons. It will be added after the * NEW-button and before the VIEW-buttons. */ /** * @insert main.toolbar.actions.last * Insertion point for populating the main toolbar with buttons. It will be added after the * VIEW-buttons. */ /** * @constructor * @param config Configuration structure */ constructor : function(config) { config = config || {}; Ext.applyIf(config, { // Override from Ext.Component xtype: 'zarafa.maintoolbar', id : 'zarafa-maintoolbar', cls : 'zarafa-maintoolbar' }); Zarafa.core.ui.MainToolbar.superclass.constructor.call(this, config); this.initButtonGroups(); }, /** * Add default button groups to toolbar * @private */ initButtonGroups : function() { // Initialize the items list with all default buttons, and add buttons which were // registered through insertion points. this.addNewItems(); this.addActionItems(); this.addPrintButton(); this.addViewItems(); this.addItems([], 'main.toolbar.actions.last'); }, /** * Creates the "New" {@link Ext.Button}. The NEW-button menu consists of three parts. The first * part is the button that will be considered the default button for the active context. The * second part contains items that deal with folders and the last part will deal with the * creation of items. * The menu will be populated by using the main.maintoolbar.new.folder and * main.maintoolbar.new.item insertion points. The first one is for adding items to the second * (folder) part and the latter one is for adding items to the third (item) part of the menu. * * Based on the newMenuIndex property of each button the items are sorted. Based on the text * property, double items are filtered out of the list. When the list contains items a dummy * button and a separator is added at the top of the list. The dummy button will "replace" the * item of the active context. The other item will not be removed, but it will be hidden and * properties like the icon and the handler are also set on the dummy button. This switch is * done when the contexts are switched by the {@link Zarafa.core.Container Container}. * @private */ addNewItems : function() { var menu = []; var itemMenu = container.populateInsertionPoint('main.maintoolbar.new.item', this) || []; // Make sure the items are properly sorted by priority. itemMenu = Zarafa.core.Util.sortArray(itemMenu, 'ASC', 'newMenuIndex'); // Remove doubles itemMenu = Zarafa.core.Util.uniqueArray(itemMenu, 'text'); // menu.length should practically always be non-zero, but // just in case, we check it, and add the divider to separate // the default buttons from the rest. if (itemMenu.length !== 0) { // Hide the first item as we copy that to the default button. itemMenu[0].hidden = true; itemMenu[0].ref = 'defaultButton'; menu.push({ xtype: 'menuitem', id: 'zarafa-maintoolbar-newitem-defaultbutton', tooltip : itemMenu[0].tooltip, plugins : 'zarafa.menuitemtooltipplugin', // The following config properties copy the first item for the default button. iconCls: itemMenu[0].iconCls, text: itemMenu[0].text, handler : itemMenu[0].handler, scope : itemMenu[0].scope }, '-'); } // Add the item list to to the menu if (itemMenu.length !== 0) { menu = menu.concat(itemMenu); } this.addItems({ xtype: 'splitbutton', id: 'zarafa-maintoolbar-newitem', cls: 'zarafa-action', scale: 'large', ref: 'newButton', rowspan: 2, menu: menu, listeners: { render: this.onRenderNewButton, scope: this }, // The following config properties set the first item (that is now item number // three in the menu) as the button in the toolbar. iconCls: itemMenu[0] ? itemMenu[0].iconCls : undefined, handler : itemMenu[0] ? itemMenu[0].handler : undefined, scope : itemMenu[0] ? itemMenu[0].scope : undefined }); }, /** * Adds an event handler to the NEW-button that is registered to the contextswitch event of the * {@link Zarafa.core.Container Container}. This event handler will set the correct icon and * handler for the {@link Ext.SplitButton SplitButton} in the toolbar. It will also add the icon, * handler and text for the first item: the dummy button that holds the default action for the * active context. This event handler is called within the scope of the SplitButton. * It will loop through all the menu items in the last part of the menu and based on the * activate context it will hide or show the menu items. If the button is marked to belong to * the active context it will be hidden and the dummy button will be changed so it will look * like the button has moved to the top. All other buttons will remain visible. * If no button is marked to belong to the active context the first button in the list, after * the dummy button and the separator, will become the new default button. * @param {Ext.Component} cmp The SplitButton */ onRenderNewButton: function(cmp) { cmp.mon(container, 'contextswitch', this.onNewButtonContextSwitch, this); this.onNewButtonContextSwitch(null, container.getCurrentContext(), container.getCurrentContext()); }, /** * Fired when the {@link Zarafa.core.Container container} fires the {@link Zarafa.core.Container#contextswitch} event. * This will update the default new button to be shown. * @param {Zarafa.hierarchy.data.MAPIFolderRecord} folder folder that is loaded for the new context * @param {Zarafa.core.Context} oldContext context that was switched out * @param {Zarafa.core.Context} newContext new context that was switched * @private */ onNewButtonContextSwitch : function(parameters, oldContext, newContext) { var menu = this.newButton.menu; // The dummy button is the first button in the context menu that shows the button first // button registered by the active context. var dummyButton = menu.items.itemAt(0); // The default button is the button that will be set as the SplitButton if the active // context has not registered any buttons. The first button in the item-list will become // the default button. var defaultButton = menu.defaultButton; // Find the index of the default button. From this index on the list will be run down to // find the button that should be put as the SplitButton/dummy button. var itemIndex = menu.items.indexOf(defaultButton); // Use this variable to check whether there has already been assigned // a button to the default item. It could be that there are two buttons // being set by the same context. var button = false; // Only loop through the list if the default button is found. if(itemIndex >= 0){ // Loop from the itemIndex onwards. for(var i=itemIndex,len=menu.items.length;i<len;i++){ var item = menu.items.itemAt(i); // Only get the first button of the context that is active if(button===false && item.context == newContext.getName()){ button = item; // Hide the found button of the active context to prevent doubles item.setVisible(false); }else{ // Enable all other buttons item.setVisible(true); } } } // If no button was found, fall back to the default button if(button===false && defaultButton){ button = defaultButton; // Hide the defaultButton so it does not show twice in the menu defaultButton.setVisible(false); } // If we have a button set the SplitButton and the dummy button properties if(button!==false){ // Set the icon class and handler for the button in the toolbar this.newButton.setIconClass(button.iconCls); this.newButton.setHandler(button.handler, button.scope); // Set the default item (first item in the dropdown) dummyButton.tooltip = button.tooltip; dummyButton.setText(button.text); dummyButton.setIconClass(button.iconCls); dummyButton.setHandler(button.handler, button.scope); } }, /** * Creates the "View" {@link Ext.Button buttons}. * For each context a "View" button will be created which will be populated with the * main.maintoolbar.view.[context]. The first item from that list will also be used to set the * properties like iconCls and handler to the {@link Ext.SplitButton SplitButton}. * @private */ addViewItems : function() { var menu, menuItems = []; var contexts = container.getContexts(); for(var i = 0,len = contexts.length; i < len; i++){ var context = contexts[i]; menu = context.getMainToolbarViewButtons(); if (Array.isArray(menu) && menu.length) { if (context.groupViewBtns) { menuItems.push({ xtype: 'splitbutton', id: 'zarafa-maintoolbar-view-'+context.getName(), scale: 'large', iconCls: 'view_icon', tooltip: _('Switch view') + ' (Ctrl + Alt + 1..9)', hidden: true, contextName: context.getName(), menu: Zarafa.core.Util.uniqueArray(menu, 'text'), listeners : { render : this.onRenderViewButton, menuhide : this.onSwitchViewMenuHide, menushow : this.onSwitchViewMenuShow.createDelegate(this,[context], true), scope : this } }); } else { for (var j = 0, jlen = menu.length; j < jlen; j++) { var item = Ext.apply({}, menu[j], { xtype : 'button', scale : 'large', hidden : true, contextName : context.getName() }); // Move the 'text' property to the tooltip var viewCounter = j + 1; item.tooltip = item.text + ' (Ctrl + Alt + '+ viewCounter +')'; delete item.text; item.listeners = Zarafa.core.Util.mergeListeners(item.listeners, { render : this.onRenderViewButton }); menuItems.push(item); } } } } this.addItems(menuItems); }, /** * Event handler which is triggered when switch view split button * menu hide. function which remove selection css class from * split button menu item. * * @param {Ext.SplitButton} splitBtn split button which contains highlighted menu item. * @param {Ext.menu.Menu} menu menu contains highlighted menu item. */ onSwitchViewMenuHide : function (splitBtn, menu) { menu.find().forEach(function(item){ var hasClass = item.getEl().hasClass('x-menu-item-selected'); if(hasClass) { item.getEl().removeClass('x-menu-item-selected'); } }, this); }, /** * Event handler which is triggered when switch view split button * menu shows. It will highlight current selected view in switch * view menu by checking {@link Zarafa.core.Context#current_view_mode view mode} * of menu item and for sticky note switch view menu we use * {@link Zarafa.core.Context#current_view view} to highlight the * menu item. * * @param {Ext.SplitButton} splitBtn split button which menu item is going to highlight. * @param {Ext.menu.Menu} menu menu contains the menu item which is going to highlight * @param {Zarafa.core.Context} context which contains the switch view split button. */ onSwitchViewMenuShow : function(splitBtn, menu, context) { if(context.getName() !== 'note') { var menuItem = menu.find('valueViewMode', context.getCurrentViewMode())[0]; if (Ext.isDefined(menuItem)) { menuItem.addClass('x-menu-item-selected'); } } else { var menuItems = menu.find('valueView', context.getCurrentView()); var currentDataMode = context.getModel().getCurrentDataMode(); menuItems.forEach(function (menuItem) { if(menuItem.valueDataMode === currentDataMode) { menuItem.addClass('x-menu-item-selected'); return; } }, this); } }, /** * Adds an event handler to the VIEW-button that is registered to the contextswitch event of the * {@link Zarafa.core.Container Container}. This event handler will enable or disable the * VIEW-button based on whether this button belong to the active context. This event handler is * called within the scope of the SplitButton/Button. * @param {Ext.Component} cmp The SplitButton/Button */ onRenderViewButton: function(cmp) { cmp.mon(container, 'contextswitch', function(parameters, oldContext, newContext) { this.setVisible(this.contextName == newContext.getName()); }, cmp); //we need this line in order to set the visibility correctly as the contextswitch event will not have fired yet cmp.setVisible(cmp.contextName === container.getCurrentContext().getName()); // We want the menu to be toggled when the splitbutton is clicked. We cannot use the regular btn handler // for this, since an opened menu will already be closed before the handler is executed and there is // no way of knowing anymore if we should open it or not. So we will add a handler for an ordinary // mousedown event that gets called when the menu is still open. if ( cmp.xtype === 'splitbutton' ){ cmp.btnEl.on('mousedown', function(){ if ( cmp.hasVisibleMenu() ){ cmp.hideMenu(); } else { cmp.showMenu(); } }); } }, /** * Creates the Print {@link Ext.Button buttons}. * This differs for each context, and is populated with * main.toolbar.view.[context]. */ addPrintButton : function() { var menu, menuItems = []; var contexts = container.getContexts(); for(var i=0,len=contexts.length;i<len;i++){ var context = contexts[i]; menu = context.getMainToolbarPrintButtons(); if(Array.isArray(menu) && menu.length){ menuItems.push({ xtype: 'splitbutton', id: 'zarafa-maintoolbar-print-'+context.getName(), scale: 'large', iconCls: 'icon_print', tooltip: _('Print') + ' (Ctrl + P)', handler: menu[0].handler, scope: menu[0].scope, hidden: true, contextName: context.getName(), menu: { xtype : 'zarafa.conditionalmenu', defaults : { context : context, // Override getRecords to obtain the // records from the current selected records getRecords : function() { return this.context.getModel().getSelectedRecords(); } }, items : Zarafa.core.Util.uniqueArray(menu, 'text'), // Override this function so the menu will not be destroyed when hidden. onMenuHide: Ext.emptyFn }, listeners : { render : this.onRenderPrintButton } }); } } this.addItems(menuItems); }, /** * Adds an event handler to the Print button that is registered to the contextswitch event of the * {@link Zarafa.core.Container Container}. This event handler will enable or disable the * VIEW-button based on whether this button belong to the active context. This event handler is * called within the scope of the SplitButton. * @param {Ext.Component} cmp The SplitButton */ onRenderPrintButton: function(cmp) { cmp.mon(container, 'contextswitch', function(parameters, oldContext, newContext) { this.setVisible(this.contextName == newContext.getName()); }, cmp); //we need this line in order to set the visibility correctly as the contextswitch event will not have fired yet cmp.setVisible(cmp.contextName === container.getCurrentContext().getName()); }, /** * Adds the action buttons to the main toolbar. It adds a couple of default buttons by default * and allows to populate the toolbar with more buttons by using the main.maintoolbar.actions * insertion point. * @private */ addActionItems : function() { var menuItems = [{ xtype: 'button', id: 'zarafa-maintoolbar-addressbook', scale: 'large', overflowText: _('Address Book'), tooltip: _('Address Book'), iconCls: 'icon_addressbook', handler : this.onAddressBook, scope: this },{ xtype: 'button', id: 'zarafa-maintoolbar-refresh', scale: 'large', title: _('Refresh'), overflowText: _('Refresh'), tooltip: _('Refresh') + ' (F5)', iconCls: 'x-tbar-loading', handler : this.onRefresh, ref: 'refreshButton', scope: this, listeners: { render: this.onRenderRefreshButton, scope: this } }]; this.addItems(menuItems, 'main.toolbar.actions'); }, /** * Open the {@link Zarafa.addressbook.dialogs.AddressBookContentPanel AddressBookContentPanel} * @private */ onAddressBook : function() { Zarafa.addressbook.Actions.openAddressBook(); }, /** * This will Refresh the view and fire {@link Zarafa.core.data.ListModuleStore#reload} * @private */ onRefresh : function() { var model = container.getCurrentContext().getModel(); if (model) { model.reload(); } }, /** * This will print the current view * @private */ onPrint : function() { var context = container.getCurrentContext(); if (context) { Zarafa.common.Actions.openPrintDialog(context); } }, /** * Adds an event handler to the Refresh button that will register the contextswitch event of the * {@link Zarafa.core.Container Container}. This event handler will hide or unhide the * Refresh button based on whether the active context have store or not. This event handler is * called within the scope of the Refresh Button. * @param {Ext.Component} cmp The {@link #refreshButton} */ onRenderRefreshButton : function(cmp) { var context = container.getCurrentContext(); cmp.mon(container, 'contextswitch', function(parameters, oldContext, newContext) { var store = newContext.getModel().getStore(); this.setVisible(Ext.isDefined(store)); }, cmp); //we need this line in order to set the visibility correctly as the contextswitch event will not have fired yet var contextModel = context.getModel(); cmp.setVisible(Ext.isDefined(contextModel) && Ext.isDefined(contextModel.getStore())); } }); Ext.reg('zarafa.maintoolbar', Zarafa.core.ui.MainToolbar);