1
0
Fork 0
lasertank-js/lib/ui/MenuBar.js

138 lines
3.9 KiB
JavaScript

/**
* 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 <http://www.gnu.org/licenses/>.
*/
/**
* 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 );
}
} );