%PDF- %PDF-
Direktori : /home/vacivi36/ava/lib/editor/atto/yui/src/editor/js/ |
Current File : /home/vacivi36/ava/lib/editor/atto/yui/src/editor/js/menu.js |
// This file is part of Moodle - http://moodle.org/ // // Moodle is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation, either version 3 of the License, or // (at your option) any later version. // // Moodle is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // You should have received a copy of the GNU General Public License // along with Moodle. If not, see <http://www.gnu.org/licenses/>. /** * A Menu for the Atto editor. * * @module moodle-editor_atto-menu * @submodule menu-base * @package editor_atto * @copyright 2013 Damyon Wiese * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later */ var LOGNAME = 'moodle-editor_atto-menu'; var MENUDIALOGUE = '' + '<div class="open {{config.buttonClass}} atto_menu" ' + 'style="min-width:{{config.innerOverlayWidth}};">' + '<ul class="dropdown-menu" role="menu" id="{{config.buttonId}}_menu" aria-labelledby="{{config.buttonId}}">' + '{{#each config.items}}' + '<li role="none" class="atto_menuentry">' + '<a href="#" role="menuitem" data-index="{{@index}}" {{#each data}}data-{{@key}}="{{this}}"{{/each}}>' + '{{{text}}}' + '</a>' + '</li>' + '{{/each}}' + '</ul>' + '</div>'; /** * A Menu for the Atto editor used in Moodle. * * This is a drop down list of buttons triggered (and aligned to) a * location. * * @namespace M.editor_atto * @class Menu * @main * @constructor * @extends M.core.dialogue */ var Menu = function() { Menu.superclass.constructor.apply(this, arguments); }; Y.extend(Menu, M.core.dialogue, { /** * A list of the menu handlers which have been attached here. * * @property _menuHandlers * @type Array * @private */ _menuHandlers: null, /** * The menu button that controls this menu. */ _menuButton: null, initializer: function(config) { var headerText, bb; this._menuHandlers = []; this._menuButton = document.getElementById(config.buttonId); // Create the actual button. var template = Y.Handlebars.compile(MENUDIALOGUE), menu = Y.Node.create(template({ config: config })); this.set('bodyContent', menu); bb = this.get('boundingBox'); bb.addClass('editor_atto_controlmenu'); bb.addClass('editor_atto_menu'); // Get the dialogue container for this menu. var content = bb.one('.moodle-dialogue-wrap'); content.removeClass('moodle-dialogue-wrap') .addClass('moodle-dialogue-content'); // Remove the dialog role attribute. content.removeAttribute('role'); // Remove aria-labelledby in the container. The aria-labelledby attribute is properly set in the menu's template. content.removeAttribute('aria-labelledby'); // Render heading if necessary. headerText = this.get('headerText').trim(); if (headerText) { var heading = Y.Node.create('<h3/>') .addClass('accesshide') .setHTML(headerText); this.get('bodyContent').prepend(heading); } // Hide the header and footer node entirely. this.headerNode.hide(); this.footerNode.hide(); this._setupHandlers(); }, /** * Setup the Event handlers. * * @method _setupHandlers * @private */ _setupHandlers: function() { var contentBox = this.get('contentBox'); // Handle menu item selection. this._menuHandlers.push( // Select the menu item on space, and enter. contentBox.delegate('key', this._chooseMenuItem, '32, enter', '.atto_menuentry', this), // Move up and down the menu on up/down. contentBox.delegate('key', this._handleKeyboardEvent, 'down:38,40', '.dropdown-menu', this), // Hide the menu when clicking outside of it. contentBox.on('focusoutside', this.hide, this), // Hide the menu on left/right, and escape keys. contentBox.delegate('key', this.hide, 'down:37,39,esc', '.dropdown-menu', this) ); }, /** * Simulate other types of menu selection. * * @method _chooseMenuItem * @param {EventFacade} e */ _chooseMenuItem: function(e) { e.target.simulate('click'); e.preventDefault(); }, /** * Hide a menu, removing all of the event handlers which trigger the hide. * * @method hide * @param {EventFacade} e */ hide: function(e) { if (this.get('preventHideMenu') === true) { return; } // We must prevent the default action (left/right/escape) because // there are other listeners on the toolbar which will focus on the // editor. if (e) { e.preventDefault(); } // Remove menu button's aria-expanded attribute when this menu is hidden. if (this._menuButton) { this._menuButton.removeAttribute('aria-expanded'); } return Menu.superclass.hide.call(this, arguments); }, /** * Implement arrow-key navigation for the items in a toolbar menu. * * @method _handleKeyboardEvent * @param {EventFacade} e The keyboard event. * @static */ _handleKeyboardEvent: function(e) { // Prevent the default browser behaviour. e.preventDefault(); // Get a list of all buttons in the menu. var buttons = e.currentTarget.all('a[role="menuitem"]'); // On cursor moves we loops through the buttons. var found = false, index = 0, direction = 1, checkCount = 0, current = e.target.ancestor('a[role="menuitem"]', true), next; // Determine which button is currently selected. while (!found && index < buttons.size()) { if (buttons.item(index) === current) { found = true; } else { index++; } } if (!found) { Y.log("Unable to find this menu item in the menu", 'debug', LOGNAME); return; } if (e.keyCode === 38) { // Moving up so reverse the direction. direction = -1; } // Try to find the next do { index += direction; if (index < 0) { index = buttons.size() - 1; } else if (index >= buttons.size()) { // Handle wrapping. index = 0; } next = buttons.item(index); // Add a counter to ensure we don't get stuck in a loop if there's only one visible menu item. checkCount++; // Loop while: // * we are not in a loop and have not already checked every button; and // * we are on a different button; and // * the next menu item is not hidden. } while (checkCount < buttons.size() && next !== current && next.hasAttribute('hidden')); if (next) { next.focus(); } e.preventDefault(); e.stopImmediatePropagation(); } }, { NAME: "menu", ATTRS: { /** * The header for the drop down (only accessible to screen readers). * * @attribute headerText * @type String * @default '' */ headerText: { value: '' } } }); Y.Base.modifyAttrs(Menu, { /** * The width for this menu. * * @attribute width * @default 'auto' */ width: { value: 'auto' }, /** * When to hide this menu. * * By default, this attribute consists of: * <ul> * <li>an object which will cause the menu to hide when the user clicks outside of the menu</li> * </ul> * * @attribute hideOn */ hideOn: { value: [ { eventName: 'clickoutside' } ] }, /** * The default list of extra classes for this menu. * * @attribute extraClasses * @type Array * @default editor_atto_menu */ extraClasses: { value: [ 'editor_atto_menu' ] }, /** * Override the responsive nature of the core dialogues. * * @attribute responsive * @type boolean * @default false */ responsive: { value: false }, /** * The default visibility of the menu. * * @attribute visible * @type boolean * @default false */ visible: { value: false }, /** * Whether to centre the menu. * * @attribute center * @type boolean * @default false */ center: { value: false }, /** * Hide the close button. * @attribute closeButton * @type boolean * @default false */ closeButton: { value: false } }); Y.namespace('M.editor_atto').Menu = Menu;