/** * Handles CSS-drive menu bar * * Copyright (C) 2012 Mike Gerwitz * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program 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 Affero General Public License for more details. * * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . */ /** * Basic MenuBar * * This class provides basic scripting for a menu bar; it expected the majority * of the menu bar to be handled via CSS. */ ltjs.ui.MenuBar = Class( 'MenuBar', { /** * DOM element representing the menu bar * @type {Element} */ 'private _bar': null, /** * Initialize menu bar with a DOM element * * The provided DOM element should be a UL element with each LI element * containing an A element, containing the title, and a sub-UL element * containing the sub-menu. * * @param {Element} element DOM element representing menu bar */ __construct: function( element ) { // we'll need an id set for this element if ( !element.id ) { element.id = '__menubar'; } this._bar = element; this._initMenuActivation(); }, /** * Initialize menu activation * * When any menu item is clicked, the menu bar will be considered active * (focus), which will apply a CSS class to the menu bar. On mouse out the * active state will be cleared. * * @return {undefined} */ 'private _initMenuActivation': function() { var _self = this, id = this._bar.id, menus = this._bar.parentNode.querySelectorAll( '#'+id+' > li > a' ), i = menus.length, click = function( event ) { event.target.parentNode.parentNode.className += ' focus'; return false; }; // on menu click, apply focus class (this allows the menu to be opened // properly on click rather than a simple CSS hover menu) while ( i-- ) { // ultimately we'll want to use onmousedown, but we'll leave it as // onclick for now since we don't offer mouseup menus[ i ].addEventListener( 'click', click ); } this._hookMenuMouseOut(); }, /** * Clear active (focus) on mouse out * * To determine if the mouse has left the menu bar, we need to ensure that * the mouse has not been moved over any child element (as we do not want to * close the menu). * * @return {undefined} */ 'private _hookMenuMouseOut': function() { var _self = this, bar = this._bar; this._bar.addEventListener( 'mouseout', function( event ) { // do not close the menu if our new target is a menu child element if ( _self._isNodeOrChildOf( bar, event.relatedTarget ) ) { return; } bar.className = bar.className.replace( ' focus', '' ); } ); }, /** * Determines if the given node is a child of, or is, the given parent node * * @param {Element} parent parent node * @param {Element} node node to check * * @return {boolean} TRUE if child or node itself, otherwise FALSE */ 'private _isNodeOrChildOf': function( parent, node ) { if ( !node || !node.parentNode ) return false; return ( node === parent ) ? true : this._isNodeOrChildOf( parent, node.parentNode ); } } );