htmlToolbar.js

Summary

Provides an HTML based toolbar GUI.

Version: 0.8 $Id: overview-summary-htmlToolbar.js.html,v 1.10 2008/02/20 18:47:09 jameso Exp $

Author: James A. Overton


Class Summary
mozile.gui.htmlToolbar.Button  
mozile.gui.htmlToolbar.Menu  
mozile.gui.htmlToolbar.MenuItem  

/* ***** BEGIN LICENSE BLOCK *****
 * Licensed under Version: MPL 1.1/GPL 2.0/LGPL 2.1
 * Full Terms at http://mozile.mozdev.org/0.8/LICENSE
 *
 * Software distributed under the License is distributed on an "AS IS" basis,
 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
 * for the specific language governing rights and limitations under the
 * License.
 *
 * The Original Code is James A. Overton's code (james@overton.ca).
 *
 * The Initial Developer of the Original Code is James A. Overton.
 * Portions created by the Initial Developer are Copyright (C) 2005-2006
 * the Initial Developer. All Rights Reserved.
 *
 * Contributor(s):
 *	James A. Overton <james@overton.ca>
 *
 * ***** END LICENSE BLOCK ***** */

/**
 * @fileoverview Provides an HTML based toolbar GUI.
 * @link http://mozile.mozdev.org 
 * @author James A. Overton <james@overton.ca>
 * @version 0.8
 * $Id: overview-summary-htmlToolbar.js.html,v 1.10 2008/02/20 18:47:09 jameso Exp $
 */

mozile.require("mozile.dom");
mozile.require("mozile.edit");
mozile.require("mozile.gui");
mozile.provide("mozile.gui.htmlToolbar");


/**
 * A GUI factory which uses a HTML and CSS to display a toolbar at the top of the window.
 * NOTE: There are several CSS hacks coded into this file which override the default style sheet "htmlToolbar.css". Be careful.
 */
mozile.gui.htmlToolbar = new mozile.gui.Factory("HTMLToolbarFactory");
// Set as the default factory.
mozile.gui.factory = mozile.gui.htmlToolbar;

/**
 * Localization strings for this module.
 * @type Object
 */
mozile.gui.htmlToolbar.strings = mozile.getLocalization("mozile.gui", "htmlToolbar");

/**
 * Indicates that the toolbar is visible.
 * @type Boolean
 */
mozile.gui.htmlToolbar.visible = false;

/**
 * The toolbar "div" element.
 * @type Element
 */
mozile.gui.htmlToolbar.toolbar = null;

/**
 * A window.setInterval() value for the interval which controls the toolbar's position.
 * @type Number
 */
mozile.gui.htmlToolbar.interval = null;

/**
 * A checkmark character.
 * @type String
 */
mozile.gui.htmlToolbar.checkmark = "\u2713";

/**
 * Some CSS values for Internet Explorer to use.
 * This hack is required because of CSS problems with IE.
 * @type String
 */
mozile.gui.htmlToolbar.ieColor = "#C2C2C2"; // Matches PNG matte color.
mozile.gui.htmlToolbar.ieActiveColor = "#C1D2EE";
mozile.gui.htmlToolbar.ieMenuWidth = "170px";
mozile.gui.htmlToolbar.ieBorder = "";
mozile.gui.htmlToolbar.ieActiveBorder = "1px solid #316AC5";
mozile.gui.htmlToolbar.iePadding = "1px";
mozile.gui.htmlToolbar.ieActivePadding = "0px";



/**** Global Commands ****/

/**
 * Display information about Mozile.
 * @type mozile.edit.Command
 */
mozile.gui.htmlToolbar.about = new mozile.edit.Command("about");

/**
 * Displays a dialog with information about Mozile.
 * @param {mozile.edit.State} state The state information needed to execute this command.
 * @param {Boolean} fresh Optional. A value of "true" indicates that the window's selection is already in the correct place and does not need to be moved.
 * @type Object
 */
mozile.gui.htmlToolbar.about.execute = function(state, fresh) {
	alert([
		"About Mozile "+ mozile.version, 
		mozile.homepage, 
		mozile.about, 
		mozile.copyright +" "+ mozile.license, 
		"Contributors: "+ mozile.credits, 
		"Acknowledgements: "+ mozile.acknowledgements
	].join("\n"));
	state.reversible = false;
	state.executed = true;
	return state;
}

/**
 * Display information about Mozile.
 * @type mozile.edit.Command
 */
mozile.gui.htmlToolbar.help = new mozile.edit.Command("help");

/**
 * Displays help information.
 * @param {mozile.edit.State} state The state information needed to execute this command.
 * @param {Boolean} fresh Optional. A value of "true" indicates that the window's selection is already in the correct place and does not need to be moved.
 * @type Object
 */
mozile.gui.htmlToolbar.help.execute = function(state, fresh) {
	if(mozile.enhance && mozile.enhance.isEnhanced("showHelp")) {
		mozile.enhance.clientRequest("showHelp");
	}
	else {
		var help = mozile.getAbsolutePath(mozile.help, mozile.root);
		window.open(help, "MozileHelp", "");
	}
	state.reversible = false;
	state.executed = true;
	return state;
}


/**
 * Groups togther commands into the main Mozile menu.
 * @type mozile.edit.Command
 */
mozile.gui.htmlToolbar.mainMenu = new mozile.edit.CommandGroup("Main Menu");
mozile.gui.htmlToolbar.mainMenu.image = "Mozile-16";
mozile.gui.htmlToolbar.mainMenu.addCommand(mozile.gui.htmlToolbar.about);
mozile.gui.htmlToolbar.mainMenu.addCommand(mozile.gui.htmlToolbar.help);

mozile.gui.htmlToolbar._commands = new Array(mozile.gui.htmlToolbar.mainMenu);


/**** Implement Interfaces ****/

/**
 * Create HTML or XHTML elements.
 * When there is no mozile.defaultNS, the element is created in the default namespace. If there is a mozile.defaultNS, the element is created in the XHTML namespace.
 * @param {String} name The name of the element to create.
 * @type Element
 */
mozile.gui.htmlToolbar.createElement = function(name) {
	if(mozile.defaultNS) {
		mozile.require("mozile.xml");
		return mozile.dom.createElementNS(mozile.xml.ns.xhtml, name);
	}
	else return mozile.dom.createElement(name);
}

/**
 * Create an image. THis can be complicated because IE has crappy PNG support.
 * @param {String} name The name of the image file. This will be a partial path.
 * @type Element
 */
mozile.gui.htmlToolbar.createImage = function(name) {
	if(!name || typeof(name) != "string") return null;

	var filetype = ".png";
	if(name.indexOf(".") > -1) filetype = "";
	var img;
	var src = [mozile.root, "images", name + filetype].join(mozile.filesep);
	
	// Hack to work around IE's PNG failings.
	if(false && mozile.browser.isIE && (filetype == ".png" || 
		name.toLowerCase().substring(name.length-3, name.length) == "png") ) {
		img = mozile.gui.htmlToolbar.createElement("span");
		img.style.cssText = "width: 16px; height: 16px; display:inline-block; "
			+ "filter:progid:DXImageTransform.Microsoft.AlphaImageLoader"
			+ "(src=\'" + src + "\', sizingMethod='image');";
    //mozile.debug.debug("mozile.gui.htmlToolbar.createImage", img.style.cssText);
	}
	else {
		img = mozile.gui.htmlToolbar.createElement("img");
		img.setAttribute("src", src);
	}

	return img;
}

/**
 * Set up the toolbar.
 * @type Void
 */
mozile.gui.htmlToolbar.create = function() {
	if(this.toolbar) return;

	// Add style sheet
	var href = [mozile.root, "src", "gui", "htmlToolbar.css"].join(mozile.filesep);
	mozile.dom.addStyleSheet(href, "text/css");

	// Create toolbar.
	this.toolbar = mozile.gui.htmlToolbar.createElement("div");
	this.toolbar.setAttribute("id", "mozileToolbar");
	mozile.dom.setClass(this.toolbar, "mozileGUI");
    mozile.protectElement(this.toolbar);
	var body = mozile.dom.getBody();
	body.appendChild(this.toolbar);
	
	// TODO: Fix this IE CSS hack
	if(mozile.browser.isIE) {
		mozile.dom.setStyle(this.toolbar, "background-color", this.ieColor);
	}

	// Update toolbar.
	this.updateButtons();
	this.reposition();
}

/**
 * Destroy the toolbar.
 * @type Void
 */
mozile.gui.htmlToolbar.destroy = function() {
	this.hide();
	delete this.toolbar;
	var command;
	for(var name in mozile.edit.allCommands) {
		command = mozile.edit.allCommands[name];
		if(command.button != undefined) delete command.button;
		if(command.menuItem != undefined) delete command.menuItem;
		if(command.menu != undefined) delete command.menu;
	}
}

/**
 * Reposition the toolbar.
 * This includes hacks to make Mozile use CSS "position: fixed".
 * @type Void
 */
mozile.gui.htmlToolbar.reposition = function() {
	if(!mozile.gui.htmlToolbar.toolbar) mozile.gui.htmlToolbar.create();
	if(mozile.edit.editable) mozile.gui.htmlToolbar.show();
	//else mozile.gui.htmlToolbar.hide();

	if(!mozile.browser.isIE) {
		mozile.dom.setStyle(mozile.gui.htmlToolbar.toolbar, "position", "fixed");
		mozile.dom.setStyle(mozile.gui.htmlToolbar.toolbar, "top", "-1px");
	}
	else {
		var top = document.documentElement.scrollTop;
		if(top) mozile.dom.setStyle(mozile.gui.htmlToolbar.toolbar, "top", top +"px");
	}
	
	if(document.documentElement.clientWidth) {
		var left = (document.documentElement.clientWidth - mozile.gui.htmlToolbar.toolbar.offsetWidth) / 2
		if(left) mozile.dom.setStyle(mozile.gui.htmlToolbar.toolbar, "left", left +"px");
	}
}

/**
 * Update the toolbar, given the information from the event.
 * Only events from new nodes which might change the state of the toolbar are handled.
 * @param {Event} event The current event object.
 * @param {String} change Optional. The type of change made. See mozile.edit.Command.respond for possible values.
 * @type Boolean
 */
mozile.gui.htmlToolbar.update = function(event, change) {
try {
	this._delayEvent = event;
	if(change && mozile.edit.isHigherPriority(change, this._delayChange))
		this._delayChange = change;

	if(this._delay) window.clearTimeout(this._delay);
	this._delay = window.setTimeout(
		"mozile.gui.htmlToolbar._callUpdate()", this.updateDelay);

} catch(e) {
	console.info(e);
}
	return true;
}
mozile.gui.htmlToolbar.updateDelay = 100;

mozile.gui.htmlToolbar._callUpdate = function() {
	mozile.gui.htmlToolbar._update.apply(mozile.gui.htmlToolbar);
}

mozile.gui.htmlToolbar._update = function() {
try {
	var event = this._delayEvent;
	var change = this._delayChange;
	this._delay = null;
	this._delayEvent = null;
	this._delayChange = null;
	
	//console.info("_update", event, change);

	if(!event) return false;
	
	if(mozile.edit.editable && mozile.edit.status) {
		mozile.gui.htmlToolbar.show();
	}
	else {
		//mozile.gui.htmlToolbar.hide();
		return true;
	}
	
	if(!change) {
		// Ignore key events, except for keyup.
		if(event.type.indexOf("key") > -1 && event.type != "keyup") return false;
	}
	this.reposition();

	if(!event || !event.node) {
		mozile.gui.htmlToolbar.closeMenus();
		return false;
	}
	if(!change) change = "none";
	
	// Refresh the set of buttons.
	if(change == "node" || event.node != this.lastNode) {
		change = "node";
		if(mozile.dom.isAncestorOf(this.toolbar, event.node)) return false;
		else mozile.gui.htmlToolbar.closeMenus();
		this.lastNode = event.node;
		
		if(!event.rng) event.rng = mozile.edit.lookupRNG(event.node);
		this.updateButtons(event.rng, event);
	}

	this.updateCommands(event, change);
} catch(e) {
	alert(mozile.dumpError(e));
}
	this.reposition();
}

/**
 * Update all the toolbar's buttons.
 * @param {mozile.rng.Element} rng Optional. When provided, commands belonging to the RNG Element will be updated.
 * @param {Event} event Optional. The current event object.
 * @type Void
 */
mozile.gui.htmlToolbar.updateButtons = function(rng, event) {
	mozile.dom.removeChildNodes(this.toolbar);
	this.toolbar.commands = new Array();
	var i=0;

	// GUI commands
	for(i=0; i < mozile.gui.htmlToolbar._commands.length; i++) {
		this.updateButton(mozile.gui.htmlToolbar._commands[i]);
	}	
	this.toolbar.appendChild(document.createTextNode("|"));

	// Global commands
	for(i=0; i < mozile.edit.commands._commands.length; i++) {
		this.updateButton(mozile.edit.commands._commands[i]);
	}

	// Context commands
	if(rng && rng.commands._commands && rng.commands._commands.length) {
		this.toolbar.appendChild(document.createTextNode("|"));
		for(i=0; i < rng.commands._commands.length; i++) {
			this.updateButton(rng.commands._commands[i], event);
		}
	}
}

/**
 * Adds a button to the toolbar for the given command. Creates the button if necessary.
 * @param {mozile.edit.Command} command
 * @param {Event} event Optional. The current event object.
 * @type Void
 */
mozile.gui.htmlToolbar.updateButton = function(command, event) {
	if(command.button) {
		this.toolbar.appendChild(command.button.element);
	}
	else if(command.group || command.image) {
		var button = new mozile.gui.htmlToolbar.Button(command);
		this.toolbar.appendChild(button.element);
		this.toolbar.commands.push(command);
	}
	if(command.button) {
		this.toolbar.commands.push(command);
	}
}

/**
 * Update all the buttons on the toolbar.
 * @param {Event} event Optional. The current event object.
 * @param {String} change Optional. The type of change made. See mozile.edit.Command.respond for possible values.
 * @type Void
 */
mozile.gui.htmlToolbar.updateCommands = function(event, change) {
	if(!change || typeof(change) != "string") return;
	if(change == "none") return;
	for(var i=0; i < this.toolbar.commands.length; i++) {
		var command = this.toolbar.commands[i];
		if(command.respond(change)) {
			//mozile.debug.debug("mozile.gui.htmlToolbar.updateCommand", "Updating "+ command.name +" because of change "+ change);
			mozile.gui.htmlToolbar.updateCommand(command, event);
		}
	}
}

/**
 * Update the status of a command's button, if it has one.
 * @param {mozile.edit.Command} command
 * @param {Event} event Optional. The current event object.
 * @type Void
 */
mozile.gui.htmlToolbar.updateCommand = function(command, event) {
	if(command.button) {
		command.button.isAvailable(event);
		command.button.isActive(event);
	}
}

/**
 * Close all the menus belonging to the toolbar.
 * @type Void
 */
mozile.gui.htmlToolbar.closeMenus = function() {
	if(!this.toolbar.commands) return;
	for(var i=0; i < this.toolbar.commands.length; i++) {
		var button = this.toolbar.commands[i].button;
		if(button.menu && button.menu.opened) button.menu.close();
	}
}

/**
 * Displays the content string in a new window.
 * @param {String} content
 * @type Boolean
 */
mozile.gui.htmlToolbar.display = function(content) {
	var win = window.open("", "MozileDisplay", "");
	win.document.write(content);
}

/**
 * Makes sure that the toolbar is visible.
 * @type Boolean
 */
mozile.gui.htmlToolbar.show = function() {
	if(!mozile.gui.htmlToolbar.toolbar) mozile.gui.htmlToolbar.create();
	if(!mozile.gui.htmlToolbar.visible) {
		mozile.dom.setStyle(this.toolbar, "display", "block");
		mozile.gui.htmlToolbar.visible = true;

		// IE doesn't support CSS position: fixed
		// Mozilla's designMode disables window.setInterval
		if(mozile.browser.isIE || !mozile.useDesignMode) {
			mozile.gui.htmlToolbar.interval = window.setInterval("mozile.gui.htmlToolbar.reposition()", mozile.updateInterval);
		}
	}
	return mozile.gui.htmlToolbar.visible;
}

/**
 * Makes sure that the toolbar is not visible.
 * @type Boolean
 */
mozile.gui.htmlToolbar.hide = function() {
	if(mozile.gui.htmlToolbar.toolbar &&
		mozile.gui.htmlToolbar.visible) {
		mozile.dom.setStyle(this.toolbar, "display", "none");
		mozile.gui.htmlToolbar.visible = false;
		window.clearInterval(mozile.gui.htmlToolbar.interval);
	}
	return mozile.gui.htmlToolbar.visible;
}





/**
 * Creates a button for a command.
 * @constructor
 * @param {mozile.edit.Command} command
 */
mozile.gui.htmlToolbar.Button = function(command) {
	if(!command) return;
	/**
	 * The command that owns this button.
	 * @type mozile.edit.Command
	 */
	this.command = command;

	/**
	 * The type of this object.
	 * @type String
	 */
	this.type = "Button";

	/**
	 * The button or menu that this command belongs to, if any.
	 * @type mozile.edit.Command
	 */
	this.parent = null;

	/**
	 * The button's element.
	 * @type Element
	 */
	this.element = mozile.gui.htmlToolbar.createElement("span");
	this.element.setAttribute("class", "mozileButton");
	var press = function(event) { 
		var c = mozile.edit.getCommand(command.name); 
		if(c) c.button.press(event);
	}
	if(mozile.browser.isIE) this.element.onmouseup = press;
	else this.element.onclick = press;
	if(command.tooltip) this.element.setAttribute("title", command.tooltip);

	// Create the button's icon.
	this.image = mozile.gui.htmlToolbar.createImage(command.image);
	this.element.appendChild(this.image);
	
	// Create a pull down menu.
	if(command.group) {
		this.menu = new mozile.gui.htmlToolbar.Menu(command);
		this.menu.parent = this;
		this.element.appendChild(this.menu.element);
		var img = mozile.gui.htmlToolbar.createImage("arrow-down.gif");
		this.element.appendChild(img);
	}

	command.button = this;
}

/**
 * Activate the button.
 * @param {Event} event The event object which caused the button press.
 * @type Void
 */
mozile.gui.htmlToolbar.Button.prototype.press = function(event) {
	mozile.event.normalize(event);

	var opened = false;
	if(this.menu && this.menu.opened) opened = true;
	if(!this.parent) mozile.gui.htmlToolbar.closeMenus();
	if(this.menu) {
		if(opened) this.menu.close();
		else this.menu.open(event);
	}
	else {
		mozile.gui.htmlToolbar.closeMenus();
		var state = mozile.execCommand(this.command.name);
	}

	mozile.event.cancel(event);
}


/**
 * Get the position of the button.
 * @type Void
 */
mozile.gui.htmlToolbar.Button.prototype.getPosition = function() {
	var position = {
		x: mozile.dom.getX(this.element),
		y: mozile.dom.getY(this.element),
		width: this.element.offsetWidth,
		height: this.element.offsetHeight
	};
	//alert(mozile.util.dumpValues(position));
	return position;
}

/**
 * Determine if the command is available.
 * @param {Event} event Optional. The current event.
 * @type Boolean
 */
mozile.gui.htmlToolbar.Button.prototype.isAvailable = function(event) {
	var available = this.command.isAvailable(event);
	if(available == this.available) return available;
	this.element.setAttribute("available", available);
	if(mozile.browser.isIE && this.image) {
		if(available) this.image.style.cssText = "";
		else this.image.style.cssText = "filter:alpha(opacity=50)";
	}
	this.available = available;
	return available;
}

/**
 * Determine if the command is active. 
 * @param {Event} event Optional. The current event.
 * @type Boolean
 */
mozile.gui.htmlToolbar.Button.prototype.isActive = function(event) {
	var active = this.command.isActive(event);
	if(active == this.active) return active;
	this.element.setAttribute("active", active);
	if(mozile.browser.isIE && this.image) {
		if(active) {
			mozile.dom.setStyle(this.image, "border", mozile.gui.htmlToolbar.ieActiveBorder);
			mozile.dom.setStyle(this.image, "padding", mozile.gui.htmlToolbar.ieActivePadding);
		}
		else {
			mozile.dom.setStyle(this.image, "border", mozile.gui.htmlToolbar.ieBorder);
			mozile.dom.setStyle(this.image, "padding", mozile.gui.htmlToolbar.iePadding);
		}
	}
	this.active = active;
	return active;
}




/**
 * Creates a menu item for a command.
 * @constructor
 * @param {mozile.edit.Command} command
 */
mozile.gui.htmlToolbar.MenuItem = function(command) {
	if(!command) return;

	/**
	 * The command that owns this button.
	 * @type mozile.edit.Command
	 */
	this.command = command;

	/**
	 * The type of this object.
	 * @type String
	 */
	this.type = "MenuItem";

	/**
	 * The button or menu that this command belongs to, if any.
	 * @type mozile.edit.Command
	 */
	this.parent = null;

	/**
	 * The button's element.
	 * @type Element
	 */
	this.element = mozile.gui.htmlToolbar.createElement("tr");
	this.element.setAttribute("class", "mozileMenuItem");
	var press = function(event) { 
		var c = mozile.edit.getCommand(command.name); 
		if(c) c.menuItem.press(event);
	}
	if(mozile.browser.isIE) this.element.onmouseup = press;
	else this.element.onclick = press;
	if(command.tooltip) this.element.setAttribute("title", command.tooltip);
	
	this.cells = {};
	this.cells.active = mozile.gui.htmlToolbar.createElement("td");
	this.cells.icon = mozile.gui.htmlToolbar.createElement("td");
	this.cells.label = mozile.gui.htmlToolbar.createElement("td");
	this.cells.accel = mozile.gui.htmlToolbar.createElement("td");
	if(mozile.browser.isIE) {
		this.cells.active.className = "mozileActive";
		this.cells.icon.className = "mozileIcon";
		this.cells.label.className = "mozileLabel";
		this.cells.accel.className = "mozileAccel";
	}
	else {
		this.cells.active.setAttribute("class", "mozileActive");
		this.cells.icon.setAttribute("class", "mozileIcon");
		this.cells.label.setAttribute("class", "mozileLabel");
		this.cells.accel.setAttribute("class", "mozileAccel");
	}
	this.element.appendChild(this.cells.active);
	this.element.appendChild(this.cells.icon);
	this.element.appendChild(this.cells.label);
	this.element.appendChild(this.cells.accel);

	// Create the button's icon.
	if(command.image) {
		var img = mozile.gui.htmlToolbar.createImage(command.image);
		this.cells.icon.appendChild(img);
	}

	// Create the button's label.
	var name = command.name;
	if(command.label) name = command.label;
	this.cells.label.appendChild(document.createTextNode(name));
	
	// Create a submenu.
	if(command.group) {
		this.menu = new mozile.gui.htmlToolbar.Menu(command);
		this.menu.parent = this;
		this.element.appendChild(this.menu.element);
		img = mozile.gui.htmlToolbar.createImage("menu-arrow.gif");
		this.cells.accel.appendChild(img);
	}
	// Create an accelerator notification.
	else if(command.accel) {
		var accel = mozile.edit.parseAccelerator(command.accel);
		var span = mozile.gui.htmlToolbar.createElement("span");
		span.appendChild(document.createTextNode(accel.abbr));
		this.cells.accel.appendChild(span);
	}
	
	command.menuItem = this;
}
mozile.gui.htmlToolbar.MenuItem.prototype = new mozile.gui.htmlToolbar.Button;
mozile.gui.htmlToolbar.MenuItem.prototype.constructor = mozile.gui.htmlToolbar.MenuItem;


/**
 * Determine if the command is active. 
 * @param {Event} event Optional. The current event.
 * @type Boolean
 */
mozile.gui.htmlToolbar.MenuItem.prototype.isActive = function(event) {
	var active = this.command.isActive(event);
	if(active == this.active) return active;
	mozile.dom.removeChildNodes(this.cells.active);
	if(active) {
		//this.cells.active.appendChild(document.createTextNode(mozile.gui.htmlToolbar.checkmark));
		this.cells.active.appendChild(
			mozile.gui.htmlToolbar.createImage("silk/tick"));
	}
	this.active = active;
	return active;
}



/**
 * Creates a menu for a command group.
 * @constructor
 * @param {mozile.edit.Command} command
 */
mozile.gui.htmlToolbar.Menu = function(command) {
	if(!command) return;

	/**
	 * The command that owns this button.
	 * @type mozile.edit.Command
	 */
	this.command = command;

	/**
	 * The type of this object.
	 * @type String
	 */
	this.type = "Menu";

	/**
	 * The button or menu that this command belongs to, if any.
	 * @type mozile.edit.Command
	 */
	this.parent = null;

	/**
	 * The button's element.
	 * @type Element
	 */
	this.element = mozile.gui.htmlToolbar.createElement("table");
	this.element.setAttribute("class", "mozileMenu");
	this.element.setAttribute("cellspacing", "0px");
	mozile.dom.setStyle(this.element, "display", "none");
	// The tbody element is require for IE.
	var tbody = mozile.gui.htmlToolbar.createElement("tbody");
	this.element.appendChild(tbody);

	// TODO: Fix this IE CSS hack
	if(mozile.browser.isIE) {
		mozile.dom.setStyle(this.element, "background-color", mozile.gui.htmlToolbar.ieColor);
	}
	
	// Attach menu items.
	this.menuItems = new Array();
	for(var i=0; i < command._commands.length; i++) {
		var menuItem = new mozile.gui.htmlToolbar.MenuItem(command._commands[i]);
		if(menuItem) {
			this.menuItems.push(menuItem);
			menuItem.parent = this;
			tbody.appendChild(menuItem.element);
		}
	}

	/**
	 * Indicates that the menu is currently open.
	 * @type Boolean
	 */
	this.opened = false;
	
	command.menu = this;
}
mozile.gui.htmlToolbar.Menu.prototype = new mozile.gui.htmlToolbar.Button;
mozile.gui.htmlToolbar.Menu.prototype.constructor = mozile.gui.htmlToolbar.Menu;


/**
 * Open the menu. First the menu is moved into position, and then the CSS "display" property is set to "block".
 * @param {Event} event Optional. The current event.
 * @type Void
 */
mozile.gui.htmlToolbar.Menu.prototype.open = function(event) {
try{
	//mozile.debug.debug("mozile.gui.htmlToolbar.Menu.open", mozile.xpath.getXPath(this.element));
	this.reposition();
	mozile.dom.setStyle(this.element, "display", "block");
	this.opened = true;
	for(var i=0; i < this.menuItems.length; i++) {
		this.menuItems[i].isAvailable(event);
		this.menuItems[i].isActive(event);
	}
} catch(e) { alert(mozile.dumpError(e)); }
}

/**
 * Close the menu. The CSS "display" property is set to "none", so the menu is hidden. All open child menus are also closed.
 * @type Void
 */
mozile.gui.htmlToolbar.Menu.prototype.close = function() {
	mozile.dom.setStyle(this.element, "display", "none");
	this.opened = false;
	for(var i=0; i < this.menuItems.length; i++) {
		if(this.menuItems[i].menu && this.menuItems[i].menu.opened) {
			this.menuItems[i].menu.close();
		}
	}
}

/**
 * Move the menu into the proper position.
 * @type Void
 */
mozile.gui.htmlToolbar.Menu.prototype.reposition = function() {
	if(!this.parent) return;
	var left = 0;
	var top = 0;
	var position = this.parent.getPosition();

	// TODO: Fix these CSS hacks.
	if(mozile.browser.isIE) {
		mozile.dom.setStyle(this.element, "position", "absolute");
		mozile.dom.setStyle(this.element, "width", mozile.gui.htmlToolbar.ieMenuWidth);
		mozile.dom.setStyle(this.element, "border", mozile.gui.htmlToolbar.ieBorder);
		left = this.parent.element.offsetLeft;
		top = this.parent.element.offsetTop;
	}
	else {
		var width = this.element.clientWidth;
		mozile.dom.setStyle(this.element, "position", "fixed");
		mozile.debug.debug("", position.x +" + "+ width +" = "+ (position.x + width) +" ? "+ document.documentElement.clientWidth);
		if(position.x + width > document.documentElement.clientWidth) {
			left = document.documentElement.clientWidth - width;
		}
		else left = position.x;
		top = position.y;
	}

	if(this.parent.type == "Button") {
		top += position.height;
		// Browser dependant tweaking.
		//if(mozile.browser.isMozilla) top += 1;
	}
	else {
		left += position.width;
		// Browser dependant tweaking.
		//if(mozile.browser.isMozilla) left += 3;
	}

	mozile.dom.setStyle(this.element, "left", left +"px");
	mozile.dom.setStyle(this.element, "top", top +"px");
}



Documentation generated by JSDoc on Wed Feb 20 13:25:28 2008