| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244 |
- /**
- * MenuButton.js
- *
- * Copyright, Moxiecode Systems AB
- * Released under LGPL License.
- *
- * License: http://www.tinymce.com/license
- * Contributing: http://www.tinymce.com/contributing
- */
- /**
- * Creates a new menu button.
- *
- * @-x-less MenuButton.less
- * @class tinymce.ui.MenuButton
- * @extends tinymce.ui.Button
- */
- define("tinymce/ui/MenuButton", [
- "tinymce/ui/Button",
- "tinymce/ui/Factory",
- "tinymce/ui/MenuBar"
- ], function(Button, Factory, MenuBar) {
- "use strict";
- // TODO: Maybe add as some global function
- function isChildOf(node, parent) {
- while (node) {
- if (parent === node) {
- return true;
- }
- node = node.parentNode;
- }
- return false;
- }
- var MenuButton = Button.extend({
- /**
- * Constructs a instance with the specified settings.
- *
- * @constructor
- * @param {Object} settings Name/value object with settings.
- */
- init: function(settings) {
- var self = this;
- self._renderOpen = true;
- self._super(settings);
- self.addClass('menubtn');
- if (settings.fixedWidth) {
- self.addClass('fixed-width');
- }
- self.aria('haspopup', true);
- self.hasPopup = true;
- },
- /**
- * Shows the menu for the button.
- *
- * @method showMenu
- */
- showMenu: function() {
- var self = this, settings = self.settings, menu;
- if (self.menu && self.menu.visible()) {
- return self.hideMenu();
- }
- if (!self.menu) {
- menu = settings.menu || [];
- // Is menu array then auto constuct menu control
- if (menu.length) {
- menu = {
- type: 'menu',
- items: menu
- };
- } else {
- menu.type = menu.type || 'menu';
- }
- self.menu = Factory.create(menu).parent(self).renderTo();
- self.fire('createmenu');
- self.menu.reflow();
- self.menu.on('cancel', function(e) {
- if (e.control.parent() === self.menu) {
- e.stopPropagation();
- self.focus();
- self.hideMenu();
- }
- });
- // Move focus to button when a menu item is selected/clicked
- self.menu.on('select', function() {
- self.focus();
- });
- self.menu.on('show hide', function(e) {
- if (e.control == self.menu) {
- self.activeMenu(e.type == 'show');
- }
- self.aria('expanded', e.type == 'show');
- }).fire('show');
- }
- self.menu.show();
- self.menu.layoutRect({w: self.layoutRect().w});
- self.menu.moveRel(self.getEl(), self.isRtl() ? ['br-tr', 'tr-br'] : ['bl-tl', 'tl-bl']);
- },
- /**
- * Hides the menu for the button.
- *
- * @method hideMenu
- */
- hideMenu: function() {
- var self = this;
- if (self.menu) {
- self.menu.items().each(function(item) {
- if (item.hideMenu) {
- item.hideMenu();
- }
- });
- self.menu.hide();
- }
- },
- /**
- * Sets the active menu state.
- *
- * @private
- */
- activeMenu: function(state) {
- this.toggleClass('active', state);
- },
- /**
- * Renders the control as a HTML string.
- *
- * @method renderHtml
- * @return {String} HTML representing the control.
- */
- renderHtml: function() {
- var self = this, id = self._id, prefix = self.classPrefix;
- var icon = self.settings.icon ? prefix + 'ico ' + prefix + 'i-' + self.settings.icon : '';
- self.aria('role', self.parent() instanceof MenuBar ? 'menuitem' : 'button');
- return (
- '<div id="' + id + '" class="' + self.classes() + '" tabindex="-1" aria-labelledby="' + id + '">' +
- '<button id="' + id + '-open" role="presentation" type="button" tabindex="-1">' +
- (icon ? '<i class="' + icon + '"></i>' : '') +
- '<span>' + (self._text ? (icon ? '\u00a0' : '') + self.encode(self._text) : '') + '</span>' +
- ' <i class="' + prefix + 'caret"></i>' +
- '</button>' +
- '</div>'
- );
- },
- /**
- * Gets invoked after the control has been rendered.
- *
- * @method postRender
- */
- postRender: function() {
- var self = this;
- self.on('click', function(e) {
- if (e.control === self && isChildOf(e.target, self.getEl())) {
- self.showMenu();
- if (e.aria) {
- self.menu.items()[0].focus();
- }
- }
- });
- self.on('mouseenter', function(e) {
- var overCtrl = e.control, parent = self.parent(), hasVisibleSiblingMenu;
- if (overCtrl && parent && overCtrl instanceof MenuButton && overCtrl.parent() == parent) {
- parent.items().filter('MenuButton').each(function(ctrl) {
- if (ctrl.hideMenu && ctrl != overCtrl) {
- if (ctrl.menu && ctrl.menu.visible()) {
- hasVisibleSiblingMenu = true;
- }
- ctrl.hideMenu();
- }
- });
- if (hasVisibleSiblingMenu) {
- overCtrl.focus(); // Fix for: #5887
- overCtrl.showMenu();
- }
- }
- });
- return self._super();
- },
- /**
- * Sets/gets the current button text.
- *
- * @method text
- * @param {String} [text] New button text.
- * @return {String|tinymce.ui.MenuButton} Current text or current MenuButton instance.
- */
- text: function(text) {
- var self = this, i, children;
- if (self._rendered) {
- children = self.getEl('open').getElementsByTagName('span');
- for (i = 0; i < children.length; i++) {
- children[i].innerHTML = (self.settings.icon && text ? '\u00a0' : '') + self.encode(text);
- }
- }
- return this._super(text);
- },
- /**
- * Removes the control and it's menus.
- *
- * @method remove
- */
- remove: function() {
- this._super();
- if (this.menu) {
- this.menu.remove();
- }
- }
- });
- return MenuButton;
- });
|