dojoToolbar.js

Summary

Provides an HTML toolbar GUI using widgets from the Dojo toolkit: .

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

Author: James A. Overton


Class Summary
mozile.gui.dojoToolbar.Button  

/*
	Copyright 2007 jool.nl. All rights reserved.
*/

/**
 * @fileoverview Provides an HTML toolbar GUI using widgets from the Dojo toolkit: <http://dojotoolkit.org>.
 * @link http://mozile.mozdev.org 
 * @author James A. Overton <james@overton.ca>
 * @version 0.8
 * $Id: overview-summary-dojoToolbar.js.html,v 1.1 2008/02/20 18:47:09 jameso Exp $
 */

mozile.require("mozile.dom");
mozile.require("mozile.edit");
mozile.require("mozile.gui");
dojo.require("dojo.event.*");
mozile.provide("mozile.gui.dojoToolbar");


/**
 * A GUI factory which uses Dojo widgets, HTML, and CSS to display a toolbar.
 */
mozile.gui.dojoToolbar = new mozile.gui.Factory("DojoToolbarFactory");
// Set as the default factory.
mozile.gui.factory = mozile.gui.dojoToolbar;

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

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

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

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


/**** Global Methods ****/

/**
 * Creates the GUI.
 * This method sets up the module, while the createButtons() method creates the buttons.
 * @type Void
 */
mozile.gui.dojoToolbar.create = function() {
	if(this.created) return;
	
	var templatePath = mozile.joinPaths(mozile.root, "src", "gui", "templates", "dojoToolbar.html");
	mozile.dom.attachTemplate(templatePath, this);

	// Add style sheet
	var href = mozile.joinPaths(mozile.root, "src", "gui", "dojoToolbar.css");
	mozile.dom.addStyleSheet(href, "text/css");

	this.override();
	this.created = true;
}

/**
 * Destroys the GUI.
 * @type Void
 */
mozile.gui.dojoToolbar.destroy = function() {
	alert("Destroying GUI.");
}

/**
 * Updates the GUI using the current event.
 * @param {Event} event The current event.
 * @param {String} change Optional. The type of change made. See mozile.edit.Command.respond for possible values.
 * @type Boolean
 * @return True if the GUI has been updated, false otherwise.
 */
mozile.gui.dojoToolbar.update = function(event, change) {
	// Taken care of by the Mozile Editor widget for Dojo.
	var node = event.node;
	while(node) {
		if(node.widget) return node.widget.update(event, change);
		node = node.parentNode;
	}
	return true;
}

/**
 * Displays content is a general Dojo Dialog widget.
 * @param {String} content
 * @type Void
 */
mozile.gui.dojoToolbar.display = function(content) {
	if(!this.dialog) {
		this.dialog = dojo.widget.createWidget("Dialog");
		dojo.html.addClass(this.dialog.wrapper, "mozileDialog");
		mozile.dom.getBody().appendChild(this.dialog.domNode);
		this.dialog.containerNode.appendChild(this.displayNode);
		this.dialog.setCloseControl(this.displayOkButton);
	}
	mozile.dom.removeChildNodes(this.displayContent);
	this.displayContent.appendChild(document.createTextNode(content));
	this.dialog.show();
	return true;
}



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

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

/**
 * 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.dojoToolbar.about.execute = function(state, fresh) {
	// Create a new dialog if necessary.
	if(!this.dialog) {
		this.dialog = dojo.widget.createWidget("Dialog");
		dojo.html.addClass(this.dialog.wrapper, "mozileDialog");
		mozile.dom.getBody().appendChild(this.dialog.domNode);
		this.dialog.containerNode.appendChild(this.dialogNode);
		this.dialog.setCloseControl(this.okButton);
	}
	this.dialog.show();
	state.reversible = false;
	state.executed = true;
	return state;
}

/**
 * Display Mozile help information.
 * @type mozile.edit.Command
 */
mozile.gui.dojoToolbar.help = new mozile.edit.Command("help",
	mozile.gui.dojoToolbar.strings);

/**
 * Displays help information in a new window.
 * @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.dojoToolbar.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;
}

/**
 * Display a properties dialog for the current element.
 * @type mozile.edit.Command
 */
mozile.gui.dojoToolbar.properties = new mozile.edit.Command("properties",
	mozile.gui.dojoToolbar.strings);
mozile.gui.dojoToolbar.properties.target = "element";
mozile.gui.dojoToolbar.properties.direction = "ancestor";

/**
 * Creates a dialog with fields for all of the attributes available to this element.
 * @param {Event} event The event Optional. object to be converted into a state.
 * @param {Integer} direction Optional. The direction for the removal to use. Defaults to previous.
 * @param {String} content Optional. The content removed.
 * @type mozile.edit.State
 */
mozile.gui.dojoToolbar.properties.prepare = function(event) {
	var state = new mozile.edit.State(this);
	
	var target;
	if(event) target = event.target;
	if(!target && event) target = event.srcElement;
	if(!target) target = mozile.edit._getNode(event);
	if(!target || !target.nodeType) return false;
	if(target.nodeType != mozile.dom.ELEMENT_NODE) target = target.parentNode;
	if(!target || !target.nodeType) return false;
	state.targetNode = target;
	state.target = state.storeNode(target);
	
	var rng = mozile.schema.getNodes("element", target.nodeName.toLowerCase())[0];
	state.rng = rng;

	var attributes = state.rng.getDescendants("attribute", true);
	var table = mozile.dom.createElement("table");
	var tbody = table.appendChild(mozile.dom.createElement("tbody"));
	state.fields = [];
	for(var i=0; i < attributes.length; i++) {
		tbody.appendChild(this._generatePropertyField(state, attributes[i]));
	}
	if(target.nodeName.toLowerCase() == "select") {
		row = tbody.appendChild(mozile.dom.createElement("tr"));
		cell = row.appendChild(mozile.dom.createElement("td"));
		cell.setAttribute("colSpan", 2);
		this.optionTable = cell.appendChild(mozile.dom.createElement("table"));
		row = this.optionTable.insertRow(0);
		cell = row.insertCell(0);
		cell.appendChild(document.createTextNode(
			mozile.gui.dojoToolbar.strings["nameLabel"]));
		cell = row.insertCell(1);
		cell.appendChild(document.createTextNode(
			mozile.gui.dojoToolbar.strings["valueLabel"]));
		cell = row.insertCell(2);
		cell.appendChild(document.createTextNode(
			mozile.gui.dojoToolbar.strings["selectedLabel"]));
		var options = target.options;
		for(i=0; i < options.length; i++) {
			row = this._generateOptionField(state, options[i]);
			this.optionTable.tBodies[0].appendChild(row);
		}
	}
	else this.optionTable = null;

	// Create a new dialog if necessary.
	if(!this.dialog) {
		this.dialog = dojo.widget.createWidget("Dialog");
		dojo.html.addClass(this.dialog.wrapper, "mozileDialog");
		mozile.dom.getBody().appendChild(this.dialog.domNode);
		this.dialog.containerNode.appendChild(this.dialogNode);
		this.dialog.setCloseControl(this.cancelButton);
		this.dialog.setCloseControl(this.okButton);
	}
	mozile.dom.removeChildNodes(this.container);
	this.container.appendChild(table);
	this.dialog.show();
	this.state = state;
	
	state.dialogReturned = false;
	return state;
}

/**
 * Makes changes to the target element based on the data entered in the properties dialog.
 * @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.dojoToolbar.properties.execute = function(state, fresh) {
	if(!state.dialogReturned) return state;
	var selection = mozile.dom.selection.get();
	if(!fresh) selection.restore(state.selection.before);
	state.actions = new Array();

	// Update any changed attributes.
	var target = mozile.xpath.getNode(state.target);
	var field;
	var content = [];
	for(var i=0; i < state.fields.length; i++) {
		field = state.fields[i];
		newValue = field.object[field.property];
		if(newValue == field.value) continue;
		mozile.edit.setAttribute.request(state, fresh, target, field.name, newValue);
	}

	// Update the options which belong to a "select" element.	
	if(this.optionTable) {
		var rows = this.optionTable.rows;
		var name, value, selected, option;
		for(i=1; i < rows.length; i++) {
			name = rows[i].cells[0].firstChild.value;
			value = rows[i].cells[1].firstChild.value;
			selected = rows[i].cells[2].firstChild.checked;
			// Change an exisitng option.
			if(i-1 < target.options.length) {
				option = target.options[i-1];
				if(option.value != value) {
					mozile.edit.setAttribute.request(
						state, fresh, option, "value", value);
				}
				if(option.selected != selected) {
					mozile.edit.setAttribute.request(
						state, fresh, option, "selected", selected);
				}
				if(option.childNodes.length != 1 ||
					option.firstChild.nodeType != mozile.dom.textNode ||
					option.firstChild.data != name) {
					while(option.childNodes.length) {
						mozile.edit.removeNode.request(state, fresh, option.firstChild);
					}
					var text = document.createTextNode(name);
					mozile.edit.insertNode.request(state, fresh, option, null, text);
				}
			}
			// Create a new option.
			else {
				option = target.appendChild(mozile.dom.createElement("option"));
				option.setAttribute("value", value);
				if(selected) option.setAttribute("selected", true);
				option.appendChild(document.createTextNode(name));
			}
		}
		// Remove extra options.
		while(target.options.length > i-1) {
			mozile.edit.removeNode.request(state, fresh, target.options[i-1]);
		}
	}
	
	state.selection.after = selection.store();
	state.executed = true;
	return state;
}

/**
 * Hide the properties dialog and execute any changes.
 * @private
 * @type Boolean
 */
mozile.gui.dojoToolbar.properties._hideProperties = function() {
	if(!this.state) return false;

	// Fix a focus problem.
	if(mozile.browser.isIE) {
		var target = mozile.xpath.getNode(this.state.target);
		var container = mozile.edit.getContainer(target);
		mozile.dom.focus(container);
	}

	// Restore the selection, execute the command, and store the result.
	var selection = mozile.dom.selection.get();
	selection.restore();
	this.state.dialogReturned = true;
	var state = this.execute(this.state, false);
	mozile.edit.done(state);

	return true;
}



/**
 * Create a field for editing a particular attribute of the target element.
 * @private
 * @param {mozile.edit.State} state The state object used to store the attribute's old value.
 * @param {mozile.rng.Attribute} attribute The RNG attribute element corresponding to this attribute.
 * @type Element
 */
mozile.gui.dojoToolbar.properties._generatePropertyField = function(state, attribute) {
	var row = mozile.dom.createElement("tr");
	var cell = row.appendChild(mozile.dom.createElement("td"));
	cell.setAttribute("align", "right");
	cell.appendChild(document.createTextNode(attribute.getName()));
	cell = row.appendChild(mozile.dom.createElement("td"));

	var node = state.targetNode;
	
	var type = null;
	var data = attribute.getDescendants("data", true);
	if(data.length) type = data[0].getDataType();
	else {
		var values = attribute.getDescendants("value", true);
		if(values.length) type = "choice";
	}
	//alert(attribute.getName() +" "+ type);
	var name = attribute.getName();
	var object, property, value;
	switch(type) {
		case "boolean":
			object = cell.appendChild(mozile.dom.createElement("input"));
			object.setAttribute("type", "checkbox");
			property = "checked";
			value = Boolean(node.getAttribute(name));
			object.checked = value;
			break;
		case "choice":
			var select = cell.appendChild(mozile.dom.createElement("select"));
			var option, value;
			// Add a null option.
			if(values.length < 2)
				values.unshift({getValue: function() {return ""}});
			// Create a list of options.
			for(var i=0; i < values.length; i++) {
				value = values[i].getValue();
				option = select.appendChild(mozile.dom.createElement("option"));
				option.setAttribute("value", value);
				option.appendChild(document.createTextNode(value));
			}
			object = select;
			property = "value";
			value = node[name] || node.getAttribute(name) || "";
			object.value = value;
			break;
		default:
			object = cell.appendChild(mozile.dom.createElement("input"));
			object.setAttribute("type", "text");
			property = "value";
			value = node[name] || node.getAttribute(name) || "";
			object.value = value;
			break;
	}
	
	state.fields.push({
		attribute: attribute,
		name: name,
		value: value,
		object: object,
		property: property
	});
	
	return row;
};


/**
 * Create a row for editing a particular HTML option element.
 * @private
 * @param {mozile.edit.State} state The state object used to store the attribute's old value.
 * @param {Element} option Optional. The HTML option element to use.
 * @type Element
 */
mozile.gui.dojoToolbar.properties._generateOptionField = function(state, option) {
	var row = mozile.dom.createElement("tr");
	var cell = row.appendChild(mozile.dom.createElement("td"));
	var input = cell.appendChild(mozile.dom.createElement("input"));
	input.setAttribute("type", "text");
	if(option) input.value = option.text;

	cell = row.appendChild(mozile.dom.createElement("td"));
	input = cell.appendChild(mozile.dom.createElement("input"));
	input.setAttribute("type", "text");
	if(option) input.value = option.value;

	cell = row.appendChild(mozile.dom.createElement("td"));
	cell.setAttribute("align", "center");
	input = cell.appendChild(mozile.dom.createElement("input"));
	input.setAttribute("type", "checkbox");
	if(option) input.checked = option.selected;

	cell = row.appendChild(mozile.dom.createElement("td"));
	cell.setAttribute("align", "center");
	input = cell.appendChild(mozile.dom.createElement("input"));
	input.setAttribute("type", "button");
	input.value = "-";
	input.onclick = this._removeOption;

	cell = row.appendChild(mozile.dom.createElement("td"));
	cell.setAttribute("align", "center");
	input = cell.appendChild(mozile.dom.createElement("input"));
	input.setAttribute("type", "button");
	input.value = "+";
	input.onclick = this._addOption;
	
	return row;
}

/**
 * Add a row for editing a new option to the properties dialog.
 * @private
 * @param {Event} event The event that triggered this method, used to find the target row.
 * @type Boolean
 */
mozile.gui.dojoToolbar.properties._addOption = function(event) {
	if(!event) return false;
	var target = event.target;
	if(!target) target = event.srcElement;
	if(!target) return false;
	while(target) {
		if(target.nodeName.toLowerCase() == "tr") break;
		target = target.parentNode;
	}
	
	var row = mozile.gui.dojoToolbar.properties._generateOptionField();
	mozile.dom.insertAfter(row, target);
	
	return true;
}

/**
 * Remove an option editing row from the properties dialog.
 * @private
 * @param {Event} event The event that triggered this method, used to find the target row.
 * @type Boolean
 */
mozile.gui.dojoToolbar.properties._removeOption = function(event) {
	if(!event) return false;
	var target = event.target;
	if(!target) target = event.srcElement;
	if(!target) return false;
	while(target) {
		if(target.nodeName.toLowerCase() == "tr") break;
		target = target.parentNode;
	}

	target.parentNode.removeChild(target);
	
	return true;
}


/**
 * Find and replace text.
 * @type mozile.edit.Command
 */
mozile.gui.dojoToolbar.findReplace = new mozile.edit.Command("findReplace",
	mozile.gui.dojoToolbar.strings);

/**
 * Display a find and replace dialog.
 * @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.dojoToolbar.findReplace.execute = function(state, fresh) {
	// Create a new dialog if necessary.
	if(!this.dialog) {
		this.dialog = dojo.widget.createWidget("Dialog");
		dojo.html.addClass(this.dialog.wrapper, "mozileDialog");
		mozile.dom.getBody().appendChild(this.dialog.domNode);
		this.dialog.containerNode.appendChild(this.dialogNode);
		this.dialog.setCloseControl(this.okButton);
	}
	this.dialog.show();
	state.reversible = false;
	state.executed = true;
	return state;
}

/**
 * Replace all instances of the given text with the given replacement.
 * @private
 * @type Boolean
 */
mozile.gui.dojoToolbar.findReplace._replaceAll = function() {
	// Fix a focus problem.
	if(mozile.browser.isIE && mozile.dom.selection.last) {
		var container = mozile.edit.getContainer(mozile.dom.selection.last.anchorNode);
		mozile.dom.focus(container);
	}

	mozile.execCommand("replaceText", this.findField.value, this.replaceField.value, this.ignoreCaseCheck.checked, this.wrapCheck.checked);
    this.findField.focus();
    return true;
}

/**
 * Replace one instance of the given text with the given replacement.
 * @private
 * @type Boolean
 */
mozile.gui.dojoToolbar.findReplace._replace = function() {
	// Fix a focus problem.
	if(mozile.browser.isIE && mozile.dom.selection.last) {
		var container = mozile.edit.getContainer(mozile.dom.selection.last.anchorNode);
		mozile.dom.focus(container);
	}

	var selection = mozile.dom.selection.get();
	selection.restore();

	if(selection.toString() != this.findField.value) return;
	mozile.execCommand("insertText", null, this.replaceField.value);
	return true;
}

/**
 * Replace one instance of the given text with the given replacement, then find the next one.
 * @private
 * @type Boolean
 */
mozile.gui.dojoToolbar.findReplace._replaceAndFind = function() {
	this._replace();
	this._next();
	return true;
}

/**
 * Find the next instance of the given text.
 * @private
 * @type Boolean
 */
mozile.gui.dojoToolbar.findReplace._next = function() {
	return this._seek(mozile.edit.NEXT);
}

/**
 * Find the previous instance of the given text.
 * @private
 * @type Boolean
 */
mozile.gui.dojoToolbar.findReplace._previous = function() {
	return this._seek(mozile.edit.PREVIOUS);
}

/**
 * Find the next or previous instance of the given text.
 * @private
 * @param {Integer} direction 1 indicates next, -1 indicates previous.
 * @type Boolean
 */
mozile.gui.dojoToolbar.findReplace._seek = function(direction) {
	// Fix a focus problem.
	if(mozile.browser.isIE && mozile.dom.selection.last) {
		var container = mozile.edit.getContainer(mozile.dom.selection.last.anchorNode);
		mozile.dom.focus(container);
	}

	mozile.execCommand("findText", this.findField.value, direction, this.ignoreCaseCheck.checked, this.wrapCheck.checked);
	return true;
}


/**
 * Add and remove style-sheets from the page.
 * @type mozile.edit.Command
 */
mozile.gui.dojoToolbar.styles = new mozile.edit.Command("styles",
	mozile.gui.dojoToolbar.strings);

/**
 * Display a dialog showing all of the stylesheets attached to a page.
 * @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.dojoToolbar.styles.execute = function(state, fresh) {
	// Create a new dialog if necessary.
	if(!this.dialog) {
		this.dialog = dojo.widget.createWidget("Dialog");
		dojo.html.addClass(this.dialog.wrapper, "mozileDialog");
		mozile.dom.getBody().appendChild(this.dialog.domNode);
		this.dialog.containerNode.appendChild(this.dialogNode);
		this.dialog.setCloseControl(this.okButton);
	}

	var links = mozile.dom.getElements("local name", "link");
	mozile.dom.removeChildNodes(this.stylesheetsList);
	var option, href;
	for(var i=0; i < links.length; i++) {
		if(!links[i].getAttribute("rel") ||
			links[i].getAttribute("rel").toLowerCase() != "stylesheet")
			continue;
		href = links[i].getAttribute("href");
		if(!href) continue;
		option = mozile.dom.createElement("option");
		option.setAttribute("value", href);
		option.appendChild(document.createTextNode(href));
		this.stylesheetsList.appendChild(option);
	}

	this.dialog.show();
	state.reversible = false;
	state.executed = true;
	return state;
}

/**
 * Remove the selected stylesheet from the document.
 * @private
 * @type Boolean
 */
mozile.gui.dojoToolbar.styles._remove = function() {
	var links = mozile.dom.getElements("local name", "link");
	var options = this.stylesheetsList.childNodes;
	var i, j, href;
	var state = new mozile.edit.State(mozile.edit.executionGroup);
	for(i=0; i < options.length; i++) {
		if(!options[i].selected) continue;
		href = options[i].value;
		for(j=0; j < links.length; j++) {
			if(links[j].getAttribute("href") != href) continue;
			mozile.edit.removeNode.request(state, false, links[j]);
			links.splice(j, 1);
			j--;
		}
		options[i].parentNode.removeChild(options[i]);
	}
	mozile.edit.done(state);
	return true;
}

/**
 * Add the given selected stylesheet to the document.
 * @private
 * @type Boolean
 */
mozile.gui.dojoToolbar.styles._add = function() {
	var href = this.addField.value;
	var element = mozile.dom.createElement("link");
	element.setAttribute("rel", "stylesheet");
	element.setAttribute("type", "text/css");
	element.setAttribute("href", href);

	var state = new mozile.edit.State(mozile.edit.executionGroup);
	var head = mozile.dom.getHead();
	mozile.edit.insertNode.request(state, false, head, head.lastChild, element);
	mozile.edit.done(state);

	var option = mozile.dom.createElement("option");
	option.setAttribute("value", href);
	option.appendChild(document.createTextNode(href));
	this.stylesheetsList.appendChild(option);

	return true;
}


/**
 * Display special characters.
 * @type mozile.edit.Command
 */
mozile.gui.dojoToolbar.specialCharacters = new mozile.edit.Command("specialCharacters", mozile.gui.dojoToolbar.strings);
mozile.gui.dojoToolbar.specialCharacters.group = true;

// A grouped list of all the special characters to display.
mozile.gui.dojoToolbar.specialCharacters.data = [
	{name:"Currency", characters:[169,174,36,162,163,8364,402,165,164]},
	{name:"Punctuation", characters:[176,8216,8217,8220,8221,171,187,8230,161,191,166,167,182]},
	{name:"Numbers", characters:[188,189,190,185,178,179,960]},
	{name:"Math", characters:[215,247,183,8730,8733,8734,177,8773,8776,8800,8804,8805,8756,8747]},
	{name:"Arrows", characters:[8592,8593,8594,8595,8596,8656,8657,8658,8659,8660]},
	{name:"Accents", characters:[192,193,194,195,196,197,198,199,200,201,202,203,204,205,206,207,208,209,210,211,212,213,214,216,338,352,217,218,219,220,221,222,376,223,
	224,225,226,227,228,229,230,231,232,233,234,235,236,237,238,239,240,241,242,243,244,245,246,248,339,353,249,250,251,252,253,254,255]},
	{name:"Greek", characters:[913,914,915,916,917,918,919,920,921,922,923,924,925,926,927,928,929,931,932,933,934,935,936,937,
	945,946,947,948,949,950,951,952,953,954,955,956,957,958,959,960,961,963,962,964,965,966,967,968,969,
	977,978,982]}
]


/**
 * Displays a special characters dialog.
 * @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.dojoToolbar.specialCharacters.execute = function(state, fresh) {
	// Create a new dialog if necessary.
	if(!this.popup) {
		this.popup = dojo.widget.createWidget("PopupContainer");
		dojo.html.addClass(this.dialogNode, "mozilePopup");
		this.popup.domNode.appendChild(this.dialogNode);
		
		var option;
		for(var i=0; i < this.data.length; i++) {
			option = mozile.dom.createElement("option");
			option.setAttribute("value", this.data[i].name);
			option.appendChild(document.createTextNode(this.data[i].name));
			this.characterSetList.appendChild(option);
		}
		
		this.characterSetList.value = this.data[0].name;
		this._selectSet();
	}

	if(this.popup.isShowingNow) this.popup.close();
	else this.popup.open(this.button.element, null, this.button.element);
	state.reversible = false;
	state.executed = true;
	return state;
}


/**
 * Select one or more sets of special characters to display.
 * @private
 * @type Boolean
 */
mozile.gui.dojoToolbar.specialCharacters._selectSet = function() {
	var i, j, header, table, characters, rows, row, cells, cell, target;
	var options = this.characterSetList.options;
	var table = this.characterTable;
	mozile.dom.removeChildNodes(table);
	rows = 0;
	for(i=0; i < options.length; i++) {
		if(!options[i].selected) continue;
		characters = this.data[i].characters;
		for(j=0; j < characters.length; j++) {
			if(j % 10 == 0) {
				row = table.insertRow(rows++);
				cells = 0;
			}
			cell = row.insertCell(cells++);
			if(!target) target = cell;
			cell.appendChild(document.createTextNode(String.fromCharCode(characters[j])));
		}
	}
	this._select({target: target});
	return true;
}

/**
 * Select a particular special character.
 * @private
 * @type Boolean
 */
mozile.gui.dojoToolbar.specialCharacters._select = function(event) {
	if(!event) return false;
	if(!event.target) event.target = event.srcElement;
	if(!event.target || !event.target.innerHTML) return false;
	var character = event.target.innerHTML;
	character = character.charAt(0);
	if(!character) return false;
	//if(character == this.selectedCharacter.innerHTML)
	//	return this._insertThis(event);
	this.selectedCharacter.innerHTML = character;
	this.selectedNumber.value = character.charCodeAt(0);
	return true;
}

/**
 * Update the special character preview.
 * @private
 * @type Boolean
 */
mozile.gui.dojoToolbar.specialCharacters._update = function() {
	var value = this.selectedNumber.value;
	var character = "";
	if(value && String.fromCharCode(value)) character = String.fromCharCode(value);
	this.selectedCharacter.innerHTML = character;
	return true;
}

/**
 * Insert the selected special character.
 * @private
 * @type Boolean
 */
mozile.gui.dojoToolbar.specialCharacters._insert = function() {
	// Fix a focus problem.
	if(mozile.browser.isIE && mozile.dom.selection.last) {
		var container = mozile.edit.getContainer(mozile.dom.selection.last.anchorNode);
		mozile.dom.focus(container);
	}

	var character = String.fromCharCode(this.selectedNumber.value);
	if(!character) return false;
	mozile.execCommand("insertText", null, character);
	var selection = mozile.dom.selection.get();
	selection.collapseToEnd();
	return true;
}

/**
 * Select and insert a special character, then close the dialog.
 * @private
 * @type Boolean
 */
mozile.gui.dojoToolbar.specialCharacters._insertThis = function(event) {
	//this._select(event);
	this._insert(event);
	this.popup.close();
}


/**
 * Embed a Flash movie into the document
 * @type mozile.edit.Command
 */
mozile.gui.dojoToolbar.embedFlash = new mozile.edit.Insert("embedFlash",
	mozile.gui.dojoToolbar.strings);

/**
 * Creates a dialog with fields for all of the attributes available to this element.
 * @param {Event} event The event Optional. object to be converted into a state.
 * @param {Integer} direction Optional. The direction for the removal to use. Defaults to previous.
 * @param {String} content Optional. The content removed.
 * @type mozile.edit.State
 */
mozile.gui.dojoToolbar.embedFlash.prepare = function(event) {
	var state = new mozile.edit.State(this);

	// Create a new dialog if necessary.
	if(!this.dialog) {
		this.dialog = dojo.widget.createWidget("Dialog");
		dojo.html.addClass(this.dialog.wrapper, "mozileDialog");
		mozile.dom.getBody().appendChild(this.dialog.domNode);
		this.dialog.containerNode.appendChild(this.dialogNode);
		this.dialog.setCloseControl(this.cancelButton);
		this.dialog.setCloseControl(this.okButton);
	}
	this.dialog.show();
	this.state = state;
	
	state.delayExecution = true;
	return state;
}

/**
 * Create a new element for insertion, then execute the command.
 * @type Boolean
 */
mozile.gui.dojoToolbar.embedFlash._postPrepare = function() {
	this.state.source = this.sourceField.value;
	this.state.id = this.idField.value;
	this.state.quality = this.qualityList.value;
	this.state.width = this.widthField.value;
	this.state.height = this.heightField.value;
	this.state.bgcolor = this.bgcolorField.value;
	var templatePath = [mozile.root, "src", "gui", "templates", "embedFlash.html"].join(mozile.filesep);
	this.state.element = mozile.dom.attachTemplate(templatePath, this.state);
	this.state.delayExecution = false;
	this.execute(this.state, false);
	mozile.edit.done(this.state);
	return true;
}


/**
 * Groups togther commands into the main Mozile menu.
 * @type mozile.edit.Command
 */
mozile.gui.dojoToolbar.mainMenu = new mozile.edit.CommandGroup("mainMenu",
	mozile.gui.dojoToolbar.strings);
mozile.gui.dojoToolbar.mainMenu.addCommand(mozile.gui.dojoToolbar.about);
mozile.gui.dojoToolbar.mainMenu.addCommand(mozile.gui.dojoToolbar.help);
mozile.edit.commands.addCommand(mozile.gui.dojoToolbar.findReplace);
mozile.edit.commands.addCommand(mozile.gui.dojoToolbar.properties);
mozile.edit.commands.addCommand(mozile.gui.dojoToolbar.specialCharacters);

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



/**** Local Methods ****/

/**
 * 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.dojoToolbar.createImage = function(name) {
	if(!name || typeof(name) != "string") return null;

	var filetype = ".png";
	if(name.indexOf(".") > -1) filetype = "";
	var src = [mozile.root, "images", name + filetype].join(mozile.filesep);
	var img;
	
	// 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.dojoToolbar.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.dojoToolbar.createImage", img.style.cssText);
	}
	else {
		img = mozile.dom.createElement("img");
		img.setAttribute("src", src);
	}

	return img;
}

/**
 * Create a set of buttons and attach them to the given toolbar element. Return an array of the new buttons.
 * @type Array
 */
mozile.gui.dojoToolbar.createButtons = function(toolbar) {
	mozile.dom.removeChildNodes(toolbar);
	var buttons = new Array();
	var command, button;
	var i=0;

	// GUI commands
	for(i=0; i < mozile.gui.dojoToolbar._commands.length; i++) {
		command = mozile.gui.dojoToolbar._commands[i];
		if(command.group || command.image) {
			button = new mozile.gui.dojoToolbar.Button(command);
			buttons.push(button);
			toolbar.appendChild(button.element);
		}
	}	
	toolbar.appendChild(document.createTextNode("|"));

	// Global commands
	for(i=0; i < mozile.edit.commands._commands.length; i++) {
		command = mozile.edit.commands._commands[i];
		if(command.group || command.image) {
			button = new mozile.gui.dojoToolbar.Button(command);
			buttons.push(button);
			toolbar.appendChild(button.element);
		}
	}

	// Context commands
	// NOTE: The command for the "P" element are used, which won't be 
	// appropriate in all cases.
	var rng = mozile.schema.getNodes("element", "p")[0];
	if(rng && rng.commands && rng.commands._commands && 
		rng.commands._commands.length) {
		toolbar.appendChild(document.createTextNode("|"));
		for(i=0; i < rng.commands._commands.length; i++) {
			command = rng.commands._commands[i];
			if(command.group || command.image) {
				button = new mozile.gui.dojoToolbar.Button(command);
				buttons.push(button);
				toolbar.appendChild(button.element);
			}
		}
	}

	return buttons;
}


/**
 * Creates a button for a command.
 * @constructor
 * @param {mozile.edit.Command} command
 */
mozile.gui.dojoToolbar.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.dom.createElement("span");
	this.element.setAttribute("class", "mozileButton");
	if(command.tooltip) this.element.setAttribute("title", command.tooltip);

	// Create the button's icon.
	this.image = mozile.gui.dojoToolbar.createImage(command.image);
	this.element.appendChild(this.image);
	
	// Create a pull down menu.
	if(command.group) {
		var img = mozile.gui.dojoToolbar.createImage("arrow-down.gif");
		this.element.appendChild(img);
	}
	
	if(command._commands) {
		this.menu = dojo.widget.createWidget("PopupMenu2");
		dojo.html.addClass(this.menu.domNode, "mozileMenu");
		this.menu.bindDomNode(this.element);
		this.menu.onItemClick = function(item) { mozile.execCommand(item.commandName) };
		
		// Attach menu items.
		var thisCommand, commandString, menuItem;
		for(var i=0; i < command._commands.length; i++) {
			thisCommand = command._commands[i];
			image = null;
			if(thisCommand.image) image = [mozile.root, "images", thisCommand.image + ".png"].join(mozile.filesep);
			menuItem = dojo.widget.createWidget("MenuItem2", {caption: thisCommand.label, iconSrc: image});
			menuItem.commandName = thisCommand.name;
			this.menu.addChild(menuItem);
		}
	}

	dojo.event.connect(this.element, "onmousedown", this, "onMouseDown");
	dojo.event.connect(this.element, "onclick", this, "onClick");

	command.button = this;
}

mozile.gui.dojoToolbar.Button.prototype.onMouseDown = function(event) {
	mozile.gui.dojoToolbar.lastStatus = mozile.edit.status;
}

/**
 * Click the button.
 * @param {Event} event The event object which caused the button press.
 * @type Void
 */
mozile.gui.dojoToolbar.Button.prototype.onClick = function(event) {
	this.command.button = this;

	if(this.menu) {
		if(this.menu.isShowingNow) this.menu.close();
		else this.menu.open(this.element, null, this.element);
		return true;
	}

	if(!mozile.gui.dojoToolbar.lastStatus) return false;
	mozile.execCommand(this.command.name);
	mozile.event.cancel(event);


	return true;
}

/**
 * Determine if the command is available.
 * @param {Event} event Optional. The current event.
 * @type Boolean
 */
mozile.gui.dojoToolbar.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.dojoToolbar.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.dojoToolbar.ieActiveBorder);
			mozile.dom.setStyle(this.image, "padding", mozile.gui.dojoToolbar.ieActivePadding);
		}
		else {
			mozile.dom.setStyle(this.image, "border", mozile.gui.dojoToolbar.ieBorder);
			mozile.dom.setStyle(this.image, "padding", mozile.gui.dojoToolbar.iePadding);
		}
	}
	this.active = active;
	return active;
}



/**
 * Override basic commands with some special features.
 * @type Void
 */
mozile.gui.dojoToolbar.override = function() {
	if(this.overridden) return;

	var p = mozile.schema.getNodes("element", "p")[0];

	// Move the removeFormatting command.
	var removeFormatting = mozile.edit.getCommand("removeFormatting");
	var subscript = mozile.edit.getCommand("subscript");
	p.commands.addCommand(removeFormatting, subscript);

	// Override the source command's execute method.
	mozile.edit.source.execute = function(state, fresh) {
	try {
		var selection = mozile.dom.selection.get();
		if(!fresh) selection.restore(state.selection.before);

		var node = selection.anchorNode;
		while(node) {
			if(node.widget) break;
			node = node.parentNode;
		}
		if(node && node.widget) {
			mozile.gui.dojoToolbar.display(node.widget.getValue());
		}
	} catch(e) { alert(mozile.dumpError(e)); }
		state.reversible = false;
		state.executed = true;
		return state;
	}

	// Override the textColor command and create a Dojo ColorPicker.
	var textColor = mozile.edit.getCommand("textColor");
	textColor.prototype = new mozile.edit.Command;
	textColor._commands = null;
	new mozile.gui.dojoToolbar.Button(textColor);
	textColor.popup = dojo.widget.createWidget("PopupContainer");
	textColor.button.element.appendChild(textColor.popup.domNode);
	textColor.palette = dojo.widget.createWidget("dojo:ColorPalette",
		{palette:"7x10"});
	dojo.event.connect(textColor.palette, "onColorSelect", textColor, "_pickColor");
	textColor.popup.domNode.appendChild(textColor.palette.domNode);
	textColor.execute = function(state, fresh) {
		if(this.popup.isShowingNow) this.popup.close();
		else this.popup.open(this.button.element, null, this.button.element);
		state.reversible = false;
		state.executed = true;
		return state;
	}
	textColor.setTextColor = new mozile.edit.Wrap("setTextColor");
	textColor.setTextColor.nested = true;
	textColor.setTextColor.element = mozile.dom.createElement("span")
	textColor._pickColor = function(color) {
		this.popup.close();
		textColor.setTextColor.element.setAttribute("style", "color:"+color);
		mozile.execCommand("setTextColor");
	}
	
	// Override the backgroundColor command and create a Dojo ColorPicker.
	var backgroundColor = mozile.edit.getCommand("backgroundColor");
	backgroundColor.prototype = new mozile.edit.Command;
	backgroundColor._commands = null;
	new mozile.gui.dojoToolbar.Button(backgroundColor);
	backgroundColor.popup = dojo.widget.createWidget("PopupContainer");
	backgroundColor.button.element.appendChild(backgroundColor.popup.domNode);
	backgroundColor.palette = dojo.widget.createWidget("dojo:ColorPalette",
		{palette:"7x10"});
	dojo.event.connect(backgroundColor.palette, "onColorSelect", backgroundColor, "_pickColor");
	backgroundColor.popup.domNode.appendChild(backgroundColor.palette.domNode);
	backgroundColor.execute = function(state, fresh) {
		if(this.popup.isShowingNow) this.popup.close();
		else this.popup.open(this.button.element, null, this.button.element);
		state.reversible = false;
		state.executed = true;
		return state;
	}
	backgroundColor.setBackgroundColor = new mozile.edit.Wrap("setBackgroundColor");
	backgroundColor.setBackgroundColor.nested = true;
	backgroundColor.setBackgroundColor.element = mozile.dom.createElement("span")
	backgroundColor._pickColor = function(color) {
		this.popup.close();
		backgroundColor.setBackgroundColor.element.setAttribute("style", "background-color:"+color);
		mozile.execCommand("setBackgroundColor");
	}
	
	// Add the styles and embedFlash commands to insertion command group.
	var insertion = mozile.edit.getCommand("insertion");
	var image = mozile.edit.getCommand("image");
	insertion.addCommand(mozile.gui.dojoToolbar.styles, image);
	insertion.addCommand(mozile.gui.dojoToolbar.embedFlash, image);

	// Add a new indent command to handle both blocks and lists.
	var indentAny = new mozile.edit.Command("indentAny");
	var indent = mozile.edit.getCommand("indent");
	indentAny.label = indent.label;
	indentAny.tooltip = indent.tooltip;
	indentAny.image = indent.image;
	indent.image = null;
	p.commands.addCommand(indentAny, indent);

	indentAny.prepare = function(event) {
		var state = new mozile.edit.State(this);
		var block = mozile.edit._getTarget(event, "block", "ancestor");
		if(block && block.nodeName && block.nodeName.toLowerCase() == "li")
			state.useCommand = mozile.edit.getCommand("indentList");
		else state.useCommand = mozile.edit.getCommand("indent");
		return state;
	}
	indentAny.execute = function(state, fresh) {
		//return mozile.execCommand(state.useCommand.name);
		var selection = mozile.dom.selection.get();
		if(!fresh) selection.restore(state.selection.before);
		state.actions = new Array();
		state.useCommand.request(state, fresh);
		state.selection.after = selection.store();
		state.executed = true;
		return state;
	}

	// Add a new unindent command to handle both blocks and lists.
	var unindentAny = new mozile.edit.Command("unindentAny");
	var unindent = mozile.edit.getCommand("unindent");
	unindentAny.label = unindent.label;
	unindentAny.tooltip = unindent.tooltip;
	unindentAny.image = unindent.image;
	unindent.image = null;
	p.commands.addCommand(unindentAny, unindent);

	unindentAny.prepare = function(event) {
		var state = new mozile.edit.State(this);
		var block = mozile.edit._getTarget(event, "block", "ancestor");
		if(block && block.nodeName && block.nodeName.toLowerCase() == "li")
			state.useCommand = mozile.edit.getCommand("unindentList");
		else state.useCommand = mozile.edit.getCommand("unindent");
		return state;
	}
	unindentAny.execute = function(state, fresh) {
		//return mozile.execCommand(state.useCommand.name);
		var selection = mozile.dom.selection.get();
		if(!fresh) selection.restore(state.selection.before);
		state.actions = new Array();
		state.useCommand.request(state, fresh);
		state.selection.after = selection.store();
		state.executed = true;
		return state;
	}

	this.overridden = true;
}








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