incubator-xap-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From mtu...@apache.org
Subject svn commit: r518313 [28/43] - in /incubator/xap/trunk/codebase/src/dojo: ./ src/ src/animation/ src/cal/ src/charting/ src/charting/svg/ src/charting/vml/ src/collections/ src/crypto/ src/data/ src/data/core/ src/data/old/ src/data/old/format/ src/data...
Date Wed, 14 Mar 2007 20:37:27 GMT
Added: incubator/xap/trunk/codebase/src/dojo/src/widget/Dialog.js
URL: http://svn.apache.org/viewvc/incubator/xap/trunk/codebase/src/dojo/src/widget/Dialog.js?view=auto&rev=518313
==============================================================================
--- incubator/xap/trunk/codebase/src/dojo/src/widget/Dialog.js (added)
+++ incubator/xap/trunk/codebase/src/dojo/src/widget/Dialog.js Wed Mar 14 13:36:44 2007
@@ -0,0 +1,443 @@
+/*
+	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.require("dojo.widget.*");
+dojo.require("dojo.widget.ContentPane");
+dojo.require("dojo.event.*");
+dojo.require("dojo.gfx.color");
+dojo.require("dojo.html.layout");
+dojo.require("dojo.html.display");
+dojo.require("dojo.html.iframe");
+
+dojo.declare(
+	"dojo.widget.ModalDialogBase", 
+	null,
+	{
+		// summary
+		//	Mixin for widgets implementing a modal dialog
+
+		isContainer: true,
+
+		// focusElement: String
+		//	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: "",
+
+		// bgColor: String
+		//	color of viewport when displaying a dialog
+		bgColor: "black",
+		
+		// bgOpacity: Number
+		//	opacity (0~1) of viewport color (see bgColor attribute)
+		bgOpacity: 0.4,
+
+		// followScroll: Boolean
+		//	if true, readjusts the dialog (and dialog background) when the user moves the scrollbar
+		followScroll: true,
+
+		// closeOnBackgroundClick: Boolean
+		//	clicking anywhere on the background will close the dialog
+		closeOnBackgroundClick: false,
+
+		trapTabs: function(/*Event*/ e){
+			// summary
+			//	callback on focus
+			if(e.target == this.tabStartOuter) {
+				if(this._fromTrap) {
+					this.tabStart.focus();
+					this._fromTrap = false;
+				} else {
+					this._fromTrap = true;
+					this.tabEnd.focus();
+				}
+			} else if (e.target == this.tabStart) {
+				if(this._fromTrap) {
+					this._fromTrap = false;
+				} else {
+					this._fromTrap = true;
+					this.tabEnd.focus();
+				}
+			} else if(e.target == this.tabEndOuter) {
+				if(this._fromTrap) {
+					this.tabEnd.focus();
+					this._fromTrap = false;
+				} else {
+					this._fromTrap = true;
+					this.tabStart.focus();
+				}
+			} else if(e.target == this.tabEnd) {
+				if(this._fromTrap) {
+					this._fromTrap = false;
+				} else {
+					this._fromTrap = true;
+					this.tabStart.focus();
+				}
+			}
+		},
+
+		clearTrap: function(/*Event*/ e) {
+			// summary
+			//	callback on blur
+			var _this = this;
+			setTimeout(function() {
+				_this._fromTrap = false;
+			}, 100);
+		},
+
+		postCreate: function() {
+			// summary
+			//	if the target mixin class already defined postCreate,
+			//	dojo.widget.ModalDialogBase.prototype.postCreate.call(this)
+			//	should be called in its postCreate()
+			with(this.domNode.style){
+				position = "absolute";
+				zIndex = 999;
+				display = "none";
+				overflow = "visible";
+			}
+			var b = dojo.body();
+			b.appendChild(this.domNode);
+
+			// make background (which sits behind the dialog but above the normal text)
+			this.bg = document.createElement("div");
+			this.bg.className = "dialogUnderlay";
+			with(this.bg.style){
+				position = "absolute";
+				left = top = "0px";
+				zIndex = 998;
+				display = "none";
+			}
+			b.appendChild(this.bg);
+			this.setBackgroundColor(this.bgColor);
+
+			this.bgIframe = new dojo.html.BackgroundIframe();
+            if(this.bgIframe.iframe){
+				with(this.bgIframe.iframe.style){
+					position = "absolute";
+					left = top = "0px";
+					zIndex = 90;
+					display = "none";
+				}
+			}
+
+			if(this.closeOnBackgroundClick){
+				dojo.event.kwConnect({srcObj: this.bg, srcFunc: "onclick",
+					adviceObj: this, adviceFunc: "onBackgroundClick", once: true});
+			}
+		},
+
+		uninitialize: function(){
+			this.bgIframe.remove();
+			dojo.html.removeNode(this.bg, true);
+		},
+
+		setBackgroundColor: function(/*String*/ color) {
+			// summary
+			//	changes background color specified by "bgColor" parameter
+			//	usage:
+			//		setBackgroundColor("black");
+			//		setBackgroundColor(0xff, 0xff, 0xff);
+			if(arguments.length >= 3) {
+				color = new dojo.gfx.color.Color(arguments[0], arguments[1], arguments[2]);
+			} else {
+				color = new dojo.gfx.color.Color(color);
+			}
+			this.bg.style.backgroundColor = color.toString();
+			return this.bgColor = color;	// String: the color
+		},
+
+		setBackgroundOpacity: function(/*Number*/ op) {
+			// summary
+			//	changes background opacity set by "bgOpacity" parameter
+			if(arguments.length == 0) { op = this.bgOpacity; }
+			dojo.html.setOpacity(this.bg, op);
+			try {
+				this.bgOpacity = dojo.html.getOpacity(this.bg);
+			} catch (e) {
+				this.bgOpacity = op;
+			}
+			return this.bgOpacity;	// Number: the opacity
+		},
+
+		_sizeBackground: function() {
+			if(this.bgOpacity > 0) {
+				
+				var viewport = dojo.html.getViewport();
+				var h = viewport.height;
+				var w = viewport.width;
+				with(this.bg.style){
+					width = w + "px";
+					height = h + "px";
+				}
+				var scroll_offset = dojo.html.getScroll().offset;
+				this.bg.style.top = scroll_offset.y + "px";
+				this.bg.style.left = scroll_offset.x + "px";
+				// process twice since the scroll bar may have been removed
+				// by the previous resizing
+				var viewport = dojo.html.getViewport();
+				if (viewport.width != w) { this.bg.style.width = viewport.width + "px"; }
+				if (viewport.height != h) { this.bg.style.height = viewport.height + "px"; }
+			}
+			this.bgIframe.size(this.bg);
+		},
+
+		_showBackground: function() {
+			if(this.bgOpacity > 0) {
+				this.bg.style.display = "block";
+			}
+			if(this.bgIframe.iframe){
+				this.bgIframe.iframe.style.display = "block";
+			}
+		},
+
+		placeModalDialog: function() {
+			// summary: position modal dialog in center of screen
+
+			var scroll_offset = dojo.html.getScroll().offset;
+			var viewport_size = dojo.html.getViewport();
+			
+			// find the size of the dialog (dialog needs to be showing to get the size)
+			var mb;
+			if(this.isShowing()){
+				mb = dojo.html.getMarginBox(this.domNode);
+			}else{
+				dojo.html.setVisibility(this.domNode, false);
+				dojo.html.show(this.domNode);
+				mb = dojo.html.getMarginBox(this.domNode);
+				dojo.html.hide(this.domNode);
+				dojo.html.setVisibility(this.domNode, true);
+			}
+			
+			var x = scroll_offset.x + (viewport_size.width - mb.width)/2;
+			var y = scroll_offset.y + (viewport_size.height - mb.height)/2;
+			with(this.domNode.style){
+				left = x + "px";
+				top = y + "px";
+			}
+		},
+
+		_onKey: function(/*Event*/ evt){
+			if (evt.key){
+				// see if the key is for the dialog
+				var node = evt.target;
+				while (node != null){
+					if (node == this.domNode){
+						return; // yes, so just let it go
+					}
+					node = node.parentNode;
+				}
+				// this key is for the disabled document window
+				if (evt.key != evt.KEY_TAB){ // allow tabbing into the dialog for a11y
+					dojo.event.browser.stopEvent(evt);
+				// opera won't tab to a div
+				}else if (!dojo.render.html.opera){
+					try {
+						this.tabStart.focus(); 
+					} catch(e){}
+				}
+			}
+		},
+
+		showModalDialog: function() {
+			// summary
+			//	call this function in show() of subclass before calling superclass.show()
+			if (this.followScroll && !this._scrollConnected){
+				this._scrollConnected = true;
+				dojo.event.connect(window, "onscroll", this, "_onScroll");
+			}
+			dojo.event.connect(document.documentElement, "onkey", this, "_onKey");
+
+			this.placeModalDialog();
+			this.setBackgroundOpacity();
+			this._sizeBackground();
+			this._showBackground();
+			this._fromTrap = true; 
+
+			// set timeout to allow the browser to render dialog 
+			setTimeout(dojo.lang.hitch(this, function(){
+				try{
+					this.tabStart.focus();
+				}catch(e){}
+			}), 50);
+
+		},
+
+		hideModalDialog: function(){
+			// summary
+			//	call this function in hide() of subclass
+
+			// workaround for FF focus going into outer space
+			if (this.focusElement) {
+				dojo.byId(this.focusElement).focus(); 
+				dojo.byId(this.focusElement).blur();
+			}
+
+			this.bg.style.display = "none";
+			this.bg.style.width = this.bg.style.height = "1px";
+            if(this.bgIframe.iframe){
+				this.bgIframe.iframe.style.display = "none";
+			}
+
+			dojo.event.disconnect(document.documentElement, "onkey", this, "_onKey");
+			if (this._scrollConnected){
+				this._scrollConnected = false;
+				dojo.event.disconnect(window, "onscroll", this, "_onScroll");
+			}
+		},
+
+		_onScroll: function(){
+			var scroll_offset = dojo.html.getScroll().offset;
+			this.bg.style.top = scroll_offset.y + "px";
+			this.bg.style.left = scroll_offset.x + "px";
+			this.placeModalDialog();
+		},
+
+		checkSize: function() {
+			if(this.isShowing()){
+				this._sizeBackground();
+				this.placeModalDialog();
+				this.onResized();
+			}
+		},
+		
+		onBackgroundClick: function(){
+			// summary
+			//		Callback on background click.
+			//		Clicking anywhere on the background will close the dialog, but only
+			//		if the dialog doesn't have an explicit close button, and only if
+			//		the dialog doesn't have a blockDuration.
+			if(this.lifetime - this.timeRemaining >= this.blockDuration){ return; }
+			this.hide();
+		}
+	});
+
+dojo.widget.defineWidget(
+	"dojo.widget.Dialog",
+	[dojo.widget.ContentPane, dojo.widget.ModalDialogBase],
+	{
+		// summary
+		//	Pops up a modal dialog window, blocking access to the screen and also graying out the screen
+		//	Dialog is extended from ContentPane so it supports all the same parameters (href, etc.)
+
+		templatePath: dojo.uri.dojoUri("src/widget/templates/Dialog.html"),
+
+		// blockDuration: Integer
+		//	number of seconds for which the user cannot dismiss the dialog
+		blockDuration: 0,
+		
+		// lifetime: Integer
+		//	if set, this controls the number of seconds the dialog will be displayed before automatically disappearing
+		lifetime: 0,
+
+		// closeNode: String
+		//	Id of button or other dom node to click to close this dialog
+		closeNode: "",
+
+		postMixInProperties: function(){
+			dojo.widget.Dialog.superclass.postMixInProperties.apply(this, arguments);
+			if(this.closeNode){
+				this.setCloseControl(this.closeNode);
+			}
+		},
+
+		postCreate: function(){
+			dojo.widget.Dialog.superclass.postCreate.apply(this, arguments);
+			dojo.widget.ModalDialogBase.prototype.postCreate.apply(this, arguments);
+		},
+
+		show: function() {
+			if(this.lifetime){
+				this.timeRemaining = this.lifetime;
+				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";
+					}
+				}
+				if (this.timer) {
+					clearInterval(this.timer);
+				}
+				this.timer = setInterval(dojo.lang.hitch(this, "_onTick"), 100);
+			}
+
+			this.showModalDialog();
+			dojo.widget.Dialog.superclass.show.call(this);
+		},
+
+		onLoad: function(){
+			// when href is specified we need to reposition
+			// the dialog after the data is loaded
+			this.placeModalDialog();
+			dojo.widget.Dialog.superclass.onLoad.call(this);
+		},
+		
+		fillInTemplate: function(){
+			// dojo.event.connect(this.domNode, "onclick", this, "killEvent");
+		},
+
+		hide: function(){
+			this.hideModalDialog();
+			dojo.widget.Dialog.superclass.hide.call(this);
+
+			if(this.timer){
+				clearInterval(this.timer);
+			}
+		},
+		
+		setTimerNode: function(node){
+			// summary
+			//	specify into which node to write the remaining # of seconds
+			// TODO: make this a parameter too
+			this.timerNode = node;
+		},
+
+		setCloseControl: function(/*String|DomNode*/ node) {
+			// summary
+			//	Specify which node is the close button for this dialog.
+			//	If no close node is specified then clicking anywhere on the screen will close the dialog.
+			this.closeNode = dojo.byId(node);
+			dojo.event.connect(this.closeNode, "onclick", this, "hide");
+		},
+
+		setShowControl: function(/*String|DomNode*/ node) {
+			// summary
+			//	when specified node is clicked, show this dialog
+			// TODO: make this a parameter too
+			node = dojo.byId(node);
+			dojo.event.connect(node, "onclick", this, "show");
+		},
+
+		_onTick: function(){
+			// summary
+			//	callback every second that the timer clicks
+			if(this.timer){
+				this.timeRemaining -= 100;
+				if(this.lifetime - this.timeRemaining >= this.blockDuration){
+					// TODO: this block of code is executing over and over again, rather than just once
+					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);
+				}
+			}
+		}
+	}
+);

Added: incubator/xap/trunk/codebase/src/dojo/src/widget/DocPane.js
URL: http://svn.apache.org/viewvc/incubator/xap/trunk/codebase/src/dojo/src/widget/DocPane.js?view=auto&rev=518313
==============================================================================
--- incubator/xap/trunk/codebase/src/dojo/src/widget/DocPane.js (added)
+++ incubator/xap/trunk/codebase/src/dojo/src/widget/DocPane.js Wed Mar 14 13:36:44 2007
@@ -0,0 +1,386 @@
+/*
+	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.require("dojo.widget.*");
+dojo.require("dojo.io.*");
+dojo.require("dojo.event.*");
+dojo.require("dojo.widget.HtmlWidget");
+dojo.require("dojo.widget.Editor2");
+dojo.require("dojo.widget.Dialog");
+
+dojo.require("dojo.html.common");
+dojo.require("dojo.html.display");
+
+dojo.widget.DocPane = function(){
+	dojo.event.topic.subscribe("/docs/function/results", this, "onDocResults");
+	dojo.event.topic.subscribe("/docs/package/results", this, "onPkgResults");
+	dojo.event.topic.subscribe("/docs/function/detail", this, "onDocSelectFunction");
+}
+
+dojo.widget.defineWidget(
+	"dojo.widget.DocPane",
+	dojo.widget.HtmlWidget,
+	{
+		// summary
+		//		This widget is used by the API documentation system;
+		//		Users aren't expected to use this widget directly.
+
+		// Template parameters
+		dialog: null,
+		dialogBg: null,
+		dialogFg: null,
+		logIn: null,
+		edit: null,
+		save: null,
+		cancel: null,
+		detail: null,
+		result: null,
+		packag: null,
+		fn: null,
+		fnLink: null,
+		count: null,
+		row: null,
+		summary: null,
+		description: null,
+		variables: null,
+		vRow: null,
+		vLink: null,
+		vDesc: null,
+		methods: null,
+		mRow: null,
+		mLink: null,
+		mDesc: null,
+		requires: null,
+		rRow: null,
+		rRow2: null,
+		rH3: null,
+		rLink: null,
+		parameters: null,
+		pRow: null,
+		pLink: null,
+		pDesc: null,
+		pOpt: null,
+		pType: null,
+		sType: null,
+		sName: null,
+		sParams: null,
+		sPType: null,
+		sPTypeSave: null,
+		sPName: null,
+		sPNameSave: null,
+		pkgDescription: null,
+
+		// Fields and methods
+		_appends: [],
+		templatePath: dojo.uri.dojoUri("src/widget/templates/DocPane.html"),
+		templateCssPath: dojo.uri.dojoUri("src/widget/templates/DocPane.css"),
+		isContainer: true,
+		fillInTemplate: function(){
+			this.requires = dojo.html.removeNode(this.requires);
+			this.rRow.style.display = "none";
+			this.rRow2.style.display = "none";
+			
+			this.methods = dojo.html.removeNode(this.methods);
+			this.mRow.style.display = "none";
+			
+			this.dialog = dojo.widget.createWidget("dialog", {}, this.dialog);
+			this.dialog.setCloseControl(this.cancel);
+			dojo.html.setOpacity(this.dialogBg, 0.8);
+			dojo.html.setOpacity(this.dialogFg, 1);
+
+			dojo.event.connect(this.edit, "onclick", dojo.lang.hitch(this, function(){
+				if(!this._isLoggedIn){
+					this.dialog.show();
+				}
+			}));
+			dojo.event.connect(this.logIn, "onclick", this, "_logIn");
+			dojo.event.connect(this.save, "onclick", this, "_save");
+			dojo.event.connect(dojo.docs, "logInSuccess", this, "_loggedIn");
+			
+			/*
+			this.pkgDescription = dojo.widget.createWidget("editor2", {
+				toolbarAlwaysVisible: true
+			}, this.pkgDescription);
+			*/
+			
+			this.homeSave = this.containerNode.cloneNode(true);
+			this.detailSave = dojo.html.removeNode(this.detail);
+			this.resultSave = dojo.html.removeNode(this.result);
+			this.packageSave = dojo.html.removeNode(this.packag);
+			this.results = dojo.html.removeNode(this.results);
+			this.rowParent = this.row.parentNode;
+			this.rowSave = dojo.html.removeNode(this.row);
+			this.vParent = this.vRow.parentNode;
+			this.vSave = dojo.html.removeNode(this.vRow);
+			this.pParent = this.pRow.parentNode;
+			this.pSave = dojo.html.removeNode(this.pRow);
+			this.sPTypeSave = dojo.html.removeNode(this.sPType);
+			this.sPNameSave = dojo.html.removeNode(this.sPName);
+			this.navSave = dojo.html.removeNode(this.nav);
+		},
+
+		_logIn: function(){
+			dojo.docs.setUserName(this.userName.value);
+			dojo.docs.setPassword(this.password.value);
+		},
+
+		_loggedIn: function(){
+			this._isLoggedIn = true;
+			this.dialog.hide();
+			this.pkgEditor = dojo.widget.createWidget("editor2", {
+				toolbarAlwaysVisible: true
+			}, this.pkgDescription);
+		},
+
+		_save: function(){
+			if(this.pkgEditor){
+				dojo.docs.savePackage(this._pkgPath, {
+					description: this.pkgEditor.getEditorContent()
+				});
+			}
+		},
+
+		onDocSelectFunction: function(message){
+			dojo.debug("onDocSelectFunction()");
+			for(var key in message){
+				dojo.debug(key + ": " + dojo.json.serialize(message[key]));
+			}
+			var meta = message.meta;
+			if(meta){
+				var variables = meta.variables;
+				var this_variables = meta.this_variables;
+				var child_variables = meta.child_variables;
+				var parameters = meta.parameters;
+			}
+			var doc = message.doc;
+			dojo.debug(dojo.json.serialize(doc));
+
+			var appends = this._appends;
+			dojo.html.removeChildren(this.domNode);
+			this.fn.innerHTML = message.name;
+
+			this.variables.style.display = "block";
+			var all = [];
+			if(variables){
+				all = variables;
+			}
+			if(this_variables){
+				all = all.concat(this_variables);
+			}
+			if(child_variables){
+				all = all.concat(child_variables);
+			}
+			if(!all.length){
+				this.variables.style.display = "none";
+			}else{
+				for(var i = 0, one; one = all[i]; i++){
+					this.vLink.innerHTML = one;
+					this.vDesc.parentNode.style.display = "none";
+					appends.push(this.vParent.appendChild(this.vSave.cloneNode(true)));
+				}
+			}
+
+			this.sParams.innerHTML = "";
+			var first = true;
+			for(var param in parameters){
+				var paramType = parameters[param].type;
+				var paramSummary = parameters[param].summary;
+				var paramName = param;
+				this.parameters.style.display = "block";		
+				this.pLink.innerHTML = paramName;
+				this.pOpt.style.display = "none";
+				if(parameters[param].opt){
+					this.pOpt.style.display = "inline";				
+				}
+				this.pType.parentNode.style.display = "none";
+				if(parameters[param][0]){
+					this.pType.parentNode.style.display = "inline";
+					this.pType.innerHTML = paramType;
+				}
+				this.pDesc.parentNode.style.display = "none";
+				if(paramSummary){
+					this.pDesc.parentNode.style.display = "inline";
+					this.pDesc.innerHTML = paramSummary;
+				}
+				appends.push(this.pParent.appendChild(this.pSave.cloneNode(true)));
+
+				if(!first) {
+					this.sParams.appendChild(document.createTextNode(", "));
+				}
+				first = false;
+				if(paramType){
+					dojo.debug(this.sPTypeSave);
+					this.sPTypeSave.innerHTML = paramType;
+					this.sParams.appendChild(this.sPTypeSave.cloneNode(true));
+					this.sParams.appendChild(document.createTextNode(" "));
+				}
+				dojo.debug(this.sPNameSave);
+				this.sPNameSave.innerHTML = paramName;
+				this.sParams.appendChild(this.sPNameSave.cloneNode(true))
+			}
+
+			if(message.returns){
+				this.sType.innerHTML = message.returns;
+			}else{
+				this.sType.innerHTML = "void";
+			}
+
+			this.sName.innerHTML = message.name;
+
+			this.domNode.appendChild(this.navSave);
+			this.domNode.appendChild(this.detailSave.cloneNode(true));
+
+			for(var i = 0, append; append = appends[i]; i++){
+				dojo.html.removeNode(append);
+			}
+		},
+
+		onPkgResult: function(/*Object*/ results){
+			if(this.pkgEditor){
+				this.pkgEditor.close(true);
+				dojo.debug(this.pkgDescription);
+			}
+			var methods = results.methods;
+			var requires = results.requires;
+			var description = results.description;
+			this._pkgPath = results.path;
+			var requireLinks = [];
+			var appends = this._appends;
+			while(appends.length){
+				dojo.html.removeNode(appends.shift());
+			}
+
+			dojo.html.removeChildren(this.domNode);
+			
+			this.pkg.innerHTML = results.pkg;
+			
+			var hasRequires = false;
+			for(var env in requires){
+				hasRequires = true;
+
+				this.rH3.style.display = "none";
+				if(env != "common"){
+					this.rH3.style.display = "";
+					this.rH3.innerHTML = env;
+				}
+
+				for(var i = 0, require; require = requires[env][i]; i++){
+					requireLinks.push({
+						name: require
+					});
+					this.rLink.innerHTML = require;
+					this.rLink.href = "#" + require;
+					var rRow2 = this.rRow2.parentNode.insertBefore(this.rRow2.cloneNode(true), this.rRow2);
+					rRow2.style.display = "";
+					appends.push(rRow2);
+				}
+				var rRow = this.rRow.parentNode.insertBefore(this.rRow.cloneNode(true), this.rRow);
+				rRow.style.display = "";
+				appends.push(rRow);
+			}
+			
+			if(hasRequires){
+				appends.push(this.packageSave.appendChild(this.requires.cloneNode(true)));
+			}
+
+			if(results.size){
+				for(var i = 0, method; method = methods[i]; i++){
+					this.mLink.innerHTML = method.name;
+					this.mLink.href = "#" + method.name;
+					this.mDesc.parentNode.style.display = "none";
+					if(method.summary){
+						this.mDesc.parentNode.style.display = "inline";				
+						this.mDesc.innerHTML = method.summary;
+					}
+					var mRow = this.mRow.parentNode.insertBefore(this.mRow.cloneNode(true), this.mRow);
+					mRow.style.display = "";
+					appends.push(mRow);
+				}
+				appends.push(this.packageSave.appendChild(this.methods.cloneNode(true)));
+			}
+
+			this.domNode.appendChild(this.packageSave);
+			
+			/*
+			dojo.debug(description);
+			function fillContent(){
+				this.pkgDescription.replaceEditorContent(description);
+				this.pkgDescription._updateHeight();
+			}
+			if(this.pkgDescription.isLoaded){
+				fillContent();
+			}else{
+				dojo.event.connect(this.pkgDescription, "onLoad", dojo.lang.hitch(this, fillContent));
+			}
+			*/
+			this.pkgDescription.innerHTML = description;
+			
+			function makeSelect(fOrP, x){
+				return function(e) {
+					dojo.event.topic.publish("/docs/" + fOrP + "/select", x);
+				}
+			}
+
+			var as = this.domNode.getElementsByTagName("a");
+			for(var i = 0, a; a = as[i]; i++){
+				if(a.className == "docMLink"){
+					dojo.event.connect(a, "onclick", makeSelect("function", methods[i]));
+				}else if(a.className == "docRLink"){
+					dojo.event.connect(a, "onclick", makeSelect("package", requireLinks[i]));
+				}
+			}
+		},
+
+		onDocResults: function(fns){
+			dojo.debug("onDocResults(): called");
+
+			if(fns.length == 1){
+				dojo.event.topic.publish("/docs/function/select", fns[0]);
+				return;
+			}
+
+			dojo.html.removeChildren(this.domNode);
+
+			this.count.innerHTML = fns.length;
+			var appends = [];
+			for(var i = 0, fn; fn = fns[i]; i++){
+				this.fnLink.innerHTML = fn.name;
+				this.fnLink.href = "#" + fn.name;
+				if(fn.id){
+					this.fnLink.href = this.fnLink.href + "," + fn.id;	
+				}
+				this.summary.parentNode.style.display = "none";
+				if(fn.summary){
+					this.summary.parentNode.style.display = "inline";				
+					this.summary.innerHTML = fn.summary;
+				}
+				appends.push(this.rowParent.appendChild(this.rowSave.cloneNode(true)));
+			}
+
+			function makeSelect(x){
+				return function(e) {
+					dojo.event.topic.publish("/docs/function/select", x);
+				}
+			}
+
+			this.domNode.appendChild(this.resultSave.cloneNode(true));
+			var as = this.domNode.getElementsByTagName("a");
+			for(var i = 0, a; a = as[i]; i++){
+				dojo.event.connect(a, "onclick", makeSelect(fns[i]));
+			}
+
+			for(var i = 0, append; append = appends[i]; i++){
+				this.rowParent.removeChild(append);
+			}
+		}
+	}
+);

Added: incubator/xap/trunk/codebase/src/dojo/src/widget/DomWidget.js
URL: http://svn.apache.org/viewvc/incubator/xap/trunk/codebase/src/dojo/src/widget/DomWidget.js?view=auto&rev=518313
==============================================================================
--- incubator/xap/trunk/codebase/src/dojo/src/widget/DomWidget.js (added)
+++ incubator/xap/trunk/codebase/src/dojo/src/widget/DomWidget.js Wed Mar 14 13:36:44 2007
@@ -0,0 +1,902 @@
+/*
+	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.html.style");
+dojo.require("dojo.xml.Parse");
+dojo.require("dojo.uri.*");
+dojo.require("dojo.lang.func");
+dojo.require("dojo.lang.extras");
+
+dojo.widget._cssFiles = {};
+dojo.widget._cssStrings = {};
+dojo.widget._templateCache = {};
+
+dojo.widget.defaultStrings = {
+	// summary: a mapping of strings that are used in template variable replacement
+	dojoRoot: dojo.hostenv.getBaseScriptUri(),
+	baseScriptUri: dojo.hostenv.getBaseScriptUri()
+};
+
+dojo.widget.fillFromTemplateCache = function(obj, templatePath, templateString, avoidCache){
+	// summary:
+	//		static method to build from a template w/ or w/o a real widget in
+	//		place
+	// obj: DomWidget
+	//		an instance of dojo.widget.DomWidget to initialize the template for
+	// templatePath: String
+	//		the URL to get the template from. dojo.uri.Uri is often passed as well.
+	// templateString: String?
+	//		a string to use in lieu of fetching the template from a URL
+	// avoidCache: Boolean?
+	//		should the template system not use whatever is in the cache and
+	//		always use the passed templatePath or templateString?
+
+	// dojo.debug("avoidCache:", avoidCache);
+	var tpath = templatePath || obj.templatePath;
+
+	var tmplts = dojo.widget._templateCache;
+	if(!tpath && !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 = tpath?tpath.toString():obj.widgetType;
+
+	var ts = tmplts[wt];
+	if(!ts){
+		tmplts[wt] = {"string": null, "node": null};
+		if(avoidCache){
+			ts = {};
+		}else{
+			ts = tmplts[wt];
+		}
+	}
+	if((!obj.templateString)&&(!avoidCache)){
+		obj.templateString = templateString || ts["string"];
+	}
+	if((!obj.templateNode)&&(!avoidCache)){
+		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){
+			// strip <?xml ...?> declarations so that external SVG and XML
+			// documents can be added to a document without worry
+			tstring = tstring.replace(/^\s*<\?xml(\s)+version=[\'\"](\d)*.(\d)*[\'\"](\s)*\?>/im, "");
+			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;
+
+// Array: list of properties to search for node-to-property mappings
+dojo.widget.attachProperties = ["dojoAttachPoint", "id"];
+
+// String: name of the property to use for mapping DOM events to widget functions
+dojo.widget.eventAttachProperty = "dojoAttachEvent";
+
+// String: property name of code to evaluate when the widget is constructed
+dojo.widget.onBuildProperty = "dojoOnBuild";
+
+// Array:  possible accessibility values to set on widget elements - role or state
+dojo.widget.waiNames  = ["waiRole", "waiState"];
+
+dojo.widget.wai = {
+	// summary: Contains functions to set accessibility roles and states
+	//		onto widget elements
+	waiRole: { 	
+				// name: String:
+				//		information for mapping accessibility role
+				name: "waiRole", 
+				// namespace: String:
+				//		URI of the namespace for the set of roles
+				"namespace": "http://www.w3.org/TR/xhtml2", 
+				// alias: String:
+				//		The alias to assign the namespace
+				alias: "x2",
+				// prefix: String:
+				//		The prefix to assign to the role value
+				prefix: "wairole:"
+	},
+	waiState: { 
+				// name: String:
+				//		information for mapping accessibility state
+				name: "waiState", 
+				// namespace: String:
+				//		URI of the namespace for the set of states
+				"namespace": "http://www.w3.org/2005/07/aaa", 
+				// alias: String:
+				//		The alias to assign the namespace
+				alias: "aaa",
+				// prefix: String:
+				//		empty string - state value does not require prefix
+				prefix: ""
+	},
+	setAttr: function(/*DomNode*/node, /*String*/ ns, /*String*/ attr, /*String|Boolean*/value){
+		// summary: Use appropriate API to set the role or state attribute onto the element.
+		// description: In IE use the generic setAttribute() api.  Append a namespace
+		//   alias to the attribute name and appropriate prefix to the value. 
+		//   Otherwise, use the setAttribueNS api to set the namespaced attribute. Also
+		//   add the appropriate prefix to the attribute value.
+		if(dojo.render.html.ie){
+			node.setAttribute(this[ns].alias+":"+ attr, this[ns].prefix+value);
+		}else{
+			node.setAttributeNS(this[ns]["namespace"], attr, this[ns].prefix+value);
+		}
+	},
+
+	getAttr: function(/*DomNode*/ node, /*String*/ ns, /*String|Boolena*/ attr){
+		// Summary:  Use the appropriate API to retrieve the role or state value
+		// Description: In IE use the generic getAttribute() api.  An alias value 
+		// 	was added to the attribute name to simulate a namespace when the attribute
+		//  was set.  Otherwise use the getAttributeNS() api to retrieve the state value
+		if(dojo.render.html.ie){
+			return node.getAttribute(this[ns].alias+":"+attr);
+		}else{
+			return node.getAttributeNS(this[ns]["namespace"], attr);
+		}
+	},
+	removeAttr: function(/*DomNode*/ node, /*String*/ ns, /*String|Boolena*/ attr){
+		// summary:  Use the appropriate API to remove the role or state value
+		// description: In IE use the generic removeAttribute() api.  An alias value 
+		// 	was added to the attribute name to simulate a namespace when the attribute
+		//  was set.  Otherwise use the removeAttributeNS() api to remove the state value
+		var success = true; //only IE returns a value
+		if(dojo.render.html.ie){
+			 success = node.removeAttribute(this[ns].alias+":"+attr);
+		}else{
+			node.removeAttributeNS(this[ns]["namespace"], attr);
+		}
+		return success;
+	}
+};
+
+dojo.widget.attachTemplateNodes = function(rootNode, /*Widget*/ targetObj, events ){
+	// summary:
+	//		map widget properties and functions to the handlers specified in
+	//		the dom node and it's descendants. This function iterates over all
+	//		nodes and looks for these properties:
+	//			* dojoAttachPoint
+	//			* dojoAttachEvent	
+	//			* waiRole
+	//			* waiState
+	//			* any "dojoOn*" proprties passed in the events array
+	// rootNode: DomNode
+	//		the node to search for properties. All children will be searched.
+	// events: Array
+	//		a list of properties generated from getDojoEventsFromStr.
+
+	// 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 = [];
+		if(!targetObj.widgetsInTemplate || !baseNode.getAttribute('dojoType')){
+			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;
+				}
+			}
+
+			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]));
+					}
+				}
+			}
+		}
+		// 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;
+		}
+
+		dojo.lang.forEach(dojo.widget.waiNames, function(name){
+			var wai = dojo.widget.wai[name];
+			var val = baseNode.getAttribute(wai.name);
+			if(val){
+				if(val.indexOf('-') == -1){ 
+					dojo.widget.wai.setAttr(baseNode, wai.name, "role", val);
+				}else{
+					// this is a state-value pair
+					var statePair = val.split('-');
+					dojo.widget.wai.setAttr(baseNode, wai.name, statePair[0], statePair[1]);
+				}
+			}
+		}, this);
+
+		var onBuild = baseNode.getAttribute(this.onBuildProperty);
+		if(onBuild){
+			eval("var node = baseNode; var widget = targetObj; "+onBuild);
+		}
+	}
+
+}
+
+dojo.widget.getDojoEventsFromStr = function(str){
+	// summary:
+	//		generates a list of properties with names that match the form
+	//		dojoOn*
+	// str: String
+	//		the template string to search
+	
+	// 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].length < 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; // Array
+}
+
+dojo.declare("dojo.widget.DomWidget", 
+	dojo.widget.Widget,
+	function(){
+		// summary:
+		//		dojo.widget.DomWidget is the superclass that provides behavior for all
+		//		DOM-based renderers, including HtmlWidget and SvgWidget. DomWidget
+		//		implements the templating system that most widget authors use to define
+		//		the UI for their widgets.
+		if((arguments.length>0)&&(typeof arguments[0] == "object")){
+			this.create(arguments[0]);
+		}
+	},
+	{							 
+		// templateNode: DomNode
+		//		a node that represents the widget template. Pre-empts both templateString and templatePath.
+		templateNode: null,
+
+		// templateString String:
+		//		a string that represents the widget template. Pre-empts the
+		//		templatePath. In builds that have their strings "interned", the
+		//		templatePath is converted to an inline templateString, thereby
+		//		preventing a synchronous network call.
+		templateString: null,
+
+		// templateCssString String:
+		//		a string that represents the CSS for the widgettemplate.
+		//		Pre-empts the templateCssPath. In builds that have their
+		//		strings "interned", the templateCssPath is converted to an
+		//		inline templateCssString, thereby preventing a synchronous
+		//		network call.
+		templateCssString: null,
+
+		// preventClobber Boolean:
+		//		should the widget not replace the node from which it was
+		//		constructed? Widgets that apply behaviors to pre-existing parts
+		//		of a page can be implemented easily by setting this to "true".
+		//		In these cases, the domNode property will point to the node
+		//		which the widget was created from.
+		preventClobber: false,
+
+		// domNode DomNode:
+		//		this is our visible representation of the widget! Other DOM
+		//		Nodes may by assigned to other properties, usually through the
+		//		template system's dojoAttachPonit syntax, but the domNode
+		//		property is the canonical "top level" node in widget UI.
+		domNode: null, 
+
+		// containerNode DomNode:
+		//		holds child elements. "containerNode" is generally set via a
+		//		dojoAttachPoint assignment and it designates where widgets that
+		//		are defined as "children" of the parent will be placed
+		//		visually.
+		containerNode: null,
+
+		// widgetsInTemplate Boolean:
+		//		should we parse the template to find widgets that might be
+		//		declared in markup inside it? false by default.
+		widgetsInTemplate: false,
+
+		addChild: function(/*Widget*/	widget, overrideContainerNode, pos, ref, insertIndex){
+			// summary:
+			//		Process the given child widget, inserting it's dom node as
+			//		a child of our dom node
+			// overrideContainerNode: DomNode?
+			//		a non-default container node for the widget
+			// pos: String?
+			//		can be one of "before", "after", "first", or "last". This
+			//		has the same meaning as in dojo.dom.insertAtPosition()
+			// ref: DomNode?
+			//		a node to place the widget relative to
+			// insertIndex: int?
+			//		DOM index, same meaning as in dojo.dom.insertAtIndex()
+			// returns: the widget that was inserted
+
+			// FIXME: should we support addition at an index in the children arr and
+			// order the display accordingly? Right now we always append.
+			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{
+				if(insertIndex == undefined){
+					insertIndex = this.children.length;
+				}
+				this.addWidgetAsDirectChild(widget, overrideContainerNode, pos, ref, insertIndex);
+				this.registerChild(widget, insertIndex);
+			}
+			return widget; // Widget
+		},
+		
+		addWidgetAsDirectChild: function(/*Widget*/	widget, overrideContainerNode, pos, ref, insertIndex){
+			// summary:
+			//		Process the given child widget, inserting it's dom node as
+			//		a child of our dom node
+			// overrideContainerNode: DomNode
+			//		a non-default container node for the widget
+			// pos: String?
+			//		can be one of "before", "after", "first", or "last". This
+			//		has the same meaning as in dojo.dom.insertAtPosition()
+			// ref: DomNode?
+			//		a node to place the widget relative to
+			// insertIndex: int?
+			//		DOM index, same meaning as in dojo.dom.insertAtIndex()
+			if((!this.containerNode)&&(!overrideContainerNode)){
+				this.containerNode = this.domNode;
+			}
+			var cn = (overrideContainerNode) ? overrideContainerNode : this.containerNode;
+			if(!pos){ pos = "after"; }
+			if(!ref){ 
+				if(!cn){ cn = dojo.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);
+					}
+				}
+			}
+		},
+
+		registerChild: function(widget, insertionIndex){
+			// summary: record that given widget descends from me
+			// widget: Widget
+			//		the widget that is now a child
+			// insertionIndex: int
+			//		where in the children[] array to place it
+
+			// 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++){
+
+				//This appears to fix an out of order issue in the case of mixed
+				//markup and programmatically added children.  Previously, if a child
+				//existed from markup, and another child was addChild()d without specifying
+				//any additional parameters, it would end up first in the list, when in fact
+				//it should be after.  I can't see cases where this would break things, but
+				//I could see no other obvious solution. -dustin
+
+				if (this.children[i].dojoInsertionIndex <= insertionIndex){
+					idx = i;
+				}
+			}
+
+			this.children.splice(idx+1, 0, widget);
+
+			widget.parent = this;
+			widget.addedTo(this, idx+1);
+			
+			// 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*/ widget){
+			// summary: 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); // Widget
+		},
+
+		getFragNodeRef: function(frag){
+			// summary:
+			//		returns the source node, if any, that the widget was
+			//		declared from
+			// frag: Object
+			//		an opaque data structure generated by the first-pass parser
+			if(!frag){return null;} // null
+			if(!frag[this.getNamespacedType()]){
+				dojo.raise("Error: no frag for widget type " + this.getNamespacedType() 
+					+ ", id " + this.widgetId
+					+ " (maybe a widget has set it's type incorrectly)");
+			}
+			return frag[this.getNamespacedType()]["nodeRef"]; // DomNode
+		},
+		
+		postInitialize: function(/*Object*/ args, /*Object*/ frag, /*Widget*/ parentComp){
+			// summary:
+			//		Replace the source domNode with the generated dom
+			//		structure, and register the widget with its parent.
+			//		This is an implementation of the stub function defined in
+			//		dojo.widget.Widget.
+			
+			//dojo.profile.start(this.widgetType + " postInitialize");
+			
+			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)){
+					this._sourceNodeRef = dojo.dom.replaceNode(sourceNodeRef, this.domNode);
+				}
+			}
+
+			// 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;
+			}
+
+			if(this.widgetsInTemplate){
+				var parser = new dojo.xml.Parse();
+
+				var subContainerNode;
+				//TODO: use xpath here?
+				var subnodes = this.domNode.getElementsByTagName("*");
+				for(var i=0;i<subnodes.length;i++){
+					if(subnodes[i].getAttribute('dojoAttachPoint') == 'subContainerWidget'){
+						subContainerNode = subnodes[i];
+//						break;
+					}
+					if(subnodes[i].getAttribute('dojoType')){
+						subnodes[i].setAttribute('isSubWidget', true);
+					}
+				}
+				if (this.isContainer && !this.containerNode){
+					//no containerNode is available, which means a widget is used as a container. find it here and move
+					//all dom nodes defined in the main html page as children of this.domNode into the actual container
+					//widget's node (at this point, the subwidgets defined in the template file is not parsed yet)
+					if(subContainerNode){
+						var src = this.getFragNodeRef(frag);
+						if (src){
+							dojo.dom.moveChildren(src, subContainerNode);
+							//do not need to follow children nodes in the main html page, as they
+							//will be dealt with in the subContainerWidget
+							frag['dojoDontFollow'] = true;
+						}
+					}else{
+						dojo.debug("No subContainerWidget node can be found in template file for widget "+this);
+					}
+				}
+
+				var templatefrag = parser.parseElement(this.domNode, null, true);
+				// createSubComponents not createComponents because frag has already been created
+				dojo.widget.getParser().createSubComponents(templatefrag, this);
+	
+				//find all the sub widgets defined in the template file of this widget
+				var subwidgets = [];
+				var stack = [this];
+				var w;
+				while((w = stack.pop())){
+					for(var i = 0; i < w.children.length; i++){
+						var cwidget = w.children[i];
+						if(cwidget._processedSubWidgets || !cwidget.extraArgs['issubwidget']){ continue; }
+						subwidgets.push(cwidget);
+						if(cwidget.isContainer){
+							stack.push(cwidget);
+						}
+					}
+				}
+	
+				//connect event to this widget/attach dom node
+				for(var i = 0; i < subwidgets.length; i++){
+					var widget = subwidgets[i];
+					if(widget._processedSubWidgets){
+						dojo.debug("This should not happen: widget._processedSubWidgets is already true!");
+						return;
+					}
+					widget._processedSubWidgets = true;
+					if(widget.extraArgs['dojoattachevent']){
+						var evts = widget.extraArgs['dojoattachevent'].split(";");
+						for(var j=0; j<evts.length; j++){
+							var thisFunc = null;
+							var tevt = dojo.string.trim(evts[j]);
+							if(tevt.indexOf(":") >= 0){
+								// oh, if only JS had tuple assignment
+								var funcNameArr = tevt.split(":");
+								tevt = dojo.string.trim(funcNameArr[0]);
+								thisFunc = dojo.string.trim(funcNameArr[1]);
+							}
+							if(!thisFunc){
+								thisFunc = tevt;
+							}
+							if(dojo.lang.isFunction(widget[tevt])){
+								dojo.event.kwConnect({
+									srcObj: widget, 
+									srcFunc: tevt, 
+									targetObj: this, 
+									targetFunc: thisFunc
+								});
+							}else{
+								alert(tevt+" is not a function in widget "+widget);
+							}
+						}
+					}
+	
+					if(widget.extraArgs['dojoattachpoint']){
+						//don't attach widget.domNode here, as we do not know which
+						//dom node we should connect to (in checkbox widget case, 
+						//it is inputNode). So we make the widget itself available
+						this[widget.extraArgs['dojoattachpoint']] = widget;
+					}
+				}
+			}
+
+			//dojo.profile.end(this.widgetType + " postInitialize");
+
+			// Expand my children widgets
+			/* dojoDontFollow is important for a very special case
+			 * basically if you have a widget that you instantiate from script
+			 * and that widget is a container, and it contains a reference to a parent
+			 * instance, the parser will start recursively parsing until the browser
+			 * complains.  So the solution is to set an initialization property of 
+			 * dojoDontFollow: true and then it won't recurse where it shouldn't
+			 */
+			if(this.isContainer && !frag["dojoDontFollow"]){
+				//alert("recurse from " + this.widgetId);
+				// build any sub-components with us as the parent
+				dojo.widget.getParser().createSubComponents(frag, this);
+			}
+		},
+
+		// method over-ride
+		buildRendering: function(/*Object*/ args, /*Object*/ frag){
+			// summary:
+			//		Construct the UI for this widget, generally from a
+			//		template. This can be over-ridden for custom UI creation to
+			//		to side-step the template system.  This is an
+			//		implementation of the stub function defined in
+			//		dojo.widget.Widget.
+
+			// DOM widgets construct themselves from a template
+			var ts = dojo.widget._templateCache[this.widgetType];
+			
+			// Handle style for this widget here, as even if templatePath
+			// is not set, style specified by templateCssString or templateCssPath
+			// should be applied. templateCssString has higher priority
+			// than templateCssPath
+			if(args["templatecsspath"]){
+				args["templateCssPath"] = args["templatecsspath"];
+			}
+			var cpath = args["templateCssPath"] || this.templateCssPath;
+			if(cpath && !dojo.widget._cssFiles[cpath.toString()]){
+				if((!this.templateCssString)&&(cpath)){
+					this.templateCssString = dojo.hostenv.getText(cpath);
+					this.templateCssPath = null;
+				}
+				dojo.widget._cssFiles[cpath.toString()] = true;
+			}
+		
+			if((this["templateCssString"])&&(!dojo.widget._cssStrings[this.templateCssString])){
+				dojo.html.insertCssText(this.templateCssString, null, cpath);
+				dojo.widget._cssStrings[this.templateCssString] = true;
+			}
+			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(/*Object*/ args, /*Object*/ frag){
+			// summary:
+			//		Called by buildRendering, creates the actual UI in a DomWidget.
+
+			// 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["templatepath"]){
+//				avoidCache = true;
+				args["templatePath"] = args["templatepath"];
+			}
+			dojo.widget.fillFromTemplateCache(	this, 
+												args["templatePath"], 
+												null,
+												avoidCache);
+			var ts = dojo.widget._templateCache[this.templatePath?this.templatePath.toString():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.") ? dojo.lang.getObjPathValue(key.substring(5), this) : hash[key];
+						var value;
+						if((kval)||(dojo.lang.isString(kval))){
+							value = new String((dojo.lang.isFunction(kval)) ? kval.call(this, key, this.templateString) : kval);
+							// Safer substitution, see heading "Attribute values" in  
+							// http://www.w3.org/TR/REC-html40/appendix/notes.html#h-B.3.2
+							while (value.indexOf("\"") > -1) {
+								value=value.replace("\"","&quot;");
+							}
+							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];
+					if(!avoidCache){
+						ts.node = this.templateNode;
+					}
+				}
+			}
+			if((!this.templateNode)&&(!matches)){ 
+				dojo.debug("DomWidget.buildFromTemplate: could not 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();
+			// 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){
+			// summary: 
+			//		hooks up event handlers and property/node linkages. Calls
+			//		dojo.widget.attachTemplateNodes to do all the hard work.
+			// baseNode: DomNode
+			//		defaults to "this.domNode"
+			// targetObj: Widget
+			//		defaults to "this"
+			if(!baseNode){ baseNode = this.domNode; }
+			if(!targetObj){ targetObj = this; }
+			return dojo.widget.attachTemplateNodes(baseNode, targetObj, 
+						dojo.widget.getDojoEventsFromStr(this.templateString));
+		},
+
+		fillInTemplate: function(){
+			// summary:
+			//		stub function! sub-classes may use as a default UI
+			//		initializer function. The UI rendering will be available by
+			//		the time this is called from buildRendering. If
+			//		buildRendering is over-ridden, this function may not be
+			//		fired!
+
+			// dojo.unimplemented("dojo.widget.DomWidget.fillInTemplate");
+		},
+		
+		// method over-ride
+		destroyRendering: function(){
+			// summary: UI destructor.  Destroy the dom nodes associated w/this widget.
+			try{
+				dojo.dom.destroyNode(this.domNode);
+				delete this.domNode;
+			}catch(e){ /* squelch! */ }
+			if(this._sourceNodeRef){
+				try{
+					dojo.dom.destroyNode(this._sourceNodeRef);
+				}catch(e){ /* squelch! */ }
+			}
+		},
+
+		createNodesFromText: function(){
+			// summary
+			//	Attempts to create a set of nodes based on the structure of the passed text.
+			//	Implemented in HtmlWidget and SvgWidget.
+			dojo.unimplemented("dojo.widget.DomWidget.createNodesFromText");
+		}
+	}
+);

Added: incubator/xap/trunk/codebase/src/dojo/src/widget/DropdownContainer.js
URL: http://svn.apache.org/viewvc/incubator/xap/trunk/codebase/src/dojo/src/widget/DropdownContainer.js?view=auto&rev=518313
==============================================================================
--- incubator/xap/trunk/codebase/src/dojo/src/widget/DropdownContainer.js (added)
+++ incubator/xap/trunk/codebase/src/dojo/src/widget/DropdownContainer.js Wed Mar 14 13:36:44 2007
@@ -0,0 +1,118 @@
+/*
+	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.widget.PopupContainer");
+dojo.require("dojo.event.*");
+dojo.require("dojo.html.layout");
+dojo.require("dojo.html.display");
+dojo.require("dojo.html.iframe");
+dojo.require("dojo.html.util");
+
+dojo.widget.defineWidget(
+	"dojo.widget.DropdownContainer",
+	dojo.widget.HtmlWidget,
+	{
+		// summary:
+		//		provides an input box and a button for a dropdown.
+		//		In subclass, the dropdown can be specified.
+
+		// inputWidth: String: width of the input box
+		inputWidth: "7em",
+
+		// id: String: id of this widget
+		id: "",
+
+		// inputId: String: id of the input box
+		inputId: "",
+
+		// inputName: String: name of the input box
+		inputName: "",
+
+		// iconURL: dojo.uri.Uri: icon for the dropdown button
+		iconURL: dojo.uri.dojoUri("src/widget/templates/images/combo_box_arrow.png"),
+
+		// copyClass:
+		//		should we use the class properties on the source node instead
+		//		of our own styles?
+		copyClasses: false,
+
+		// iconAlt: dojo.uri.Uri: alt text for the dropdown button icon
+		iconAlt: "",
+
+		// containerToggle: String: toggle property of the dropdown
+		containerToggle: "plain",
+
+		// containerToggleDuration: Integer: toggle duration property of the dropdown
+		containerToggleDuration: 150,
+
+		templateString: '<span style="white-space:nowrap"><input type="hidden" name="" value="" dojoAttachPoint="valueNode" /><input name="" type="text" value="" style="vertical-align:middle;" dojoAttachPoint="inputNode" autocomplete="off" /> <img src="${this.iconURL}" alt="${this.iconAlt}" dojoAttachEvent="onclick:onIconClick" dojoAttachPoint="buttonNode" style="vertical-align:middle; cursor:pointer; cursor:hand" /></span>',
+		templateCssPath: "",
+		isContainer: true,
+
+		attachTemplateNodes: function(){
+			// summary: use attachTemplateNodes to specify containerNode, as fillInTemplate is too late for this
+			dojo.widget.DropdownContainer.superclass.attachTemplateNodes.apply(this, arguments);
+			this.popup = dojo.widget.createWidget("PopupContainer", {toggle: this.containerToggle, toggleDuration: this.containerToggleDuration});
+			this.containerNode = this.popup.domNode;
+		},
+
+		fillInTemplate: function(args, frag){
+			this.domNode.appendChild(this.popup.domNode);
+			if(this.id) { this.domNode.id = this.id; }
+			if(this.inputId){ this.inputNode.id = this.inputId; }
+			if(this.inputName){ this.inputNode.name = this.inputName; }
+			this.inputNode.style.width = this.inputWidth;
+			this.inputNode.disabled = this.disabled;
+
+			if(this.copyClasses){
+				this.inputNode.style = "";
+				this.inputNode.className = this.getFragNodeRef(frag).className;
+			}
+
+
+			dojo.event.connect(this.inputNode, "onchange", this, "onInputChange");
+		},
+
+		onIconClick: function(/*Event*/ evt){
+			if(this.disabled) return;
+			if(!this.popup.isShowingNow){
+				this.popup.open(this.inputNode, this, this.buttonNode);
+			}else{
+				this.popup.close();
+			}
+		},
+
+		hideContainer: function(){
+			// summary: hide the dropdown
+			if(this.popup.isShowingNow){
+				this.popup.close();
+			}
+		},
+
+		onInputChange: function(){
+			// summary: signal for changes in the input box
+		},
+		
+		enable: function() {
+			// summary: enable this widget to accept user input
+			this.inputNode.disabled = false;
+			dojo.widget.DropdownContainer.superclass.enable.apply(this, arguments);
+		},
+		
+		disable: function() {
+			// summary: lock this widget so that the user can't change the value
+			this.inputNode.disabled = true;
+			dojo.widget.DropdownContainer.superclass.disable.apply(this, arguments);
+		}
+	}
+);

Added: incubator/xap/trunk/codebase/src/dojo/src/widget/DropdownDatePicker.js
URL: http://svn.apache.org/viewvc/incubator/xap/trunk/codebase/src/dojo/src/widget/DropdownDatePicker.js?view=auto&rev=518313
==============================================================================
--- incubator/xap/trunk/codebase/src/dojo/src/widget/DropdownDatePicker.js (added)
+++ incubator/xap/trunk/codebase/src/dojo/src/widget/DropdownDatePicker.js Wed Mar 14 13:36:44 2007
@@ -0,0 +1,239 @@
+/*
+	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.require("dojo.date.format");
+dojo.require("dojo.date.serialize");
+dojo.require("dojo.string.common");
+dojo.require("dojo.i18n.common");
+dojo.requireLocalization("dojo.widget", "DropdownDatePicker", null, "ROOT");
+
+
+dojo.widget.defineWidget(
+	"dojo.widget.DropdownDatePicker",
+	dojo.widget.DropdownContainer,
+	{
+		/*
+		summary: 
+			A form input for entering dates with a pop-up dojo.widget.DatePicker to aid in selection
+		
+			description: 
+				This is DatePicker in a DropdownContainer, it supports all features of DatePicker.
+		
+				The value displayed in the widget is localized according to the default algorithm provided
+				in dojo.date.format and dojo.date.parse.  It is possible to customize the user-visible formatting
+				with either the formatLength or displayFormat attributes.  The value sent to the server is
+				typically a locale-independent value in a hidden field as defined by the name attribute.
+				RFC3339 representation is used by default, but other options are available with saveFormat.
+		
+			usage: 
+				var ddp = dojo.widget.createWidget("DropdownDatePicker", {},   
+				dojo.byId("DropdownDatePickerNode")); 
+		 	 
+				<input dojoType="DropdownDatePicker">
+		*/
+
+		iconURL: dojo.uri.dojoUri("src/widget/templates/images/dateIcon.gif"),
+
+		// formatLength: String
+		// 	Type of formatting used for visual display, appropriate to locale (choice of long, short, medium or full)
+		//  See dojo.date.format for details.
+		formatLength: "short",
+
+		// displayFormat: String
+		//	A pattern used for the visual display of the formatted date, e.g. dd/MM/yyyy.
+		//	Setting this overrides the default locale-specific settings as well as the formatLength
+		//	attribute.  See dojo.date.format for a reference which defines the formatting patterns.
+		displayFormat: "",
+
+		dateFormat: "", // deprecated, will be removed for 0.5
+
+		// saveFormat: String
+		//	Formatting scheme used when submitting the form element.  This formatting is used in a hidden
+		//  field (name) intended for server use, and is therefore typically locale-independent.
+		//  By default, uses rfc3339 style date formatting (rfc)
+		//	Use a pattern string like displayFormat or one of the following:
+		//	rfc|iso|posix|unix
+		saveFormat: "",
+
+		// value: String|Date
+		//	form value property in rfc3339 format. If =='today', will use today's date
+		value: "",
+
+		// name: String
+		// 	name of the form element, used to create a hidden field by this name for form element submission.
+		name: "",
+
+		// Implement various attributes from DatePicker
+
+		// displayWeeks: Integer
+		//	number of weeks to display 
+		displayWeeks: 6,
+
+		// adjustWeeks: Boolean
+		//	if true, weekly size of calendar changes to accomodate the month if false, 42 day format is used
+		adjustWeeks: false,
+
+		// startDate: String|Date
+		//	first available date in the calendar set
+		startDate: "1492-10-12",
+
+		// endDate: String|Date
+		//	last available date in the calendar set
+		endDate: "2941-10-12",
+
+		// weekStartsOn: Integer
+		//	adjusts the first day of the week 0==Sunday..6==Saturday
+		weekStartsOn: "",
+
+		// staticDisplay: Boolean
+		//	disable all incremental controls, must pick a date in the current display
+		staticDisplay: false,
+		
+		postMixInProperties: function(localProperties, frag){
+			// summary: see dojo.widget.DomWidget
+
+			dojo.widget.DropdownDatePicker.superclass.postMixInProperties.apply(this, arguments);
+			var messages = dojo.i18n.getLocalization("dojo.widget", "DropdownDatePicker", this.lang);
+			this.iconAlt = messages.selectDate;
+
+			//FIXME: should this be if/else/else?
+			if(typeof(this.value)=='string'&&this.value.toLowerCase()=='today'){
+				this.value = new Date();
+			}
+			if(this.value && isNaN(this.value)){
+				var orig = this.value;
+				this.value = dojo.date.fromRfc3339(this.value);
+				if(!this.value){this.value = new Date(orig); dojo.deprecated("dojo.widget.DropdownDatePicker", "date attributes must be passed in Rfc3339 format", "0.5");}
+			}
+			if(this.value && !isNaN(this.value)){
+				this.value = new Date(this.value);
+			}
+		},
+
+		fillInTemplate: function(args, frag){
+			// summary: see dojo.widget.DomWidget
+			dojo.widget.DropdownDatePicker.superclass.fillInTemplate.call(this, args, frag);
+			//attributes to be passed on to DatePicker
+			var dpArgs = {widgetContainerId: this.widgetId, lang: this.lang, value: this.value,
+				startDate: this.startDate, endDate: this.endDate, displayWeeks: this.displayWeeks,
+				weekStartsOn: this.weekStartsOn, adjustWeeks: this.adjustWeeks, staticDisplay: this.staticDisplay};
+
+			//build the args for DatePicker based on the public attributes of DropdownDatePicker
+			this.datePicker = dojo.widget.createWidget("DatePicker", dpArgs, this.containerNode, "child");
+			dojo.event.connect(this.datePicker, "onValueChanged", this, "_updateText");
+			
+			if(this.value){
+				this._updateText();
+			}
+			this.containerNode.explodeClassName = "calendarBodyContainer";
+			this.valueNode.name=this.name;
+		},
+
+		getValue: function(){
+			// summary: return current date in RFC 3339 format
+			return this.valueNode.value; /*String*/
+		},
+
+		getDate: function(){
+			// summary: return current date as a Date object
+			return this.datePicker.value; /*Date*/
+		},
+
+		setValue: function(/*Date|String*/rfcDate){
+			//summary: set the current date from RFC 3339 formatted string or a date object, synonymous with setDate
+			this.setDate(rfcDate);
+		},
+
+		setDate: function(/*Date|String*/dateObj){
+			// summary: set the current date and update the UI
+			this.datePicker.setDate(dateObj);
+			this._syncValueNode();
+		},
+	
+		_updateText: function(){
+			// summary: updates the <input> field according to the current value (ie, displays the formatted date)
+			if(this.dateFormat){
+				dojo.deprecated("dojo.widget.DropdownDatePicker",
+				"Must use displayFormat attribute instead of dateFormat.  See dojo.date.format for specification.", "0.5");
+				this.inputNode.value = dojo.date.strftime(this.datePicker.value, this.dateFormat, this.lang);
+			}else if(this.datePicker.value){
+				this.inputNode.value = dojo.date.format(this.datePicker.value,
+					{formatLength:this.formatLength, datePattern:this.displayFormat, selector:'dateOnly', locale:this.lang});
+			}else{
+				this.inputNode.value = "";
+			}
+
+			if(this.value < this.datePicker.startDate||this.value>this.datePicker.endDate){
+				this.inputNode.value = "";
+			}
+			this._syncValueNode();
+			this.onValueChanged(this.getDate());
+			this.hideContainer();
+		},
+
+		onValueChanged: function(/*Date*/dateObj){
+			//summary: triggered when this.value is changed
+		},
+		
+		onInputChange: function(){
+			// summary: callback when user manually types a date into the <input> field
+			if(this.dateFormat){
+				dojo.deprecated("dojo.widget.DropdownDatePicker",
+				"Cannot parse user input.  Must use displayFormat attribute instead of dateFormat.  See dojo.date.format for specification.", "0.5");
+			}else{
+				var input = dojo.string.trim(this.inputNode.value);
+				if(input){
+					var inputDate = dojo.date.parse(input,
+							{formatLength:this.formatLength, datePattern:this.displayFormat, selector:'dateOnly', locale:this.lang});			
+					if(inputDate){
+						this.setDate(inputDate);
+					}
+				} else {
+					this.valueNode.value = input;
+				}
+			}
+			// If the date entered didn't parse, reset to the old date.  KISS, for now.
+			//TODO: usability?  should we provide more feedback somehow? an error notice?
+			// seems redundant to do this if the parse failed, but at least until we have validation,
+			// this will fix up the display of entries like 01/32/2006
+			if(input){ this._updateText(); }
+		},
+
+		_syncValueNode: function(){
+			var date = this.datePicker.value;
+				var value = "";
+			switch(this.saveFormat.toLowerCase()){
+				case "rfc": case "iso": case "":
+					value = dojo.date.toRfc3339(date, 'dateOnly');
+					break;
+				case "posix": case "unix":
+					value = Number(date);
+					break;
+				default:
+					if(date){
+						value = dojo.date.format(date, {datePattern:this.saveFormat, selector:'dateOnly', locale:this.lang});
+					}
+			}
+			this.valueNode.value = value;
+		},
+		
+		destroy: function(/*Boolean*/finalize){
+			this.datePicker.destroy(finalize);
+			dojo.widget.DropdownDatePicker.superclass.destroy.apply(this, arguments);
+		}
+	}
+);

Added: incubator/xap/trunk/codebase/src/dojo/src/widget/DropdownTimePicker.js
URL: http://svn.apache.org/viewvc/incubator/xap/trunk/codebase/src/dojo/src/widget/DropdownTimePicker.js?view=auto&rev=518313
==============================================================================
--- incubator/xap/trunk/codebase/src/dojo/src/widget/DropdownTimePicker.js (added)
+++ incubator/xap/trunk/codebase/src/dojo/src/widget/DropdownTimePicker.js Wed Mar 14 13:36:44 2007
@@ -0,0 +1,242 @@
+/*
+	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.DropdownTimePicker");
+
+dojo.require("dojo.widget.*");
+dojo.require("dojo.widget.DropdownContainer");
+dojo.require("dojo.widget.TimePicker");
+dojo.require("dojo.event.*");
+dojo.require("dojo.html.*");
+dojo.require("dojo.date.format");
+dojo.require("dojo.date.serialize");
+dojo.require("dojo.i18n.common");
+dojo.requireLocalization("dojo.widget", "DropdownTimePicker", null, "ROOT");
+
+dojo.widget.defineWidget(
+	"dojo.widget.DropdownTimePicker",
+	dojo.widget.DropdownContainer,
+	{
+		/*
+		summary: 
+			A form input for entering times with a pop-up dojo.widget.TimePicker to aid in selection
+		
+			description: 
+				This is TimePicker in a DropdownContainer, it supports all features of TimeePicker.
+		
+				It is possible to customize the user-visible formatting with either the formatLength or 
+				displayFormat attributes.  The value sent to the server is typically a locale-independent 
+				value in a hidden field as defined by the name attribute. RFC3339 representation is used 
+				by default, but other options are available with saveFormat.
+		
+			usage: 
+				var dtp = dojo.widget.createWidget("DropdownTimePicker", {},   
+				dojo.byId("DropdownTimePickerNode")); 
+		 	 
+				<input dojoType="DropdownTimePicker">
+		*/
+
+		// iconURL: URL
+		//	path of icon for button to display time picker widget
+		iconURL: dojo.uri.dojoUri("src/widget/templates/images/timeIcon.gif"),
+		
+		// formatLength: String
+		//	Type of formatting used for visual display, appropriate to locale (choice of long, short, medium or full)
+		//	See dojo.date.format for details.
+		formatLength: "short",
+
+		// displayFormat: String
+		//	A pattern used for the visual display of the formatted date.
+		//	Setting this overrides the default locale-specific settings as well as the formatLength
+		//	attribute.  See dojo.date.format for a reference which defines the formatting patterns.
+		displayFormat: "",
+
+		timeFormat: "", // deprecated, will be removed for 0.5
+
+//FIXME: need saveFormat attribute support
+		// saveFormat: String
+		//	Formatting scheme used when submitting the form element.  This formatting is used in a hidden
+		//  field (name) intended for server use, and is therefore typically locale-independent.
+		//  By default, uses rfc3339 style date formatting (rfc)
+		//	Use a pattern string like displayFormat or one of the following:
+		//	rfc|iso|posix|unix
+		saveFormat: "",
+
+		// value: String|Date
+		//	form value property in rfc3339 format. ex: 12:00
+		value: "",
+
+		// name: String
+		// 	name of the form element, used to create a hidden field by this name for form element submission.
+		name: "",
+
+		postMixInProperties: function() {
+			// summary: see dojo.widget.DomWidget
+			dojo.widget.DropdownTimePicker.superclass.postMixInProperties.apply(this, arguments);
+			var messages = dojo.i18n.getLocalization("dojo.widget", "DropdownTimePicker", this.lang);
+			this.iconAlt = messages.selectTime;
+
+			//FIXME: should this be if/else/else?
+			if(typeof(this.value)=='string'&&this.value.toLowerCase()=='today'){
+				this.value = new Date();
+			}
+			if(this.value && isNaN(this.value)){
+				var orig = this.value;
+				this.value = dojo.date.fromRfc3339(this.value);
+				if(!this.value){
+					var d = dojo.date.format(new Date(), { selector: "dateOnly", datePattern: "yyyy-MM-dd" });
+					var c = orig.split(":");
+					for(var i = 0; i < c.length; ++i){
+						if(c[i].length == 1) c[i] = "0" + c[i];
+					}
+					orig = c.join(":");
+					this.value = dojo.date.fromRfc3339(d + "T" + orig);
+					dojo.deprecated("dojo.widget.DropdownTimePicker", "time attributes must be passed in Rfc3339 format", "0.5");
+				}
+			}
+			if(this.value && !isNaN(this.value)){
+				this.value = new Date(this.value);
+			}
+		},
+
+		fillInTemplate: function(){
+			// summary: see dojo.widget.DomWidget
+
+			dojo.widget.DropdownTimePicker.superclass.fillInTemplate.apply(this, arguments);
+
+			var value = "";
+			if(this.value instanceof Date) {
+				value = this.value;
+			} else if(this.value) {
+				var orig = this.value;
+				var d = dojo.date.format(new Date(), { selector: "dateOnly", datePattern: "yyyy-MM-dd" });
+				var c = orig.split(":");
+				for(var i = 0; i < c.length; ++i){
+					if(c[i].length == 1) c[i] = "0" + c[i];
+				}
+				orig = c.join(":");
+				value = dojo.date.fromRfc3339(d + "T" + orig);
+			}
+			
+			var tpArgs = { widgetContainerId: this.widgetId, lang: this.lang, value: value };
+			this.timePicker = dojo.widget.createWidget("TimePicker", tpArgs, this.containerNode, "child");
+			
+			dojo.event.connect(this.timePicker, "onValueChanged", this, "_updateText");
+			
+			if(this.value){
+				this._updateText();
+			}
+			this.containerNode.style.zIndex = this.zIndex;
+			this.containerNode.explodeClassName = "timeContainer";
+			this.valueNode.name = this.name;
+		},
+		
+		getValue: function(){
+			// summary: return current time in time-only portion of RFC 3339 format
+			return this.valueNode.value; /*String*/
+		},
+
+		getTime: function(){
+			// summary: return current time as a Date object
+			return this.timePicker.storedTime; /*Date*/
+		},
+
+		setValue: function(/*Date|String*/rfcDate){
+			//summary: set the current time from RFC 3339 formatted string or a date object, synonymous with setTime
+			this.setTime(rfcDate);
+		},
+
+		setTime: function(/*Date|String*/dateObj){
+			// summary: set the current time and update the UI
+			var value = "";
+			if(dateObj instanceof Date) {
+				value = dateObj;
+			} else if(this.value) {
+				var orig = this.value;
+				var d = dojo.date.format(new Date(), { selector: "dateOnly", datePattern: "yyyy-MM-dd" });
+				var c = orig.split(":");
+				for(var i = 0; i < c.length; ++i){
+					if(c[i].length == 1) c[i] = "0" + c[i];
+				}
+				orig = c.join(":");
+				value = dojo.date.fromRfc3339(d + "T" + orig);
+			}
+
+			this.timePicker.setTime(value);
+			this._syncValueNode();
+		},
+	
+		_updateText: function(){
+			// summary: updates the <input> field according to the current value (ie, displays the formatted date)
+			if(this.timePicker.selectedTime.anyTime){
+				this.inputNode.value = "";
+			}else if(this.timeFormat){
+				dojo.deprecated("dojo.widget.DropdownTimePicker",
+				"Must use displayFormat attribute instead of timeFormat.  See dojo.date.format for specification.", "0.5");
+				this.inputNode.value = dojo.date.strftime(this.timePicker.time, this.timeFormat, this.lang);
+			}else{
+				this.inputNode.value = dojo.date.format(this.timePicker.time,
+					{formatLength:this.formatLength, timePattern:this.displayFormat, selector:'timeOnly', locale:this.lang});
+			}
+			this._syncValueNode();
+			this.onValueChanged(this.getTime());
+			this.hideContainer();
+		},
+
+		onValueChanged: function(/*Date*/dateObj){
+			// summary: triggered when this.value is changed
+		},
+		
+		onInputChange: function(){
+			// summary: callback when user manually types a time into the <input> field
+			if(this.dateFormat){
+				dojo.deprecated("dojo.widget.DropdownTimePicker",
+				"Cannot parse user input.  Must use displayFormat attribute instead of dateFormat.  See dojo.date.format for specification.", "0.5");
+			}else{
+				var input = dojo.string.trim(this.inputNode.value);
+				if(input){
+					var inputTime = dojo.date.parse(input,
+							{formatLength:this.formatLength, timePattern:this.displayFormat, selector:'timeOnly', locale:this.lang});			
+					if(inputTime){
+						this.setTime(inputTime);
+					}
+				} else {
+					this.valueNode.value = input;
+				}
+			}
+			// If the time entered didn't parse, reset to the old time.  KISS, for now.
+			//TODO: usability?  should we provide more feedback somehow? an error notice?
+			// seems redundant to do this if the parse failed, but at least until we have validation,
+			// this will fix up the display of entries like 01/32/2006
+			if(input){ this._updateText(); }
+		},
+
+		_syncValueNode: function(){
+			var time = this.timePicker.time;
+			var value;
+			switch(this.saveFormat.toLowerCase()){
+				case "rfc": case "iso": case "":
+					value = dojo.date.toRfc3339(time, 'timeOnly');
+					break;
+				case "posix": case "unix":
+					value = Number(time);
+					break;
+				default:
+					value = dojo.date.format(time, {datePattern:this.saveFormat, selector:'timeOnly', locale:this.lang});
+			}
+			this.valueNode.value = value;
+		},
+		
+		destroy: function(/*Boolean*/finalize){
+			this.timePicker.destroy(finalize);
+			dojo.widget.DropdownTimePicker.superclass.destroy.apply(this, arguments);
+		}
+	}
+);



Mime
View raw message