You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@myfaces.apache.org by sv...@apache.org on 2006/11/10 10:15:40 UTC

svn commit: r473277 [31/45] - in /myfaces/tomahawk/trunk/core/src/main/resources/org/apache/myfaces/custom/dojo/resource: ./ src/ src/animation/ src/cal/ src/charting/ src/charting/svg/ src/charting/vml/ src/collections/ src/crypto/ src/data/ src/data/...

Propchange: myfaces/tomahawk/trunk/core/src/main/resources/org/apache/myfaces/custom/dojo/resource/src/widget/Editor2Plugin/TableOperation.js
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: myfaces/tomahawk/trunk/core/src/main/resources/org/apache/myfaces/custom/dojo/resource/src/widget/Editor2Plugin/TableOperation.js
------------------------------------------------------------------------------
    svn:keywords = "Id Author LastChangedDate LastChangedBy LastChangedRevision"

Propchange: myfaces/tomahawk/trunk/core/src/main/resources/org/apache/myfaces/custom/dojo/resource/src/widget/Editor2Plugin/TableOperation.js
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Added: myfaces/tomahawk/trunk/core/src/main/resources/org/apache/myfaces/custom/dojo/resource/src/widget/Editor2Plugin/ToolbarDndSupport.js
URL: http://svn.apache.org/viewvc/myfaces/tomahawk/trunk/core/src/main/resources/org/apache/myfaces/custom/dojo/resource/src/widget/Editor2Plugin/ToolbarDndSupport.js?view=auto&rev=473277
==============================================================================
--- myfaces/tomahawk/trunk/core/src/main/resources/org/apache/myfaces/custom/dojo/resource/src/widget/Editor2Plugin/ToolbarDndSupport.js (added)
+++ myfaces/tomahawk/trunk/core/src/main/resources/org/apache/myfaces/custom/dojo/resource/src/widget/Editor2Plugin/ToolbarDndSupport.js Fri Nov 10 01:15:01 2006
@@ -0,0 +1,68 @@
+/*
+	Copyright (c) 2004-2006, The Dojo Foundation
+	All Rights Reserved.
+
+	Licensed under the Academic Free License version 2.1 or above OR the
+	modified BSD license. For more information on Dojo licensing, see:
+
+		http://dojotoolkit.org/community/licensing.shtml
+*/
+
+/*TODO:
+ * Add a command to toggle DnD support for a toolbar
+ * Save/restore order of toolbar/item
+ */
+dojo.provide("dojo.widget.Editor2Plugin.ToolbarDndSupport");
+dojo.require("dojo.dnd.*");
+
+dojo.event.topic.subscribe("dojo.widget.Editor2::preLoadingToolbar", function(editor){
+	dojo.dnd.dragManager.nestedTargets = true;
+	var p = new dojo.widget.Editor2Plugin.ToolbarDndSupport(editor);
+});
+
+dojo.declare("dojo.widget.Editor2Plugin.ToolbarDndSupport", null,{
+	lookForClass: "dojoEditorToolbarDnd TB_ToolbarSet TB_Toolbar",
+	initializer: function(editor){
+		this.editor = editor;
+		dojo.event.connect(this.editor, "toolbarLoaded", this, "setup");
+		this.editor.registerLoadedPlugin(this);
+	},
+
+	setup: function(){
+		dojo.event.disconnect(this.editor, "toolbarLoaded", this, "setup");
+		var tbw = this.editor.toolbarWidget;
+		dojo.event.connect("before", tbw, "destroy", this, "destroy");
+
+		var nodes = dojo.html.getElementsByClass(this.lookForClass, tbw.domNode, null, dojo.html.classMatchType.ContainsAny);
+		if(!nodes){
+			dojo.debug("dojo.widget.Editor2Plugin.ToolbarDndSupport: No dom node with class in "+this.lookForClass);
+			return;
+		}
+		for(var i=0; i<nodes.length; i++){
+			var node = nodes[i];
+			var droptarget = node.getAttribute("dojoETDropTarget");
+			if(droptarget){
+				(new dojo.dnd.HtmlDropTarget(node, [droptarget+tbw.widgetId])).vertical = true;
+			}
+			var dragsource = node.getAttribute("dojoETDragSource");
+			if(dragsource){
+				new dojo.dnd.HtmlDragSource(node, dragsource+tbw.widgetId);
+			}
+		}
+	},
+
+	destroy: function(){
+		this.editor.unregisterLoadedPlugin(this);
+	}
+});
+
+//let's have a command to enable DnD
+/*dojo.declare("dojo.widget.Editor2Plugin.ToolbarDndCommand", dojo.widget.Editor2Command,{
+	execute: function(text, option){
+		var curInst = dojo.widget.Editor2Manager.getCurrentInstance();
+		if(curInst){
+		}
+	},
+	getState: function(){	
+	}
+});*/
\ No newline at end of file

Propchange: myfaces/tomahawk/trunk/core/src/main/resources/org/apache/myfaces/custom/dojo/resource/src/widget/Editor2Plugin/ToolbarDndSupport.js
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: myfaces/tomahawk/trunk/core/src/main/resources/org/apache/myfaces/custom/dojo/resource/src/widget/Editor2Plugin/ToolbarDndSupport.js
------------------------------------------------------------------------------
    svn:keywords = "Id Author LastChangedDate LastChangedBy LastChangedRevision"

Propchange: myfaces/tomahawk/trunk/core/src/main/resources/org/apache/myfaces/custom/dojo/resource/src/widget/Editor2Plugin/ToolbarDndSupport.js
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Added: myfaces/tomahawk/trunk/core/src/main/resources/org/apache/myfaces/custom/dojo/resource/src/widget/Editor2Plugin/__package__.js
URL: http://svn.apache.org/viewvc/myfaces/tomahawk/trunk/core/src/main/resources/org/apache/myfaces/custom/dojo/resource/src/widget/Editor2Plugin/__package__.js?view=auto&rev=473277
==============================================================================
--- myfaces/tomahawk/trunk/core/src/main/resources/org/apache/myfaces/custom/dojo/resource/src/widget/Editor2Plugin/__package__.js (added)
+++ myfaces/tomahawk/trunk/core/src/main/resources/org/apache/myfaces/custom/dojo/resource/src/widget/Editor2Plugin/__package__.js Fri Nov 10 01:15:01 2006
@@ -0,0 +1,15 @@
+/*
+	Copyright (c) 2004-2006, The Dojo Foundation
+	All Rights Reserved.
+
+	Licensed under the Academic Free License version 2.1 or above OR the
+	modified BSD license. For more information on Dojo licensing, see:
+
+		http://dojotoolkit.org/community/licensing.shtml
+*/
+
+dojo.kwCompoundRequire({
+	common: [ "dojo.widget.Editor2", 
+			 "dojo.widget.Editor2Toolbar"]
+});
+dojo.provide("dojo.widget.Editor2Plugin.*");

Propchange: myfaces/tomahawk/trunk/core/src/main/resources/org/apache/myfaces/custom/dojo/resource/src/widget/Editor2Plugin/__package__.js
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: myfaces/tomahawk/trunk/core/src/main/resources/org/apache/myfaces/custom/dojo/resource/src/widget/Editor2Plugin/__package__.js
------------------------------------------------------------------------------
    svn:keywords = "Id Author LastChangedDate LastChangedBy LastChangedRevision"

Propchange: myfaces/tomahawk/trunk/core/src/main/resources/org/apache/myfaces/custom/dojo/resource/src/widget/Editor2Plugin/__package__.js
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Modified: myfaces/tomahawk/trunk/core/src/main/resources/org/apache/myfaces/custom/dojo/resource/src/widget/Editor2Toolbar.js
URL: http://svn.apache.org/viewvc/myfaces/tomahawk/trunk/core/src/main/resources/org/apache/myfaces/custom/dojo/resource/src/widget/Editor2Toolbar.js?view=diff&rev=473277&r1=473276&r2=473277
==============================================================================
--- myfaces/tomahawk/trunk/core/src/main/resources/org/apache/myfaces/custom/dojo/resource/src/widget/Editor2Toolbar.js (original)
+++ myfaces/tomahawk/trunk/core/src/main/resources/org/apache/myfaces/custom/dojo/resource/src/widget/Editor2Toolbar.js Fri Nov 10 01:15:01 2006
@@ -9,307 +9,588 @@
 */
 
 dojo.provide("dojo.widget.Editor2Toolbar");
-dojo.provide("dojo.widget.html.Editor2Toolbar");
 
 dojo.require("dojo.lang.*");
 dojo.require("dojo.widget.*");
 dojo.require("dojo.event.*");
+dojo.require("dojo.html.layout");
+dojo.require("dojo.html.display");
 dojo.require("dojo.widget.RichText");
+dojo.require("dojo.widget.PopupContainer");
 dojo.require("dojo.widget.ColorPalette");
 
-dojo.widget.defineWidget(
-	"dojo.widget.html.Editor2Toolbar",
-	dojo.widget.HtmlWidget,
-	{
-		commandList: [ "bold", "italic", "underline", "subscript", "superscript",
-			"fontname", "fontsize", "forecolor", "hilitecolor", "justifycenter",
-			"justifyfull", "justifyleft", "justifyright", "cut", "copy", "paste",
-			"delete", "undo", "redo", "createlink", "unlink", "removeformat",
-			"inserthorizontalrule", "insertimage", "insertorderedlist",
-			"insertunorderedlist", "indent", "outdent", "formatblock", "strikethrough", 
-			"inserthtml", "blockdirltr", "blockdirrtl", "dirltr", "dirrtl",
-			"inlinedirltr", "inlinedirrtl", "inserttable", "insertcell",
-			"insertcol", "insertrow", "deletecells", "deletecols", "deleterows",
-			"mergecells", "splitcell"
-		],
+// Object: Manager available editor2 toolbar items
+dojo.widget.Editor2ToolbarItemManager = {
+	_registeredItemHandlers: [],
+	registerHandler: function(/*Object*/obj, /*String*/func){
+		// summary: register a toolbar item handler
+		// obj: object which has the function to call
+		// func: the function in the object
+		if(arguments.length == 2){
+			this._registeredItemHandlers.push(function(){return obj[func].apply(obj, arguments);});
+		}else{
+			/* obj: Function
+			    func: null
+			    pId: f */
+//			for(i in this._registeredItemHandlers){
+//				if(func === this._registeredItemHandlers[i]){
+//					dojo.debug("Editor2ToolbarItemManager handler "+func+" is already registered, ignored");
+//					return;
+//				}
+//			}
+			this._registeredItemHandlers.push(obj);
+		}
+	},
+	removeHandler: function(func){
+		// summary: remove a registered handler
+		for(var i in this._registeredItemHandlers){
+			if(func === this._registeredItemHandlers[i]){
+				delete this._registeredItemHandlers[i];
+				return;
+			}
+		}
+		dojo.debug("Editor2ToolbarItemManager handler "+func+" is not registered, can not remove.");
+	},
+	destroy: function(){
+		for(var i in this._registeredItemHandlers){
+			delete this._registeredItemHandlers[i];
+		}
+	},
+	getToolbarItem: function(/*String*/name){
+		// summary: return a toobar item with the given name
+		var item;
+		name = name.toLowerCase();
+		for(var i in this._registeredItemHandlers){
+			item = this._registeredItemHandlers[i](name);
+			if(item){
+				break;
+			}
+		}
+
+		if(!item){
+			switch(name){
+				//button for builtin functions
+				case 'bold':
+				case 'copy':
+				case 'cut':
+				case 'delete':
+				case 'indent':
+				case 'inserthorizontalrule':
+				case 'insertorderedlist':
+				case 'insertunorderedlist':
+				case 'italic':
+				case 'justifycenter':
+				case 'justifyfull':
+				case 'justifyleft':
+				case 'justifyright':
+				case 'outdent':
+				case 'paste':
+				case 'redo':
+				case 'removeformat':
+				case 'selectall':
+				case 'strikethrough':
+				case 'subscript':
+				case 'superscript':
+				case 'underline':
+				case 'undo':
+				case 'unlink':
+				case 'createlink':
+				case 'insertimage':
+				//extra simple buttons
+				case 'htmltoggle':
+					item = new dojo.widget.Editor2ToolbarButton(name);
+					break;
+				case 'forecolor':
+				case 'hilitecolor':
+					item = new dojo.widget.Editor2ToolbarColorPaletteButton(name);
+					break;
+				case 'plainformatblock':
+					item = new dojo.widget.Editor2ToolbarFormatBlockPlainSelect("formatblock");
+					break;
+				case 'formatblock':
+					item = new dojo.widget.Editor2ToolbarFormatBlockSelect("formatblock");
+					break;
+				case 'fontsize':
+					item = new dojo.widget.Editor2ToolbarFontSizeSelect("fontsize");
+					break;
+				case 'fontname':
+					item = new dojo.widget.Editor2ToolbarFontNameSelect("fontname");
+					break;
+				case 'inserttable':
+				case 'insertcell':
+				case 'insertcol':
+				case 'insertrow':
+				case 'deletecells':
+				case 'deletecols':
+				case 'deleterows':
+				case 'mergecells':
+				case 'splitcell':
+					dojo.debug(name + " is implemented in dojo.widget.Editor2Plugin.TableOperation, please require it first.");
+					break;
+				//TODO:
+				case 'inserthtml':
+				case 'blockdirltr':
+				case 'blockdirrtl':
+				case 'dirltr':
+				case 'dirrtl':
+				case 'inlinedirltr':
+				case 'inlinedirrtl':
+					dojo.debug("Not yet implemented toolbar item: "+name);
+					break;
+				default:
+					dojo.debug("dojo.widget.Editor2ToolbarItemManager.getToolbarItem: Unknown toolbar item: "+name);
+			}
+		}
+		return item;
+	}
+};
+
+dojo.addOnUnload(dojo.widget.Editor2ToolbarItemManager, "destroy");
+// summary:
+//		dojo.widget.Editor2ToolbarButton is the base class for all toolbar item in Editor2Toolbar
+dojo.declare("dojo.widget.Editor2ToolbarButton", null,{
+	initializer: function(name){
+		// summary: constructor
+		this._name = name;
+		this._command = dojo.widget.Editor2Manager.getCommand(name);
+	},
+	create: function(/*DomNode*/node, /*dojo.widget.Editor2Toolbar*/toolbar, /*Boolean*/nohover){
+		// summary: create the item
+		// node: the dom node which is the root of this toolbar item
+		// toolbar: the Editor2Toolbar widget this toolbar item belonging to
+		// nohover: whether this item in charge of highlight this item
+		this._domNode = node;
+		//make this unselectable: different browsers
+		//use different properties for this, so use
+		//js do it automatically
+		this.disableSelection(this._domNode);
+		this._parentToolbar = toolbar;
+		dojo.event.connect(this._domNode, 'onclick', this, 'onClick');
+		if(!nohover){
+			dojo.event.connect(this._domNode, 'onmouseover', this, 'onMouseOver');
+			dojo.event.connect(this._domNode, 'onmouseout', this, 'onMouseOut');
+		}
+	},
+	disableSelection: function(/*DomNode*/rootnode){
+		// summary: disable selection on the passed node and all its children
+		dojo.html.disableSelection(rootnode);
+		var nodes = rootnode.all || rootnode.getElementsByTagName("*");
+		for(var x=0; x<nodes.length; x++){
+			dojo.html.disableSelection(nodes[x]);
+		}
+	},
+	onMouseOver: function(){
+		if(this._command.getState() != dojo.widget.Editor2Manager.commandState.Disabled){
+			this.highlightToolbarItem();
+		}
+	},
+	onMouseOut: function(){
+		this.unhighlightToolbarItem();
+	},
+	destroy: function(){
+		// summary: destructor
+		this._domNode = null;
+		delete this._command;
+		this._parentToolbar = null;
+	},
+	onClick: function(e){
+		if(this._domNode && !this._domNode.disabled && this._command){
+			e.preventDefault();
+			e.stopPropagation();
+			this._command.execute();
+		}
+	},
+	refreshState: function(){
+		// summary: update the state of the toolbar item
+		if(this._domNode && this._command){
+			var em = dojo.widget.Editor2Manager;
+			var state = this._command.getState();
+			if(state != this._lastState){
+				switch(state){
+					case em.commandState.Latched:
+						this.latchToolbarItem();
+						break;
+					case em.commandState.Enabled:
+						this.enableToolbarItem();
+						break;
+					case em.commandState.Disabled:
+					default:
+						this.disableToolbarItem();
+				}
+				this._lastState = state;
+			}
+			return state;
+		}
+	},
 
-		templatePath: dojo.uri.dojoUri("src/widget/templates/HtmlEditorToolbar.html"),
-		templateCssPath: dojo.uri.dojoUri("src/widget/templates/HtmlEditorToolbar.css"),
+	latchToolbarItem: function(){
+		this._domNode.disabled = false;
+		this.removeToolbarItemStyle(this._domNode);
+		dojo.html.addClass(this._domNode, this._parentToolbar.ToolbarLatchedItemStyle);
+	},
 
-		forecolorPalette: null,
-		hilitecolorPalette: null,
+	enableToolbarItem: function(){
+		this._domNode.disabled = false;
+		this.removeToolbarItemStyle(this._domNode);
+		dojo.html.addClass(this._domNode, this._parentToolbar.ToolbarEnabledItemStyle);
+	},
 
-		// DOM Nodes
-		wikiwordButton: null,
-		htmltoggleButton: null,
-		insertimageButton: null,
-		styleDropdownButton: null,
-		styleDropdownContainer: null,
-		copyButton: null,
-		boldButton: null,
-		italicButton: null,
-		underlineButton: null,
-		justifycenterButton: null,
-		justifyleftButton: null,
-		justifyfullButton: null,
-		justifyrightButton: null,
-		pasteButton: null,
-		undoButton: null,
-		redoButton: null,
-		linkButton: null,
-		insertunorderedlistButton: null,
-		insertorderedlistButton: null,
-		forecolorButton: null,
-		forecolorDropDown: null,
-		hilitecolorButton: null,
-		hilitecolorDropDown: null,
-		formatSelectBox: null,
-		inserthorizontalruleButton: null,
-		strikethroughButton: null,
-		clickInterceptDiv: null,
-		oneLineTr: null,
-
-		buttonClick: function(e){ e.preventDefault(); /* dojo.debug("buttonClick"); */ },
-
-		buttonMouseOver: function(e){  },
-		buttonMouseOut: function(e){  },
-
-
-		// event signals
-		preventSelect: function(e){ if(dojo.render.html.safari){ e.preventDefault(); } },
-		wikiwordClick: function(){ },
-		insertimageClick: function(){ },
-		htmltoggleClick: function(){ },
-
-		styleDropdownClick: function(){
-			dojo.debug("styleDropdownClick:", this.styleDropdownContainer);
-			dojo.style.toggleShowing(this.styleDropdownContainer);
-		},
+	disableToolbarItem: function(){
+		this._domNode.disabled = true;
+		this.removeToolbarItemStyle(this._domNode);
+		dojo.html.addClass(this._domNode, this._parentToolbar.ToolbarDisabledItemStyle);
+	},
 
+	highlightToolbarItem: function(){
+		dojo.html.addClass(this._domNode, this._parentToolbar.ToolbarHighlightedItemStyle);
+	},
 
-		copyClick: function(){ this.exec("copy"); },
-		boldClick: function(){ this.exec("bold"); },
-		italicClick: function(){ this.exec("italic"); },
-		underlineClick: function(){ this.exec("underline"); },
-		justifyleftClick: function(){ this.exec("justifyleft"); },
-		justifycenterClick: function(){ this.exec("justifycenter"); },
-		justifyfullClick: function(){ this.exec("justifyfull"); },
-		justifyrightClick: function(){ this.exec("justifyright"); },
-		pasteClick: function(){ this.exec("paste"); },
-		undoClick: function(){ this.exec("undo"); },
-		redoClick: function(){ this.exec("redo"); },
-		linkClick: function(){ 
-			// FIXME: we need to alert the user if they haven't selected any text
-			// this.exec(	"createlink", 
-			// 			prompt("Please enter the URL of the link:", "http://"));
-		},
-		insertunorderedlistClick: function(){ this.exec("insertunorderedlist"); },
-		insertorderedlistClick: function(){ this.exec("insertorderedlist"); },
-		inserthorizontalruleClick: function(){ this.exec("inserthorizontalrule"); },
-		strikethroughClick: function(){ this.exec("strikethrough"); },
-
-		formatSelectClick: function(){ 
-			var sv = this.formatSelectBox.value.toLowerCase();
-			this.exec("formatblock", sv);
-		},
+	unhighlightToolbarItem: function(){
+		dojo.html.removeClass(this._domNode, this._parentToolbar.ToolbarHighlightedItemStyle);
+	},
 
-		normalTextClick: function(){ this.exec("formatblock", "p"); },
-		h1TextClick: function(){ this.exec("formatblock", "h1"); },
-		h2TextClick: function(){ this.exec("formatblock", "h2"); },
-		h3TextClick: function(){ this.exec("formatblock", "h3"); },
-		h4TextClick: function(){ this.exec("formatblock", "h4"); },
-		indentClick: function(){ this.exec("indent"); },
-		outdentClick: function(){ this.exec("outdent"); },
-
-
-		hideAllDropDowns: function(){
-			this.domNode.style.height = "";
-			dojo.lang.forEach(dojo.widget.byType("Editor2Toolbar"), function(tb){
-				try{
-					dojo.style.hide(tb.forecolorDropDown);
-					dojo.style.hide(tb.hilitecolorDropDown);
-					dojo.style.hide(tb.styleDropdownContainer);
-					if(tb.clickInterceptDiv){
-						dojo.style.hide(tb.clickInterceptDiv);
-					}
-				}catch(e){}
-				if(dojo.render.html.ie){
-					try{
-						dojo.style.hide(tb.forecolorPalette.bgIframe);
-					}catch(e){}
-					try{
-						dojo.style.hide(tb.hilitecolorPalette.bgIframe);
-					}catch(e){}
-				}
-			});
-		},
+	removeToolbarItemStyle: function(){
+		dojo.html.removeClass(this._domNode, this._parentToolbar.ToolbarEnabledItemStyle);
+		dojo.html.removeClass(this._domNode, this._parentToolbar.ToolbarLatchedItemStyle);
+		dojo.html.removeClass(this._domNode, this._parentToolbar.ToolbarDisabledItemStyle);
+		this.unhighlightToolbarItem();
+	}
+});
+
+// summary: dojo.widget.Editor2ToolbarDropDownButton extends the basic button with a dropdown list
+dojo.declare("dojo.widget.Editor2ToolbarDropDownButton", dojo.widget.Editor2ToolbarButton,{
+	onClick: function(){
+		if(this._domNode){
+			if(!this._dropdown){
+				this._dropdown = dojo.widget.createWidget("PopupContainer", {});
+				this._domNode.appendChild(this._dropdown.domNode);
+			}
+			if(this._dropdown.isShowingNow){
+				this._dropdown.close();
+			}else{
+				this.onDropDownShown();
+				this._dropdown.open(this._domNode, null, this._domNode);
+			}
+		}
+	},
+	destroy: function(){
+		this.onDropDownDestroy();
+		if(this._dropdown){
+			this._dropdown.destroy();
+		}
+		dojo.widget.Editor2ToolbarDropDownButton.superclass.destroy.call(this);
+	},
+	onDropDownShown: function(){},
+	onDropDownDestroy: function(){}
+});
+
+// summary: dojo.widget.Editor2ToolbarColorPaletteButton provides a dropdown color palette picker
+dojo.declare("dojo.widget.Editor2ToolbarColorPaletteButton", dojo.widget.Editor2ToolbarDropDownButton,{
+	onDropDownShown: function(){
+		if(!this._colorpalette){
+			this._colorpalette = dojo.widget.createWidget("ColorPalette", {});
+			this._dropdown.addChild(this._colorpalette);
+
+			this.disableSelection(this._dropdown.domNode);
+			this.disableSelection(this._colorpalette.domNode);
+			//do we need a destory to delete this._colorpalette manually?
+			//I assume as it is added to this._dropdown via addChild, it
+			//should be deleted when this._dropdown is destroyed
+
+			dojo.event.connect(this._colorpalette, "onColorSelect", this, 'setColor');
+			dojo.event.connect(this._dropdown, "open", this, 'latchToolbarItem');
+			dojo.event.connect(this._dropdown, "close", this, 'enableToolbarItem');
+		}
+	},
+	setColor: function(color){
+		this._dropdown.close();
+		this._command.execute(color);
+	}
+});
+
+// summary: dojo.widget.Editor2ToolbarFormatBlockPlainSelect provides a simple select for setting block format
+dojo.declare("dojo.widget.Editor2ToolbarFormatBlockPlainSelect", dojo.widget.Editor2ToolbarButton,{
+	create: function(node, toolbar){
+		//TODO: check node is a select
+		this._domNode = node;
+		this.disableSelection(this._domNode);
+		this._parentToolbar = toolbar;
+		dojo.event.connect(this._domNode, 'onchange', this, 'onChange');
+	},
 
-		selectFormat: function(format){
-			dojo.lang.forEach(this.formatSelectBox.options, function(item){
+	destroy: function(){
+		this._domNode = null;
+		this._command = null;
+		this._parentToolbar = null;
+	},
+
+	onChange: function(){
+		if(this._domNode){
+			var sv = this._domNode.value.toLowerCase();
+			this._command.execute(sv);
+		}
+	},
+
+	refreshState: function(){
+		if(this._domNode && this._command){
+			dojo.widget.Editor2ToolbarFormatBlockPlainSelect.superclass.refreshState.call(this);
+			var format = this._command.getValue();
+			if(!format){ format = ""; }
+			dojo.lang.forEach(this._domNode.options, function(item){
 				if(item.value.toLowerCase() == format.toLowerCase()){
 					item.selected = true;
 				}
 			});
-		},
+		}
+	}
+});
 
-		forecolorClick: function(e){
-			this.colorClick(e, "forecolor");
-		},
+// summary: dojo.widget.Editor2ToolbarComboItem provides an external loaded dropdown list
+dojo.declare("dojo.widget.Editor2ToolbarComboItem", dojo.widget.Editor2ToolbarDropDownButton,{
+	href: null,
+	create: function(node, toolbar){
+		dojo.widget.Editor2ToolbarComboItem.superclass.create.call(this, node, toolbar);
+		//do not use lazy initilization, as we need the local names in refreshState()
+		if(!this._contentPane){
+			dojo.require("dojo.widget.ContentPane");
+			this._contentPane = dojo.widget.createWidget("ContentPane", {preload: 'true'});
+			this._contentPane.addOnLoad(this, "setup");
+			this._contentPane.setUrl(this.href);
+		}
+	},
 
-		hilitecolorClick: function(e){
-			this.colorClick(e, "hilitecolor");
-		},
+	onMouseOver: function(e){
+		dojo.html.addClass(e.currentTarget, this._parentToolbar.ToolbarHighlightedSelectStyle);
+	},
+	onMouseOut:function(e){
+		dojo.html.removeClass(e.currentTarget, this._parentToolbar.ToolbarHighlightedSelectStyle);
+	},
 
-		// FIXME: these methods aren't currently dealing with clicking in the
-		// general document to hide the menu
-		colorClick: function(e, type){
-			var h = dojo.render.html;
-			this.hideAllDropDowns();
-			// FIXME: if we've been "popped out", we need to set the height of the toolbar.
-			e.stopPropagation();
-			var dd = this[type+"DropDown"];
-			var pal = this[type+"Palette"];
-			dojo.style.toggleShowing(dd);
-			if(!pal){
-				pal = this[type+"Palette"] = dojo.widget.createWidget("ColorPalette", {}, dd, "first");
-				var fcp = pal.domNode;
-				with(dd.style){
-					width = dojo.html.getOuterWidth(fcp) + "px";
-					height = dojo.html.getOuterHeight(fcp) + "px";
-					zIndex = 1002;
-					position = "absolute";
-				}
+	onDropDownShown: function(){
+		if(!this._dropdown.__addedContentPage){
+			this._dropdown.addChild(this._contentPane);
+			this._dropdown.__addedContentPage = true;
+		}
+	},
+
+	setup: function(){
+		// summary: overload this to connect event
+	},
+
+	onChange: function(e){
+		var name = e.currentTarget.getAttribute("dropDownItemName");
+		this._command.execute(name);
+		this._dropdown.close();
+	},
+
+	onMouseOverItem: function(e){
+		dojo.html.addClass(e.currentTarget, this._parentToolbar.ToolbarHighlightedSelectItemStyle);
+	},
+
+	onMouseOutItem: function(e){
+		dojo.html.removeClass(e.currentTarget, this._parentToolbar.ToolbarHighlightedSelectItemStyle);
+	},
+
+	refreshState: function(){
+		// summary: overload this to update GUI item
+	}
+});
+
+// summary: dojo.widget.Editor2ToolbarFormatBlockSelect is an improved format block setting item
+dojo.declare("dojo.widget.Editor2ToolbarFormatBlockSelect", dojo.widget.Editor2ToolbarComboItem,{
+	href: dojo.uri.dojoUri("src/widget/templates/Editor2/EditorToolbar_FormatBlock.html"),
+
+	setup: function(){
+		dojo.widget.Editor2ToolbarFormatBlockSelect.superclass.setup.call(this);
+
+		var nodes = this._contentPane.domNode.all || this._contentPane.domNode.getElementsByTagName("*");
+		this._blockNames = {};
+		this._blockDisplayNames = {};
+		for(var x=0; x<nodes.length; x++){
+			var node = nodes[x];
+			dojo.html.disableSelection(node);
+			var name=node.getAttribute("dropDownItemName")
+			if(name){
+				this._blockNames[name] = node;
+				var childrennodes = node.getElementsByTagName(name);
+				this._blockDisplayNames[name] = childrennodes[childrennodes.length-1].innerHTML;
+			}
+		}
+		for(var name in this._blockNames){
+			dojo.event.connect(this._blockNames[name], "onclick", this, "onChange");
+			dojo.event.connect(this._blockNames[name], "onmouseover", this, "onMouseOverItem");
+			dojo.event.connect(this._blockNames[name], "onmouseout", this, "onMouseOutItem");
+		}
+	},
 
-				dojo.event.connect(	"after",
-									pal, "onColorSelect",
-									this, "exec",
-									function(mi){ mi.args.unshift(type); return mi.proceed(); }
-				);
-
-				dojo.event.connect(	"after",
-									pal, "onColorSelect",
-									dojo.style, "toggleShowing",
-									this, function(mi){ mi.args.unshift(dd); return mi.proceed(); }
-				);
-
-				var cid = this.clickInterceptDiv;
-				if(!cid){
-					cid = this.clickInterceptDiv = document.createElement("div");
-					document.body.appendChild(cid);
-					with(cid.style){
-						backgroundColor = "transparent";
-						top = left = "0px";
-						height = width = "100%";
-						position = "absolute";
-						border = "none";
-						display = "none";
-						zIndex = 1001;
+	onDropDownDestroy: function(){
+		if(this._blockNames){
+			for(var name in this._blockNames){
+				delete this._blockNames[name];
+				delete this._blockDisplayNames[name];
+			}
+		}
+	},
+
+	refreshState: function(){
+		if(this._command){
+			//dojo.widget.Editor2ToolbarFormatBlockSelect.superclass.refreshState.call(this);
+			var format = this._command.getValue();
+			if(format == this._lastSelectedFormat && this._blockDisplayNames){
+				return;
+			}
+			this._lastSelectedFormat = format;
+			var label = this._domNode.getElementsByTagName("label")[0];
+			var isSet = false;
+			if(this._blockDisplayNames){
+				for(var name in this._blockDisplayNames){
+					if(name == format){
+						label.innerHTML = 	this._blockDisplayNames[name];
+						isSet = true;
+						break;
 					}
-					dojo.event.connect(cid, "onclick", function(){ cid.style.display = "none"; });
 				}
-				dojo.event.connect(pal, "onColorSelect", function(){ cid.style.display = "none"; });
-
-				dojo.event.kwConnect({
-					srcObj:		document.body, 
-					srcFunc:	"onclick", 
-					targetObj:	this,
-					targetFunc:	"hideAllDropDowns",
-					once:		true
-				});
-				document.body.appendChild(dd);
-			}
-			dojo.style.toggleShowing(this.clickInterceptDiv);
-			var pos = dojo.style.abs(this[type+"Button"]);
-			dojo.html.placeOnScreenPoint(dd, pos.x, pos.y, 0, false);
-			if(pal.bgIframe){
-				with(pal.bgIframe.style){
-					display = "block";
-					left = dd.style.left;
-					top = dd.style.top;
-					width = dojo.style.getOuterWidth(dd)+"px";
-					height = dojo.style.getOuterHeight(dd)+"px";
+				if(!isSet){
+					label.innerHTML = "&nbsp;";
 				}
 			}
-		},
+		}
+	}
+});
 
-		uninitialize: function(){
-			if(!dojo.render.html.ie){
-				// apparently this causes leakage on IE!
-				dojo.event.kwDisconnect({
-					srcObj:		document.body, 
-					srcFunc:	"onclick", 
-					targetObj:	this,
-					targetFunc:	"hideAllDropDowns",
-					once:		true
-				});
+// summary: dojo.widget.Editor2ToolbarFontSizeSelect provides a dropdown list for setting fontsize
+dojo.declare("dojo.widget.Editor2ToolbarFontSizeSelect", dojo.widget.Editor2ToolbarComboItem,{
+	href: dojo.uri.dojoUri("src/widget/templates/Editor2/EditorToolbar_FontSize.html"),
+
+	setup: function(){
+		dojo.widget.Editor2ToolbarFormatBlockSelect.superclass.setup.call(this);
+
+		var nodes = this._contentPane.domNode.all || this._contentPane.domNode.getElementsByTagName("*");
+		this._fontsizes = {};
+		this._fontSizeDisplayNames = {};
+		for(var x=0; x<nodes.length; x++){
+			var node = nodes[x];
+			dojo.html.disableSelection(node);
+			var name=node.getAttribute("dropDownItemName")
+			if(name){
+				this._fontsizes[name] = node;
+				this._fontSizeDisplayNames[name] = node.getElementsByTagName('font')[0].innerHTML;
 			}
-		},
+		}
+		for(var name in this._fontsizes){
+			dojo.event.connect(this._fontsizes[name], "onclick", this, "onChange");
+			dojo.event.connect(this._fontsizes[name], "onmouseover", this, "onMouseOverItem");
+			dojo.event.connect(this._fontsizes[name], "onmouseout", this, "onMouseOutItem");
+		}
+	},
 
-		// stub for observers
-		exec: function(what, arg){ /* dojo.debug(what, new Date()); */ },
+	onDropDownDestroy: function(){
+		if(this._fontsizes){
+			for(var name in this._fontsizes){
+				delete this._fontsizes[name];
+				delete this._fontSizeDisplayNames[name];
+			}
+		}
+	},
 
-		hideUnusableButtons: function(obj){
-			var op = obj||dojo.widget.html.RichText.prototype;
-			dojo.lang.forEach(this.commandList,
-				function(cmd){
-					if(this[cmd+"Button"]){
-						var cb = this[cmd+"Button"];
-						if(!op.queryCommandAvailable(cmd)){
-							cb.style.display = "none";
-							cb.parentNode.style.display = "none";
-						}
+	refreshState: function(){
+		if(this._command){
+			//dojo.widget.Editor2ToolbarFormatBlockSelect.superclass.refreshState.call(this);
+			var size = this._command.getValue();
+			if(size == this._lastSelectedSize && this._fontSizeDisplayNames){
+				return;
+			}
+			this._lastSelectedSize = size;
+			var label = this._domNode.getElementsByTagName("label")[0];
+			var isSet = false;
+			if(this._fontSizeDisplayNames){
+				for(var name in this._fontSizeDisplayNames){
+					if(name == size){
+						label.innerHTML = 	this._fontSizeDisplayNames[name];
+						isSet = true;
+						break;
 					}
-				},
-				this);
-				if(this.oneLineTr){
-					var lastVisibleIsSpacer = false;
-					var lastVisible = false;
-					var tds = this.oneLineTr.getElementsByTagName("td");
-					dojo.lang.forEach(tds, function(td){
-						if(td.getAttribute("isSpacer")){
-							if(td.style.display != "none"){
-								if(lastVisibleIsSpacer){
-									td.style.display = "none";
-								}
-								lastVisibleIsSpacer = true;
-							}else{
-								lastVisible = td;
-								lastVisibleIsSpacer = true;
-							}
-						}else{
-							if(td.style.display != "none"){
-								lastVisible = td;
-								lastVisibleIsSpacer = false;
-							}
-						}
-					});
 				}
-		},
+				if(!isSet){
+					label.innerHTML = "&nbsp;";
+				}
+			}
+		}
+	}
+});
+
+// summary: dojo.widget.Editor2ToolbarFontNameSelect provides a dropdown list for setting fontname
+dojo.declare("dojo.widget.Editor2ToolbarFontNameSelect", dojo.widget.Editor2ToolbarFontSizeSelect,{
+	href: dojo.uri.dojoUri("src/widget/templates/Editor2/EditorToolbar_FontName.html")
+});
 
-		highlightButton: function(name){
-			var bn = name+"Button";
-			if(this[bn]){
-				with(this[bn].style){
-					backgroundColor = "White";
-					border = "1px solid #aeaeab";
+// summary:
+//		dojo.widget.Editor2Toolbar is the main widget for the toolbar associated with an Editor2
+dojo.widget.defineWidget(
+	"dojo.widget.Editor2Toolbar",
+	dojo.widget.HtmlWidget,
+	{
+		templatePath: dojo.uri.dojoUri("src/widget/templates/EditorToolbar.html"),
+		templateCssPath: dojo.uri.dojoUri("src/widget/templates/EditorToolbar.css"),
+
+		// DOM Nodes
+//		saveButton: null,
+
+		// String: class name for latched toolbar button items
+		ToolbarLatchedItemStyle: "ToolbarButtonLatched",
+		// String: class name for enabled toolbar button items
+		ToolbarEnabledItemStyle: "ToolbarButtonEnabled",
+		// String: class name for disabled toolbar button items
+		ToolbarDisabledItemStyle: "ToolbarButtonDisabled",
+		// String: class name for highlighted toolbar button items
+		ToolbarHighlightedItemStyle: "ToolbarButtonHighlighted",
+		// String: class name for highlighted toolbar select items
+		ToolbarHighlightedSelectStyle: "ToolbarSelectHighlighted",
+		// String: class name for highlighted toolbar select dropdown items
+		ToolbarHighlightedSelectItemStyle: "ToolbarSelectHighlightedItem",
+
+//		itemNodeType: 'span', //all the items (with attribute dojoETItemName set) defined in the toolbar should be a of this type
+
+		postCreate: function(){
+			var nodes = dojo.html.getElementsByClass("dojoEditorToolbarItem", this.domNode/*, this.itemNodeType*/);
+
+			this.items = {};
+			for(var x=0; x<nodes.length; x++){
+				var node = nodes[x];
+				var itemname = node.getAttribute("dojoETItemName");
+				if(itemname){
+					var item = dojo.widget.Editor2ToolbarItemManager.getToolbarItem(itemname);
+					if(item){
+						item.create(node, this);
+						this.items[itemname.toLowerCase()] = item;
+					}else{
+						//hide unsupported toolbar items
+						node.style.display = "none";
+					}
 				}
 			}
 		},
 
-		unhighlightButton: function(name){
-			var bn = name+"Button";
-			if(this[bn]){
-				// dojo.debug("unhighlighting:", name);
-				with(this[bn].style){
-					backgroundColor = "";
-					border = "";
-				}
+		update: function(){
+			// summary: update all the toolbar items
+			for(var cmd in this.items){
+				this.items[cmd].refreshState();
 			}
-		}
+		},
+
+		destroy: function(){
+			for(var it in this.items){
+				this.items[it].destroy();
+				delete this.items[it];
+			}
+			dojo.widget.Editor2Toolbar.superclass.destroy.call(this);
+		}//,
+
+		// stub for observers
+//		exec: function(what, arg){ /* dojo.debug(what, new Date()); */ }
 	},
 	"html",
 	function(){
-		// dojo.event.connect(this, "fillInTemplate", this, "hideUnusableButtons");
 		dojo.event.connect(this, "fillInTemplate", dojo.lang.hitch(this, function(){
 			if(dojo.render.html.ie){
 				this.domNode.style.zoom = 1.0;

Added: myfaces/tomahawk/trunk/core/src/main/resources/org/apache/myfaces/custom/dojo/resource/src/widget/FilteringTable.js
URL: http://svn.apache.org/viewvc/myfaces/tomahawk/trunk/core/src/main/resources/org/apache/myfaces/custom/dojo/resource/src/widget/FilteringTable.js?view=auto&rev=473277
==============================================================================
--- myfaces/tomahawk/trunk/core/src/main/resources/org/apache/myfaces/custom/dojo/resource/src/widget/FilteringTable.js (added)
+++ myfaces/tomahawk/trunk/core/src/main/resources/org/apache/myfaces/custom/dojo/resource/src/widget/FilteringTable.js Fri Nov 10 01:15:01 2006
@@ -0,0 +1,961 @@
+/*
+	Copyright (c) 2004-2006, The Dojo Foundation
+	All Rights Reserved.
+
+	Licensed under the Academic Free License version 2.1 or above OR the
+	modified BSD license. For more information on Dojo licensing, see:
+
+		http://dojotoolkit.org/community/licensing.shtml
+*/
+
+dojo.provide("dojo.widget.FilteringTable");
+
+dojo.require("dojo.date.format");
+dojo.require("dojo.collections.Store");
+dojo.require("dojo.html.*");
+dojo.require("dojo.html.util");
+dojo.require("dojo.html.style");
+dojo.require("dojo.html.selection");
+dojo.require("dojo.event.*");
+dojo.require("dojo.widget.*");
+dojo.require("dojo.widget.HtmlWidget");
+
+dojo.widget.defineWidget(
+	"dojo.widget.FilteringTable", 
+	dojo.widget.HtmlWidget, 
+	function(){
+		//	summary
+		//	Initializes all properties for the widget.
+		this.store=new dojo.collections.Store();
+
+		//declare per instance changeable widget properties
+		this.valueField="Id";
+		this.multiple=false;
+		this.maxSelect=0;
+		this.maxSortable=1;  // how many columns can be sorted at once.
+		this.minRows=0;
+		this.defaultDateFormat = "%D";
+		this.isInitialized=false;
+		this.alternateRows=false;
+
+		this.columns=[];
+		this.sortInformation=[{
+			index:0,
+			direction:0
+		}];
+
+		// CSS definitions
+		this.headClass="";
+		this.tbodyClass="";
+		this.headerClass="";
+		this.headerUpClass="selectedUp";
+		this.headerDownClass="selectedDown";
+		this.rowClass="";
+		this.rowAlternateClass="alt";
+		this.rowSelectedClass="selected";
+		this.columnSelected="sorted-column";
+	},
+{
+	//	dojo widget properties
+	isContainer: false,
+	templatePath: null,
+	templateCssPath: null,
+
+	//	methods.
+	getTypeFromString: function(/* string */s){
+		//	summary
+		//	Gets a function based on the passed string.
+		var parts = s.split("."), i = 0, obj = dj_global; 
+		do{ 
+			obj = obj[parts[i++]]; 
+		} while (i < parts.length && obj); 
+		return (obj != dj_global) ? obj : null;	//	function
+	},
+
+	//	custom data access.
+	getByRow: function(/*HTMLTableRow*/row){
+		//	summary
+		//	Returns the data object based on the passed row.
+		return this.store.getByKey(dojo.html.getAttribute(row, "value"));	//	object
+	},
+	getDataByRow: function(/*HTMLTableRow*/row){
+		//	summary
+		//	Returns the source data object based on the passed row.
+		return this.store.getDataByKey(dojo.html.getAttribute(row, "value")); // object
+	},
+
+	getRow: function(/* Object */ obj){
+		//	summary
+		//	Finds the row in the table based on the passed data object.
+		var rows = this.domNode.tBodies[0].rows;
+		for(var i=0; i<rows.length; i++){
+			if(this.store.getDataByKey(dojo.html.getAttribute(rows[i], "value")) == obj){
+				return rows[i];	//	HTMLTableRow
+			}
+		}
+		return null;	//	HTMLTableRow
+	},
+	getColumnIndex: function(/* string */fieldPath){
+		//	summary
+		//	Returns index of the column that represents the passed field path.
+		for(var i=0; i<this.columns.length; i++){
+			if(this.columns[i].getField() == fieldPath){
+				return i;	//	integer
+			}
+		}
+		return -1;	//	integer
+	},
+
+	getSelectedData: function(){
+		//	summary
+		//	returns all objects that are selected.
+		var data=this.store.get();
+		var a=[];
+		for(var i=0; i<data.length; i++){
+			if(data[i].isSelected){
+				a.push(data[i].src);
+			}
+		}
+		if(this.multiple){
+			return a;		//	array
+		} else {
+			return a[0];	//	object
+		}
+	},
+	
+	isSelected: function(/* object */obj){
+		//	summary
+		//	Returns whether the passed object is currently selected.
+		var data = this.store.get();
+		for(var i=0; i<data.length; i++){
+			if(data[i].src == obj){
+				return true;	//	boolean
+			}
+		}
+		return false;	//	boolean
+	},
+	isValueSelected: function(/* string */val){
+		//	summary
+		//	Returns the object represented by key "val" is selected.
+		var v = this.store.getByKey(val);
+		if(v){
+			return v.isSelected;	//	boolean
+		}
+		return false;	//	boolean
+	},
+	isIndexSelected: function(/* number */idx){
+		//	summary
+		//	Returns the object represented by integer "idx" is selected.
+		var v = this.store.getByIndex(idx);
+		if(v){
+			return v.isSelected;	//	boolean
+		}
+		return false;	//	boolean
+	},
+	isRowSelected: function(/* HTMLTableRow */row){
+		//	summary
+		//	Returns if the passed row is selected.
+		var v = this.getByRow(row);
+		if(v){
+			return v.isSelected;	//	boolean
+		}
+		return false;	//	boolean
+	},
+
+	reset: function(){
+		//	summary
+		//	Resets the widget to its initial internal state.
+		this.store.clearData();
+		this.columns = [];
+		this.sortInformation = [ {index:0, direction:0} ];
+		this.resetSelections();
+		this.isInitialized = false;
+		this.onReset();
+	},
+	resetSelections: function(){
+		//	summary
+		//	Unselects all data objects.
+		this.store.forEach(function(element){
+			element.isSelected = false;
+		});
+	},
+	onReset:function(){ 
+		//	summary
+		//	Stub for onReset event.
+	},
+
+	//	selection and toggle functions
+	select: function(/*object*/ obj){
+		//	summary
+		//	selects the passed object.
+		var data = this.store.get();
+		for(var i=0; i<data.length; i++){
+			if(data[i].src == obj){
+				data[i].isSelected = true;
+				break;
+			}
+		}
+		this.onDataSelect(obj);
+	},
+	selectByValue: function(/*string*/ val){
+		//	summary
+		//	selects the object represented by key "val".
+		this.select(this.store.getDataByKey(val));
+	},
+	selectByIndex: function(/*number*/ idx){
+		//	summary
+		//	selects the object represented at index "idx".
+		this.select(this.store.getDataByIndex(idx));
+	},
+	selectByRow: function(/*HTMLTableRow*/ row){
+		//	summary
+		//	selects the object represented by HTMLTableRow row.
+		this.select(this.getDataByRow(row));
+	},
+	selectAll: function(){
+		//	summary
+		//	selects all objects.
+		this.store.forEach(function(element){
+			element.isSelected = true;
+		});
+	},
+	onDataSelect: function(/* object */obj){ 
+		//	summary
+		//	Stub for onDataSelect event.
+	},
+
+	toggleSelection: function(/*object*/obj){
+		//	summary
+		//	Flips the selection state of passed obj.
+		var data = this.store.get();
+		for(var i=0; i<data.length; i++){
+			if(data[i].src == obj){
+				data[i].isSelected = !data[i].isSelected;
+				break;
+			}
+		}
+		this.onDataToggle(obj);
+	},
+	toggleSelectionByValue: function(/*string*/val){
+		//	summary
+		//	Flips the selection state of object represented by val.
+		this.toggleSelection(this.store.getDataByKey(val));
+	},
+	toggleSelectionByIndex: function(/*number*/idx){
+		//	summary
+		//	Flips the selection state of object at index idx.
+		this.toggleSelection(this.store.getDataByIndex(idx));
+	},
+	toggleSelectionByRow: function(/*HTMLTableRow*/row){
+		//	summary
+		//	Flips the selection state of object represented by row.
+		this.toggleSelection(this.getDataByRow(row));
+	},
+	toggleAll: function(){
+		//	summary
+		//	Flips the selection state of all objects.
+		this.store.forEach(function(element){
+			element.isSelected = !element.isSelected;
+		});
+	},
+	onDataToggle: function(/* object */obj){ 
+		//	summary
+		//	Stub for onDataToggle event.
+	},
+
+	//	parsing functions, from HTML to metadata/SimpleStore
+	_meta:{
+		field:null,
+		format:null,
+		filterer:null,
+		noSort:false,
+		sortType:"String",
+		dataType:String,
+		sortFunction:null,
+		filterFunction:null,
+		label:null,
+		align:"left",
+		valign:"middle",
+		getField:function(){ 
+			return this.field || this.label; 
+		},
+		getType:function(){ 
+			return this.dataType; 
+		}
+	},
+	createMetaData: function(/* object */obj){
+		//	summary
+		//	Take a JSON-type structure and make it into a ducktyped metadata object.
+		for(var p in this._meta){
+			//	rudimentary mixin
+			if(!obj[p]){
+				obj[p] = this._meta[p];
+			}
+		}
+		if(!obj.label){
+			obj.label=obj.field;
+		}
+		if(!obj.filterFunction){
+			obj.filterFunction=this._defaultFilter;
+		}
+		return obj;	//	object
+	},
+	parseMetadata: function(/* HTMLTableHead */head){
+		//	summary
+		//	Parses the passed HTMLTableHead element to create meta data.
+		this.columns=[];
+		this.sortInformation=[];
+		var row = head.getElementsByTagName("tr")[0];
+		var cells = row.getElementsByTagName("td");
+		if (cells.length == 0){
+			cells = row.getElementsByTagName("th");
+		}
+		for(var i=0; i<cells.length; i++){
+			var o = this.createMetaData({ });
+			
+			//	presentation attributes
+			if(dojo.html.hasAttribute(cells[i], "align")){
+				o.align = dojo.html.getAttribute(cells[i],"align");
+			}
+			if(dojo.html.hasAttribute(cells[i], "valign")){
+				o.valign = dojo.html.getAttribute(cells[i],"valign");
+			}
+			if(dojo.html.hasAttribute(cells[i], "nosort")){
+				o.noSort = (dojo.html.getAttribute(cells[i],"nosort")=="true");
+			}
+			if(dojo.html.hasAttribute(cells[i], "sortusing")){
+				var trans = dojo.html.getAttribute(cells[i],"sortusing");
+				var f = this.getTypeFromString(trans);
+				if (f != null && f != window && typeof(f)=="function"){
+					o.sortFunction=f;
+				}
+			}
+			o.label = dojo.html.renderedTextContent(cells[i]);
+			if(dojo.html.hasAttribute(cells[i], "field")){
+				o.field=dojo.html.getAttribute(cells[i],"field");
+			} else if(o.label.length > 0){
+				o.field=o.label;
+			} else {
+				o.field = "field" + i;
+			}
+			if(dojo.html.hasAttribute(cells[i], "format")){
+				o.format=dojo.html.getAttribute(cells[i],"format");
+			}
+			if(dojo.html.hasAttribute(cells[i], "dataType")){
+				var sortType = dojo.html.getAttribute(cells[i],"dataType");
+				if(sortType.toLowerCase()=="html" || sortType.toLowerCase()=="markup"){
+					o.sortType = "__markup__";	//	always convert to "__markup__"
+				}else{
+					var type = this.getTypeFromString(sortType);
+					if(type){
+						o.sortType = sortType;
+						o.dataType = type;
+					}
+				}
+			}
+
+			//	TODO: set up filtering mechanisms here.
+			if(dojo.html.hasAttribute(cells[i], "filterusing")){
+				var trans = dojo.html.getAttribute(cells[i],"filterusing");
+				var f = this.getTypeFromString(trans);
+				if (f != null && f != window && typeof(f)=="function"){
+					o.filterFunction=f;
+				}
+			}
+			
+			this.columns.push(o);
+
+			//	check to see if there's a default sort, and set the properties necessary
+			if(dojo.html.hasAttribute(cells[i], "sort")){
+				var info = {
+					index:i,
+					direction:0
+				};
+				var dir = dojo.html.getAttribute(cells[i], "sort");
+				if(!isNaN(parseInt(dir))){
+					dir = parseInt(dir);
+					info.direction = (dir != 0) ? 1 : 0;
+				}else{
+					info.direction = (dir.toLowerCase() == "desc") ? 1 : 0;
+				}
+				this.sortInformation.push(info);
+			}
+		}
+		if(this.sortInformation.length == 0){
+			this.sortInformation.push({
+				index:0,
+				direction:0
+			});
+		} else if (this.sortInformation.length > this.maxSortable){
+			this.sortInformation.length = this.maxSortable;
+		}
+	},
+	parseData: function(/* HTMLTableBody */body){
+		//	summary
+		//	Parse HTML data into native JSON structure for the store.
+		if(body.rows.length == 0 && this.columns.length == 0){
+			return;	//	there's no data, ignore me.
+		}
+
+		//	create a data constructor based on what we've got for the fields.
+		var self=this;
+		this["__selected__"] = [];
+		var arr = this.store.getFromHtml(this.columns, body, function(obj, row){
+			obj[self.valueField] = dojo.html.getAttribute(row, "value");
+			if(dojo.html.getAttribute(row, "selected")=="true"){
+				self["__selected__"].push(obj);
+			}
+		});
+		this.store.setData(arr);
+		for(var i=0; i<this["__selected__"].length; i++){
+			this.select(this["__selected__"][i]);
+		}
+		this.renderSelections();
+
+		delete this["__selected__"];
+
+		//	say that we are already initialized so that we don't kill anything
+		this.isInitialized=true;
+	},
+
+	//	standard events
+	onSelect: function(/* HTMLEvent */e){
+		//	summary
+		//	Handles the onclick event of any element.
+		var row = dojo.html.getParentByType(e.target,"tr");
+		if(dojo.html.hasAttribute(row,"emptyRow")){
+			return;
+		}
+		var body = dojo.html.getParentByType(row,"tbody");
+		if(this.multiple){
+			if(e.shiftKey){
+				var startRow;
+				var rows=body.rows;
+				for(var i=0;i<rows.length;i++){
+					if(rows[i]==row){
+						break;
+					}
+					if(this.isRowSelected(rows[i])){
+						startRow=rows[i];
+					}
+				}
+				if(!startRow){
+					startRow = row;
+					for(; i<rows.length; i++){
+						if(this.isRowSelected(rows[i])){
+							row = rows[i];
+							break;
+						}
+					}
+				}
+				this.resetSelections();
+				if(startRow == row){
+					this.toggleSelectionByRow(row);
+				} else {
+					var doSelect = false;
+					for(var i=0; i<rows.length; i++){
+						if(rows[i] == startRow){
+							doSelect=true;
+						}
+						if(doSelect){
+							this.selectByRow(rows[i]);
+						}
+						if(rows[i] == row){
+							doSelect = false;
+						}
+					}
+				}
+			} else {
+				this.toggleSelectionByRow(row);
+			}
+		} else {
+			this.resetSelections();
+			this.toggleSelectionByRow(row);
+		}
+		this.renderSelections();
+	},
+	onSort: function(/* HTMLEvent */e){
+		//	summary
+		//	Sort the table based on the column selected.
+		var oldIndex=this.sortIndex;
+		var oldDirection=this.sortDirection;
+		
+		var source=e.target;
+		var row=dojo.html.getParentByType(source,"tr");
+		var cellTag="td";
+		if(row.getElementsByTagName(cellTag).length==0){
+			cellTag="th";
+		}
+
+		var headers=row.getElementsByTagName(cellTag);
+		var header=dojo.html.getParentByType(source,cellTag);
+		
+		for(var i=0; i<headers.length; i++){
+			dojo.html.setClass(headers[i], this.headerClass);
+			if(headers[i]==header){
+				if(this.sortInformation[0].index != i){
+					this.sortInformation.unshift({ 
+						index:i, 
+						direction:0
+					});
+				} else {
+					this.sortInformation[0] = {
+						index:i,
+						direction:(~this.sortInformation[0].direction)&1
+					};
+				}
+			}
+		}
+
+		this.sortInformation.length = Math.min(this.sortInformation.length, this.maxSortable);
+		for(var i=0; i<this.sortInformation.length; i++){
+			var idx=this.sortInformation[i].index;
+			var dir=(~this.sortInformation[i].direction)&1;
+			dojo.html.setClass(headers[idx], dir==0?this.headerDownClass:this.headerUpClass);
+		}
+		this.render();
+	},
+	onFilter: function(){
+		//	summary
+		//	show or hide rows based on the parameters of the passed filter.
+	},
+
+	//	Filtering methods
+	_defaultFilter: function(/* Object */obj){
+		//	summary
+		//	Always return true as the result of the default filter.
+		return true;
+	},
+	setFilter: function(/* string */field, /* function */fn){
+		//	summary
+		//	set a filtering function on the passed field.
+		for(var i=0; i<this.columns.length; i++){
+			if(this.columns[i].getField() == field){
+				this.columns[i].filterFunction=fn;
+				break;
+			}
+		}
+		this.applyFilters();
+	},
+	setFilterByIndex: function(/* number */idx, /* function */fn){
+		//	summary
+		//	set a filtering function on the passed column index.
+		this.columns[idx].filterFunction=fn;
+		this.applyFilters();
+	},
+	clearFilter: function(/* string */field){
+		//	summary
+		//	clear a filtering function on the passed field.
+		for(var i=0; i<this.columns.length; i++){
+			if(this.columns[i].getField() == field){
+				this.columns[i].filterFunction=this._defaultFilter;
+				break;
+			}
+		}
+		this.applyFilters();
+	}, 
+	clearFilterByIndex: function(/* number */idx){
+		//	summary
+		//	clear a filtering function on the passed column index.
+		this.columns[idx].filterFunction=this._defaultFilter;
+		this.applyFilters();
+	}, 
+	clearFilters: function(){
+		//	summary
+		//	clears all filters.
+		for(var i=0; i<this.columns.length; i++){
+			this.columns[i].filterFunction=this._defaultFilter;
+		}
+		//	we'll do the clear manually, it will be faster.
+		var rows=this.domNode.tBodies[0].rows;
+		for(var i=0; i<rows.length; i++){
+			rows[i].style.display="";
+			if(this.alternateRows){
+				dojo.html[((i % 2 == 1)?"addClass":"removeClass")](rows[i], this.rowAlternateClass);
+			}
+		}
+		this.onFilter();
+	},
+	applyFilters: function(){
+		//	summary
+		//	apply all filters to the table.
+		var alt=0;
+		var rows=this.domNode.tBodies[0].rows;
+		for(var i=0; i<rows.length; i++){
+			var b=true;
+			var row=rows[i];
+			for(var j=0; j<this.columns.length; j++){
+				var value = this.store.getField(this.getDataByRow(row), this.columns[j].getField());
+				if(this.columns[j].getType() == Date && value != null && !value.getYear){
+					value = new Date(value);
+				}
+				if(!this.columns[j].filterFunction(value)){
+					b=false;
+					break;
+				}
+			}
+			row.style.display=(b?"":"none");
+			if(b && this.alternateRows){
+				dojo.html[((alt++ % 2 == 1)?"addClass":"removeClass")](row, this.rowAlternateClass);
+			}
+		}
+		this.onFilter();
+	},
+
+	//	sorting functionality
+	createSorter: function(/* array */info){
+		//	summary
+		//	creates a custom function to be used for sorting.
+		var self=this;
+		var sortFunctions=[];	//	our function stack.
+	
+		function createSortFunction(fieldIndex, dir){
+			var meta=self.columns[fieldIndex];
+			var field=meta.getField();
+			return function(rowA, rowB){
+				if(dojo.html.hasAttribute(rowA,"emptyRow") || dojo.html.hasAttribute(rowB,"emptyRow")){
+					return -1;
+				}
+				//	TODO: check for markup and compare by rendered text.
+				var a = self.store.getField(self.getDataByRow(rowA), field);
+				var b = self.store.getField(self.getDataByRow(rowB), field);
+				var ret = 0;
+				if(a > b) ret = 1;
+				if(a < b) ret = -1;
+				return dir * ret;
+			}
+		}
+
+		var current=0;
+		var max = Math.min(info.length, this.maxSortable, this.columns.length);
+		while(current < max){
+			var direction = (info[current].direction == 0) ? 1 : -1;
+			sortFunctions.push(
+				createSortFunction(info[current].index, direction)
+			);
+			current++;
+		}
+
+		return function(rowA, rowB){
+			var idx=0;
+			while(idx < sortFunctions.length){
+				var ret = sortFunctions[idx++](rowA, rowB);
+				if(ret != 0) return ret;
+			}
+			//	if we got here then we must be equal.
+			return 0; 	
+		};	//	function
+	},
+
+	//	rendering
+	createRow: function(/* object */obj){
+		//	summary
+		//	Create an HTML row based on the passed object
+		var row=document.createElement("tr");
+		dojo.html.disableSelection(row);
+		if(obj.key != null){
+			row.setAttribute("value", obj.key);
+		}
+		for(var j=0; j<this.columns.length; j++){
+			var cell=document.createElement("td");
+			cell.setAttribute("align", this.columns[j].align);
+			cell.setAttribute("valign", this.columns[j].valign);
+			dojo.html.disableSelection(cell);
+			var val = this.store.getField(obj.src, this.columns[j].getField());
+			if(typeof(val)=="undefined"){
+				val="";
+			}
+			this.fillCell(cell, this.columns[j], val);
+			row.appendChild(cell);
+		}
+		return row;	//	HTMLTableRow
+	},
+	fillCell: function(/* HTMLTableCell */cell, /* object */meta, /* object */val){
+		//	summary
+		//	Fill the passed cell with value, based on the passed meta object.
+		if(meta.sortType=="__markup__"){
+			cell.innerHTML=val;
+		} else {
+			if(meta.getType()==Date) {
+				val=new Date(val);
+				if(!isNaN(val)){
+					var format = this.defaultDateFormat;
+					if(meta.format){
+						format = meta.format;
+					}
+					cell.innerHTML = dojo.date.strftime(val, format);
+				} else {
+					cell.innerHTML = val;
+				}
+			} else if ("Number number int Integer float Float".indexOf(meta.getType())>-1){
+				//	TODO: number formatting
+				if(val.length == 0){
+					val="0";
+				}
+				var n = parseFloat(val, 10) + "";
+				//	TODO: numeric formatting + rounding :)
+				if(n.indexOf(".")>-1){
+					n = dojo.math.round(parseFloat(val,10),2);
+				}
+				cell.innerHTML = n;
+			}else{
+				cell.innerHTML = val;
+			}
+		}
+	},
+	prefill: function(){
+		//	summary
+		//	if there's no data in the table, then prefill it with this.minRows.
+		this.isInitialized = false;
+		var body = this.domNode.tBodies[0];
+		while (body.childNodes.length > 0){
+			body.removeChild(body.childNodes[0]);
+		}
+		
+		if(this.minRows>0){
+			for(var i=0; i < this.minRows; i++){
+				var row = document.createElement("tr");
+				if(this.alternateRows){
+					dojo.html[((i % 2 == 1)?"addClass":"removeClass")](row, this.rowAlternateClass);
+				}
+				row.setAttribute("emptyRow","true");
+				for(var j=0; j<this.columns.length; j++){
+					var cell = document.createElement("td");
+					cell.innerHTML = "&nbsp;";
+					row.appendChild(cell);
+				}
+				body.appendChild(row);
+			}
+		}
+	},
+	init: function(){
+		//	summary
+		//	initializes the table of data
+		this.isInitialized=false;
+
+		//	if there is no thead, create it now.
+		var head=this.domNode.getElementsByTagName("thead")[0];
+		if(head.getElementsByTagName("tr").length == 0){
+			//	render the column code.
+			var row=document.createElement("tr");
+			for(var i=0; i<this.columns.length; i++){
+				var cell=document.createElement("td");
+				cell.setAttribute("align", this.columns[i].align);
+				cell.setAttribute("valign", this.columns[i].valign);
+				dojo.html.disableSelection(cell);
+				cell.innerHTML=this.columns[i].label;
+				row.appendChild(cell);
+
+				//	attach the events.
+				if(!this.columns[i].noSort){
+					dojo.event.connect(cell, "onclick", this, "onSort");
+				}
+			}
+			dojo.html.prependChild(row, head);
+		}
+		
+		if(this.store.get().length == 0){
+			return false;
+		}
+
+		var idx=this.domNode.tBodies[0].rows.length;
+		if(!idx || idx==0 || this.domNode.tBodies[0].rows[0].getAttribute("emptyRow")=="true"){
+			idx = 0;
+			var body = this.domNode.tBodies[0];
+			while(body.childNodes.length>0){
+				body.removeChild(body.childNodes[0]);
+			}
+
+			var data = this.store.get();
+			for(var i=0; i<data.length; i++){
+				var row = this.createRow(data[i]);
+				dojo.event.connect(row, "onclick", this, "onSelect");
+				body.appendChild(row);
+				idx++;
+			}
+		}
+
+		//	add empty rows
+		if(this.minRows > 0 && idx < this.minRows){
+			idx = this.minRows - idx;
+			for(var i=0; i<idx; i++){
+				row=document.createElement("tr");
+				row.setAttribute("emptyRow","true");
+				for(var j=0; j<this.columns.length; j++){
+					cell=document.createElement("td");
+					cell.innerHTML="&nbsp;";
+					row.appendChild(cell);
+				}
+				body.appendChild(row);
+			}
+		}
+
+		//	last but not least, show any columns that have sorting already on them.
+		var row=this.domNode.getElementsByTagName("thead")[0].rows[0];
+		var cellTag="td";
+		if(row.getElementsByTagName(cellTag).length==0) cellTag="th";
+		var headers=row.getElementsByTagName(cellTag);
+		for(var i=0; i<headers.length; i++){
+			dojo.html.setClass(headers[i], this.headerClass);
+		}
+		for(var i=0; i<this.sortInformation.length; i++){
+			var idx=this.sortInformation[i].index;
+			var dir=(~this.sortInformation[i].direction)&1;
+			dojo.html.setClass(headers[idx], dir==0?this.headerDownClass:this.headerUpClass);
+		}
+
+		this.isInitialized=true;
+		return this.isInitialized;
+	},
+	render: function(){
+		//	summary
+		//	Renders the actual table data.
+
+	/*	The method that should be called once underlying changes
+	 *	are made, including sorting, filtering, data changes.
+	 *	Rendering the selections themselves are a different method,
+	 *	which render() will call as the last step.
+	 ****************************************************************/
+		if(!this.isInitialized){
+			var b = this.init();
+			if(!b){
+				this.prefill();
+				return;
+			}
+		}
+		
+		//	do the sort
+		var rows=[];
+		var body=this.domNode.tBodies[0];
+		var emptyRowIdx=-1;
+		for(var i=0; i<body.rows.length; i++){
+			rows.push(body.rows[i]);
+		}
+
+		//	build the sorting function, and do the sorting.
+		var sortFunction = this.createSorter(this.sortInformation);
+		if(sortFunction){
+			rows.sort(sortFunction);
+		}
+
+		//	append the rows without killing them, this should help with the HTML problems.
+		for(var i=0; i<rows.length; i++){
+			if(this.alternateRows){
+				dojo.html[((i%2==1)?"addClass":"removeClass")](rows[i], this.rowAlternateClass);
+			}
+			dojo.html[(this.isRowSelected(body.rows[i])?"addClass":"removeClass")](body.rows[i], this.rowSelectedClass);
+			body.appendChild(rows[i]);
+		}
+	},
+	renderSelections: function(){
+		//	summary
+		//	Render all selected objects using CSS.
+		var body=this.domNode.tBodies[0];
+		for(var i=0; i<body.rows.length; i++){
+			dojo.html[(this.isRowSelected(body.rows[i])?"addClass":"removeClass")](body.rows[i], this.rowSelectedClass);
+		}
+	},
+
+	//	widget lifetime handlers
+	initialize: function(){ 
+		//	summary
+		//	Initializes the widget.
+		var self=this;
+		//	connect up binding listeners here.
+		dojo.event.connect(this.store, "onSetData", function(){
+			self.store.forEach(function(element){
+				element.isSelected = false;
+			});
+			self.isInitialized=false;
+			var body = self.domNode.tBodies[0];
+			if(body){
+				while(body.childNodes.length>0){
+					body.removeChild(body.childNodes[0]);
+				}
+			}
+			self.render();
+		});
+		dojo.event.connect(this.store, "onClearData", function(){
+			self.render();
+		});
+		dojo.event.connect(this.store, "onAddData", function(addedObject){
+			var row=self.createRow(addedObject);
+			dojo.event.connect(row, "onclick", self, "onSelect");
+			self.domNode.tBodies[0].appendChild(row);
+			self.render();
+		});
+		dojo.event.connect(this.store, "onAddDataRange", function(arr){
+			for(var i=0; i<arr.length; i++){
+				arr[i].isSelected=false;
+				var row=self.createRow(arr[i]);
+				dojo.event.connect(row, "onclick", self, "onSelect");
+				self.domNode.tBodies[0].appendChild(row);
+			};
+			self.render();
+		});
+		dojo.event.connect(this.store, "onRemoveData", function(removedObject){
+			var rows = self.domNode.tBodies[0].rows;
+			for(var i=0; i<rows.length; i++){
+				if(self.getDataByRow(rows[i]) == removedObject.src){
+					rows[i].parentNode.removeChild(rows[i]);
+					break;
+				}
+			}
+			self.render();
+		});
+		dojo.event.connect(this.store, "onUpdateField", function(obj, fieldPath, val){
+			var row = self.getRow(obj);
+			var idx = self.getColumnIndex(fieldPath);
+			if(row && row.cells[idx] && self.columns[idx]){
+				self.fillCell(row.cells[idx], self.columns[idx], val);
+			}
+		});
+	},
+	postCreate: function(){
+		//	summary
+		//	finish widget initialization.
+		this.store.keyField = this.valueField;
+
+		if(this.domNode){
+			//	start by making sure domNode is a table element;
+			if(this.domNode.nodeName.toLowerCase() != "table"){
+			}
+
+			//	see if there is columns set up already
+			if(this.domNode.getElementsByTagName("thead")[0]){
+				var head=this.domNode.getElementsByTagName("thead")[0];
+				if(this.headClass.length > 0){
+					head.className = this.headClass;
+				}
+				dojo.html.disableSelection(this.domNode);
+				this.parseMetadata(head);
+
+				var header="td";
+				if(head.getElementsByTagName(header).length==0){
+					header="th";
+				}
+				var headers = head.getElementsByTagName(header);
+				for(var i=0; i<headers.length; i++){
+					if(!this.columns[i].noSort){
+						dojo.event.connect(headers[i], "onclick", this, "onSort");
+					}
+				}
+			} else {
+				this.domNode.appendChild(document.createElement("thead"));
+			}
+
+			// if the table doesn't have a tbody already, add one and grab a reference to it
+			if (this.domNode.tBodies.length < 1) {
+				var body = document.createElement("tbody");
+				this.domNode.appendChild(body);
+			} else {
+				var body = this.domNode.tBodies[0];
+			}
+
+			if (this.tbodyClass.length > 0){
+				body.className = this.tbodyClass;
+			}
+			this.parseData(body);
+		}
+	}
+});

Propchange: myfaces/tomahawk/trunk/core/src/main/resources/org/apache/myfaces/custom/dojo/resource/src/widget/FilteringTable.js
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: myfaces/tomahawk/trunk/core/src/main/resources/org/apache/myfaces/custom/dojo/resource/src/widget/FilteringTable.js
------------------------------------------------------------------------------
    svn:keywords = "Id Author LastChangedDate LastChangedBy LastChangedRevision"

Propchange: myfaces/tomahawk/trunk/core/src/main/resources/org/apache/myfaces/custom/dojo/resource/src/widget/FilteringTable.js
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Modified: myfaces/tomahawk/trunk/core/src/main/resources/org/apache/myfaces/custom/dojo/resource/src/widget/FisheyeList.js
URL: http://svn.apache.org/viewvc/myfaces/tomahawk/trunk/core/src/main/resources/org/apache/myfaces/custom/dojo/resource/src/widget/FisheyeList.js?view=diff&rev=473277&r1=473276&r2=473277
==============================================================================
--- myfaces/tomahawk/trunk/core/src/main/resources/org/apache/myfaces/custom/dojo/resource/src/widget/FisheyeList.js (original)
+++ myfaces/tomahawk/trunk/core/src/main/resources/org/apache/myfaces/custom/dojo/resource/src/widget/FisheyeList.js Fri Nov 10 01:15:01 2006
@@ -9,8 +9,6 @@
 */
 
 dojo.provide("dojo.widget.FisheyeList");
-dojo.provide("dojo.widget.html.FisheyeList");
-dojo.provide("dojo.widget.html.FisheyeListItem");
 
 //
 // TODO
@@ -20,76 +18,114 @@
 
 dojo.require("dojo.widget.*");
 dojo.require("dojo.widget.HtmlWidget");
-dojo.require("dojo.dom");
-dojo.require("dojo.html");
-dojo.require("dojo.style");
-dojo.require("dojo.event");
-
-dojo.widget.tags.addParseTreeHandler("dojo:FisheyeList");
-dojo.widget.tags.addParseTreeHandler("dojo:FisheyeListItem");
-
-dojo.widget.html.FisheyeList = function(){
-	dojo.widget.HtmlWidget.call(this);
-}
-dojo.inherits(dojo.widget.html.FisheyeList, dojo.widget.HtmlWidget);
+dojo.require("dojo.html.style");
+dojo.require("dojo.html.selection");
+dojo.require("dojo.html.util");
+dojo.require("dojo.event.*");
+
+/*
+ * summary
+ *	Menu similar to the fish eye menu on the Mac OS
+ * usage
+ *	<div dojoType="FisheyeList"
+ *	itemWidth="40" itemHeight="40"
+ *	itemMaxWidth="150" itemMaxHeight="150"
+ *	orientation="horizontal"
+ *	effectUnits="2"
+ *	itemPadding="10"
+ *	attachEdge="center"
+ *	labelEdge="bottom">
+ *
+ *		<div dojoType="FisheyeListItem"
+ *			id="item1"
+ *			onclick="alert('click on' + this.caption + '(from widget id ' + this.widgetId + ')!');"
+ *			caption="Item 1"
+ *			iconsrc="images/fisheye_1.png">
+ *		</div>
+ *		...
+ *	</div>
+ */
+dojo.widget.defineWidget(
+	"dojo.widget.FisheyeList",
+	dojo.widget.HtmlWidget,
+function(){
+	this.pos = {x: -1, y: -1};		// current cursor position, relative to the grid
 
-dojo.lang.extend(dojo.widget.html.FisheyeList, {
-
-	templateString: '<div class="dojoHtmlFisheyeListBar"></div>',
-	templateCssPath: dojo.uri.dojoUri("src/widget/templates/HtmlFisheyeList.css"),
-	widgetType: "FisheyeList",
-
-	EDGE: {
+	this.EDGE = {
 		CENTER: 0,
 		LEFT: 1,
 		RIGHT: 2,
 		TOP: 3,
 		BOTTOM: 4
-	},
-
-	isContainer: true,
-	snarfChildDomOutput: true,
-	
-	pos: {x: -1, y: -1},		// current cursor position, relative to the grid
+	};
 	
 	// for conservative trigger mode, when triggered, timerScale is gradually increased from 0 to 1
-	timerScale: 1.0,
+	this.timerScale = 1.0;
 
-	/////////////////////////////////////////////////////////////////
-	//
-	// i spy OPTIONS!!!!
-	//
+},
+{
+	templateString: '<div class="dojoHtmlFisheyeListBar"></div>',
+	templateCssPath: dojo.uri.dojoUri("src/widget/templates/FisheyeList.css"),
 
+	isContainer: true,
+	snarfChildDomOutput: true,
+
+	// Integer
+	//	width of menu item (in pixels) in it's dormant state (when the mouse is far away)
 	itemWidth: 40,
+
+	// Integer
+	//	height of menu item (in pixels) in it's dormant state (when the mouse is far away)
 	itemHeight: 40,
 
+	// Integer
+	//	width of menu item (in pixels) in it's fully enlarged state (when the mouse is directly over it)
 	itemMaxWidth: 150,
+
+	// Integer
+	//	height of menu item (in pixels) in it's fully enlarged state (when the mouse is directly over it)
 	itemMaxHeight: 150,
 
+
+	// String
+	//	orientation of the menu, either "horizontal" or "vertical"
 	orientation: 'horizontal',
-	
-	conservativeTrigger: false,		// don't active menu until mouse is over an image (macintosh style)
 
+	// Boolean
+	//	if true, don't start enlarging menu items until mouse is over an image;
+	//	if false, start enlarging menu items as the mouse moves near them.
+	conservativeTrigger: false,
+
+	// Number
+	//	controls how much reaction the menu makes, relative to the distance of the mouse from the menu
 	effectUnits: 2,
+	
+	// Integer
+	//	padding (in pixels) betweeen each menu item
 	itemPadding: 10,
 
+	// String
+	//	controls the border that the menu items don't expand past;
+	//	for example, if set to "top", then the menu items will drop downwards as they expand.
+	// values
+	//	"center", "left", "right", "top", "bottom".
 	attachEdge: 'center',
+
+	// String
+	//	controls were the labels show up in relation to the menu item icons
+	// values
+	//	"center", "left", "right", "top", "bottom".
 	labelEdge: 'bottom',
 
+	// Boolean
+	//	for browsers that support svg, use the svg image (specified in FisheyeListIem.svgSrc)
+	//	rather than the iconSrc image attribute
 	enableCrappySvgSupport: false,
 
-
-	//
-	//
-	//
-	/////////////////////////////////////////////////////////////////
-
-	fillInTemplate: function(args, frag) {
-		//dojo.debug(this.orientation);
-
+	fillInTemplate: function() {
 		dojo.html.disableSelection(this.domNode);
 
-		this.isHorizontal = (this.orientation == 'horizontal') ? 1 : 0;
+		this.isHorizontal = (this.orientation == 'horizontal');
 		this.selectedNode = -1;
 
 		this.isOver = false;
@@ -101,9 +137,8 @@
 		//
 		// only some edges make sense...
 		//
-
-		this.anchorEdge = this.toEdge(this.attachEdge, this.EDGE.CENTER);
-		this.labelEdge  = this.toEdge(this.labelEdge,  this.EDGE.TOP);
+		this.anchorEdge = this._toEdge(this.attachEdge, this.EDGE.CENTER);
+		this.labelEdge  = this._toEdge(this.labelEdge,  this.EDGE.TOP);
 
 		if ( this.isHorizontal && (this.anchorEdge == this.EDGE.LEFT  )){ this.anchorEdge = this.EDGE.CENTER; }
 		if ( this.isHorizontal && (this.anchorEdge == this.EDGE.RIGHT )){ this.anchorEdge = this.EDGE.CENTER; }
@@ -116,11 +151,9 @@
 		if (!this.isHorizontal && (this.labelEdge == this.EDGE.TOP   )){ this.labelEdge = this.EDGE.LEFT; }
 		if (!this.isHorizontal && (this.labelEdge == this.EDGE.BOTTOM)){ this.labelEdge = this.EDGE.LEFT; }
 
-
 		//
 		// figure out the proximity size
 		//
-
 		this.proximityLeft   = this.itemWidth  * (this.effectUnits - 0.5);
 		this.proximityRight  = this.itemWidth  * (this.effectUnits - 0.5);
 		this.proximityTop    = this.itemHeight * (this.effectUnits - 0.5);
@@ -146,22 +179,22 @@
 		}
 	},
 	
-	postCreate: function(args, frag) {
-		this.initializePositioning();
+	postCreate: function() {
+		this._initializePositioning();
 
 		//
 		// in liberal trigger mode, activate menu whenever mouse is close
 		//
 		if( !this.conservativeTrigger ){
-			dojo.event.connect(document.documentElement, "onmousemove", this, "mouseHandler");
+			dojo.event.connect(document.documentElement, "onmousemove", this, "_onMouseMove");
 		}
 		
 		// Deactivate the menu if mouse is moved off screen (doesn't work for FF?)
-		dojo.event.connect(document.documentElement, "onmouseout", this, "onBodyOut");
-		dojo.event.connect(this, "addChild", this, "initializePositioning");
+		dojo.event.connect(document.documentElement, "onmouseout", this, "_onBodyOut");
+		dojo.event.connect(this, "addChild", this, "_initializePositioning");
 	},
 
-	initializePositioning: function(){
+	_initializePositioning: function(){
 		this.itemCount = this.children.length;
 
 		this.barWidth  = (this.isHorizontal ? this.itemCount : 1) * this.itemWidth;
@@ -173,7 +206,6 @@
 		//
 		// calculate effect ranges for each item
 		//
-
 		for (var i=0; i<this.children.length; i++){
 
 			this.children[i].posX = this.itemWidth  * (this.isHorizontal ? i : 0);
@@ -201,15 +233,12 @@
 			//dojo.debug('effect range for '+i+' is '+range_lhs+'/'+range_rhs);
 		}
 
-
 		//
 		// create the bar
 		//
-
 		this.domNode.style.width = this.barWidth + 'px';
 		this.domNode.style.height = this.barHeight + 'px';
 
-
 		//
 		// position the items
 		//
@@ -241,76 +270,78 @@
 		//
 		// calc the grid
 		//
-
-		this.calcHitGrid();
+		this._calcHitGrid();
 	},
 
-	onBodyOut: function(e){
+	_onBodyOut: function(/*Event*/ e){
 		// clicking over an object inside of body causes this event to fire; ignore that case
-		if( dojo.html.overElement(document.body, e) ){
+		if( dojo.html.overElement(dojo.body(), e) ){
 			return;
 		}
-		this.setDormant(e);
+		this._setDormant(e);
 	},
 
-	// when mouse moves out of menu's range
-	setDormant: function(e){
+	_setDormant: function(/*Event*/ e){
+		// summary: called when mouse moves out of menu's range
+
 		if( !this.isOver ){ return; }	// already dormant?
 		this.isOver = false;
 
 		if ( this.conservativeTrigger ) {
 			// user can't re-trigger the menu expansion
 			// until he mouses over a icon again
-			dojo.event.disconnect(document.documentElement, "onmousemove", this, "mouseHandler");
+			dojo.event.disconnect(document.documentElement, "onmousemove", this, "_onMouseMove");
 		}
-		this.onGridMouseMove(-1, -1);
+		this._onGridMouseMove(-1, -1);
 	},
 
-	// when mouse is moved into menu's range
-	setActive: function(e){
+	_setActive: function(/*Event*/ e){
+		// summary: called when mouse is moved into menu's range
+
 		if( this.isOver ){ return; }	// already activated?
 		this.isOver = true;
 
 		if ( this.conservativeTrigger ) {
 			// switch event handlers so that we handle mouse events from anywhere near
 			// the menu
-			dojo.event.connect(document.documentElement, "onmousemove", this, "mouseHandler");
+			dojo.event.connect(document.documentElement, "onmousemove", this, "_onMouseMove");
 
 			this.timerScale=0.0;
 
 			// call mouse handler to do some initial necessary calculations/positioning
-			this.mouseHandler(e);
+			this._onMouseMove(e);
 
 			// slowly expand the icon size so it isn't jumpy
-			this.expandSlowly();
+			this._expandSlowly();
 		}
 	},
 
-	// when mouse is moved
-	mouseHandler: function(e) {
+	_onMouseMove: function(/*Event*/ e) {
+		// summary: called when mouse is moved
 		if ((e.pageX >= this.hitX1) && (e.pageX <= this.hitX2) &&
 			(e.pageY >= this.hitY1) && (e.pageY <= this.hitY2)){
 			if( !this.isOver ){
-				this.setActive(e);
+				this._setActive(e);
 			}
-			this.onGridMouseMove(e.pageX-this.hitX1, e.pageY-this.hitY1);
+			this._onGridMouseMove(e.pageX-this.hitX1, e.pageY-this.hitY1);
 		}else{
 			if (this.isOver){
-				this.setDormant(e);
+				this._setDormant(e);
 			}
 		}
 	},
 
 	onResized: function() {
-		this.calcHitGrid();
+		this._calcHitGrid();
 	},
 
-	onGridMouseMove: function(x, y){
+	_onGridMouseMove: function(x, y){
+		// summary: called when mouse is moved in the vicinity of the menu
 		this.pos = {x:x, y:y};
-		this.paint();
+		this._paint();
 	},
 	
-	paint: function(){
+	_paint: function(){
 		var x=this.pos.x;
 		var y=this.pos.y;
 
@@ -319,7 +350,6 @@
 		//
 		// figure out our main index
 		//
-
 		var pos = this.isHorizontal ? x : y;
 		var prx = this.isHorizontal ? this.proximityLeft : this.proximityTop;
 		var siz = this.isHorizontal ? this.itemWidth : this.itemHeight;
@@ -332,11 +362,9 @@
 
 		if (max_off_cen > this.effectUnits){ max_off_cen = this.effectUnits; }
 
-
 		//
 		// figure out our off-axis weighting
 		//
-
 		var off_weight = 0;
 
 		if (this.anchorEdge == this.EDGE.BOTTOM){
@@ -356,7 +384,6 @@
 			off_weight = (cen2 < 0.5) ? 1 : (this.totalWidth - x) / (this.proximityRight + (this.itemWidth / 2));
 		}
 		if (this.anchorEdge == this.EDGE.CENTER){
-
 			if (this.isHorizontal){
 				off_weight = y / (this.totalHeight);
 			}else{
@@ -370,18 +397,13 @@
 			off_weight *= 2;
 		}
 
-
 		//
 		// set the sizes
 		//
-
 		for(var i=0; i<this.itemCount; i++){
-
-			var weight = this.weightAt(cen, i);
-
+			var weight = this._weighAt(cen, i);
 			if (weight < 0){weight = 0;}
-
-			this.setitemsize(i, weight * off_weight);
+			this._setItemSize(i, weight * off_weight);
 		}
 
 		//
@@ -403,40 +425,16 @@
 			offset = (cen - main_p) * ((this.isHorizontal ? this.itemWidth : this.itemHeight) - this.children[main_p].sizeMain);
 		}
 
-		this.positionElementsFrom(main_p, offset);
+		this._positionElementsFrom(main_p, offset);
 	},
 
-	weightAt: function(cen, i){
-
+	_weighAt: function(/*Integer*/ cen, /*Integer*/ i){
 		var dist = Math.abs(cen - i);
-
 		var limit = ((cen - i) > 0) ? this.children[i].effectRangeRght : this.children[i].effectRangeLeft;
-
-		return (dist > limit) ? 0 : (1 - dist / limit);
+		return (dist > limit) ? 0 : (1 - dist / limit);			// Integer
 	},
 
-	positionFromNode: function(p, w){
-
-		//
-		// we need to grow all the nodes growing out from node 'i'
-		//
-
-		this.setitemsize(p, w);
-
-		var wx = w;
-		for(var i=p; i<this.itemCount; i++){
-			wx = 0.8 * wx;
-			this.setitemsize(i, wx);
-		}
-
-		var wx = w;
-		for(var i=p; i>=0; i--){
-			wx = 0.8 * wx;
-			this.setitemsize(i, wx);
-		}
-	},
-
-	setitemsize: function(p, scale){
+	_setItemSize: function(p, scale){
 		scale *= this.timerScale;
 		var w = Math.round(this.itemWidth  + ((this.itemMaxWidth  - this.itemWidth ) * scale));
 		var h = Math.round(this.itemHeight + ((this.itemMaxHeight - this.itemHeight) * scale));
@@ -450,24 +448,16 @@
 			this.children[p].sizeOff  = h;
 
 			var y = 0;
-
 			if (this.anchorEdge == this.EDGE.TOP){
-
 				y = (this.children[p].cenY - (this.itemHeight / 2));
-
 			}else if (this.anchorEdge == this.EDGE.BOTTOM){
-
 				y = (this.children[p].cenY - (h - (this.itemHeight / 2)));
-
 			}else{
-
 				y = (this.children[p].cenY - (h / 2));
 			}
 
 			this.children[p].usualX = Math.round(this.children[p].cenX - (w / 2));
-			
 			this.children[p].domNode.style.top  = y + 'px';
-
 			this.children[p].domNode.style.left  = this.children[p].usualX + 'px';
 
 		}else{
@@ -479,16 +469,11 @@
 			this.children[p].sizeMain = h;
 
 			var x = 0;
-
 			if (this.anchorEdge == this.EDGE.LEFT){
-
 				x = this.children[p].cenX - (this.itemWidth / 2);
-
 			}else if (this.anchorEdge == this.EDGE.RIGHT){
-
 				x = this.children[p].cenX - (w - (this.itemWidth / 2));
 			}else{
-
 				x = this.children[p].cenX - (w / 2);
 			}
 
@@ -506,7 +491,7 @@
 		}
 	},
 
-	positionElementsFrom: function(p, offset){
+	_positionElementsFrom: function(p, offset){
 
 		var pos = 0;
 
@@ -517,17 +502,14 @@
 			pos = Math.round(this.children[p].usualY + offset);
 			this.children[p].domNode.style.top = pos + 'px';
 		}
-		this.positionLabel(this.children[p]);
+		this._positionLabel(this.children[p]);
 
 
 		//
 		// position before
 		//
-
 		var bpos = pos;
-
 		for(var i=p-1; i>=0; i--){
-
 			bpos -= this.children[i].sizeMain;
 
 			if (this.isHorizontal){
@@ -535,17 +517,14 @@
 			}else{
 				this.children[i].domNode.style.top = bpos + 'px';
 			}
-			this.positionLabel(this.children[i]);
+			this._positionLabel(this.children[i]);
 		}
 
 		//
 		// position after
 		//
-
 		var apos = pos;
-
 		for(var i=p+1; i<this.itemCount; i++){
-
 			apos += this.children[i-1].sizeMain;
 
 			if (this.isHorizontal){
@@ -553,46 +532,45 @@
 			}else{
 				this.children[i].domNode.style.top = apos + 'px';
 			}
-			this.positionLabel(this.children[i]);
+			this._positionLabel(this.children[i]);
 		}
 
 	},
 
-	positionLabel: function(itm){
+	_positionLabel: function(itm){
 
 		var x = 0;
 		var y = 0;
 		
-		var labelW = dojo.style.getOuterWidth(itm.lblNode);
-		var labelH = dojo.style.getOuterHeight(itm.lblNode);
+		var mb = dojo.html.getMarginBox(itm.lblNode);
 
 		if (this.labelEdge == this.EDGE.TOP){
-			x = Math.round((itm.sizeW / 2) - (labelW / 2));
-			y = -labelH;
+			x = Math.round((itm.sizeW / 2) - (mb.width / 2));
+			y = -mb.height;
 		}
 
 		if (this.labelEdge == this.EDGE.BOTTOM){
-			x = Math.round((itm.sizeW / 2) - (labelW / 2));
+			x = Math.round((itm.sizeW / 2) - (mb.width / 2));
 			y = itm.sizeH;
 		}
 
 		if (this.labelEdge == this.EDGE.LEFT){
-			x = -labelW;
-			y = Math.round((itm.sizeH / 2) - (labelH / 2));
+			x = -mb.width;
+			y = Math.round((itm.sizeH / 2) - (mb.height / 2));
 		}
 
 		if (this.labelEdge == this.EDGE.RIGHT){
 			x = itm.sizeW;
-			y = Math.round((itm.sizeH / 2) - (labelH / 2));
+			y = Math.round((itm.sizeH / 2) - (mb.height / 2));
 		}
 
 		itm.lblNode.style.left = x + 'px';
 		itm.lblNode.style.top  = y + 'px';
 	},
 
-	calcHitGrid: function(){
+	_calcHitGrid: function(){
 
-		var pos = dojo.style.getAbsolutePosition(this.domNode, true);
+		var pos = dojo.html.getAbsolutePosition(this.domNode, true);
 
 		this.hitX1 = pos.x - this.proximityLeft;
 		this.hitY1 = pos.y - this.proximityTop;
@@ -602,42 +580,54 @@
 		//dojo.debug(this.hitX1+','+this.hitY1+' // '+this.hitX2+','+this.hitY2);
 	},
 
-	toEdge: function(inp, def){
+	_toEdge: function(inp, def){
 		return this.EDGE[inp.toUpperCase()] || def;
 	},
 	
-	// slowly expand the image to user specified max size
-	expandSlowly: function(){
+	_expandSlowly: function(){
+		// summary: slowly expand the image to user specified max size
 		if( !this.isOver ){ return; }
 		this.timerScale += 0.2;
-		this.paint();
+		this._paint();
 		if ( this.timerScale<1.0 ) {
-			dojo.lang.setTimeout(this, "expandSlowly", 10);
+			dojo.lang.setTimeout(this, "_expandSlowly", 10);
 		}
 	},
 
 	destroy: function(){
 		// need to disconnect when we destroy
-		dojo.event.disconnect(document.documentElement, "onmouseout", this, "onBodyOut");
-		dojo.event.disconnect(document.documentElement, "onmousemove", this, "mouseHandler");
-		dojo.widget.html.FisheyeList.superclass.destroy.call(this);
+		dojo.event.disconnect(document.documentElement, "onmouseout", this, "_onBodyOut");
+		dojo.event.disconnect(document.documentElement, "onmousemove", this, "_onMouseMove");
+		dojo.widget.FisheyeList.superclass.destroy.call(this);
 	}
 });
 
-dojo.widget.html.FisheyeListItem = function(){
-	dojo.widget.HtmlWidget.call(this);
-}
-dojo.inherits(dojo.widget.html.FisheyeListItem, dojo.widget.HtmlWidget);
-
-dojo.lang.extend(dojo.widget.html.FisheyeListItem, {
-	widgetType: "FisheyeListItem",
-	
-	// Constructor arguments
+/*
+ * summary
+ *	Menu item inside of a FisheyeList.
+ *	See FisheyeList documentation for details on usage.
+ */
+dojo.widget.defineWidget(
+	"dojo.widget.FisheyeListItem",
+	dojo.widget.HtmlWidget,
+{
+	// String
+	//	pathname to image file (jpg, gif, png, etc.) of icon for this menu item
 	iconSrc: "",
+
+	// String
+	//	pathname to svg file of icon for this menu item
 	svgSrc: "",
+	
+	// String
+	//	label to print next to the icon, when it is moused-over
 	caption: "",
 
-	blankImgPath: dojo.uri.dojoUri("src/widget/templates/images/blank.gif"),
+	// String
+	//	will be set to the id of the orginal div element
+	id: "",
+
+	_blankImgPath: dojo.uri.dojoUri("src/widget/templates/images/blank.gif"),
 
 	templateString:
 		'<div class="dojoHtmlFisheyeListItem">' +
@@ -645,8 +635,6 @@
 		'  <div class="dojoHtmlFisheyeListItemLabel" dojoAttachPoint="lblNode"></div>' +
 		'</div>',
 	
-	imgNode: null,
-
 	fillInTemplate: function() {
 		//
 		// set image
@@ -654,13 +642,22 @@
 		// this.parent.enableCrappySvgSupport is not available to this function
 		//
 		if (this.svgSrc != ""){
-			this.svgNode = this.createSvgNode(this.svgSrc);
+			this.svgNode = this._createSvgNode(this.svgSrc);
 			this.domNode.appendChild(this.svgNode);
 			this.imgNode.style.display = 'none';
-		} else if((this.iconSrc.toLowerCase().substring(this.iconSrc.length-4)==".png")&&(dojo.render.html.ie)){
+		} else if((this.iconSrc.toLowerCase().substring(this.iconSrc.length-4)==".png")&&(dojo.render.html.ie)&&(!dojo.render.html.ie70)){
+			/* we set the id of the new fisheyeListItem to the id of the div defined in the HTML */
+			if (dojo.dom.hasParent(this.imgNode) && this.id != ""){
+				var parent = this.imgNode.parentNode;
+				parent.setAttribute("id", this.id);
+			}
 			this.imgNode.style.filter = "progid:DXImageTransform.Microsoft.AlphaImageLoader(src='"+this.iconSrc+"', sizingMethod='scale')";
-			this.imgNode.src = this.blankImgPath.toString();
+			this.imgNode.src = this._blankImgPath.toString();
 		} else {
+			if (dojo.dom.hasParent(this.imgNode) && this.id != ""){
+				var parent = this.imgNode.parentNode;
+				parent.setAttribute("id", this.id);
+			}
 			this.imgNode.src = this.iconSrc;
 		}
 
@@ -673,8 +670,7 @@
 		dojo.html.disableSelection(this.domNode);
 	},
 	
-	createSvgNode: function(src){
-
+	_createSvgNode: function(src){
 		var elm = document.createElement('embed');
 		elm.src = src;
 		elm.type = 'image/svg+xml';
@@ -722,22 +718,25 @@
 		return elm;
 	},
 
-	onMouseOver: function(e) {
+	onMouseOver: function(/*Event*/ e) {
+		// summary: callback when user moves mouse over this menu item
 		// in conservative mode, don't activate the menu until user mouses over an icon
 		if( !this.parent.isOver ){
-			this.parent.setActive(e);
+			this.parent._setActive(e);
 		}
 		if ( this.caption != "" ) {
 			dojo.html.addClass(this.lblNode, "selected");
-			this.parent.positionLabel(this);
+			this.parent._positionLabel(this);
 		}
 	},
 	
-	onMouseOut: function() {
+	onMouseOut: function(/*Event*/ e) {
+		// summary: callback when user moves mouse off of this menu item
 		dojo.html.removeClass(this.lblNode, "selected");
 	},
 
-	onClick: function() {
+	onClick: function(/*Event*/ e) {
+		// summary: user overridable callback when user clicks this menu item
 	}
 });