You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@tapestry.apache.org by jk...@apache.org on 2006/05/23 01:11:13 UTC

svn commit: r408783 [18/27] - in /tapestry/tapestry4/trunk: examples/TimeTracker/src/context/ framework/src/descriptor/META-INF/ framework/src/java/org/apache/tapestry/ framework/src/java/org/apache/tapestry/dojo/ framework/src/java/org/apache/tapestry...

Added: tapestry/tapestry4/trunk/framework/src/js/dojo/src/widget/Editor2.js
URL: http://svn.apache.org/viewvc/tapestry/tapestry4/trunk/framework/src/js/dojo/src/widget/Editor2.js?rev=408783&view=auto
==============================================================================
--- tapestry/tapestry4/trunk/framework/src/js/dojo/src/widget/Editor2.js (added)
+++ tapestry/tapestry4/trunk/framework/src/js/dojo/src/widget/Editor2.js Mon May 22 16:10:12 2006
@@ -0,0 +1,378 @@
+/*
+	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:
+ * - font selector
+ * - test, bug fix, more features :)
+*/
+dojo.provide("dojo.widget.Editor2");
+dojo.provide("dojo.widget.html.Editor2");
+dojo.require("dojo.io.*");
+dojo.require("dojo.widget.*");
+dojo.require("dojo.widget.RichText");
+dojo.require("dojo.widget.Editor2Toolbar");
+// dojo.require("dojo.widget.ColorPalette");
+// dojo.require("dojo.string.extras");
+
+dojo.widget.defineWidget(
+	"dojo.widget.html.Editor2",
+	dojo.widget.html.RichText,
+	{
+		saveUrl: "",
+		saveMethod: "post",
+		saveArgName: "editorContent",
+		closeOnSave: false,
+		shareToolbar: false,
+		toolbarAlwaysVisible: false,
+		htmlEditing: false,
+		_inHtmlMode: false,
+		_htmlEditNode: null,
+
+		commandList: dojo.widget.html.Editor2Toolbar.prototype.commandList,
+		toolbarWidget: null,
+		scrollInterval: null,
+		
+
+		editorOnLoad: function(){
+			var toolbars = dojo.widget.byType("Editor2Toolbar");
+			if((!toolbars.length)||(!this.shareToolbar)){
+				var tbOpts = {};
+				tbOpts.templatePath = dojo.uri.dojoUri("src/widget/templates/HtmlEditorToolbarOneline.html");
+				this.toolbarWidget = dojo.widget.createWidget("Editor2Toolbar", 
+										tbOpts, this.domNode, "before");
+				dojo.event.connect(this, "destroy", this.toolbarWidget, "destroy");
+				this.toolbarWidget.hideUnusableButtons(this);
+
+				if(this.object){
+					this.tbBgIframe = new dojo.html.BackgroundIframe(this.toolbarWidget.domNode);
+					this.tbBgIframe.iframe.style.height = "30px";
+				}
+
+				// need to set position fixed to wherever this thing has landed
+				if(this.toolbarAlwaysVisible){
+					var src = document["documentElement"]||window;
+					this.scrollInterval = setInterval(dojo.lang.hitch(this, "globalOnScrollHandler"), 100);
+					// dojo.event.connect(src, "onscroll", this, "globalOnScrollHandler");
+					dojo.event.connect("before", this, "destroyRendering", this, "unhookScroller");
+				}
+			}else{
+				// FIXME: 	should we try harder to explicitly manage focus in
+				// 			order to prevent too many editors from all querying
+				// 			for button status concurrently?
+				// FIXME: 	selecting in one shared toolbar doesn't clobber
+				// 			selection in the others. This is problematic.
+				this.toolbarWidget = toolbars[0];
+			}
+			dojo.event.topic.registerPublisher("Editor2.clobberFocus", this.editNode, "onfocus");
+			// dojo.event.topic.registerPublisher("Editor2.clobberFocus", this.editNode, "onclick");
+			dojo.event.topic.subscribe("Editor2.clobberFocus", this, "setBlur");
+			dojo.event.connect(this.editNode, "onfocus", this, "setFocus");
+			dojo.event.connect(this.toolbarWidget.linkButton, "onclick", 
+				dojo.lang.hitch(this, function(){
+					var range;
+					if(this.document.selection){
+						range = this.document.selection.createRange().text;
+					}else if(dojo.render.html.mozilla){
+						range = this.window.getSelection().toString();
+					}
+					if(range.length){
+						this.toolbarWidget.exec("createlink", 
+							prompt("Please enter the URL of the link:", "http://"));
+					}else{
+						alert("Please select text to link");
+					}
+				})
+			);
+
+			var focusFunc = dojo.lang.hitch(this, function(){ 
+				if(dojo.render.html.ie){
+					this.editNode.focus();
+				}else{
+					this.window.focus(); 
+				}
+			});
+
+			dojo.event.connect(this.toolbarWidget, "formatSelectClick", focusFunc);
+			dojo.event.connect(this, "execCommand", focusFunc);
+
+			if(this.htmlEditing){
+				var tb = this.toolbarWidget.htmltoggleButton;
+				if(tb){
+					tb.style.display = "";
+					dojo.event.connect(this.toolbarWidget, "htmltoggleClick",
+										this, "toggleHtmlEditing");
+				}
+			}
+		},
+
+		toggleHtmlEditing: function(){
+			if(!this._inHtmlMode){
+				this._inHtmlMode = true;
+				this.toolbarWidget.highlightButton("htmltoggle");
+				if(!this._htmlEditNode){
+					this._htmlEditNode = document.createElement("textarea");
+					dojo.html.insertBefore(this._htmlEditNode, this.domNode);
+				}
+				this._htmlEditNode.style.display = "";
+				this._htmlEditNode.style.width = "100%";
+				this._htmlEditNode.style.height = dojo.style.getInnerHeight(this.editNode)+"px";
+				this._htmlEditNode.value = this.editNode.innerHTML;
+				this.domNode.style.display = "none";
+			}else{
+				this._inHtmlMode = false;
+				this.domNode.style.display = "";
+				this.toolbarWidget.unhighlightButton("htmltoggle");
+				dojo.lang.setTimeout(this, "replaceEditorContent", 1, this._htmlEditNode.value);
+				this._htmlEditNode.style.display = "none";
+				this.editNode.focus();
+			}
+		},
+
+		setFocus: function(){
+			// dojo.debug("setFocus:", this);
+			dojo.event.connect(this.toolbarWidget, "exec", this, "execCommand");
+		},
+
+		setBlur: function(){
+			// dojo.debug("setBlur:", this);
+			dojo.event.disconnect(this.toolbarWidget, "exec", this, "execCommand");
+		},
+
+		_scrollSetUp: false,
+		_fixEnabled: false,
+		_scrollThreshold: false,
+		_handleScroll: true,
+		globalOnScrollHandler: function(){
+			var isIE = dojo.render.html.ie;
+			if(!this._handleScroll){ return; }
+			var ds = dojo.style;
+			var tdn = this.toolbarWidget.domNode;
+			var db = document["body"];
+			var totalHeight = ds.getOuterHeight(tdn);
+			if(!this._scrollSetUp){
+				this._scrollSetUp = true;
+				var editorWidth =  ds.getOuterWidth(this.domNode); 
+				this._scrollThreshold = ds.abs(tdn, false).y;
+				// dojo.debug("threshold:", this._scrollThreshold);
+				if((isIE)&&(db)&&(ds.getStyle(db, "background-image")=="none")){
+					with(db.style){
+						backgroundImage = "url(" + dojo.uri.dojoUri("src/widget/templates/images/blank.gif") + ")";
+						backgroundAttachment = "fixed";
+					}
+				}
+			}
+
+			var scrollPos = (window["pageYOffset"]) ? window["pageYOffset"] : (document["documentElement"]||document["body"]).scrollTop;
+
+			// FIXME: need to have top and bottom thresholds so toolbar doesn't keep scrolling past the bottom
+			if(scrollPos > this._scrollThreshold){
+				// dojo.debug(scrollPos);
+				if(!this._fixEnabled){
+					this.domNode.style.marginTop = totalHeight+"px";
+					if(isIE){
+						// FIXME: should we just use setBehvior() here instead?
+						var cl = dojo.style.abs(tdn).x;
+						document.body.appendChild(tdn);
+						tdn.style.left = cl+dojo.style.getPixelValue(document.body, "margin-left")+"px";
+						dojo.html.addClass(tdn, "IEFixedToolbar");
+						if(this.object){
+							dojo.html.addClass(this.tbBgIframe, "IEFixedToolbar");
+						}
+						
+					}else{
+						with(tdn.style){
+							position = "fixed";
+							top = "0px";
+						}
+					}
+					tdn.style.zIndex = 1000;
+					this._fixEnabled = true;
+				}
+			}else if(this._fixEnabled){
+				this.domNode.style.marginTop = null;
+				with(tdn.style){
+					position = "";
+					top = "";
+					zIndex = "";
+					if(isIE){
+						marginTop = "";
+					}
+				}
+				if(isIE){
+					dojo.html.removeClass(tdn, "IEFixedToolbar");
+					dojo.html.insertBefore(tdn, this._htmlEditNode||this.domNode);
+				}
+				this._fixEnabled = false;
+			}
+		},
+
+		unhookScroller: function(){
+			this._handleScroll = false;
+			clearInterval(this.scrollInterval);
+			// var src = document["documentElement"]||window;
+			// dojo.event.disconnect(src, "onscroll", this, "globalOnScrollHandler");
+			if(dojo.render.html.ie){
+				dojo.html.removeClass(this.toolbarWidget.domNode, "IEFixedToolbar");
+			}
+		},
+
+		_updateToolbarLastRan: null,
+		_updateToolbarTimer: null,
+		_updateToolbarFrequency: 500,
+
+		updateToolbar: function(force){
+			if((!this.isLoaded)||(!this.toolbarWidget)){ return; }
+
+			// keeps the toolbar from updating too frequently
+			// TODO: generalize this functionality?
+			var diff = new Date() - this._updateToolbarLastRan;
+			if( (!force)&&(this._updateToolbarLastRan)&&
+				((diff < this._updateToolbarFrequency)) ){
+
+				clearTimeout(this._updateToolbarTimer);
+				var _this = this;
+				this._updateToolbarTimer = setTimeout(function() {
+					_this.updateToolbar();
+				}, this._updateToolbarFrequency/2);
+				return;
+
+			}else{
+				this._updateToolbarLastRan = new Date();
+			}
+			// end frequency checker
+
+			dojo.lang.forEach(this.commandList, function(cmd){
+					if(cmd == "inserthtml"){ return; }
+					try{
+						if(this.queryCommandEnabled(cmd)){
+							if(this.queryCommandState(cmd)){
+								this.toolbarWidget.highlightButton(cmd);
+							}else{
+								this.toolbarWidget.unhighlightButton(cmd);
+							}
+						}
+					}catch(e){
+						// alert(cmd+":"+e);
+					}
+				}, this);
+
+			var h = dojo.render.html;
+			
+			// safari f's us for selection primitives
+			if(h.safari){ return; }
+
+			var selectedNode = (h.ie) ? this.document.selection.createRange().parentElement() : this.window.getSelection().anchorNode;
+			// make sure we actuall have an element
+			while((selectedNode)&&(selectedNode.nodeType != 1)){
+				selectedNode = selectedNode.parentNode;
+			}
+			if(!selectedNode){ return; }
+
+			var formats = ["p", "pre", "h1", "h2", "h3", "h4"];
+			// gotta run some specialized updates for the various
+			// formatting options
+			var type = formats[dojo.lang.find(formats, selectedNode.nodeName.toLowerCase())];
+			while((selectedNode)&&(selectedNode!=this.editNode)&&(!type)){
+				selectedNode = selectedNode.parentNode;
+				type = formats[dojo.lang.find(formats, selectedNode.nodeName.toLowerCase())];
+			}
+			if(!type){
+				type = "";
+			}else{
+				if(type.charAt(0)=="h"){
+					this.toolbarWidget.unhighlightButton("bold");
+				}
+			}
+			this.toolbarWidget.selectFormat(type);
+		},
+
+		updateItem: function(item) {
+			try {
+				var cmd = item._name;
+				var enabled = this._richText.queryCommandEnabled(cmd);
+				item.setEnabled(enabled, false, true);
+
+				var active = this._richText.queryCommandState(cmd);
+				if(active && cmd == "underline") {
+					// don't activate underlining if we are on a link
+					active = !this._richText.queryCommandEnabled("unlink");
+				}
+				item.setSelected(active, false, true);
+				return true;
+			} catch(err) {
+				return false;
+			}
+		},
+
+
+		_save: function(e){
+			// FIXME: how should this behave when there's a larger form in play?
+			if(!this.isClosed){
+				if(this.saveUrl.length){
+					var content = {};
+					content[this.saveArgName] = this.getHtml();
+					dojo.io.bind({
+						method: this.saveMethod,
+						url: this.saveUrl,
+						content: content
+					});
+				}else{
+					dojo.debug("please set a saveUrl for the editor");
+				}
+				if(this.closeOnSave){
+					this.close(e.getName().toLowerCase() == "save");
+				}
+			}
+		},
+
+		wireUpOnLoad: function(){
+			if(!dojo.render.html.ie){
+				/*
+				dojo.event.kwConnect({
+					srcObj:		this.document,
+					srcFunc:	"click", 
+					targetObj:	this.toolbarWidget,
+					targetFunc:	"hideAllDropDowns",
+					once:		true
+				});
+				*/
+			}
+		}
+	},
+	"html",
+	function(){
+		var cp = dojo.widget.html.Editor2.prototype;
+		if(!cp._wrappersSet){
+			cp._wrappersSet = true;
+			cp.fillInTemplate = (function(fit){
+				return function(){
+					fit.call(this);
+					this.editorOnLoad();
+				};
+			})(cp.fillInTemplate);
+		
+			cp.onDisplayChanged = (function(odc){
+				return function(){
+					try{
+						odc.call(this);
+						this.updateToolbar();
+					}catch(e){}
+				};
+			})(cp.onDisplayChanged);
+
+			cp.onLoad = (function(ol){
+				return function(){
+					ol.call(this);
+					this.wireUpOnLoad();
+				};
+			})(cp.onLoad);
+		}
+	}
+);

Added: tapestry/tapestry4/trunk/framework/src/js/dojo/src/widget/Editor2Toolbar.js
URL: http://svn.apache.org/viewvc/tapestry/tapestry4/trunk/framework/src/js/dojo/src/widget/Editor2Toolbar.js?rev=408783&view=auto
==============================================================================
--- tapestry/tapestry4/trunk/framework/src/js/dojo/src/widget/Editor2Toolbar.js (added)
+++ tapestry/tapestry4/trunk/framework/src/js/dojo/src/widget/Editor2Toolbar.js Mon May 22 16:10:12 2006
@@ -0,0 +1,316 @@
+/*
+	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.Editor2Toolbar");
+dojo.provide("dojo.widget.html.Editor2Toolbar");
+
+dojo.require("dojo.lang.*");
+dojo.require("dojo.widget.*");
+dojo.require("dojo.event.*");
+dojo.require("dojo.widget.RichText");
+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"
+		],
+
+		templatePath: dojo.uri.dojoUri("src/widget/templates/HtmlEditorToolbar.html"),
+		templateCssPath: dojo.uri.dojoUri("src/widget/templates/HtmlEditorToolbar.css"),
+
+		forecolorPalette: null,
+		hilitecolorPalette: null,
+
+		// 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);
+		},
+
+
+		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);
+		},
+
+		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){}
+				}
+			});
+		},
+
+		selectFormat: function(format){
+			dojo.lang.forEach(this.formatSelectBox.options, function(item){
+				if(item.value.toLowerCase() == format.toLowerCase()){
+					item.selected = true;
+				}
+			});
+		},
+
+		forecolorClick: function(e){
+			this.colorClick(e, "forecolor");
+		},
+
+		hilitecolorClick: function(e){
+			this.colorClick(e, "hilitecolor");
+		},
+
+		// 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";
+				}
+
+				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;
+					}
+					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";
+				}
+			}
+		},
+
+		uninitialize: function(){
+			dojo.event.kwDisconnect({
+				srcObj:		document.body, 
+				srcFunc:	"onclick", 
+				targetObj:	this,
+				targetFunc:	"hideAllDropDowns",
+				once:		true
+			});
+		},
+
+		// stub for observers
+		exec: function(what, arg){ /* dojo.debug(what, new Date()); */ },
+
+		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";
+						}
+					}
+				},
+				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;
+							}
+						}
+					});
+				}
+		},
+
+		highlightButton: function(name){
+			var bn = name+"Button";
+			if(this[bn]){
+				with(this[bn].style){
+					backgroundColor = "White";
+					border = "1px solid #aeaeab";
+				}
+			}
+		},
+
+		unhighlightButton: function(name){
+			var bn = name+"Button";
+			if(this[bn]){
+				// dojo.debug("unhighlighting:", name);
+				with(this[bn].style){
+					backgroundColor = "";
+					border = "";
+				}
+			}
+		}
+	},
+	"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: tapestry/tapestry4/trunk/framework/src/js/dojo/src/widget/FisheyeList.js
URL: http://svn.apache.org/viewvc/tapestry/tapestry4/trunk/framework/src/js/dojo/src/widget/FisheyeList.js?rev=408783&view=auto
==============================================================================
--- tapestry/tapestry4/trunk/framework/src/js/dojo/src/widget/FisheyeList.js (added)
+++ tapestry/tapestry4/trunk/framework/src/js/dojo/src/widget/FisheyeList.js Mon May 22 16:10:12 2006
@@ -0,0 +1,733 @@
+/*
+	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.FisheyeList");
+dojo.provide("dojo.widget.html.FisheyeList");
+dojo.provide("dojo.widget.html.FisheyeListItem");
+
+//
+// TODO
+// fix SVG support, and turn it on only if the browser supports it
+// fix really long labels in vertical mode
+//
+
+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.lang.extend(dojo.widget.html.FisheyeList, {
+
+	templateString: '<div class="dojoHtmlFisheyeListBar"></div>',
+	templateCssPath: dojo.uri.dojoUri("src/widget/templates/HtmlFisheyeList.css"),
+	widgetType: "FisheyeList",
+
+	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,
+
+	/////////////////////////////////////////////////////////////////
+	//
+	// i spy OPTIONS!!!!
+	//
+
+	itemWidth: 40,
+	itemHeight: 40,
+
+	itemMaxWidth: 150,
+	itemMaxHeight: 150,
+
+	orientation: 'horizontal',
+	
+	conservativeTrigger: false,		// don't active menu until mouse is over an image (macintosh style)
+
+	effectUnits: 2,
+	itemPadding: 10,
+
+	attachEdge: 'center',
+	labelEdge: 'bottom',
+
+	enableCrappySvgSupport: false,
+
+
+	//
+	//
+	//
+	/////////////////////////////////////////////////////////////////
+
+	fillInTemplate: function(args, frag) {
+		//dojo.debug(this.orientation);
+
+		dojo.html.disableSelection(this.domNode);
+
+		this.isHorizontal = (this.orientation == 'horizontal') ? 1 : 0;
+		this.selectedNode = -1;
+
+		this.isOver = false;
+		this.hitX1 = -1;
+		this.hitY1 = -1;
+		this.hitX2 = -1;
+		this.hitY2 = -1;
+
+		//
+		// only some edges make sense...
+		//
+
+		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; }
+		if (!this.isHorizontal && (this.anchorEdge == this.EDGE.TOP   )){ this.anchorEdge = this.EDGE.CENTER; }
+		if (!this.isHorizontal && (this.anchorEdge == this.EDGE.BOTTOM)){ this.anchorEdge = this.EDGE.CENTER; }
+
+		if (this.labelEdge == this.EDGE.CENTER){ this.labelEdge = this.EDGE.TOP; }
+		if ( this.isHorizontal && (this.labelEdge == this.EDGE.LEFT  )){ this.labelEdge = this.EDGE.TOP; }
+		if ( this.isHorizontal && (this.labelEdge == this.EDGE.RIGHT )){ this.labelEdge = this.EDGE.TOP; }
+		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);
+		this.proximityBottom = this.itemHeight * (this.effectUnits - 0.5);
+
+		if (this.anchorEdge == this.EDGE.LEFT){
+			this.proximityLeft = 0;
+		}
+		if (this.anchorEdge == this.EDGE.RIGHT){
+			this.proximityRight = 0;
+		}
+		if (this.anchorEdge == this.EDGE.TOP){
+			this.proximityTop = 0;
+		}
+		if (this.anchorEdge == this.EDGE.BOTTOM){
+			this.proximityBottom = 0;
+		}
+		if (this.anchorEdge == this.EDGE.CENTER){
+			this.proximityLeft   /= 2;
+			this.proximityRight  /= 2;
+			this.proximityTop    /= 2;
+			this.proximityBottom /= 2;
+		}
+	},
+	
+	postCreate: function(args, frag) {
+
+		this.itemCount = this.children.length;
+
+		this.barWidth  = (this.isHorizontal ? this.itemCount : 1) * this.itemWidth;
+		this.barHeight = (this.isHorizontal ? 1 : this.itemCount) * this.itemHeight;
+
+		this.totalWidth  = this.proximityLeft + this.proximityRight  + this.barWidth;
+		this.totalHeight = this.proximityTop  + this.proximityBottom + this.barHeight;
+
+		//
+		// 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);
+			this.children[i].posY = this.itemHeight * (this.isHorizontal ? 0 : i);
+
+			this.children[i].cenX = this.children[i].posX + (this.itemWidth  / 2);
+			this.children[i].cenY = this.children[i].posY + (this.itemHeight / 2);
+
+			var isz = this.isHorizontal ? this.itemWidth : this.itemHeight;
+			var r = this.effectUnits * isz;
+			var c = this.isHorizontal ? this.children[i].cenX : this.children[i].cenY;
+			var lhs = this.isHorizontal ? this.proximityLeft : this.proximityTop;
+			var rhs = this.isHorizontal ? this.proximityRight : this.proximityBottom;
+			var siz = this.isHorizontal ? this.barWidth : this.barHeight;
+
+			var range_lhs = r;
+			var range_rhs = r;
+
+			if (range_lhs > c+lhs){ range_lhs = c+lhs; }
+			if (range_rhs > (siz-c+rhs)){ range_rhs = siz-c+rhs; }
+
+			this.children[i].effectRangeLeft = range_lhs / isz;
+			this.children[i].effectRangeRght = range_rhs / isz;
+
+			//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
+		//
+		for (var i=0; i<this.children.length; i++){
+			var itm = this.children[i];
+			var elm = itm.domNode;
+			elm.style.left   = itm.posX + 'px';
+			elm.style.top    = itm.posY + 'px';
+			elm.style.width  = this.itemWidth + 'px';
+			elm.style.height = this.itemHeight + 'px';
+			
+			if ( itm.svgNode ) {
+				itm.svgNode.style.position = 'absolute';
+				itm.svgNode.style.left = this.itemPadding+'%';
+				itm.svgNode.style.top = this.itemPadding+'%';
+				itm.svgNode.style.width = (100 - 2 * this.itemPadding) + '%';
+				itm.svgNode.style.height = (100 - 2 * this.itemPadding) + '%';
+				itm.svgNode.style.zIndex = 1;
+	
+				itm.svgNode.setSize(this.itemWidth, this.itemHeight);
+			} else {
+				itm.imgNode.style.left = this.itemPadding+'%';
+				itm.imgNode.style.top = this.itemPadding+'%';
+				itm.imgNode.style.width = (100 - 2 * this.itemPadding) + '%';
+				itm.imgNode.style.height = (100 - 2 * this.itemPadding) + '%';
+			}
+		}
+
+		//
+		// calc the grid
+		//
+
+		this.calcHitGrid();
+
+		//
+		// in liberal trigger mode, activate menu whenever mouse is close
+		//
+		if( !this.conservativeTrigger ){
+			dojo.event.connect(document.documentElement, "onmousemove", this, "mouseHandler");
+		}
+		
+		// Deactivate the menu if mouse is moved off screen (doesn't work for FF?)
+		dojo.event.connect(document.documentElement, "onmouseout", this, "onBodyOut");
+	},
+
+	onBodyOut: function(e){
+		// clicking over an object inside of body causes this event to fire; ignore that case
+		if( dojo.html.overElement(document.body, e) ){
+			return;
+		}
+		this.setDormant(e);
+	},
+
+	// when mouse moves out of menu's range
+	setDormant: function(e){
+		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");
+		}
+		this.onGridMouseMove(-1, -1);
+	},
+
+	// when mouse is moved into menu's range
+	setActive: function(e){
+		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");
+
+			this.timerScale=0.0;
+
+			// call mouse handler to do some initial necessary calculations/positioning
+			this.mouseHandler(e);
+
+			// slowly expand the icon size so it isn't jumpy
+			this.expandSlowly();
+		}
+	},
+
+	// when mouse is moved
+	mouseHandler: function(e) {
+		if ((e.pageX >= this.hitX1) && (e.pageX <= this.hitX2) &&
+			(e.pageY >= this.hitY1) && (e.pageY <= this.hitY2)){
+			if( !this.isOver ){
+				this.setActive(e);
+			}
+			this.onGridMouseMove(e.pageX-this.hitX1, e.pageY-this.hitY1);
+		}else{
+			if (this.isOver){
+				this.setDormant(e);
+			}
+		}
+	},
+
+	onResized: function() {
+		this.calcHitGrid();
+	},
+
+	onGridMouseMove: function(x, y){
+		this.pos = {x:x, y:y};
+		this.paint();
+	},
+	
+	paint: function(){
+		var x=this.pos.x;
+		var y=this.pos.y;
+
+		if( this.itemCount <= 0 ){ return; }
+
+		//
+		// 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;
+		var sim = this.isHorizontal ? 
+			(1.0-this.timerScale)*this.itemWidth + this.timerScale*this.itemMaxWidth :
+			(1.0-this.timerScale)*this.itemHeight + this.timerScale*this.itemMaxHeight ;
+
+		var cen = ((pos - prx) / siz) - 0.5;
+		var max_off_cen = (sim / siz) - 0.5;
+
+		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){
+			var cen2 = (y - this.proximityTop) / this.itemHeight;
+			off_weight = (cen2 > 0.5) ? 1 : y / (this.proximityTop + (this.itemHeight / 2));
+		}
+		if (this.anchorEdge == this.EDGE.TOP){
+			var cen2 = (y - this.proximityTop) / this.itemHeight;
+			off_weight = (cen2 < 0.5) ? 1 : (this.totalHeight - y) / (this.proximityBottom + (this.itemHeight / 2));
+		}
+		if (this.anchorEdge == this.EDGE.RIGHT){
+			var cen2 = (x - this.proximityLeft) / this.itemWidth;
+			off_weight = (cen2 > 0.5) ? 1 : x / (this.proximityLeft + (this.itemWidth / 2));
+		}
+		if (this.anchorEdge == this.EDGE.LEFT){
+			var cen2 = (x - this.proximityLeft) / this.itemWidth;
+			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{
+				off_weight = x / (this.totalWidth);
+			}
+
+			if (off_weight > 0.5){
+				off_weight = 1 - off_weight;
+			}
+
+			off_weight *= 2;
+		}
+
+
+		//
+		// set the sizes
+		//
+
+		for(var i=0; i<this.itemCount; i++){
+
+			var weight = this.weightAt(cen, i);
+
+			if (weight < 0){weight = 0;}
+
+			this.setitemsize(i, weight * off_weight);
+		}
+
+		//
+		// set the positions
+		//
+
+		var main_p = Math.round(cen);
+		var offset = 0;
+
+		if (cen < 0){
+			main_p = 0;
+
+		}else if (cen > this.itemCount - 1){
+
+			main_p = this.itemCount -1;
+
+		}else{
+
+			offset = (cen - main_p) * ((this.isHorizontal ? this.itemWidth : this.itemHeight) - this.children[main_p].sizeMain);
+		}
+
+		this.positionElementsFrom(main_p, offset);
+	},
+
+	weightAt: function(cen, 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);
+	},
+
+	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){
+		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));
+
+		if (this.isHorizontal){
+
+			this.children[p].sizeW = w;
+			this.children[p].sizeH = h;
+
+			this.children[p].sizeMain = w;
+			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{
+
+			this.children[p].sizeW = w;
+			this.children[p].sizeH = h;
+
+			this.children[p].sizeOff  = w;
+			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);
+			}
+
+			this.children[p].domNode.style.left = x + 'px';
+			this.children[p].usualY = Math.round(this.children[p].cenY - (h / 2));
+
+			this.children[p].domNode.style.top  = this.children[p].usualY + 'px';
+		}
+
+		this.children[p].domNode.style.width  = w + 'px';
+		this.children[p].domNode.style.height = h + 'px';
+
+		if (this.children[p].svgNode){
+			this.children[p].svgNode.setSize(w, h);
+		}
+	},
+
+	positionElementsFrom: function(p, offset){
+
+		var pos = 0;
+
+		if (this.isHorizontal){
+			pos = Math.round(this.children[p].usualX + offset);
+			this.children[p].domNode.style.left = pos + 'px';
+		}else{
+			pos = Math.round(this.children[p].usualY + offset);
+			this.children[p].domNode.style.top = pos + 'px';
+		}
+		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){
+				this.children[i].domNode.style.left = bpos + 'px';
+			}else{
+				this.children[i].domNode.style.top = bpos + 'px';
+			}
+			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){
+				this.children[i].domNode.style.left = apos + 'px';
+			}else{
+				this.children[i].domNode.style.top = apos + 'px';
+			}
+			this.positionLabel(this.children[i]);
+		}
+
+	},
+
+	positionLabel: function(itm){
+
+		var x = 0;
+		var y = 0;
+		
+		var labelW = dojo.style.getOuterWidth(itm.lblNode);
+		var labelH = dojo.style.getOuterHeight(itm.lblNode);
+
+		if (this.labelEdge == this.EDGE.TOP){
+			x = Math.round((itm.sizeW / 2) - (labelW / 2));
+			y = -labelH;
+		}
+
+		if (this.labelEdge == this.EDGE.BOTTOM){
+			x = Math.round((itm.sizeW / 2) - (labelW / 2));
+			y = itm.sizeH;
+		}
+
+		if (this.labelEdge == this.EDGE.LEFT){
+			x = -labelW;
+			y = Math.round((itm.sizeH / 2) - (labelH / 2));
+		}
+
+		if (this.labelEdge == this.EDGE.RIGHT){
+			x = itm.sizeW;
+			y = Math.round((itm.sizeH / 2) - (labelH / 2));
+		}
+
+		itm.lblNode.style.left = x + 'px';
+		itm.lblNode.style.top  = y + 'px';
+	},
+
+	calcHitGrid: function(){
+
+		var pos = dojo.style.getAbsolutePosition(this.domNode, true);
+
+		this.hitX1 = pos.x - this.proximityLeft;
+		this.hitY1 = pos.y - this.proximityTop;
+		this.hitX2 = this.hitX1 + this.totalWidth;
+		this.hitY2 = this.hitY1 + this.totalHeight;
+
+		//dojo.debug(this.hitX1+','+this.hitY1+' // '+this.hitX2+','+this.hitY2);
+	},
+
+	toEdge: function(inp, def){
+		return this.EDGE[inp.toUpperCase()] || def;
+	},
+	
+	// slowly expand the image to user specified max size
+	expandSlowly: function(){
+		if( !this.isOver ){ return; }
+		this.timerScale += 0.2;
+		this.paint();
+		if ( this.timerScale<1.0 ) {
+			dojo.lang.setTimeout(this, "expandSlowly", 10);
+		}
+	}
+
+});
+
+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
+	iconSrc: "",
+	svgSrc: "",
+	caption: "",
+
+	blankImgPath: dojo.uri.dojoUri("src/widget/templates/images/blank.gif"),
+
+	templateString:
+		'<div class="dojoHtmlFisheyeListItem">' +
+		'  <img class="dojoHtmlFisheyeListItemImage" dojoAttachPoint="imgNode" dojoAttachEvent="onMouseOver;onMouseOut;onClick">' +
+		'  <div class="dojoHtmlFisheyeListItemLabel" dojoAttachPoint="lblNode"></div>' +
+		'</div>',
+	
+	imgNode: null,
+
+	fillInTemplate: function() {
+		//
+		// set image
+		// TODO: turn on/off SVG support based on browser version.
+		// this.parent.enableCrappySvgSupport is not available to this function
+		//
+		if (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)){
+			this.imgNode.style.filter = "progid:DXImageTransform.Microsoft.AlphaImageLoader(src='"+this.iconSrc+"', sizingMethod='scale')";
+			this.imgNode.src = this.blankImgPath.toString();
+		} else {
+			this.imgNode.src = this.iconSrc;
+		}
+
+		//
+		// Label
+		//
+		if ( this.lblNode ) {
+			this.lblNode.appendChild(document.createTextNode(this.caption));
+		}
+		dojo.html.disableSelection(this.domNode);
+	},
+	
+	createSvgNode: function(src){
+
+		var elm = document.createElement('embed');
+		elm.src = src;
+		elm.type = 'image/svg+xml';
+		//elm.style.border = '1px solid black';
+		elm.style.width = '1px';
+		elm.style.height = '1px';
+		elm.loaded = 0;
+		elm.setSizeOnLoad = false;
+
+		elm.onload = function(){
+			this.svgRoot = this.getSVGDocument().rootElement;
+			this.svgDoc = this.getSVGDocument().documentElement;
+			this.zeroWidth = this.svgRoot.width.baseVal.value;
+			this.zeroHeight = this.svgRoot.height.baseVal.value;
+			this.loaded = true;
+
+			if (this.setSizeOnLoad){
+				this.setSize(this.setWidth, this.setHeight);
+			}
+		}
+
+		elm.setSize = function(w, h){
+			if (!this.loaded){
+				this.setWidth = w;
+				this.setHeight = h;
+				this.setSizeOnLoad = true;
+				return;
+			}
+
+			this.style.width = w+'px';
+			this.style.height = h+'px';
+			this.svgRoot.width.baseVal.value = w;
+			this.svgRoot.height.baseVal.value = h;
+
+			var scale_x = w / this.zeroWidth;
+			var scale_y = h / this.zeroHeight;
+
+			for(var i=0; i<this.svgDoc.childNodes.length; i++){
+				if (this.svgDoc.childNodes[i].setAttribute){
+					this.svgDoc.childNodes[i].setAttribute( "transform", "scale("+scale_x+","+scale_y+")" );
+				}
+			}
+		}
+
+		return elm;
+	},
+
+	onMouseOver: function(e) {
+		// in conservative mode, don't activate the menu until user mouses over an icon
+		if( !this.parent.isOver ){
+			this.parent.setActive(e);
+		}
+		if ( this.caption != "" ) {
+			dojo.html.addClass(this.lblNode, "selected");
+			this.parent.positionLabel(this);
+		}
+	},
+	
+	onMouseOut: function() {
+		dojo.html.removeClass(this.lblNode, "selected");
+	},
+
+	onClick: function() {
+	}
+});
+

Added: tapestry/tapestry4/trunk/framework/src/js/dojo/src/widget/FloatingPane.js
URL: http://svn.apache.org/viewvc/tapestry/tapestry4/trunk/framework/src/js/dojo/src/widget/FloatingPane.js?rev=408783&view=auto
==============================================================================
--- tapestry/tapestry4/trunk/framework/src/js/dojo/src/widget/FloatingPane.js (added)
+++ tapestry/tapestry4/trunk/framework/src/js/dojo/src/widget/FloatingPane.js Mon May 22 16:10:12 2006
@@ -0,0 +1,301 @@
+/*
+	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.FloatingPane");
+dojo.provide("dojo.widget.html.FloatingPane");
+
+//
+// this widget provides a window-like floating pane
+//
+
+dojo.require("dojo.widget.*");
+dojo.require("dojo.widget.Manager");
+dojo.require("dojo.html");
+dojo.require("dojo.html.shadow");
+dojo.require("dojo.style");
+dojo.require("dojo.dom");
+dojo.require("dojo.html.layout");
+dojo.require("dojo.widget.ContentPane");
+dojo.require("dojo.dnd.HtmlDragMove");
+dojo.require("dojo.dnd.HtmlDragMoveSource");
+dojo.require("dojo.dnd.HtmlDragMoveObject");
+dojo.require("dojo.widget.ResizeHandle");
+
+dojo.widget.html.FloatingPane = function(){
+	dojo.widget.html.ContentPane.call(this);
+}
+
+dojo.inherits(dojo.widget.html.FloatingPane, dojo.widget.html.ContentPane);
+
+dojo.lang.extend(dojo.widget.html.FloatingPane, {
+	widgetType: "FloatingPane",
+
+	// Constructor arguments
+	title: '',
+	iconSrc: '',
+	hasShadow: false,
+	constrainToContainer: false,
+	taskBarId: "",
+	resizable: true,
+	titleBarDisplay: "fancy",
+
+	windowState: "normal",
+	displayCloseAction: false,
+	displayMinimizeAction: false,
+	displayMaximizeAction: false,
+
+	maxTaskBarConnectAttempts: 5,
+	taskBarConnectAttempts: 0,
+
+	templatePath: dojo.uri.dojoUri("src/widget/templates/HtmlFloatingPane.html"),
+	templateCssPath: dojo.uri.dojoUri("src/widget/templates/HtmlFloatingPane.css"),
+
+	drag: null,
+
+	fillInTemplate: function(args, frag){
+		// Copy style info from input node to output node
+		var source = this.getFragNodeRef(frag);
+		dojo.html.copyStyle(this.domNode, source);
+
+		// necessary for safari, khtml (for computing width/height)
+		document.body.appendChild(this.domNode);
+
+		// if display:none then state=minimized, otherwise state=normal
+		if(!this.isShowing()){
+			this.windowState="minimized";
+		}
+
+		// <img src=""> can hang IE!  better get rid of it
+		if(this.iconSrc==""){
+			dojo.dom.removeNode(this.titleBarIcon);
+		}else{
+			this.titleBarIcon.src = this.iconSrc.toString();// dojo.uri.Uri obj req. toString()
+		}
+
+		if(this.titleBarDisplay!="none"){	
+			this.titleBar.style.display="";
+			dojo.html.disableSelection(this.titleBar);
+
+			this.titleBarIcon.style.display = (this.iconSrc=="" ? "none" : "");
+
+			this.minimizeAction.style.display = (this.displayMinimizeAction ? "" : "none");
+			this.maximizeAction.style.display= 
+				(this.displayMaximizeAction && this.windowState!="maximized" ? "" : "none");
+			this.restoreAction.style.display= 
+				(this.displayMaximizeAction && this.windowState=="maximized" ? "" : "none");
+			this.closeAction.style.display= (this.displayCloseAction ? "" : "none");
+
+			this.drag = new dojo.dnd.HtmlDragMoveSource(this.domNode);	
+			if (this.constrainToContainer) {
+				this.drag.constrainTo();
+			}
+			this.drag.setDragHandle(this.titleBar);
+
+			var self = this;
+
+			dojo.event.topic.subscribe("dragMove",
+				function (info){
+					if (info.source.domNode == self.domNode){
+						dojo.event.topic.publish('floatingPaneMove', { source: self } );
+					}
+				}
+			);
+
+		}
+
+		if(this.resizable){
+			this.resizeBar.style.display="";
+			var rh = dojo.widget.createWidget("ResizeHandle", {targetElmId: this.widgetId, id:this.widgetId+"_resize"});
+			this.resizeBar.appendChild(rh.domNode);
+		}
+
+		// add a drop shadow
+		if(this.hasShadow){
+			this.shadow=new dojo.html.shadow(this.domNode);
+		}
+
+		// Prevent IE bleed-through problem
+		this.bgIframe = new dojo.html.BackgroundIframe(this.domNode);
+
+		if( this.taskBarId ){
+			this.taskBarSetup();
+		}
+
+		if (dojo.hostenv.post_load_) {
+			this.setInitialWindowState();
+		} else {
+			dojo.addOnLoad(this, "setInitialWindowState");
+		}
+
+		// counteract body.appendChild above
+		document.body.removeChild(this.domNode);
+
+		dojo.widget.html.FloatingPane.superclass.fillInTemplate.call(this, args, frag);
+	},
+
+	postCreate: function(){
+		if(this.isShowing()){
+			this.width=-1;	// force resize
+			this.resizeTo(dojo.style.getOuterWidth(this.domNode), dojo.style.getOuterHeight(this.domNode));
+		}
+	},
+
+	maximizeWindow: function(evt) {
+		this.previous={
+			width: dojo.style.getOuterWidth(this.domNode) || this.width,
+			height: dojo.style.getOuterHeight(this.domNode) || this.height,
+			left: this.domNode.style.left,
+			top: this.domNode.style.top,
+			bottom: this.domNode.style.bottom,
+			right: this.domNode.style.right
+		};
+		this.domNode.style.left =
+			dojo.style.getPixelValue(this.domNode.parentNode, "padding-left", true) + "px";
+		this.domNode.style.top =
+			dojo.style.getPixelValue(this.domNode.parentNode, "padding-top", true) + "px";
+
+		if ((this.domNode.parentNode.nodeName.toLowerCase() == 'body')) {
+			this.resizeTo(
+				dojo.html.getViewportWidth()-dojo.style.getPaddingWidth(document.body),
+				dojo.html.getViewportHeight()-dojo.style.getPaddingHeight(document.body)
+			);
+		} else {
+			this.resizeTo(
+				dojo.style.getContentWidth(this.domNode.parentNode),
+				dojo.style.getContentHeight(this.domNode.parentNode)
+			);
+		}
+		this.maximizeAction.style.display="none";
+		this.restoreAction.style.display="";
+		this.windowState="maximized";
+	},
+
+	minimizeWindow: function(evt) {
+		this.hide();
+		this.windowState = "minimized";
+	},
+
+	restoreWindow: function(evt) {
+		for(var attr in this.previous){
+			this.domNode.style[attr] = this.previous[attr];
+		}
+		this.resizeTo(this.previous.width, this.previous.height);
+		this.previous=null;
+
+		this.restoreAction.style.display="none";
+		this.maximizeAction.style.display=this.displayMaximizeAction ? "" : "none";
+
+		this.windowState="normal";
+	},
+
+	closeWindow: function(evt) {
+		dojo.dom.removeNode(this.domNode);
+		this.destroy();
+	},
+
+	onMouseDown: function(evt) {
+		this.bringToTop();
+	},
+
+	bringToTop: function() {
+		var floatingPanes= dojo.widget.manager.getWidgetsByType(this.widgetType);
+		var windows = [];
+		for (var x=0; x<floatingPanes.length; x++) {
+			if (this.widgetId != floatingPanes[x].widgetId) {
+					windows.push(floatingPanes[x]);
+			}
+		}
+
+		windows.sort(function(a,b) {
+			return a.domNode.style.zIndex - b.domNode.style.zIndex;
+		});
+		
+		windows.push(this);
+
+		var floatingPaneStartingZ = 100;
+		for (x=0; x<windows.length;x++) {
+			windows[x].domNode.style.zIndex = floatingPaneStartingZ + x;
+		}
+	},
+
+	setInitialWindowState: function() {
+		if (this.windowState == "maximized") {
+			this.maximizeWindow();
+			this.show();
+			return;
+		}
+
+		if (this.windowState=="normal") {
+			this.show();
+			return;
+		}
+
+		if (this.windowState=="minimized") {
+			this.hide();
+			return;
+		}
+
+		this.windowState="minimized";
+	},
+
+	// add icon to task bar, connected to me
+	taskBarSetup: function() {
+		var taskbar = dojo.widget.getWidgetById(this.taskBarId);
+		if (!taskbar){
+			if (this.taskBarConnectAttempts <  this.maxTaskBarConnectAttempts) {
+				dojo.lang.setTimeout(this, this.taskBarSetup, 50);
+				this.taskBarConnectAttempts++;
+			} else {
+				dojo.debug("Unable to connect to the taskBar");
+			}
+			return;
+		}
+		taskbar.addChild(this);
+	},
+
+	show: function(){
+		dojo.widget.html.FloatingPane.superclass.show.apply(this, arguments);
+		this.bringToTop();
+	},
+
+	onShow: function(){
+		dojo.widget.html.FloatingPane.superclass.onShow.call(this);
+		this.resizeTo(dojo.style.getOuterWidth(this.domNode), dojo.style.getOuterHeight(this.domNode));
+	},
+
+	// This is called when the user adjusts the size of the floating pane
+	resizeTo: function(w, h){
+		dojo.style.setOuterWidth(this.domNode, w);
+		dojo.style.setOuterHeight(this.domNode, h);
+
+		dojo.html.layout(this.domNode,
+			[
+			  {domNode: this.titleBar, layoutAlign: "top"},
+			  {domNode: this.resizeBar, layoutAlign: "bottom"},
+			  {domNode: this.containerNode, layoutAlign: "client"}
+			] );
+
+		// If any of the children have layoutAlign specified, obey it
+		dojo.html.layout(this.containerNode, this.children, "top-bottom");
+		
+		this.bgIframe.onResized();
+		if(this.shadow){ this.shadow.size(w, h); }
+		this.onResized();
+	},
+
+	onParentResized: function() {
+		// onParentResized() is called when the user has resized the browser window,
+		// but that doesn't affect this widget (or this widget's children)
+		// so it can be safely ignored...
+		// TODO: unless we are maximized.  then we should resize ourself.
+	}
+});
+
+dojo.widget.tags.addParseTreeHandler("dojo:FloatingPane");

Added: tapestry/tapestry4/trunk/framework/src/js/dojo/src/widget/GoogleMap.js
URL: http://svn.apache.org/viewvc/tapestry/tapestry4/trunk/framework/src/js/dojo/src/widget/GoogleMap.js?rev=408783&view=auto
==============================================================================
--- tapestry/tapestry4/trunk/framework/src/js/dojo/src/widget/GoogleMap.js (added)
+++ tapestry/tapestry4/trunk/framework/src/js/dojo/src/widget/GoogleMap.js Mon May 22 16:10:12 2006
@@ -0,0 +1,44 @@
+/*
+	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.GoogleMap");
+dojo.provide("dojo.widget.GoogleMap.Controls");
+dojo.require("dojo.widget.*");
+dojo.widget.tags.addParseTreeHandler("dojo:googlemap");
+
+dojo.widget.GoogleMap=function(){
+	//	summary
+	//	base class for the Google Map widget
+	dojo.widget.Widget.call(this);
+	this.widgetType="GoogleMap";
+	this.isContainer=false;
+}
+dojo.inherits(dojo.widget.GoogleMap, dojo.widget.Widget);
+
+dojo.widget.GoogleMap.Controls={
+	LargeMap:"largemap",
+	SmallMap:"smallmap",
+	SmallZoom:"smallzoom",
+	Scale:"scale",
+	MapType:"maptype",
+	Overview:"overview",
+	get:function(s){
+		for(var p in this){
+			if(typeof(this[p])=="string"
+				&& this[p]==s
+			){
+				return p;
+			}
+		}
+		return null;
+	}
+};
+
+dojo.requireAfterIf("html", "dojo.widget.html.GoogleMap");

Added: tapestry/tapestry4/trunk/framework/src/js/dojo/src/widget/HslColorPicker.js
URL: http://svn.apache.org/viewvc/tapestry/tapestry4/trunk/framework/src/js/dojo/src/widget/HslColorPicker.js?rev=408783&view=auto
==============================================================================
--- tapestry/tapestry4/trunk/framework/src/js/dojo/src/widget/HslColorPicker.js (added)
+++ tapestry/tapestry4/trunk/framework/src/js/dojo/src/widget/HslColorPicker.js Mon May 22 16:10:12 2006
@@ -0,0 +1,25 @@
+/*
+	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.HslColorPicker");
+
+dojo.require("dojo.widget.*");
+dojo.require("dojo.widget.Widget");
+dojo.require("dojo.graphics.color");
+dojo.widget.tags.addParseTreeHandler("dojo:hslcolorpicker");
+
+dojo.requireAfterIf(dojo.render.svg.support.builtin, "dojo.widget.svg.HslColorPicker");
+
+dojo.widget.HslColorPicker=function(){
+	dojo.widget.Widget.call(this);
+	this.widgetType = "HslColorPicker";
+	this.isContainer = false;
+}
+dojo.inherits(dojo.widget.HslColorPicker, dojo.widget.Widget);

Added: tapestry/tapestry4/trunk/framework/src/js/dojo/src/widget/HtmlWidget.js
URL: http://svn.apache.org/viewvc/tapestry/tapestry4/trunk/framework/src/js/dojo/src/widget/HtmlWidget.js?rev=408783&view=auto
==============================================================================
--- tapestry/tapestry4/trunk/framework/src/js/dojo/src/widget/HtmlWidget.js (added)
+++ tapestry/tapestry4/trunk/framework/src/js/dojo/src/widget/HtmlWidget.js Mon May 22 16:10:12 2006
@@ -0,0 +1,160 @@
+/*
+	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.HtmlWidget");
+dojo.require("dojo.widget.DomWidget");
+dojo.require("dojo.html");
+dojo.require("dojo.html.extras");
+dojo.require("dojo.lang.extras");
+dojo.require("dojo.lang.func");
+dojo.require("dojo.lfx.toggle");
+
+dojo.declare("dojo.widget.HtmlWidget", dojo.widget.DomWidget, {								 
+	widgetType: "HtmlWidget",
+
+	templateCssPath: null,
+	templatePath: null,
+
+	// for displaying/hiding widget
+	toggle: "plain",
+	toggleDuration: 150,
+
+	animationInProgress: false,
+
+	initialize: function(args, frag){
+	},
+
+	postMixInProperties: function(args, frag){
+		// now that we know the setting for toggle, get toggle object
+		// (default to plain toggler if user specified toggler not present)
+		this.toggleObj =
+			dojo.lfx.toggle[this.toggle.toLowerCase()] || dojo.lfx.toggle.plain;
+	},
+
+	getContainerHeight: function(){
+		// NOTE: container height must be returned as the INNER height
+		dojo.unimplemented("dojo.widget.HtmlWidget.getContainerHeight");
+	},
+
+	getContainerWidth: function(){
+		return this.parent.domNode.offsetWidth;
+	},
+
+	setNativeHeight: function(height){
+		var ch = this.getContainerHeight();
+	},
+
+	createNodesFromText: function(txt, wrap){
+		return dojo.html.createNodesFromText(txt, wrap);
+	},
+
+	destroyRendering: function(finalize){
+		try{
+			if(!finalize){
+				dojo.event.browser.clean(this.domNode);
+			}
+			this.domNode.parentNode.removeChild(this.domNode);
+			delete this.domNode;
+		}catch(e){ /* squelch! */ }
+	},
+
+	/////////////////////////////////////////////////////////
+	// Displaying/hiding the widget
+	/////////////////////////////////////////////////////////
+	isShowing: function(){
+		return dojo.style.isShowing(this.domNode);
+	},
+
+	toggleShowing: function(){
+		// dojo.style.toggleShowing(this.domNode);
+		if(this.isHidden){
+			this.show();
+		}else{
+			this.hide();
+		}
+	},
+
+	show: function(){
+		this.animationInProgress=true;
+		this.isHidden = false;
+		this.toggleObj.show(this.domNode, this.toggleDuration, null,
+			dojo.lang.hitch(this, this.onShow), this.explodeSrc);
+	},
+
+	// called after the show() animation has completed
+	onShow: function(){
+		this.animationInProgress=false;
+	},
+
+	hide: function(){
+		this.animationInProgress = true;
+		this.isHidden = true;
+		this.toggleObj.hide(this.domNode, this.toggleDuration, null,
+			dojo.lang.hitch(this, this.onHide), this.explodeSrc);
+	},
+
+	// called after the hide() animation has completed
+	onHide: function(){
+		this.animationInProgress=false;
+	},
+
+	//////////////////////////////////////////////////////////////////////////////
+	// Sizing related methods
+	//  If the parent changes size then for each child it should call either
+	//   - resizeTo(): size the child explicitly
+	//   - or onParentResized(): notify the child the the parent has changed size
+	//////////////////////////////////////////////////////////////////////////////
+
+	// Test if my size has changed.
+	// If width & height are specified then that's my new size; otherwise,
+	// query outerWidth/outerHeight of my domNode
+	_isResized: function(w, h){
+		// If I'm not being displayed then disregard (show() must
+		// check if the size has changed)
+		if(!this.isShowing()){ return false; }
+
+		// If my parent has been resized and I have style="height: 100%"
+		// or something similar then my size has changed too.
+		w=w||dojo.style.getOuterWidth(this.domNode);
+		h=h||dojo.style.getOuterHeight(this.domNode);
+		if(this.width == w && this.height == h){ return false; }
+
+		this.width=w;
+		this.height=h;
+		return true;
+	},
+
+	// Called when my parent has changed size, but my parent won't call resizeTo().
+	// This is useful if my size is height:100% or something similar
+	onParentResized: function(){
+		if(!this._isResized()){ return; }
+		this.onResized();
+	},
+
+	// Explicitly set this widget's size (in pixels).
+	resizeTo: function(w, h){
+		if(!this._isResized(w,h)){ return; }
+		dojo.style.setOuterWidth(this.domNode, w);
+		dojo.style.setOuterHeight(this.domNode, h);
+		this.onResized();
+	},
+
+	resizeSoon: function(){
+		if(this.isShowing()){
+			dojo.lang.setTimeout(this, this.onResized, 0);
+		}
+	},
+
+	// Called when my size has changed.
+	// Must notify children if their size has (possibly) changed
+	onResized: function(){
+		dojo.lang.forEach(this.children, function(child){ child.onParentResized(); });
+	}
+});

Added: tapestry/tapestry4/trunk/framework/src/js/dojo/src/widget/InlineEditBox.js
URL: http://svn.apache.org/viewvc/tapestry/tapestry4/trunk/framework/src/js/dojo/src/widget/InlineEditBox.js?rev=408783&view=auto
==============================================================================
--- tapestry/tapestry4/trunk/framework/src/js/dojo/src/widget/InlineEditBox.js (added)
+++ tapestry/tapestry4/trunk/framework/src/js/dojo/src/widget/InlineEditBox.js Mon May 22 16:10:12 2006
@@ -0,0 +1,172 @@
+/*
+	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.InlineEditBox");
+dojo.provide("dojo.widget.html.InlineEditBox");
+
+dojo.require("dojo.widget.*");
+dojo.require("dojo.fx.*");
+dojo.require("dojo.graphics.color");
+dojo.require("dojo.string");
+dojo.require("dojo.style");
+dojo.require("dojo.html");
+
+dojo.widget.tags.addParseTreeHandler("dojo:inlineeditbox");
+
+dojo.widget.html.InlineEditBox = function(){
+	dojo.widget.HtmlWidget.call(this);
+	// mutable objects need to be in constructor to give each instance its own copy
+	this.history = [];
+}
+
+dojo.inherits(dojo.widget.html.InlineEditBox, dojo.widget.HtmlWidget);
+
+dojo.lang.extend(dojo.widget.html.InlineEditBox, {
+	templatePath: dojo.uri.dojoUri("src/widget/templates/HtmlInlineEditBox.html"),
+	templateCssPath: dojo.uri.dojoUri("src/widget/templates/HtmlInlineEditBox.css"),
+	widgetType: "InlineEditBox",
+
+	form: null,
+	editBox: null,
+	edit: null,
+	text: null,
+	textarea: null,
+	submitButton: null,
+	cancelButton: null,
+	mode: "text",
+
+	minWidth: 100, //px. minimum width of edit box
+	minHeight: 200, //px. minimum width of edit box, if it's a TA
+
+	editing: false,
+	textValue: "",
+	defaultText: "",
+	doFade: false,
+	
+	onSave: function(newValue, oldValue){},
+	onUndo: function(value){},
+
+	postCreate: function(args, frag){
+		// put original node back in the document, and attach handlers
+		// which hide it and display the editor
+		this.editable = this.getFragNodeRef(frag);
+		dojo.dom.insertAfter(this.editable, this.form);
+		dojo.event.connect(this.editable, "onmouseover", this, "mouseover");
+		dojo.event.connect(this.editable, "onmouseout", this, "mouseout");
+		dojo.event.connect(this.editable, "onclick", this, "beginEdit");
+
+		this.textValue = dojo.string.trim(this.editable.innerHTML);
+		if(dojo.string.trim(this.textValue).length == 0){
+			this.editable.innerHTML = this.defaultText;
+		}		
+	},
+
+	mouseover: function(e){
+		if(!this.editing){
+			dojo.html.addClass(this.editable, "editableRegion");
+			if(this.mode == "textarea"){
+				dojo.html.addClass(this.editable, "editableTextareaRegion");
+			}
+		}
+	},
+
+	mouseout: function(e){
+		if(!this.editing){
+			dojo.html.removeClass(this.editable, "editableRegion");
+			dojo.html.removeClass(this.editable, "editableTextareaRegion");
+		}
+	},
+
+	// When user clicks the text, then start editing.
+	// Hide the text and display the form instead.
+	beginEdit: function(e){
+		if(this.editing){ return; }
+		this.mouseout();
+		this.editing = true;
+
+		// setup the form's <input> or <textarea> field, as specified by mode
+		var ee = this[this.mode.toLowerCase()];
+		ee.value = dojo.string.trim(this.textValue);
+		ee.style.fontSize = dojo.style.getStyle(this.editable, "font-size");
+		ee.style.fontWeight = dojo.style.getStyle(this.editable, "font-weight");
+		ee.style.fontStyle = dojo.style.getStyle(this.editable, "font-style");
+		ee.style.width = Math.max(dojo.html.getInnerWidth(this.editable), this.minWidth) + "px";
+		if(this.mode.toLowerCase()=="textarea"){
+			ee.style.display = "block";
+			ee.style.height = Math.max(dojo.html.getInnerHeight(this.editable), this.minHeight) + "px";
+		} else {
+			ee.style.display = "";
+		}
+
+		// show the edit form and hide the read only version of the text
+		this.form.style.display = "";
+		this.editable.style.display = "none";
+
+		ee.select();
+		this.submitButton.disabled = true;
+	},
+
+	saveEdit: function(e){
+		e.preventDefault();
+		e.stopPropagation();
+		var ee = this[this.mode.toLowerCase()];
+		if((this.textValue != ee.value)&&
+			(dojo.string.trim(ee.value) != "")){
+			this.doFade = true;
+			this.history.push(this.textValue);
+			this.onSave(ee.value, this.textValue);
+			this.textValue = ee.value;
+			this.editable.innerHTML = this.textValue;
+		}else{
+			this.doFade = false;
+		}
+		this.finishEdit(e);
+	},
+
+	cancelEdit: function(e){
+		if(!this.editing){ return false; }
+		this.editing = false;
+		this.form.style.display="none";
+		this.editable.style.display = "";
+		return true;
+	},
+
+	finishEdit: function(e){
+		if(!this.cancelEdit(e)){ return; }
+		if(this.doFade) {
+			dojo.lfx.highlight(this.editable, dojo.graphics.color.hex2rgb("#ffc"), 700).play(300);
+		}
+		this.doFade = false;
+	},
+
+	setText: function(txt){
+		// sets the text without informing the server
+		var tt = dojo.string.trim(txt);
+		this.textValue = tt
+		this.editable.innerHTML = tt;
+	},
+
+	undo: function(){
+		if(this.history.length > 0){
+			var value = this.history.pop();
+			this.editable.innerHTML = value;
+			this.textValue = value;
+			this.onUndo(value);
+		}
+	},
+
+	checkForValueChange: function(){
+		var ee = this[this.mode.toLowerCase()];
+		if((this.textValue != ee.value)&&
+			(dojo.string.trim(ee.value) != "")){
+			this.submitButton.disabled = false;
+		}
+	}
+});

Added: tapestry/tapestry4/trunk/framework/src/js/dojo/src/widget/LayoutContainer.js
URL: http://svn.apache.org/viewvc/tapestry/tapestry4/trunk/framework/src/js/dojo/src/widget/LayoutContainer.js?rev=408783&view=auto
==============================================================================
--- tapestry/tapestry4/trunk/framework/src/js/dojo/src/widget/LayoutContainer.js (added)
+++ tapestry/tapestry4/trunk/framework/src/js/dojo/src/widget/LayoutContainer.js Mon May 22 16:10:12 2006
@@ -0,0 +1,70 @@
+/*
+	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
+*/
+
+//
+// this widget provides Delphi-style panel layout semantics
+//
+
+dojo.provide("dojo.widget.LayoutContainer");
+dojo.provide("dojo.widget.html.LayoutContainer");
+
+dojo.require("dojo.widget.*");
+dojo.require("dojo.html.layout");
+
+dojo.widget.html.LayoutContainer = function(){
+	dojo.widget.HtmlWidget.call(this);
+}
+
+dojo.inherits(dojo.widget.html.LayoutContainer, dojo.widget.HtmlWidget);
+
+dojo.lang.extend(dojo.widget.html.LayoutContainer, {
+	widgetType: "LayoutContainer",
+	isContainer: true,
+
+	layoutChildPriority: 'top-bottom',
+
+	postCreate: function(){
+		dojo.html.layout(this.domNode, this.children, this.layoutChildPriority);
+	},
+
+	addChild: function(child, overrideContainerNode, pos, ref, insertIndex){
+		dojo.widget.html.LayoutContainer.superclass.addChild.call(this, child, overrideContainerNode, pos, ref, insertIndex);
+		dojo.html.layout(this.domNode, this.children, this.layoutChildPriority);
+	},
+
+	removeChild: function(pane){
+		dojo.widget.html.LayoutContainer.superclass.removeChild.call(this,pane);
+		dojo.html.layout(this.domNode, this.children, this.layoutChildPriority);
+	},
+
+	onResized: function(){
+		dojo.html.layout(this.domNode, this.children, this.layoutChildPriority);
+	},
+
+	show: function(){
+		// If this node was created while display=="none" then it
+		// hasn't been laid out yet.  Do that now.
+		this.domNode.style.display="";
+		this.onParentResized();
+		this.domNode.style.display="none";
+		this.domNode.style.visibility="";
+
+		dojo.widget.html.LayoutContainer.superclass.show.call(this);
+	}
+});
+
+// This argument can be specified for the children of a LayoutContainer.
+// Since any widget can be specified as a LayoutContainer child, mix it
+// into the base widget class.  (This is a hack, but it's effective.)
+dojo.lang.extend(dojo.widget.Widget, {
+	layoutAlign: 'none'
+});
+
+dojo.widget.tags.addParseTreeHandler("dojo:LayoutContainer");

Added: tapestry/tapestry4/trunk/framework/src/js/dojo/src/widget/LinkPane.js
URL: http://svn.apache.org/viewvc/tapestry/tapestry4/trunk/framework/src/js/dojo/src/widget/LinkPane.js?rev=408783&view=auto
==============================================================================
--- tapestry/tapestry4/trunk/framework/src/js/dojo/src/widget/LinkPane.js (added)
+++ tapestry/tapestry4/trunk/framework/src/js/dojo/src/widget/LinkPane.js Mon May 22 16:10:12 2006
@@ -0,0 +1,17 @@
+/*
+	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.LinkPane");
+
+dojo.require("dojo.widget.*");
+dojo.requireAfterIf("html", "dojo.widget.html.LinkPane");
+dojo.widget.tags.addParseTreeHandler("dojo:LinkPane");
+
+// NOTE: there's no stub file for this widget

Added: tapestry/tapestry4/trunk/framework/src/js/dojo/src/widget/Manager.js
URL: http://svn.apache.org/viewvc/tapestry/tapestry4/trunk/framework/src/js/dojo/src/widget/Manager.js?rev=408783&view=auto
==============================================================================
--- tapestry/tapestry4/trunk/framework/src/js/dojo/src/widget/Manager.js (added)
+++ tapestry/tapestry4/trunk/framework/src/js/dojo/src/widget/Manager.js Mon May 22 16:10:12 2006
@@ -0,0 +1,306 @@
+/*
+	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.Manager");
+dojo.require("dojo.lang.array");
+dojo.require("dojo.lang.func");
+dojo.require("dojo.event.*");
+
+// Manager class
+dojo.widget.manager = new function(){
+	this.widgets = [];
+	this.widgetIds = [];
+	
+	// map of widgetId-->widget for widgets without parents (top level widgets)
+	this.topWidgets = {};
+
+	var widgetTypeCtr = {};
+	var renderPrefixCache = [];
+
+	this.getUniqueId = function (widgetType) {
+		return widgetType + "_" + (widgetTypeCtr[widgetType] != undefined ?
+			++widgetTypeCtr[widgetType] : widgetTypeCtr[widgetType] = 0);
+	}
+
+	this.add = function(widget){
+		dojo.profile.start("dojo.widget.manager.add");
+		this.widgets.push(widget);
+		// Opera9 uses ID (caps)
+		if(!widget.extraArgs["id"]){
+			widget.extraArgs["id"] = widget.extraArgs["ID"];
+		}
+		// FIXME: the rest of this method is very slow!
+		if(widget.widgetId == ""){
+			if(widget["id"]){
+				widget.widgetId = widget["id"];
+			}else if(widget.extraArgs["id"]){
+				widget.widgetId = widget.extraArgs["id"];
+			}else{
+				widget.widgetId = this.getUniqueId(widget.widgetType);
+			}
+		}
+		if(this.widgetIds[widget.widgetId]){
+			dojo.debug("widget ID collision on ID: "+widget.widgetId);
+		}
+		this.widgetIds[widget.widgetId] = widget;
+		// Widget.destroy already calls removeById(), so we don't need to
+		// connect() it here
+		dojo.profile.end("dojo.widget.manager.add");
+	}
+
+	this.destroyAll = function(){
+		for(var x=this.widgets.length-1; x>=0; x--){
+			try{
+				// this.widgets[x].destroyChildren();
+				this.widgets[x].destroy(true);
+				delete this.widgets[x];
+			}catch(e){ }
+		}
+	}
+
+	// FIXME: we should never allow removal of the root widget until all others
+	// are removed!
+	this.remove = function(widgetIndex){
+		var tw = this.widgets[widgetIndex].widgetId;
+		delete this.widgetIds[tw];
+		this.widgets.splice(widgetIndex, 1);
+	}
+	
+	// FIXME: suboptimal performance
+	this.removeById = function(id) {
+		for (var i=0; i<this.widgets.length; i++){
+			if(this.widgets[i].widgetId == id){
+				this.remove(i);
+				break;
+			}
+		}
+	}
+
+	this.getWidgetById = function(id){
+		return this.widgetIds[id];
+	}
+
+	this.getWidgetsByType = function(type){
+		var lt = type.toLowerCase();
+		var ret = [];
+		dojo.lang.forEach(this.widgets, function(x){
+			if(x.widgetType.toLowerCase() == lt){
+				ret.push(x);
+			}
+		});
+		return ret;
+	}
+
+	this.getWidgetsOfType = function (id) {
+		dojo.deprecated("getWidgetsOfType", "use getWidgetsByType", "0.4");
+		return dojo.widget.manager.getWidgetsByType(id);
+	}
+
+	this.getWidgetsByFilter = function(unaryFunc, onlyOne){
+		var ret = [];
+		dojo.lang.every(this.widgets, function(x){
+			if(unaryFunc(x)){
+				ret.push(x);
+				if(onlyOne){return false;}
+			}
+			return true;
+		});
+		return (onlyOne ? ret[0] : ret);
+	}
+
+	this.getAllWidgets = function() {
+		return this.widgets.concat();
+	}
+
+	//	added, trt 2006-01-20
+	this.getWidgetByNode = function(/* DOMNode */ node){
+		var w=this.getAllWidgets();
+		for (var i=0; i<w.length; i++){
+			if (w[i].domNode==node){
+				return w[i];
+			}
+		}
+		return null;
+	}
+
+	// shortcuts, baby
+	this.byId = this.getWidgetById;
+	this.byType = this.getWidgetsByType;
+	this.byFilter = this.getWidgetsByFilter;
+	this.byNode = this.getWidgetByNode;
+
+	// map of previousally discovered implementation names to constructors
+	var knownWidgetImplementations = {};
+
+	// support manually registered widget packages
+	var widgetPackages = ["dojo.widget"];
+	for (var i=0; i<widgetPackages.length; i++) {
+		// convenience for checking if a package exists (reverse lookup)
+		widgetPackages[widgetPackages[i]] = true;
+	}
+
+	this.registerWidgetPackage = function(pname) {
+		if(!widgetPackages[pname]){
+			widgetPackages[pname] = true;
+			widgetPackages.push(pname);
+		}
+	}
+	
+	this.getWidgetPackageList = function() {
+		return dojo.lang.map(widgetPackages, function(elt) { return(elt!==true ? elt : undefined); });
+	}
+	
+	this.getImplementation = function(widgetName, ctorObject, mixins){
+		// try and find a name for the widget
+		var impl = this.getImplementationName(widgetName);
+		if(impl){ 
+			// var tic = new Date();
+			var ret = new impl(ctorObject);
+			// dojo.debug(new Date() - tic);
+			return ret;
+		}
+	}
+
+	this.getImplementationName = function(widgetName){
+		/*
+		 * This is the overly-simplistic implemention of getImplementation (har
+		 * har). In the future, we are going to want something that allows more
+		 * freedom of expression WRT to specifying different specializations of
+		 * a widget.
+		 *
+		 * Additionally, this implementation treats widget names as case
+		 * insensitive, which does not necessarialy mesh with the markup which
+		 * can construct a widget.
+		 */
+
+		var lowerCaseWidgetName = widgetName.toLowerCase();
+
+		var impl = knownWidgetImplementations[lowerCaseWidgetName];
+		if(impl){
+			return impl;
+		}
+
+		// first store a list of the render prefixes we are capable of rendering
+		if(!renderPrefixCache.length){
+			for(var renderer in dojo.render){
+				if(dojo.render[renderer]["capable"] === true){
+					var prefixes = dojo.render[renderer].prefixes;
+					for(var i = 0; i < prefixes.length; i++){
+						renderPrefixCache.push(prefixes[i].toLowerCase());
+					}
+				}
+			}
+			// make sure we don't HAVE to prefix widget implementation names
+			// with anything to get them to render
+			renderPrefixCache.push("");
+		}
+
+		// look for a rendering-context specific version of our widget name
+		for(var i = 0; i < widgetPackages.length; i++){
+			var widgetPackage = dojo.evalObjPath(widgetPackages[i]);
+			if(!widgetPackage) { continue; }
+
+			for (var j = 0; j < renderPrefixCache.length; j++) {
+				if (!widgetPackage[renderPrefixCache[j]]) { continue; }
+				for (var widgetClass in widgetPackage[renderPrefixCache[j]]) {
+					if (widgetClass.toLowerCase() != lowerCaseWidgetName) { continue; }
+					knownWidgetImplementations[lowerCaseWidgetName] =
+						widgetPackage[renderPrefixCache[j]][widgetClass];
+					return knownWidgetImplementations[lowerCaseWidgetName];
+				}
+			}
+
+			for (var j = 0; j < renderPrefixCache.length; j++) {
+				for (var widgetClass in widgetPackage) {
+					if (widgetClass.toLowerCase() !=
+						(renderPrefixCache[j] + lowerCaseWidgetName)) { continue; }
+	
+					knownWidgetImplementations[lowerCaseWidgetName] =
+						widgetPackage[widgetClass];
+					return knownWidgetImplementations[lowerCaseWidgetName];
+				}
+			}
+		}
+		
+		throw new Error('Could not locate "' + widgetName + '" class');
+	}
+
+	// FIXME: does it even belong in this name space?
+	// NOTE: this method is implemented by DomWidget.js since not all
+	// hostenv's would have an implementation.
+	/*this.getWidgetFromPrimitive = function(baseRenderType){
+		dojo.unimplemented("dojo.widget.manager.getWidgetFromPrimitive");
+	}
+
+	this.getWidgetFromEvent = function(nativeEvt){
+		dojo.unimplemented("dojo.widget.manager.getWidgetFromEvent");
+	}*/
+
+	// Catch window resize events and notify top level widgets
+	this.resizing=false;
+	this.onWindowResized = function(){
+		if(this.resizing){
+			return;	// duplicate event
+		}
+		try{
+			this.resizing=true;
+			for(var id in this.topWidgets){
+				var child = this.topWidgets[id];
+				if(child.onParentResized ){
+					child.onParentResized();
+				}
+			};
+		}catch(e){
+		}finally{
+			this.resizing=false;
+		}
+	}
+	if(typeof window != "undefined") {
+		dojo.addOnLoad(this, 'onWindowResized');							// initial sizing
+		dojo.event.connect(window, 'onresize', this, 'onWindowResized');	// window resize
+	}
+
+	// FIXME: what else?
+};
+
+(function(){
+	var dw = dojo.widget;
+	var dwm = dw.manager;
+	var h = dojo.lang.curry(dojo.lang, "hitch", dwm);
+	var g = function(oldName, newName){
+		dw[(newName||oldName)] = h(oldName);
+	}
+	// copy the methods from the default manager (this) to the widget namespace
+	g("add", "addWidget");
+	g("destroyAll", "destroyAllWidgets");
+	g("remove", "removeWidget");
+	g("removeById", "removeWidgetById");
+	g("getWidgetById");
+	g("getWidgetById", "byId");
+	g("getWidgetsByType");
+	g("getWidgetsByFilter");
+	g("getWidgetsByType", "byType");
+	g("getWidgetsByFilter", "byFilter");
+	g("getWidgetByNode", "byNode");
+	dw.all = function(n){
+		var widgets = dwm.getAllWidgets.apply(dwm, arguments);
+		if(arguments.length > 0) {
+			return widgets[n];
+		}
+		return widgets;
+	}
+	g("registerWidgetPackage");
+	g("getImplementation", "getWidgetImplementation");
+	g("getImplementationName", "getWidgetImplementationName");
+
+	dw.widgets = dwm.widgets;
+	dw.widgetIds = dwm.widgetIds;
+	dw.root = dwm.root;
+})();

Added: tapestry/tapestry4/trunk/framework/src/js/dojo/src/widget/Menu.js
URL: http://svn.apache.org/viewvc/tapestry/tapestry4/trunk/framework/src/js/dojo/src/widget/Menu.js?rev=408783&view=auto
==============================================================================
--- tapestry/tapestry4/trunk/framework/src/js/dojo/src/widget/Menu.js (added)
+++ tapestry/tapestry4/trunk/framework/src/js/dojo/src/widget/Menu.js Mon May 22 16:10:12 2006
@@ -0,0 +1,59 @@
+/*
+	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.Menu");
+dojo.provide("dojo.widget.DomMenu");
+
+dojo.deprecated("dojo.widget.Menu, dojo.widget.DomMenu",  "use dojo.widget.Menu2", "0.4");
+
+dojo.require("dojo.widget.*");
+
+dojo.widget.tags.addParseTreeHandler("dojo:menu");
+
+/* Menu
+ *******/
+
+dojo.widget.Menu = function () {
+	dojo.widget.Menu.superclass.constructor.call(this);
+}
+dojo.inherits(dojo.widget.Menu, dojo.widget.Widget);
+
+dojo.lang.extend(dojo.widget.Menu, {
+	widgetType: "Menu",
+	isContainer: true,
+	
+	items: [],
+	push: function(item){
+		dojo.connect.event(item, "onSelect", this, "onSelect");
+		this.items.push(item);
+	},
+	onSelect: function(){}
+});
+
+
+/* DomMenu
+ **********/
+
+dojo.widget.DomMenu = function(){
+	dojo.widget.DomMenu.superclass.constructor.call(this);
+}
+dojo.inherits(dojo.widget.DomMenu, dojo.widget.DomWidget);
+
+dojo.lang.extend(dojo.widget.DomMenu, {
+	widgetType: "Menu",
+	isContainer: true,
+
+	push: function (item) {
+		dojo.widget.Menu.call(this, item);
+		this.domNode.appendChild(item.domNode);
+	}
+});
+
+dojo.requireAfterIf("html", "dojo.widget.html.Menu");