You are viewing a plain text version of this content. The canonical link for it is here.
Posted to xap-commits@incubator.apache.org by jm...@apache.org on 2006/06/27 22:49:06 UTC

svn commit: r417618 [9/19] - in /incubator/xap/trunk/src/dojo/src: ./ lfx/ logging/ rpc/ selection/ storage/ string/ text/ undo/ uri/ uuid/ widget/ widget/html/ widget/svg/ widget/templates/ widget/templates/buttons/ widget/templates/images/ widget/tem...

Added: incubator/xap/trunk/src/dojo/src/widget/Dialog.js
URL: http://svn.apache.org/viewvc/incubator/xap/trunk/src/dojo/src/widget/Dialog.js?rev=417618&view=auto
==============================================================================
--- incubator/xap/trunk/src/dojo/src/widget/Dialog.js (added)
+++ incubator/xap/trunk/src/dojo/src/widget/Dialog.js Tue Jun 27 15:48:54 2006
@@ -0,0 +1,269 @@
+/*
+	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.Dialog");
+dojo.provide("dojo.widget.html.Dialog");
+
+dojo.require("dojo.widget.*");
+dojo.require("dojo.widget.ContentPane");
+dojo.require("dojo.event.*");
+dojo.require("dojo.graphics.color");
+dojo.require("dojo.html");
+
+dojo.widget.defineWidget(
+	"dojo.widget.html.Dialog",
+	dojo.widget.html.ContentPane,
+	{
+		templatePath: dojo.uri.dojoUri("src/widget/templates/HtmlDialog.html"),
+		isContainer: true,
+		_scrollConnected: false,
+		
+		// provide a focusable element or element id if you need to
+		// work around FF's tendency to send focus into outer space on hide
+		focusElement: "",
+
+		bg: null,
+		bgColor: "black",
+		bgOpacity: 0.4,
+		followScroll: true,
+		_fromTrap: false,
+		anim: null,
+		blockDuration: 0,
+		lifetime: 0,
+
+		trapTabs: function(e){
+			if(e.target == this.tabStart) {
+				if(this._fromTrap) {
+					this._fromTrap = false;
+				} else {
+					this._fromTrap = true;
+					this.tabEnd.focus();
+				}
+			} else if(e.target == this.tabEnd) {
+				if(this._fromTrap) {
+					this._fromTrap = false;
+				} else {
+					this._fromTrap = true;
+					this.tabStart.focus();
+				}
+			}
+		},
+
+		clearTrap: function(e) {
+			var _this = this;
+			setTimeout(function() {
+				_this._fromTrap = false;
+			}, 100);
+		},
+
+		postCreate: function(args, frag, parentComp) {
+			with(this.domNode.style) {
+				position = "absolute";
+				zIndex = 999;
+				display = "none";
+				overflow = "visible";
+			}
+			var b = document.body;
+			b.appendChild(this.domNode);
+
+			this.bg = document.createElement("div");
+			this.bg.className = "dialogUnderlay";
+			with(this.bg.style) {
+				position = "absolute";
+				left = top = "0px";
+				zIndex = 998;
+				display = "none";
+			}
+			this.setBackgroundColor(this.bgColor);
+			b.appendChild(this.bg);
+
+			this.bgIframe = new dojo.html.BackgroundIframe(this.bg);
+		},
+
+		setBackgroundColor: function(color) {
+			if(arguments.length >= 3) {
+				color = new dojo.graphics.color.Color(arguments[0], arguments[1], arguments[2]);
+			} else {
+				color = new dojo.graphics.color.Color(color);
+			}
+			this.bg.style.backgroundColor = color.toString();
+			return this.bgColor = color;
+		},
+		
+		setBackgroundOpacity: function(op) {
+			if(arguments.length == 0) { op = this.bgOpacity; }
+			dojo.style.setOpacity(this.bg, op);
+			try {
+				this.bgOpacity = dojo.style.getOpacity(this.bg);
+			} catch (e) {
+				this.bgOpacity = op;
+			}
+			return this.bgOpacity;
+		},
+
+		sizeBackground: function() {
+			if(this.bgOpacity > 0) {
+				var h = Math.max(
+					document.documentElement.scrollHeight || document.body.scrollHeight,
+					dojo.html.getViewportHeight());
+				var w = dojo.html.getViewportWidth();
+				this.bg.style.width = w + "px";
+				this.bg.style.height = h + "px";
+			}
+			this.bgIframe.onResized();
+		},
+
+		showBackground: function() {
+			this.sizeBackground();
+			if(this.bgOpacity > 0) {
+				this.bg.style.display = "block";
+			}
+		},
+
+		placeDialog: function() {
+			var scroll_offset = dojo.html.getScrollOffset();
+			var viewport_size = dojo.html.getViewportSize();
+
+			// find the size of the dialog
+			var w = dojo.style.getOuterWidth(this.containerNode);
+			var h = dojo.style.getOuterHeight(this.containerNode);
+
+			var x = scroll_offset[0] + (viewport_size[0] - w)/2;
+			var y = scroll_offset[1] + (viewport_size[1] - h)/2;
+
+			with(this.domNode.style) {
+				left = x + "px";
+				top = y + "px";
+			}
+		},
+
+		show: function() {
+			this.setBackgroundOpacity();
+			this.showBackground();
+
+			dojo.widget.html.Dialog.superclass.show.call(this);
+
+			// FIXME: moz doesn't generate onscroll events for mouse or key scrolling (wtf)
+			// we should create a fake event by polling the scrolltop/scrollleft every X ms.
+			// this smells like it should be a dojo feature rather than just for this widget.
+
+			if (this.followScroll && !this._scrollConnected){
+				this._scrollConnected = true;
+				dojo.event.connect(window, "onscroll", this, "onScroll");
+			}
+			
+			if(this.lifetime){
+				this.timeRemaining = this.lifetime;
+				if(!this.blockDuration){
+					dojo.event.connect(this.bg, "onclick", this, "hide");
+				}else{
+					dojo.event.disconnect(this.bg, "onclick", this, "hide");
+				}
+				if(this.timerNode){
+					this.timerNode.innerHTML = Math.ceil(this.timeRemaining/1000);
+				}
+				if(this.blockDuration && this.closeNode){
+					if(this.lifetime > this.blockDuration){
+						this.closeNode.style.visibility = "hidden";
+					}else{
+						this.closeNode.style.display = "none";
+					}
+				}
+				this.timer = setInterval(dojo.lang.hitch(this, "onTick"), 100);
+			}
+
+			this.onParentResized();
+		},
+
+		onLoad: function(){
+			// when href is specified we need to reposition
+			// the dialog after the data is loaded
+			this.placeDialog();
+		},
+		
+		fillInTemplate: function(){
+			// dojo.event.connect(this.domNode, "onclick", this, "killEvent");
+		},
+
+		hide: function(){
+			// workaround for FF focus going into outer space
+			if (this.focusElement) { 
+				dojo.byId(this.focusElement).focus(); 
+				dojo.byId(this.focusElement).blur();
+			}
+			
+			if(this.timer){
+				clearInterval(this.timer);
+			}
+
+			this.bg.style.display = "none";
+			this.bg.style.width = this.bg.style.height = "1px";
+
+			dojo.widget.html.Dialog.superclass.hide.call(this);
+
+			if (this._scrollConnected){
+				this._scrollConnected = false;
+				dojo.event.disconnect(window, "onscroll", this, "onScroll");
+			}
+		},
+		
+		setTimerNode: function(node){
+			this.timerNode = node;
+		},
+
+		setCloseControl: function(node) {
+			this.closeNode = node;
+			dojo.event.connect(node, "onclick", this, "hide");
+		},
+
+		setShowControl: function(node) {
+			dojo.event.connect(node, "onclick", this, "show");
+		},
+		
+		onTick: function(){
+			if(this.timer){
+				this.timeRemaining -= 100;
+				if(this.lifetime - this.timeRemaining >= this.blockDuration){
+					dojo.event.connect(this.bg, "onclick", this, "hide");
+					if(this.closeNode){
+						this.closeNode.style.visibility = "visible";
+					}
+				}
+				if(!this.timeRemaining){
+					clearInterval(this.timer);
+					this.hide();
+				}else if(this.timerNode){
+					this.timerNode.innerHTML = Math.ceil(this.timeRemaining/1000);
+				}
+			}
+		},
+
+		onScroll: function(){
+			this.placeDialog();
+			this.domNode.style.display = "block";
+		},
+
+		// Called when the browser window's size is changed
+		onParentResized: function() {
+			if(this.isShowing()){
+				this.sizeBackground();
+				this.placeDialog();
+				this.domNode.style.display="block";
+				this.onResized();
+			}
+		},
+		
+		killEvent: function(evt){
+			evt.preventDefault();
+			evt.stopPropagation();
+		}
+
+	}
+);

Propchange: incubator/xap/trunk/src/dojo/src/widget/Dialog.js
------------------------------------------------------------------------------
    svn:eol-style = native

Added: incubator/xap/trunk/src/dojo/src/widget/DocPane.js
URL: http://svn.apache.org/viewvc/incubator/xap/trunk/src/dojo/src/widget/DocPane.js?rev=417618&view=auto
==============================================================================
--- incubator/xap/trunk/src/dojo/src/widget/DocPane.js (added)
+++ incubator/xap/trunk/src/dojo/src/widget/DocPane.js Tue Jun 27 15:48:54 2006
@@ -0,0 +1,12 @@
+/*
+	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.DocPane");
+dojo.requireAfterIf("html", "dojo.widget.html.DocPane");

Added: incubator/xap/trunk/src/dojo/src/widget/DomWidget.js
URL: http://svn.apache.org/viewvc/incubator/xap/trunk/src/dojo/src/widget/DomWidget.js?rev=417618&view=auto
==============================================================================
--- incubator/xap/trunk/src/dojo/src/widget/DomWidget.js (added)
+++ incubator/xap/trunk/src/dojo/src/widget/DomWidget.js Tue Jun 27 15:48:54 2006
@@ -0,0 +1,555 @@
+/*
+	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.DomWidget");
+
+dojo.require("dojo.event.*");
+dojo.require("dojo.widget.Widget");
+dojo.require("dojo.dom");
+dojo.require("dojo.xml.Parse");
+dojo.require("dojo.uri.*");
+dojo.require("dojo.lang.func");
+
+dojo.widget._cssFiles = {};
+dojo.widget._cssStrings = {};
+dojo.widget._templateCache = {};
+
+dojo.widget.defaultStrings = {
+	dojoRoot: dojo.hostenv.getBaseScriptUri(),
+	baseScriptUri: dojo.hostenv.getBaseScriptUri()
+};
+
+dojo.widget.buildFromTemplate = function() {
+	dojo.lang.forward("fillFromTemplateCache");
+}
+
+// static method to build from a template w/ or w/o a real widget in place
+dojo.widget.fillFromTemplateCache = function(obj, templatePath, templateCssPath, templateString, avoidCache){
+	// dojo.debug("avoidCache:", avoidCache);
+	var tpath = templatePath || obj.templatePath;
+	var cpath = templateCssPath || obj.templateCssPath;
+
+	// DEPRECATED: use Uri objects, not strings
+	if (tpath && !(tpath instanceof dojo.uri.Uri)) {
+		tpath = dojo.uri.dojoUri(tpath);
+		dojo.deprecated("templatePath should be of type dojo.uri.Uri");
+	}
+	if (cpath && !(cpath instanceof dojo.uri.Uri)) {
+		cpath = dojo.uri.dojoUri(cpath);
+		dojo.deprecated("templateCssPath should be of type dojo.uri.Uri");
+	}
+	
+	var tmplts = dojo.widget._templateCache;
+	if(!obj["widgetType"]) { // don't have a real template here
+		do {
+			var dummyName = "__dummyTemplate__" + dojo.widget._templateCache.dummyCount++;
+		} while(tmplts[dummyName]);
+		obj.widgetType = dummyName;
+	}
+	var wt = obj.widgetType;
+
+	if((!obj.templateCssString)&&(cpath)&&(!dojo.widget._cssFiles[cpath])){
+		obj.templateCssString = dojo.hostenv.getText(cpath);
+		obj.templateCssPath = null;
+		dojo.widget._cssFiles[cpath] = true;
+	}
+	if((obj["templateCssString"])&&(!obj.templateCssString["loaded"])){
+		dojo.style.insertCssText(obj.templateCssString, null, cpath);
+		if(!obj.templateCssString){ obj.templateCssString = ""; }
+		obj.templateCssString.loaded = true;
+	}
+
+	var ts = tmplts[wt];
+	if(!ts){
+		tmplts[wt] = { "string": null, "node": null };
+		if(avoidCache){
+			ts = {};
+		}else{
+			ts = tmplts[wt];
+		}
+	}
+	if(!obj.templateString){
+		obj.templateString = templateString || ts["string"];
+	}
+	if(!obj.templateNode){
+		obj.templateNode = ts["node"];
+	}
+	if((!obj.templateNode)&&(!obj.templateString)&&(tpath)){
+		// fetch a text fragment and assign it to templateString
+		// NOTE: we rely on blocking IO here!
+		var tstring = dojo.hostenv.getText(tpath);
+		if(tstring){
+			var matches = tstring.match(/<body[^>]*>\s*([\s\S]+)\s*<\/body>/im);
+			if(matches){
+				tstring = matches[1];
+			}
+		}else{
+			tstring = "";
+		}
+		obj.templateString = tstring;
+		if(!avoidCache){
+			tmplts[wt]["string"] = tstring;
+		}
+	}
+	if((!ts["string"])&&(!avoidCache)){
+		ts.string = obj.templateString;
+	}
+}
+dojo.widget._templateCache.dummyCount = 0;
+
+dojo.widget.attachProperties = ["dojoAttachPoint", "id"];
+dojo.widget.eventAttachProperty = "dojoAttachEvent";
+dojo.widget.onBuildProperty = "dojoOnBuild";
+
+dojo.widget.attachTemplateNodes = function(rootNode, targetObj, events){
+	// FIXME: this method is still taking WAAAY too long. We need ways of optimizing:
+	//	a.) what we are looking for on each node
+	//	b.) the nodes that are subject to interrogation (use xpath instead?)
+	//	c.) how expensive event assignment is (less eval(), more connect())
+	// var start = new Date();
+	var elementNodeType = dojo.dom.ELEMENT_NODE;
+
+	function trim(str){
+		return str.replace(/^\s+|\s+$/g, "");
+	}
+
+	if(!rootNode){ 
+		rootNode = targetObj.domNode;
+	}
+
+	if(rootNode.nodeType != elementNodeType){
+		return;
+	}
+	// alert(events.length);
+
+	var nodes = rootNode.all || rootNode.getElementsByTagName("*");
+	var _this = targetObj;
+	for(var x=-1; x<nodes.length; x++){
+		var baseNode = (x == -1) ? rootNode : nodes[x];
+		// FIXME: is this going to have capitalization problems?  Could use getAttribute(name, 0); to get attributes case-insensitve
+		var attachPoint = [];
+		for(var y=0; y<this.attachProperties.length; y++){
+			var tmpAttachPoint = baseNode.getAttribute(this.attachProperties[y]);
+			if(tmpAttachPoint){
+				attachPoint = tmpAttachPoint.split(";");
+				for(var z=0; z<attachPoint.length; z++){
+					if(dojo.lang.isArray(targetObj[attachPoint[z]])){
+						targetObj[attachPoint[z]].push(baseNode);
+					}else{
+						targetObj[attachPoint[z]]=baseNode;
+					}
+				}
+				break;
+			}
+		}
+		// continue;
+
+		// FIXME: we need to put this into some kind of lookup structure
+		// instead of direct assignment
+		var tmpltPoint = baseNode.getAttribute(this.templateProperty);
+		if(tmpltPoint){
+			targetObj[tmpltPoint]=baseNode;
+		}
+
+		var attachEvent = baseNode.getAttribute(this.eventAttachProperty);
+		if(attachEvent){
+			// NOTE: we want to support attributes that have the form
+			// "domEvent: nativeEvent; ..."
+			var evts = attachEvent.split(";");
+			for(var y=0; y<evts.length; y++){
+				if((!evts[y])||(!evts[y].length)){ continue; }
+				var thisFunc = null;
+				var tevt = trim(evts[y]);
+				if(evts[y].indexOf(":") >= 0){
+					// oh, if only JS had tuple assignment
+					var funcNameArr = tevt.split(":");
+					tevt = trim(funcNameArr[0]);
+					thisFunc = trim(funcNameArr[1]);
+				}
+				if(!thisFunc){
+					thisFunc = tevt;
+				}
+
+				var tf = function(){ 
+					var ntf = new String(thisFunc);
+					return function(evt){
+						if(_this[ntf]){
+							_this[ntf](dojo.event.browser.fixEvent(evt, this));
+						}
+					};
+				}();
+				dojo.event.browser.addListener(baseNode, tevt, tf, false, true);
+				// dojo.event.browser.addListener(baseNode, tevt, dojo.lang.hitch(_this, thisFunc));
+			}
+		}
+
+		for(var y=0; y<events.length; y++){
+			//alert(events[x]);
+			var evtVal = baseNode.getAttribute(events[y]);
+			if((evtVal)&&(evtVal.length)){
+				var thisFunc = null;
+				var domEvt = events[y].substr(4); // clober the "dojo" prefix
+				thisFunc = trim(evtVal);
+				var funcs = [thisFunc];
+				if(thisFunc.indexOf(";")>=0){
+					funcs = dojo.lang.map(thisFunc.split(";"), trim);
+				}
+				for(var z=0; z<funcs.length; z++){
+					if(!funcs[z].length){ continue; }
+					var tf = function(){ 
+						var ntf = new String(funcs[z]);
+						return function(evt){
+							if(_this[ntf]){
+								_this[ntf](dojo.event.browser.fixEvent(evt, this));
+							}
+						}
+					}();
+					dojo.event.browser.addListener(baseNode, domEvt, tf, false, true);
+					// dojo.event.browser.addListener(baseNode, domEvt, dojo.lang.hitch(_this, funcs[z]));
+				}
+			}
+		}
+
+		var onBuild = baseNode.getAttribute(this.onBuildProperty);
+		if(onBuild){
+			eval("var node = baseNode; var widget = targetObj; "+onBuild);
+		}
+	}
+
+}
+
+dojo.widget.getDojoEventsFromStr = function(str){
+	// var lstr = str.toLowerCase();
+	var re = /(dojoOn([a-z]+)(\s?))=/gi;
+	var evts = str ? str.match(re)||[] : [];
+	var ret = [];
+	var lem = {};
+	for(var x=0; x<evts.length; x++){
+		if(evts[x].legth < 1){ continue; }
+		var cm = evts[x].replace(/\s/, "");
+		cm = (cm.slice(0, cm.length-1));
+		if(!lem[cm]){
+			lem[cm] = true;
+			ret.push(cm);
+		}
+	}
+	return ret;
+}
+
+/*
+dojo.widget.buildAndAttachTemplate = function(obj, templatePath, templateCssPath, templateString, targetObj) {
+	this.buildFromTemplate(obj, templatePath, templateCssPath, templateString);
+	var node = dojo.dom.createNodesFromText(obj.templateString, true)[0];
+	this.attachTemplateNodes(node, targetObj||obj, dojo.widget.getDojoEventsFromStr(templateString));
+	return node;
+}
+*/
+
+dojo.declare("dojo.widget.DomWidget", dojo.widget.Widget, {
+	initializer: function() {
+		if((arguments.length>0)&&(typeof arguments[0] == "object")){
+			this.create(arguments[0]);
+		}
+	},
+								 
+	templateNode: null,
+	templateString: null,
+	templateCssString: null,
+	preventClobber: false,
+	domNode: null, // this is our visible representation of the widget!
+	containerNode: null, // holds child elements
+
+	// Process the given child widget, inserting it's dom node as a child of our dom node
+	// FIXME: should we support addition at an index in the children arr and
+	// order the display accordingly? Right now we always append.
+	addChild: function(widget, overrideContainerNode, pos, ref, insertIndex){
+		if(!this.isContainer){ // we aren't allowed to contain other widgets, it seems
+			dojo.debug("dojo.widget.DomWidget.addChild() attempted on non-container widget");
+			return null;
+		}else{
+			this.addWidgetAsDirectChild(widget, overrideContainerNode, pos, ref, insertIndex);
+			this.registerChild(widget, insertIndex);
+		}
+		return widget;
+	},
+	
+	addWidgetAsDirectChild: function(widget, overrideContainerNode, pos, ref, insertIndex){
+		if((!this.containerNode)&&(!overrideContainerNode)){
+			this.containerNode = this.domNode;
+		}
+		var cn = (overrideContainerNode) ? overrideContainerNode : this.containerNode;
+		if(!pos){ pos = "after"; }
+		if(!ref){ 
+			// if(!cn){ cn = document.body; }
+			if(!cn){ cn = document.body; }
+			ref = cn.lastChild; 
+		}
+		if(!insertIndex) { insertIndex = 0; }
+		widget.domNode.setAttribute("dojoinsertionindex", insertIndex);
+
+		// insert the child widget domNode directly underneath my domNode, in the
+		// specified position (by default, append to end)
+		if(!ref){
+			cn.appendChild(widget.domNode);
+		}else{
+			// FIXME: was this meant to be the (ugly hack) way to support insert @ index?
+			//dojo.dom[pos](widget.domNode, ref, insertIndex);
+
+			// CAL: this appears to be the intended way to insert a node at a given position...
+			if (pos == 'insertAtIndex'){
+				// dojo.debug("idx:", insertIndex, "isLast:", ref === cn.lastChild);
+				dojo.dom.insertAtIndex(widget.domNode, ref.parentNode, insertIndex);
+			}else{
+				// dojo.debug("pos:", pos, "isLast:", ref === cn.lastChild);
+				if((pos == "after")&&(ref === cn.lastChild)){
+					cn.appendChild(widget.domNode);
+				}else{
+					dojo.dom.insertAtPosition(widget.domNode, cn, pos);
+				}
+			}
+		}
+	},
+
+	// Record that given widget descends from me
+	registerChild: function(widget, insertionIndex){
+
+		// we need to insert the child at the right point in the parent's 
+		// 'children' array, based on the insertionIndex
+
+		widget.dojoInsertionIndex = insertionIndex;
+
+		var idx = -1;
+		for(var i=0; i<this.children.length; i++){
+			if (this.children[i].dojoInsertionIndex < insertionIndex){
+				idx = i;
+			}
+		}
+
+		this.children.splice(idx+1, 0, widget);
+
+		widget.parent = this;
+		widget.addedTo(this);
+		
+		// If this widget was created programatically, then it was erroneously added
+		// to dojo.widget.manager.topWidgets.  Fix that here.
+		delete dojo.widget.manager.topWidgets[widget.widgetId];
+	},
+
+	removeChild: function(widget){
+		// detach child domNode from parent domNode
+		dojo.dom.removeNode(widget.domNode);
+
+		// remove child widget from parent widget
+		return dojo.widget.DomWidget.superclass.removeChild.call(this, widget);
+	},
+
+	getFragNodeRef: function(frag){
+		if( !frag || !frag["dojo:"+this.widgetType.toLowerCase()] ){
+			dojo.raise("Error: no frag for widget type " + this.widgetType +
+				", id " + this.widgetId + " (maybe a widget has set it's type incorrectly)");
+		}
+		return (frag ? frag["dojo:"+this.widgetType.toLowerCase()]["nodeRef"] : null);
+	},
+	
+	// Replace source domNode with generated dom structure, and register
+	// widget with parent.
+	postInitialize: function(args, frag, parentComp){
+		var sourceNodeRef = this.getFragNodeRef(frag);
+		// Stick my generated dom into the output tree
+		//alert(this.widgetId + ": replacing " + sourceNodeRef + " with " + this.domNode.innerHTML);
+		if (parentComp && (parentComp.snarfChildDomOutput || !sourceNodeRef)){
+			// Add my generated dom as a direct child of my parent widget
+			// This is important for generated widgets, and also cases where I am generating an
+			// <li> node that can't be inserted back into the original DOM tree
+			parentComp.addWidgetAsDirectChild(this, "", "insertAtIndex", "",  args["dojoinsertionindex"], sourceNodeRef);
+		} else if (sourceNodeRef){
+			// Do in-place replacement of the my source node with my generated dom
+			if(this.domNode && (this.domNode !== sourceNodeRef)){
+				var oldNode = sourceNodeRef.parentNode.replaceChild(this.domNode, sourceNodeRef);
+			}
+		}
+
+		// Register myself with my parent, or with the widget manager if
+		// I have no parent
+		// TODO: the code below erroneously adds all programatically generated widgets
+		// to topWidgets (since we don't know who the parent is until after creation finishes)
+		if ( parentComp ) {
+			parentComp.registerChild(this, args.dojoinsertionindex);
+		} else {
+			dojo.widget.manager.topWidgets[this.widgetId]=this;
+		}
+
+		// Expand my children widgets
+		if(this.isContainer){
+			//alert("recurse from " + this.widgetId);
+			// build any sub-components with us as the parent
+			var fragParser = dojo.widget.getParser();
+			fragParser.createSubComponents(frag, this);
+		}
+	},
+
+	// method over-ride
+	buildRendering: function(args, frag){
+		// DOM widgets construct themselves from a template
+		var ts = dojo.widget._templateCache[this.widgetType];
+		if(	
+			(!this.preventClobber)&&(
+				(this.templatePath)||
+				(this.templateNode)||
+				(
+					(this["templateString"])&&(this.templateString.length) 
+				)||
+				(
+					(typeof ts != "undefined")&&( (ts["string"])||(ts["node"]) )
+				)
+			)
+		){
+			// if it looks like we can build the thing from a template, do it!
+			this.buildFromTemplate(args, frag);
+		}else{
+			// otherwise, assign the DOM node that was the source of the widget
+			// parsing to be the root node
+			this.domNode = this.getFragNodeRef(frag);
+		}
+		this.fillInTemplate(args, frag); 	// this is where individual widgets
+											// will handle population of data
+											// from properties, remote data
+											// sets, etc.
+	},
+
+	buildFromTemplate: function(args, frag){
+		// var start = new Date();
+		// copy template properties if they're already set in the templates object
+		// dojo.debug("buildFromTemplate:", this);
+		var avoidCache = false;
+		if(args["templatecsspath"]){
+			args["templateCssPath"] = args["templatecsspath"];
+		}
+		if(args["templatepath"]){
+			avoidCache = true;
+			args["templatePath"] = args["templatepath"];
+		}
+		dojo.widget.fillFromTemplateCache(	this, 
+											args["templatePath"], 
+											args["templateCssPath"],
+											null,
+											avoidCache);
+		var ts = dojo.widget._templateCache[this.widgetType];
+		if((ts)&&(!avoidCache)){
+			if(!this.templateString.length){
+				this.templateString = ts["string"];
+			}
+			if(!this.templateNode){
+				this.templateNode = ts["node"];
+			}
+		}
+		var matches = false;
+		var node = null;
+		// var tstr = new String(this.templateString); 
+		var tstr = this.templateString; 
+		// attempt to clone a template node, if there is one
+		if((!this.templateNode)&&(this.templateString)){
+			matches = this.templateString.match(/\$\{([^\}]+)\}/g);
+			if(matches) {
+				// if we do property replacement, don't create a templateNode
+				// to clone from.
+				var hash = this.strings || {};
+				// FIXME: should this hash of default replacements be cached in
+				// templateString?
+				for(var key in dojo.widget.defaultStrings) {
+					if(dojo.lang.isUndefined(hash[key])) {
+						hash[key] = dojo.widget.defaultStrings[key];
+					}
+				}
+				// FIXME: this is a lot of string munging. Can we make it faster?
+				for(var i = 0; i < matches.length; i++) {
+					var key = matches[i];
+					key = key.substring(2, key.length-1);
+					var kval = (key.substring(0, 5) == "this.") ? this[key.substring(5)] : hash[key];
+					var value;
+					if((kval)||(dojo.lang.isString(kval))){
+						value = (dojo.lang.isFunction(kval)) ? kval.call(this, key, this.templateString) : kval;
+						tstr = tstr.replace(matches[i], value);
+					}
+				}
+			}else{
+				// otherwise, we are required to instantiate a copy of the template
+				// string if one is provided.
+				
+				// FIXME: need to be able to distinguish here what should be done
+				// or provide a generic interface across all DOM implementations
+				// FIMXE: this breaks if the template has whitespace as its first 
+				// characters
+				// node = this.createNodesFromText(this.templateString, true);
+				// this.templateNode = node[0].cloneNode(true); // we're optimistic here
+				this.templateNode = this.createNodesFromText(this.templateString, true)[0];
+				ts.node = this.templateNode;
+			}
+		}
+		if((!this.templateNode)&&(!matches)){ 
+			dojo.debug("weren't able to create template!");
+			return false;
+		}else if(!matches){
+			node = this.templateNode.cloneNode(true);
+			if(!node){ return false; }
+		}else{
+			node = this.createNodesFromText(tstr, true)[0];
+		}
+
+		// recurse through the node, looking for, and attaching to, our
+		// attachment points which should be defined on the template node.
+
+		this.domNode = node;
+		// dojo.profile.start("attachTemplateNodes");
+		this.attachTemplateNodes(this.domNode, this);
+		// dojo.profile.end("attachTemplateNodes");
+		
+		// relocate source contents to templated container node
+		// this.containerNode must be able to receive children, or exceptions will be thrown
+		if (this.isContainer && this.containerNode){
+			var src = this.getFragNodeRef(frag);
+			if (src){
+				dojo.dom.moveChildren(src, this.containerNode);
+			}
+		}
+	},
+
+	attachTemplateNodes: function(baseNode, targetObj){
+		if(!targetObj){ targetObj = this; }
+		return dojo.widget.attachTemplateNodes(baseNode, targetObj, 
+					dojo.widget.getDojoEventsFromStr(this.templateString));
+	},
+
+	fillInTemplate: function(){
+		// dojo.unimplemented("dojo.widget.DomWidget.fillInTemplate");
+	},
+	
+	// method over-ride
+	destroyRendering: function(){
+		try{
+			delete this.domNode;
+		}catch(e){ /* squelch! */ }
+	},
+
+	// FIXME: method over-ride
+	cleanUp: function(){},
+	
+	getContainerHeight: function(){
+		dojo.unimplemented("dojo.widget.DomWidget.getContainerHeight");
+	},
+
+	getContainerWidth: function(){
+		dojo.unimplemented("dojo.widget.DomWidget.getContainerWidth");
+	},
+
+	createNodesFromText: function(){
+		dojo.unimplemented("dojo.widget.DomWidget.createNodesFromText");
+	}
+});

Propchange: incubator/xap/trunk/src/dojo/src/widget/DomWidget.js
------------------------------------------------------------------------------
    svn:eol-style = native

Added: incubator/xap/trunk/src/dojo/src/widget/DropdownButton.js
URL: http://svn.apache.org/viewvc/incubator/xap/trunk/src/dojo/src/widget/DropdownButton.js?rev=417618&view=auto
==============================================================================
--- incubator/xap/trunk/src/dojo/src/widget/DropdownButton.js (added)
+++ incubator/xap/trunk/src/dojo/src/widget/DropdownButton.js Tue Jun 27 15:48:54 2006
@@ -0,0 +1,29 @@
+/*
+	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.DropdownButton");
+
+dojo.deprecated("dojo.widget.DropdownButton",  "use dojo.widget.ComboButton", "0.4");
+
+// Draws a button with a down arrow;
+// when you press the down arrow something appears (usually a menu)
+
+dojo.require("dojo.widget.*");
+
+dojo.widget.tags.addParseTreeHandler("dojo:dropdownbutton");
+
+dojo.widget.DropdownButton = function(){
+	dojo.widget.Widget.call(this);
+
+	this.widgetType = "DropdownButton";
+}
+dojo.inherits(dojo.widget.DropdownButton, dojo.widget.Widget);
+
+dojo.requireAfterIf("html", "dojo.widget.html.DropdownButton");

Added: incubator/xap/trunk/src/dojo/src/widget/DropdownContainer.js
URL: http://svn.apache.org/viewvc/incubator/xap/trunk/src/dojo/src/widget/DropdownContainer.js?rev=417618&view=auto
==============================================================================
--- incubator/xap/trunk/src/dojo/src/widget/DropdownContainer.js (added)
+++ incubator/xap/trunk/src/dojo/src/widget/DropdownContainer.js Tue Jun 27 15:48:54 2006
@@ -0,0 +1,104 @@
+/*
+	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.DropdownContainer");
+dojo.require("dojo.widget.*");
+dojo.require("dojo.widget.HtmlWidget");
+dojo.require("dojo.event.*");
+dojo.require("dojo.html");
+
+dojo.widget.defineWidget(
+	"dojo.widget.DropdownContainer",
+	dojo.widget.HtmlWidget,
+	{
+		initializer: function(){
+		},
+
+		isContainer: true,
+		snarfChildDomOutput: true,
+		
+		inputWidth: "7em",
+		inputId: "",
+		inputName: "",
+		iconURL: null,
+		iconAlt: null,
+
+		inputNode: null,
+		buttonNode: null,
+		containerNode: null,
+		subWidgetNode: null,
+
+		templateString: '<div><span style="white-space:nowrap"><input type="text" value="" style="vertical-align:middle;" dojoAttachPoint="inputNode" autocomplete="off" /> <img src="" alt="" dojoAttachPoint="buttonNode" dojoAttachEvent="onclick: onIconClick;" style="vertical-align:middle; cursor:pointer; cursor:hand;" /></span><br /><div dojoAttachPoint="containerNode" style="display:none;position:absolute;width:12em;background-color:#fff;"></div></div>',
+		templateCssPath: "",
+
+		fillInTemplate: function(args, frag){
+			var source = this.getFragNodeRef(frag);
+			
+			if(args.inputId){ this.inputId = args.inputId; }
+			if(args.inputName){ this.inputName = args.inputName; }
+			if(args.iconURL){ this.iconURL = args.iconURL; }
+			if(args.iconAlt){ this.iconAlt = args.iconAlt; }
+
+			this.containerNode.style.left = "";
+			this.containerNode.style.top = "";
+
+			if(this.inputId){ this.inputNode.id = this.inputId; }
+			if(this.inputName){ this.inputNode.name = this.inputName; }
+			this.inputNode.style.width = this.inputWidth;
+
+			if(this.iconURL){ this.buttonNode.src = this.iconURL; }
+			if(this.iconAlt){ this.buttonNode.alt = this.iconAlt; }
+
+			dojo.event.connect(this.inputNode, "onchange", this, "onInputChange");
+			
+			this.containerIframe = new dojo.html.BackgroundIframe(this.containerNode);
+			this.containerIframe.size([0,0,0,0]);
+		},
+
+		onIconClick: function(evt){
+			this.toggleContainerShow();
+		},
+
+		toggleContainerShow: function(){
+			if(dojo.html.isShowing(this.containerNode)){
+				dojo.html.hide(this.containerNode);
+			}else{
+				this.showContainer();
+			}
+		},
+		
+		showContainer: function(){
+			dojo.html.show(this.containerNode);
+			this.sizeBackgroundIframe();
+		},
+		
+		onHide: function(evt){
+			dojo.html.hide(this.containerNode);
+		},
+		
+		sizeBackgroundIframe: function(){
+			var w = dojo.style.getOuterWidth(this.containerNode);
+			var h = dojo.style.getOuterHeight(this.containerNode);
+			if(w==0||h==0){
+				// need more time to calculate size
+				dojo.lang.setTimeout(this, "sizeBackgroundIframe", 100);
+				return;
+			}
+			if(dojo.html.isShowing(this.containerNode)){
+				this.containerIframe.size([0,0,w,h]);
+			}
+		},
+
+		onInputChange: function(){}
+	},
+	"html"
+);
+
+dojo.widget.tags.addParseTreeHandler("dojo:dropdowncontainer");
\ No newline at end of file

Added: incubator/xap/trunk/src/dojo/src/widget/DropdownDatePicker.js
URL: http://svn.apache.org/viewvc/incubator/xap/trunk/src/dojo/src/widget/DropdownDatePicker.js?rev=417618&view=auto
==============================================================================
--- incubator/xap/trunk/src/dojo/src/widget/DropdownDatePicker.js (added)
+++ incubator/xap/trunk/src/dojo/src/widget/DropdownDatePicker.js Tue Jun 27 15:48:54 2006
@@ -0,0 +1,67 @@
+/*
+	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.DropdownDatePicker");
+dojo.require("dojo.widget.*");
+dojo.require("dojo.widget.DropdownContainer");
+dojo.require("dojo.widget.DatePicker");
+dojo.require("dojo.event.*");
+dojo.require("dojo.html");
+
+dojo.widget.defineWidget(
+	"dojo.widget.DropdownDatePicker",
+	dojo.widget.DropdownContainer,
+	{
+		iconURL: dojo.uri.dojoUri("src/widget/templates/images/dateIcon.gif"),
+		iconAlt: "Select a Date",
+		iconTitle: "Select a Date",
+		
+		datePicker: null,
+		
+		dateFormat: "%m/%d/%Y",
+		date: null,
+		
+		fillInTemplate: function(args, frag){
+			dojo.widget.DropdownDatePicker.superclass.fillInTemplate.call(this, args, frag);
+			var source = this.getFragNodeRef(frag);
+			
+			if(args.dateFormat){ this.dateFormat = args.dateFormat; }
+			if(args.date){ this.date = new Date(args.date); }
+			
+			var dpNode = document.createElement("div");
+			this.containerNode.appendChild(dpNode);
+			
+			var dateProps = { widgetContainerId: this.widgetId };
+			if(this.date){
+				dateProps["date"] = this.date;
+				dateProps["storedDate"] = dojo.widget.DatePicker.util.toRfcDate(this.date);
+				this.inputNode.value = dojo.date.format(this.date, this.dateFormat);
+			}
+			this.datePicker = dojo.widget.createWidget("DatePicker", dateProps, dpNode);
+			dojo.event.connect(this.datePicker, "onSetDate", this, "onSetDate");
+		},
+		
+		onSetDate: function(){
+			this.inputNode.value = dojo.date.format(this.datePicker.date, this.dateFormat);
+			this.onHide();
+		},
+		
+		onInputChange: function(){
+			var tmp = new Date(this.inputNode.value);
+			this.datePicker.date = tmp;
+			this.datePicker.setDate(dojo.widget.DatePicker.util.toRfcDate(tmp));
+			this.datePicker.initData();
+			this.datePicker.initUI();
+		}
+	},
+	"html"
+);
+
+dojo.widget.tags.addParseTreeHandler("dojo:dropdowndatepicker");
\ No newline at end of file

Propchange: incubator/xap/trunk/src/dojo/src/widget/DropdownDatePicker.js
------------------------------------------------------------------------------
    svn:eol-style = native

Added: incubator/xap/trunk/src/dojo/src/widget/Editor.js
URL: http://svn.apache.org/viewvc/incubator/xap/trunk/src/dojo/src/widget/Editor.js?rev=417618&view=auto
==============================================================================
--- incubator/xap/trunk/src/dojo/src/widget/Editor.js (added)
+++ incubator/xap/trunk/src/dojo/src/widget/Editor.js Tue Jun 27 15:48:54 2006
@@ -0,0 +1,533 @@
+/*
+	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.Editor");
+dojo.provide("dojo.widget.html.Editor");
+dojo.require("dojo.io.*");
+dojo.require("dojo.widget.*");
+dojo.require("dojo.widget.Toolbar");
+dojo.require("dojo.widget.RichText");
+dojo.require("dojo.widget.ColorPalette");
+dojo.require("dojo.string.extras");
+
+dojo.widget.tags.addParseTreeHandler("dojo:Editor");
+
+dojo.widget.html.Editor = function() {
+	dojo.widget.HtmlWidget.call(this);
+	this.contentFilters = [];
+	this._toolbars = [];
+}
+dojo.inherits(dojo.widget.html.Editor, dojo.widget.HtmlWidget);
+
+dojo.widget.html.Editor.itemGroups = {
+	textGroup: ["bold", "italic", "underline", "strikethrough"],
+	blockGroup: ["formatBlock", "fontName", "fontSize"],
+	justifyGroup: ["justifyleft", "justifycenter", "justifyright"],
+	commandGroup: ["save", "cancel"],
+	colorGroup: ["forecolor", "hilitecolor"],
+	listGroup: ["insertorderedlist", "insertunorderedlist"],
+	indentGroup: ["outdent", "indent"],
+	linkGroup: ["createlink", "insertimage", "inserthorizontalrule"]
+};
+
+dojo.widget.html.Editor.formatBlockValues = {
+	"Normal": "p",
+	"Main heading": "h2",
+	"Sub heading": "h3",
+	"Sub sub heading": "h4",
+	"Preformatted": "pre"
+};
+
+dojo.widget.html.Editor.fontNameValues = {
+	"Arial": "Arial, Helvetica, sans-serif",
+	"Verdana": "Verdana, sans-serif",
+	"Times New Roman": "Times New Roman, serif",
+	"Courier": "Courier New, monospace"
+};
+
+dojo.widget.html.Editor.fontSizeValues = {
+	"1 (8 pt)" : "1",
+	"2 (10 pt)": "2",
+	"3 (12 pt)": "3",
+	"4 (14 pt)": "4",
+	"5 (18 pt)": "5",
+	"6 (24 pt)": "6",
+	"7 (36 pt)": "7"
+};
+
+dojo.widget.html.Editor.defaultItems = [
+	"commandGroup", "|", "blockGroup", "|", "textGroup", "|", "colorGroup", "|", "justifyGroup", "|", "listGroup", "indentGroup", "|", "linkGroup"
+];
+
+// ones we support by default without asking the RichText component
+// NOTE: you shouldn't put buttons like bold, italic, etc in here
+dojo.widget.html.Editor.supportedCommands = ["save", "cancel", "|", "-", "/", " "];
+
+dojo.lang.extend(dojo.widget.html.Editor, {
+	widgetType: "Editor",
+
+	saveUrl: "",
+	saveMethod: "post",
+	saveArgName: "editorContent",
+	closeOnSave: false,
+	items: dojo.widget.html.Editor.defaultItems,
+	formatBlockItems: dojo.lang.shallowCopy(dojo.widget.html.Editor.formatBlockValues),
+	fontNameItems: dojo.lang.shallowCopy(dojo.widget.html.Editor.fontNameValues),
+	fontSizeItems: dojo.lang.shallowCopy(dojo.widget.html.Editor.fontSizeValues),
+
+	// used to get the properties of an item if it is given as a string
+	getItemProperties: function(name) {
+		var props = {};
+		switch(name.toLowerCase()) {
+			case "bold":
+			case "italic":
+			case "underline":
+			case "strikethrough":
+				props.toggleItem = true;
+				break;
+
+			case "justifygroup":
+				props.defaultButton = "justifyleft";
+				props.preventDeselect = true;
+				props.buttonGroup = true;
+				break;
+
+			case "listgroup":
+				props.buttonGroup = true;
+				break;
+
+			case "save":
+			case "cancel":
+				props.label = dojo.string.capitalize(name);
+				break;
+
+			case "forecolor":
+			case "hilitecolor":
+				props.name = name;
+				props.toggleItem = true; // FIXME: they aren't exactly toggle items
+				props.icon = this.getCommandImage(name);
+				break;
+
+			case "formatblock":
+				props.name = "formatBlock";
+				props.values = this.formatBlockItems;
+				break;
+
+			case "fontname":
+				props.name = "fontName";
+				props.values = this.fontNameItems;
+
+			case "fontsize":
+				props.name = "fontSize";
+				props.values = this.fontSizeItems;
+		}
+		return props;
+	},
+
+	validateItems: true, // set to false to add items, regardless of support
+	focusOnLoad: true,
+	minHeight: "1em",
+
+	_richText: null, // RichText widget
+	_richTextType: "RichText",
+
+	_toolbarContainer: null, // ToolbarContainer widget
+	_toolbarContainerType: "ToolbarContainer",
+
+	_toolbars: [],
+	_toolbarType: "Toolbar",
+
+	_toolbarItemType: "ToolbarItem",
+
+	buildRendering: function(args, frag) {
+		// get the node from args/frag
+		var node = frag["dojo:"+this.widgetType.toLowerCase()]["nodeRef"];
+		var trt = dojo.widget.createWidget(this._richTextType, {
+			focusOnLoad: this.focusOnLoad,
+			minHeight: this.minHeight
+		}, node)
+		var _this = this;
+		// this appears to fix a weird timing bug on Safari
+		setTimeout(function(){
+			_this.setRichText(trt);
+
+			_this.initToolbar();
+
+			_this.fillInTemplate(args, frag);
+		}, 0);
+	},
+
+	setRichText: function(richText) {
+		if(this._richText && this._richText == richText) {
+			dojo.debug("Already set the richText to this richText!");
+			return;
+		}
+
+		if(this._richText && !this._richText.isClosed) {
+			dojo.debug("You are switching richTexts yet you haven't closed the current one. Losing reference!");
+		}
+		this._richText = richText;
+		dojo.event.connect(this._richText, "close", this, "onClose");
+		dojo.event.connect(this._richText, "onLoad", this, "onLoad");
+		dojo.event.connect(this._richText, "onDisplayChanged", this, "updateToolbar");
+		if(this._toolbarContainer) {
+			this._toolbarContainer.enable();
+			this.updateToolbar(true);
+		}
+	},
+
+	initToolbar: function() {
+		// var tic = new Date();
+		if(this._toolbarContainer) { return; } // only create it once
+		this._toolbarContainer = dojo.widget.createWidget(this._toolbarContainerType);
+		var tb = this.addToolbar();
+		var last = true;
+		for(var i = 0; i < this.items.length; i++) {
+			if(this.items[i] == "\n") { // new row
+				tb = this.addToolbar();
+			} else {
+				if((this.items[i] == "|")&&(!last)){
+					last = true;
+				}else{
+					last = this.addItem(this.items[i], tb);
+				}
+			}
+		}
+		this.insertToolbar(this._toolbarContainer.domNode, this._richText.domNode);
+		// alert(new Date - tic);
+	},
+
+	// allow people to override this so they can make their own placement logic
+	insertToolbar: function(tbNode, richTextNode) {
+		dojo.html.insertBefore(tbNode, richTextNode);
+		//dojo.html.insertBefore(this._toolbarContainer.domNode, this._richText.domNode);
+	},
+
+	addToolbar: function(toolbar) {
+		this.initToolbar();
+		if(!(toolbar instanceof dojo.widget.html.Toolbar)) {
+			toolbar = dojo.widget.createWidget(this._toolbarType);
+		}
+		this._toolbarContainer.addChild(toolbar);
+		this._toolbars.push(toolbar);
+		return toolbar;
+	},
+
+	addItem: function(item, tb, dontValidate) {
+		if(!tb) { tb = this._toolbars[0]; }
+		var cmd = ((item)&&(!dojo.lang.isUndefined(item["getValue"]))) ?  cmd = item["getValue"](): item;
+
+		var groups = dojo.widget.html.Editor.itemGroups;
+		if(item instanceof dojo.widget.ToolbarItem) {
+			tb.addChild(item);
+		} else if(groups[cmd]) {
+			var group = groups[cmd];
+			var worked = true;
+			if(cmd == "justifyGroup" || cmd == "listGroup") {
+				var btnGroup = [cmd];
+				for(var i = 0 ; i < group.length; i++) {
+					if(dontValidate || this.isSupportedCommand(group[i])) {
+						btnGroup.push(this.getCommandImage(group[i]));
+					}else{
+						worked = false;
+					}
+				}
+				if(btnGroup.length){
+					/*
+					// the addChild interface is assinine. Work around it.
+					var tprops = this.getItemProperties(cmd);
+					var tmpGroup = dojo.widget.createWidget("ToolbarButtonGroup", tprops);
+					dojo.debug(btnGroup);
+					dojo.event.connect(tmpGroup, "onClick", this, "_action");
+					dojo.event.connect(tmpGroup, "onChangeSelect", this, "_action");
+					*/
+					var btn = tb.addChild(btnGroup, null, this.getItemProperties(cmd));
+					dojo.event.connect(btn, "onClick", this, "_action");
+					dojo.event.connect(btn, "onChangeSelect", this, "_action");
+				}
+				return worked;
+			} else {
+				for(var i = 0; i < group.length; i++) {
+					if(!this.addItem(group[i], tb)){
+						worked = false;
+					}
+				}
+				return worked;
+			}
+		} else {
+			if((!dontValidate)&&(!this.isSupportedCommand(cmd))){
+				return false;
+			}
+			if(dontValidate || this.isSupportedCommand(cmd)) {
+				cmd = cmd.toLowerCase();
+				if(cmd == "formatblock") {
+					var select = dojo.widget.createWidget("ToolbarSelect", {
+						name: "formatBlock",
+						values: this.formatBlockItems
+					});
+					tb.addChild(select);
+					var _this = this;
+					dojo.event.connect(select, "onSetValue", function(item, value) {
+						_this.onAction("formatBlock", value);
+					});
+				} else if(cmd == "fontname") {
+					var select = dojo.widget.createWidget("ToolbarSelect", {
+						name: "fontName",
+						values: this.fontNameItems
+					});
+					tb.addChild(select);
+					dojo.event.connect(select, "onSetValue", dojo.lang.hitch(this, function(item, value) {
+						this.onAction("fontName", value);
+					}));
+				} else if(cmd == "fontsize") {
+					var select = dojo.widget.createWidget("ToolbarSelect", {
+						name: "fontSize",
+						values: this.fontSizeItems
+					});
+					tb.addChild(select);
+					dojo.event.connect(select, "onSetValue", dojo.lang.hitch(this, function(item, value) {
+						this.onAction("fontSize", value);
+					}));
+				} else if(dojo.lang.inArray(cmd, ["forecolor", "hilitecolor"])) {
+					var btn = tb.addChild(dojo.widget.createWidget("ToolbarColorDialog", this.getItemProperties(cmd)));
+					dojo.event.connect(btn, "onSetValue", this, "_setValue");
+				} else {
+					var btn = tb.addChild(this.getCommandImage(cmd), null, this.getItemProperties(cmd));
+					if(cmd == "save"){
+						dojo.event.connect(btn, "onClick", this, "_save");
+					}else if(cmd == "cancel"){
+						dojo.event.connect(btn, "onClick", this, "_close");
+					} else {
+						dojo.event.connect(btn, "onClick", this, "_action");
+						dojo.event.connect(btn, "onChangeSelect", this, "_action");
+					}
+				}
+			}
+		}
+		return true;
+	},
+
+	enableToolbar: function() {
+		if(this._toolbarContainer) {
+			this._toolbarContainer.domNode.style.display = "";
+			this._toolbarContainer.enable();
+		}
+	},
+
+	disableToolbar: function(hide){
+		if(hide){
+			if(this._toolbarContainer){
+				this._toolbarContainer.domNode.style.display = "none";
+			}
+		}else{
+			if(this._toolbarContainer){
+				this._toolbarContainer.disable();
+			}
+		}
+	},
+
+	_updateToolbarLastRan: null,
+	_updateToolbarTimer: null,
+	_updateToolbarFrequency: 500,
+
+	updateToolbar: function(force) {
+		if(!this._toolbarContainer) { 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
+
+		var items = this._toolbarContainer.getItems();
+		for(var i = 0; i < items.length; i++) {
+			var item = items[i];
+			if(item instanceof dojo.widget.html.ToolbarSeparator) { continue; }
+			var cmd = item._name;
+			if (cmd == "save" || cmd == "cancel") { continue; }
+			else if(cmd == "justifyGroup") {
+				try {
+					if(!this._richText.queryCommandEnabled("justifyleft")) {
+						item.disable(false, true);
+					} else {
+						item.enable(false, true);
+						var jitems = item.getItems();
+						for(var j = 0; j < jitems.length; j++) {
+							var name = jitems[j]._name;
+							var value = this._richText.queryCommandValue(name);
+							if(typeof value == "boolean" && value) {
+								value = name;
+								break;
+							} else if(typeof value == "string") {
+								value = "justify"+value;
+							} else {
+								value = null;
+							}
+						}
+						if(!value) { value = "justifyleft"; } // TODO: query actual style
+						item.setValue(value, false, true);
+					}
+				} catch(err) {}
+			} else if(cmd == "listGroup") {
+				var litems = item.getItems();
+				for(var j = 0; j < litems.length; j++) {
+					this.updateItem(litems[j]);
+				}
+			} else {
+				this.updateItem(item);
+			}
+		}
+	},
+
+	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;
+		}
+	},
+
+	supportedCommands: dojo.widget.html.Editor.supportedCommands.concat(),
+
+	isSupportedCommand: function(cmd) {
+		// FIXME: how do we check for ActiveX?
+		var yes = dojo.lang.inArray(cmd, this.supportedCommands);
+		if(!yes) {
+			try {
+				var richText = this._richText || dojo.widget.HtmlRichText.prototype;
+				yes = richText.queryCommandAvailable(cmd);
+			} catch(E) {}
+		}
+		return yes;
+	},
+
+	getCommandImage: function(cmd) {
+		if(cmd == "|") {
+			return cmd;
+		} else {
+			return dojo.uri.dojoUri("src/widget/templates/buttons/" + cmd + ".gif");
+		}
+	},
+
+	_action: function(e) {
+		this._fire("onAction", e.getValue());
+	},
+
+	_setValue: function(a, b) {
+		this._fire("onAction", a.getValue(), b);
+	},
+
+	_save: function(e){
+		// FIXME: how should this behave when there's a larger form in play?
+		if(!this._richText.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._richText.close(e.getName().toLowerCase() == "save");
+			}
+		}
+	},
+
+	_close: function(e) {
+		if(!this._richText.isClosed) {
+			this._richText.close(e.getName().toLowerCase() == "save");
+		}
+	},
+
+	onAction: function(cmd, value) {
+		switch(cmd) {
+			case "createlink":
+				if(!(value = prompt("Please enter the URL of the link:", "http://"))) {
+					return;
+				}
+				break;
+			case "insertimage":
+				if(!(value = prompt("Please enter the URL of the image:", "http://"))) {
+					return;
+				}
+				break;
+		}
+		this._richText.execCommand(cmd, value);
+	},
+
+	fillInTemplate: function(args, frag) {
+		// dojo.event.connect(this, "onResized", this._richText, "onResized");
+	},
+
+	_fire: function(eventName) {
+		if(dojo.lang.isFunction(this[eventName])) {
+			var args = [];
+			if(arguments.length == 1) {
+				args.push(this);
+			} else {
+				for(var i = 1; i < arguments.length; i++) {
+					args.push(arguments[i]);
+				}
+			}
+			this[eventName].apply(this, args);
+		}
+	},
+
+	getHtml: function(){
+		this._richText.contentFilters = this._richText.contentFilters.concat(this.contentFilters);
+		return this._richText.getEditorContent();
+	},
+
+	getEditorContent: function(){
+		return this.getHtml();
+	},
+
+	onClose: function(save, hide){
+		this.disableToolbar(hide);
+		if(save) {
+			this._fire("onSave");
+		} else {
+			this._fire("onCancel");
+		}
+	},
+
+	// events baby!
+	onLoad: function(){},
+	onSave: function(){},
+	onCancel: function(){}
+});
+

Propchange: incubator/xap/trunk/src/dojo/src/widget/Editor.js
------------------------------------------------------------------------------
    svn:eol-style = native

Added: incubator/xap/trunk/src/dojo/src/widget/Editor2.js
URL: http://svn.apache.org/viewvc/incubator/xap/trunk/src/dojo/src/widget/Editor2.js?rev=417618&view=auto
==============================================================================
--- incubator/xap/trunk/src/dojo/src/widget/Editor2.js (added)
+++ incubator/xap/trunk/src/dojo/src/widget/Editor2.js Tue Jun 27 15:48:54 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);
+		}
+	}
+);

Propchange: incubator/xap/trunk/src/dojo/src/widget/Editor2.js
------------------------------------------------------------------------------
    svn:eol-style = native

Added: incubator/xap/trunk/src/dojo/src/widget/Editor2Toolbar.js
URL: http://svn.apache.org/viewvc/incubator/xap/trunk/src/dojo/src/widget/Editor2Toolbar.js?rev=417618&view=auto
==============================================================================
--- incubator/xap/trunk/src/dojo/src/widget/Editor2Toolbar.js (added)
+++ incubator/xap/trunk/src/dojo/src/widget/Editor2Toolbar.js Tue Jun 27 15:48:54 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;
+			}
+		}));
+	}
+);

Propchange: incubator/xap/trunk/src/dojo/src/widget/Editor2Toolbar.js
------------------------------------------------------------------------------
    svn:eol-style = native