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

svn commit: r449122 [27/40] - in /tapestry/tapestry4/trunk/tapestry-framework/src: java/org/apache/tapestry/ java/org/apache/tapestry/dojo/ java/org/apache/tapestry/dojo/form/ java/org/apache/tapestry/dojo/html/ java/org/apache/tapestry/form/ java/org/...

Added: tapestry/tapestry4/trunk/tapestry-framework/src/js/dojo/src/widget/HslColorPicker.js
URL: http://svn.apache.org/viewvc/tapestry/tapestry4/trunk/tapestry-framework/src/js/dojo/src/widget/HslColorPicker.js?view=auto&rev=449122
==============================================================================
--- tapestry/tapestry4/trunk/tapestry-framework/src/js/dojo/src/widget/HslColorPicker.js (added)
+++ tapestry/tapestry4/trunk/tapestry-framework/src/js/dojo/src/widget/HslColorPicker.js Fri Sep 22 16:22:30 2006
@@ -0,0 +1,139 @@
+/*
+	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.svg.HslColorPicker");
+
+dojo.require("dojo.widget.*");
+dojo.require("dojo.widget.HtmlWidget");
+dojo.require("dojo.widget.HslColorPicker");
+dojo.require("dojo.math");
+dojo.require("dojo.svg");
+dojo.require("dojo.gfx.color");
+dojo.require("dojo.gfx.color.hsl");
+
+dojo.widget.defineWidget(
+	"dojo.widget.svg.HslColorPicker",
+	dojo.widget.HtmlWidget,
+	function(){
+		dojo.debug("warning: the HslColorPicker is not a finished widget, and is not yet ready for general use");
+		this.filterObject = {};
+	},
+{
+	hue: "0",
+	saturation: "0",
+	light: "0",
+	storedColor: "#0054aa",
+
+	//	widget props
+	templatePath: dojo.uri.dojoUri("src/widget/templates/HslColorPicker.svg"),
+	fillInTemplate: function() {
+		this.height = "131px";
+		this.svgDoc = this.hueNode.ownerDocument;
+		this.leftGradientColorNode = this.hueNode.ownerDocument.getElementById("leftGradientColor");
+		this.rightGradientColorNode = this.hueNode.ownerDocument.getElementById("rightGradientColor");
+		this.hueNode.setAttributeNS(dojo.dom.xmlns.xlink, "href", dojo.uri.dojoUri("src/widget/templates/images/hue.png"));
+		var hsl = dojo.gfx.color.hex2hsl(this.storedColor);
+		this.hue = hsl[0];
+		this.saturation = hsl[1];
+		this.light = hsl[2];
+		this.setSaturationStopColors();
+		//this.setHueSlider();
+		//this.setSaturationLightSlider();
+	},
+	setSaturationStopColors: function() {
+		//this.leftGradientStopColor = "rgb(" + dojo.gfx.color.hsl2rgb(this.hue, 20, 50).join(", ") + ")";
+		//this.rightGradientStopColor = "rgb(" + dojo.gfx.color.hsl2rgb(this.hue, 100, 50).join(", ") + ")";
+		//this.leftGradientStopColor = dojo.gfx.color.hsl2hex(this.hue, 20, 50);
+		//this.rightGradientStopColor = dojo.gfx.color.hsl2hex(this.hue, 100, 50);
+		this.leftGradientStopColor = dojo.gfx.color.rgb2hex(this.hsl2rgb(this.hue, 0, 50));
+		this.rightGradientStopColor = dojo.gfx.color.rgb2hex(this.hsl2rgb(this.hue, 100, 50));
+		this.leftGradientColorNode.setAttributeNS(null,'stop-color',this.leftGradientStopColor);
+		this.rightGradientColorNode.setAttributeNS(null,'stop-color',this.rightGradientStopColor);
+	},
+	setHue: function(hue) {
+		this.hue = hue;
+	},
+	setHueSlider: function() {
+		// FIXME: need to add some padding around the picker so you can see the slider at the top and bottom of the picker)
+		this.hueSliderNode.setAttribute("y", parseInt((this.hue/360) * parseInt(this.height) - 2) + "px" );
+	},
+	setSaturationLight: function(saturation, light) {
+		this.saturation = saturation;
+		this.light = light;
+	},
+	setSaturationLightSlider: function() {
+		// TODO
+	},
+	onHueClick: function(evt) {
+		// get the position that was clicked on the element
+		// FIXME: handle document scrolling, offset
+		var yPosition = parseInt(evt.clientY) - parseInt(evt.target.getAttribute("y"));
+		this.setHue( 360 - parseInt(yPosition*(360/parseInt(this.height))) );
+		this.setSaturationStopColors();
+		this.setStoredColor(dojo.gfx.color.hsl2hex(this.hue, this.saturation, this.light));
+	},
+	onHueDrag: function(evt) {
+		// TODO
+	},
+	onSaturationLightClick: function(evt) {
+		// get the position that was clicked on the element
+		// FIXME: handle document scrolling, offset
+		var xPosition = parseInt(evt.clientX) - parseInt(evt.target.getAttribute("y"));
+		var yPosition = parseInt(evt.clientY) - parseInt(evt.target.getAttribute("y"));
+		var saturation = parseInt(parseInt(xPosition)*(101/106));
+		var light = parseInt(parseInt(yPosition)*(101/106));
+		this.setSaturationLight(saturation, light);
+		this.setStoredColor(dojo.gfx.color.hsl2hex(this.hue, this.saturation, this.light));
+	},
+	onSaturationLightDrag: function(evt) {
+		// TODO
+	},
+	getStoredColor: function() {
+		return this.storedColor;
+	},
+	setStoredColor: function(rgbHexColor) {
+		this.storedColor = rgbHexColor;
+		dojo.event.topic.publish("/" + this.widgetId + "/setStoredColor", this.filterObject);
+	},
+	hsl2rgb: function(hue, saturation, light)
+	{
+		// hsl2rgb in dojo.gfx.color did not behave hte way I expected, so 
+		// I'm using some old code I wrote until I figure out what the issue is
+		// first, check to see if saturation = 0
+		function rgb(q1,q2,hue) {
+			if (hue>360) hue=hue-360;
+			if (hue<0) hue=hue+360;
+			if (hue<60) return (q1+(q2-q1)*hue/60);
+			else if (hue<180) return(q2);
+			else if (hue<240) return(q1+(q2-q1)*(240-hue)/60);
+			else return(q1);
+		}
+		this.rgb = rgb
+	
+		if (saturation==0) {
+			return [Math.round(light*255/100), Math.round(light*255/100), Math.round(light*255/100)];
+		} else {
+			light = light/100;
+			saturation = saturation/100;
+			// check to see if light > 0.5
+			if ((light)<0.5) {
+				var temp2 = (light)*(1.0+saturation)
+			} else {
+				var temp2 = (light+saturation-(light*saturation))
+			}
+			var temp1 = 2.0*light - temp2;
+			var rgbcolor = [];
+			rgbcolor[0] = Math.round(rgb(temp1,temp2,parseInt(hue)+120)*255);
+			rgbcolor[1] = Math.round(rgb(temp1,temp2,hue)*255);
+			rgbcolor[2] = Math.round(rgb(temp1,temp2,parseInt(hue)-120)*255);
+			return rgbcolor;
+		}
+	}
+});

Propchange: tapestry/tapestry4/trunk/tapestry-framework/src/js/dojo/src/widget/HslColorPicker.js
------------------------------------------------------------------------------
    svn:eol-style = native

Added: tapestry/tapestry4/trunk/tapestry-framework/src/js/dojo/src/widget/HtmlWidget.js
URL: http://svn.apache.org/viewvc/tapestry/tapestry4/trunk/tapestry-framework/src/js/dojo/src/widget/HtmlWidget.js?view=auto&rev=449122
==============================================================================
--- tapestry/tapestry4/trunk/tapestry-framework/src/js/dojo/src/widget/HtmlWidget.js (added)
+++ tapestry/tapestry4/trunk/tapestry-framework/src/js/dojo/src/widget/HtmlWidget.js Fri Sep 22 16:22:30 2006
@@ -0,0 +1,166 @@
+/*
+	Copyright (c) 2004-2006, The Dojo Foundation
+	All Rights Reserved.
+
+	Licensed under the Academic Free License version 2.1 or above OR the
+	modified BSD license. For more information on Dojo licensing, see:
+
+		http://dojotoolkit.org/community/licensing.shtml
+*/
+
+dojo.provide("dojo.widget.HtmlWidget");
+dojo.require("dojo.widget.DomWidget");
+dojo.require("dojo.html.util");
+dojo.require("dojo.html.display");
+dojo.require("dojo.html.layout");
+dojo.require("dojo.lang.extras");
+dojo.require("dojo.lang.func");
+dojo.require("dojo.lfx.toggle");
+
+dojo.declare("dojo.widget.HtmlWidget", dojo.widget.DomWidget, {								 
+	widgetType: "HtmlWidget",
+
+	templateCssPath: null,
+	templatePath: null,
+
+	lang: "",
+	// for displaying/hiding widget
+	toggle: "plain",
+	toggleDuration: 150,
+
+	animationInProgress: false,
+
+	initialize: function(args, frag){
+	},
+
+	postMixInProperties: function(args, frag){
+		if(this.lang === ""){this.lang = null;}
+		// now that we know the setting for toggle, get toggle object
+		// (default to plain toggler if user specified toggler not present)
+		this.toggleObj =
+			dojo.lfx.toggle[this.toggle.toLowerCase()] || dojo.lfx.toggle.plain;
+	},
+
+	getContainerHeight: function(){
+		// NOTE: container height must be returned as the INNER height
+		dojo.unimplemented("dojo.widget.HtmlWidget.getContainerHeight");
+	},
+
+	getContainerWidth: function(){
+		return this.parent.domNode.offsetWidth;
+	},
+
+	setNativeHeight: function(height){
+		var ch = this.getContainerHeight();
+	},
+
+	createNodesFromText: function(txt, wrap){
+		return dojo.html.createNodesFromText(txt, wrap);
+	},
+
+	destroyRendering: function(finalize){
+		try{
+			if(!finalize && this.domNode){
+				dojo.event.browser.clean(this.domNode);
+			}
+			this.domNode.parentNode.removeChild(this.domNode);
+			delete this.domNode;
+		}catch(e){ /* squelch! */ }
+	},
+
+	/////////////////////////////////////////////////////////
+	// Displaying/hiding the widget
+	/////////////////////////////////////////////////////////
+	isShowing: function(){
+		return dojo.html.isShowing(this.domNode);
+	},
+
+	toggleShowing: function(){
+		// dojo.html.toggleShowing(this.domNode);
+		if(this.isHidden){
+			this.show();
+		}else{
+			this.hide();
+		}
+	},
+
+	show: function(){
+		this.animationInProgress=true;
+		this.isHidden = false;
+		this.toggleObj.show(this.domNode, this.toggleDuration, null,
+			dojo.lang.hitch(this, this.onShow), this.explodeSrc);
+	},
+
+	// called after the show() animation has completed
+	onShow: function(){
+		this.animationInProgress=false;
+		this.checkSize();
+	},
+
+	hide: function(){
+		this.animationInProgress = true;
+		this.isHidden = true;
+		this.toggleObj.hide(this.domNode, this.toggleDuration, null,
+			dojo.lang.hitch(this, this.onHide), this.explodeSrc);
+	},
+
+	// called after the hide() animation has completed
+	onHide: function(){
+		this.animationInProgress=false;
+	},
+
+	//////////////////////////////////////////////////////////////////////////////
+	// Sizing related methods
+	//  If the parent changes size then for each child it should call either
+	//   - resizeTo(): size the child explicitly
+	//   - or checkSize(): notify the child the the parent has changed size
+	//////////////////////////////////////////////////////////////////////////////
+
+	// Test if my size has changed.
+	// If width & height are specified then that's my new size; otherwise,
+	// query outerWidth/outerHeight of my domNode
+	_isResized: function(w, h){
+		// If I'm not being displayed then disregard (show() must
+		// check if the size has changed)
+		if(!this.isShowing()){ return false; }
+
+		// If my parent has been resized and I have style="height: 100%"
+		// or something similar then my size has changed too.
+		var wh = dojo.html.getMarginBox(this.domNode);
+		var width=w||wh.width;
+		var height=h||wh.height;
+		if(this.width == width && this.height == height){ return false; }
+
+		this.width=width;
+		this.height=height;
+		return true;
+	},
+
+	// Called when my parent has changed size, but my parent won't call resizeTo().
+	// This is useful if my size is height:100% or something similar.
+	// Also called whenever I am shown, because the first time I am shown I may need
+	// to do size calculations.
+	checkSize: function(){
+		if(!this._isResized()){ return; }
+		this.onResized();
+	},
+
+	// Explicitly set this widget's size (in pixels).
+	resizeTo: function(w, h){
+		if(!this._isResized(w,h)){ return; }
+		dojo.html.setMarginBox(this.domNode, { width: w, height: h });
+		this.onResized();
+	},
+
+	resizeSoon: function(){
+		if(this.isShowing()){
+			dojo.lang.setTimeout(this, this.onResized, 0);
+		}
+	},
+
+	// Called when my size has changed.
+	// Must notify children if their size has (possibly) changed
+	onResized: function(){
+		dojo.lang.forEach(this.children, function(child){ if(child.checkSize){child.checkSize();} });
+	}
+});

Propchange: tapestry/tapestry4/trunk/tapestry-framework/src/js/dojo/src/widget/HtmlWidget.js
------------------------------------------------------------------------------
    svn:eol-style = native

Added: tapestry/tapestry4/trunk/tapestry-framework/src/js/dojo/src/widget/InlineEditBox.js
URL: http://svn.apache.org/viewvc/tapestry/tapestry4/trunk/tapestry-framework/src/js/dojo/src/widget/InlineEditBox.js?view=auto&rev=449122
==============================================================================
--- tapestry/tapestry4/trunk/tapestry-framework/src/js/dojo/src/widget/InlineEditBox.js (added)
+++ tapestry/tapestry4/trunk/tapestry-framework/src/js/dojo/src/widget/InlineEditBox.js Fri Sep 22 16:22:30 2006
@@ -0,0 +1,208 @@
+/*
+	Copyright (c) 2004-2006, The Dojo Foundation
+	All Rights Reserved.
+
+	Licensed under the Academic Free License version 2.1 or above OR the
+	modified BSD license. For more information on Dojo licensing, see:
+
+		http://dojotoolkit.org/community/licensing.shtml
+*/
+
+dojo.provide("dojo.widget.InlineEditBox");
+
+dojo.require("dojo.widget.*");
+dojo.require("dojo.event.*");
+dojo.require("dojo.lfx.*");
+dojo.require("dojo.gfx.color");
+dojo.require("dojo.string");
+dojo.require("dojo.html.*");
+dojo.require("dojo.html.layout");
+
+dojo.widget.defineWidget(
+	"dojo.widget.InlineEditBox",
+	dojo.widget.HtmlWidget,
+	function(){
+		// mutable objects need to be in constructor to give each instance its own copy
+		this.history = [];
+	},
+{
+	templatePath: dojo.uri.dojoUri("src/widget/templates/InlineEditBox.html"),
+	templateCssPath: dojo.uri.dojoUri("src/widget/templates/InlineEditBox.css"),
+
+	form: null,
+	editBox: null,
+	edit: null,
+	text: null,
+	textarea: null,
+	submitButton: null,
+	cancelButton: null,
+	mode: "text",
+
+	minWidth: 100, //px. minimum width of edit box
+	minHeight: 200, //px. minimum width of edit box, if it's a TA
+
+	editing: false,
+	textValue: "",
+	defaultText: "",
+	doFade: false,
+	
+	onSave: function(newValue, oldValue){},
+	onUndo: function(value){},
+
+	postCreate: function(args, frag){
+		// put original node back in the document, and attach handlers
+		// which hide it and display the editor
+		this.editable = this.getFragNodeRef(frag);
+		dojo.html.insertAfter(this.editable, this.form);
+		dojo.event.connect(this.editable, "onmouseover", this, "onMouseOver");
+		dojo.event.connect(this.editable, "onmouseout", this, "onMouseOut");
+		dojo.event.connect(this.editable, "onclick", this, "beginEdit");
+
+		this.textValue = dojo.string.trim(this.editable.innerHTML);
+		if(dojo.string.trim(this.textValue).length == 0){
+			this.editable.innerHTML = this.defaultText;
+		}		
+	},
+	
+	onMouseOver: function(){
+		if(!this.editing){
+			if (!this.isEnabled){
+				dojo.html.addClass(this.editable, "editableRegionDisabled");
+			} else {
+				dojo.html.addClass(this.editable, "editableRegion");
+				if(this.mode == "textarea"){
+					dojo.html.addClass(this.editable, "editableTextareaRegion");
+				}
+			}
+		}
+		
+		this.mouseover();
+	},
+	
+	mouseover: function(e){
+		// TODO: How do we deprecate a function without going into overkill with debug statements?
+		// dojo.deprecated("onMouseOver should be used instead of mouseover to listen for mouse events");
+	},
+	
+	onMouseOut: function(){
+		if(!this.editing){
+			dojo.html.removeClass(this.editable, "editableRegion");
+			dojo.html.removeClass(this.editable, "editableTextareaRegion");
+			dojo.html.removeClass(this.editable, "editableRegionDisabled");
+		}
+		
+		this.mouseout();
+	},
+	
+	mouseout: function(e){
+		// dojo.deprecated("onMouseOut should be used instead of mouseout to listen for mouse events");
+	},
+
+	// When user clicks the text, then start editing.
+	// Hide the text and display the form instead.
+	beginEdit: function(e){
+		if(this.editing || !this.isEnabled){ return; }
+		this.mouseout();
+		this.editing = true;
+
+		// setup the form's <input> or <textarea> field, as specified by mode
+		var ee = this[this.mode.toLowerCase()];
+		ee.value = dojo.string.trim(this.textValue);
+		ee.style.fontSize = dojo.html.getStyle(this.editable, "font-size");
+		ee.style.fontWeight = dojo.html.getStyle(this.editable, "font-weight");
+		ee.style.fontStyle = dojo.html.getStyle(this.editable, "font-style");
+		var bb = dojo.html.getBorderBox(this.editable);
+		ee.style.width = Math.max(bb.width, this.minWidth) + "px";
+		if(this.mode.toLowerCase()=="textarea"){
+			ee.style.display = "block";
+			ee.style.height = Math.max(bb.height, this.minHeight) + "px";
+		} else {
+			ee.style.display = "";
+		}
+
+		// show the edit form and hide the read only version of the text
+		this.form.style.display = "";
+		this.editable.style.display = "none";
+
+		ee.focus();
+		ee.select();
+		this.submitButton.disabled = true;
+	},
+
+	saveEdit: function(e){
+		e.preventDefault();
+		e.stopPropagation();
+		var ee = this[this.mode.toLowerCase()];
+		if((this.textValue != ee.value)&&
+			(dojo.string.trim(ee.value) != "")){
+			this.doFade = true;
+			this.history.push(this.textValue);
+			this.onSave(ee.value, this.textValue);
+			this.textValue = ee.value;
+			this.editable.innerHTML = "";
+			var textNode = document.createTextNode( this.textValue );
+			this.editable.appendChild( textNode );
+		}else{
+			this.doFade = false;
+		}
+		this.finishEdit(e);
+	},
+
+	cancelEdit: function(e){
+		if(!this.editing){ return false; }
+		this.editing = false;
+		this.form.style.display="none";
+		this.editable.style.display = "";
+		return true;
+	},
+
+	finishEdit: function(e){
+		if(!this.cancelEdit(e)){ return; }
+		if(this.doFade) {
+			dojo.lfx.highlight(this.editable, dojo.gfx.color.hex2rgb("#ffc"), 700).play(300);
+		}
+		this.doFade = false;
+	},
+	
+	setText: function(txt){
+		// sets the text without informing the server
+		var tt = dojo.string.trim(txt);
+		this.textValue = tt
+		this.editable.innerHTML = tt;
+	},
+
+	undo: function(){
+		if(this.history.length > 0){
+			var value = this.history.pop();
+			this.editable.innerHTML = value;
+			this.textValue = value;
+			this.onUndo(value);
+		}
+	},
+
+	checkForValueChange: function(){
+		var ee = this[this.mode.toLowerCase()];
+		if((this.textValue != ee.value)&&
+			(dojo.string.trim(ee.value) != "")){
+			this.submitButton.disabled = false;
+		}
+	},
+	
+	disable: function(){
+		this.submitButton.disabled = true;
+		this.cancelButton.disabled = true;
+		var ee = this[this.mode.toLowerCase()];
+		ee.disabled = true;
+		
+		dojo.widget.Widget.prototype.disable.call(this);
+	},
+	
+	enable: function(){
+		this.checkForValueChange();
+		this.cancelButton.disabled = false;
+		var ee = this[this.mode.toLowerCase()];
+		ee.disabled = false;
+		
+		dojo.widget.Widget.prototype.enable.call(this);
+	}
+});

Propchange: tapestry/tapestry4/trunk/tapestry-framework/src/js/dojo/src/widget/InlineEditBox.js
------------------------------------------------------------------------------
    svn:eol-style = native

Added: tapestry/tapestry4/trunk/tapestry-framework/src/js/dojo/src/widget/LayoutContainer.js
URL: http://svn.apache.org/viewvc/tapestry/tapestry4/trunk/tapestry-framework/src/js/dojo/src/widget/LayoutContainer.js?view=auto&rev=449122
==============================================================================
--- tapestry/tapestry4/trunk/tapestry-framework/src/js/dojo/src/widget/LayoutContainer.js (added)
+++ tapestry/tapestry4/trunk/tapestry-framework/src/js/dojo/src/widget/LayoutContainer.js Fri Sep 22 16:22:30 2006
@@ -0,0 +1,63 @@
+/*
+	Copyright (c) 2004-2006, The Dojo Foundation
+	All Rights Reserved.
+
+	Licensed under the Academic Free License version 2.1 or above OR the
+	modified BSD license. For more information on Dojo licensing, see:
+
+		http://dojotoolkit.org/community/licensing.shtml
+*/
+
+//
+// this widget provides Delphi-style panel layout semantics
+//
+
+dojo.provide("dojo.widget.LayoutContainer");
+
+dojo.require("dojo.widget.*");
+dojo.require("dojo.widget.html.layout");
+
+dojo.widget.defineWidget(
+	"dojo.widget.LayoutContainer",
+	dojo.widget.HtmlWidget,
+{
+	isContainer: true,
+
+	layoutChildPriority: 'top-bottom',
+
+	postCreate: function(){
+		dojo.widget.html.layout(this.domNode, this.children, this.layoutChildPriority);
+	},
+
+	addChild: function(child, overrideContainerNode, pos, ref, insertIndex){
+		dojo.widget.LayoutContainer.superclass.addChild.call(this, child, overrideContainerNode, pos, ref, insertIndex);
+		dojo.widget.html.layout(this.domNode, this.children, this.layoutChildPriority);
+	},
+
+	removeChild: function(pane){
+		dojo.widget.LayoutContainer.superclass.removeChild.call(this,pane);
+		dojo.widget.html.layout(this.domNode, this.children, this.layoutChildPriority);
+	},
+
+	onResized: function(){
+		dojo.widget.html.layout(this.domNode, this.children, this.layoutChildPriority);
+	},
+
+	show: function(){
+		// If this node was created while display=="none" then it
+		// hasn't been laid out yet.  Do that now.
+		this.domNode.style.display="";
+		this.checkSize();
+		this.domNode.style.display="none";
+		this.domNode.style.visibility="";
+
+		dojo.widget.LayoutContainer.superclass.show.call(this);
+	}
+});
+
+// This argument can be specified for the children of a LayoutContainer.
+// Since any widget can be specified as a LayoutContainer child, mix it
+// into the base widget class.  (This is a hack, but it's effective.)
+dojo.lang.extend(dojo.widget.Widget, {
+	layoutAlign: 'none'
+});

Propchange: tapestry/tapestry4/trunk/tapestry-framework/src/js/dojo/src/widget/LayoutContainer.js
------------------------------------------------------------------------------
    svn:eol-style = native

Added: tapestry/tapestry4/trunk/tapestry-framework/src/js/dojo/src/widget/LinkPane.js
URL: http://svn.apache.org/viewvc/tapestry/tapestry4/trunk/tapestry-framework/src/js/dojo/src/widget/LinkPane.js?view=auto&rev=449122
==============================================================================
--- tapestry/tapestry4/trunk/tapestry-framework/src/js/dojo/src/widget/LinkPane.js (added)
+++ tapestry/tapestry4/trunk/tapestry-framework/src/js/dojo/src/widget/LinkPane.js Fri Sep 22 16:22:30 2006
@@ -0,0 +1,41 @@
+/*
+	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
+*/
+
+//
+// a div that loads from a URL.  (Similar to an iframe, but
+// it's in the same environment as the main window)
+//
+
+dojo.provide("dojo.widget.LinkPane");
+
+dojo.require("dojo.widget.*");
+dojo.require("dojo.widget.ContentPane");
+dojo.require("dojo.html.style");
+
+dojo.widget.defineWidget(
+	"dojo.widget.LinkPane",
+	dojo.widget.ContentPane,
+{
+	// I'm using a template because the user may specify the input as
+	// <a href="foo.html">label</a>, in which case we need to get rid of the
+	// <a> because we don't want a link.
+	templateString: '<div class="dojoLinkPane"></div>',
+
+	fillInTemplate: function(args, frag){
+		var source = this.getFragNodeRef(frag);
+
+		// If user has specified node contents, they become the label
+		// (the link must be plain text)
+		this.label += source.innerHTML;
+
+		var source = this.getFragNodeRef(frag);
+		dojo.html.copyStyle(this.domNode, source);
+	}
+});

Propchange: tapestry/tapestry4/trunk/tapestry-framework/src/js/dojo/src/widget/LinkPane.js
------------------------------------------------------------------------------
    svn:eol-style = native

Added: tapestry/tapestry4/trunk/tapestry-framework/src/js/dojo/src/widget/Manager.js
URL: http://svn.apache.org/viewvc/tapestry/tapestry4/trunk/tapestry-framework/src/js/dojo/src/widget/Manager.js?view=auto&rev=449122
==============================================================================
--- tapestry/tapestry4/trunk/tapestry-framework/src/js/dojo/src/widget/Manager.js (added)
+++ tapestry/tapestry4/trunk/tapestry-framework/src/js/dojo/src/widget/Manager.js Fri Sep 22 16:22:30 2006
@@ -0,0 +1,359 @@
+/*
+	Copyright (c) 2004-2006, The Dojo Foundation
+	All Rights Reserved.
+
+	Licensed under the Academic Free License version 2.1 or above OR the
+	modified BSD license. For more information on Dojo licensing, see:
+
+		http://dojotoolkit.org/community/licensing.shtml
+*/
+
+dojo.provide("dojo.widget.Manager");
+dojo.require("dojo.lang.array");
+dojo.require("dojo.lang.func");
+dojo.require("dojo.event.*");
+
+// Manager class
+dojo.widget.manager = new function(){
+	this.widgets = [];
+	this.widgetIds = [];
+	
+	// map of widgetId-->widget for widgets without parents (top level widgets)
+	this.topWidgets = {};
+
+	var widgetTypeCtr = {};
+	var renderPrefixCache = [];
+
+	this.getUniqueId = function (widgetType) {
+		return widgetType + "_" + (widgetTypeCtr[widgetType] != undefined ?
+			++widgetTypeCtr[widgetType] : widgetTypeCtr[widgetType] = 0);
+	}
+
+	this.add = function(widget){
+		//dojo.profile.start("dojo.widget.manager.add");
+		this.widgets.push(widget);
+		// Opera9 uses ID (caps)
+		if(!widget.extraArgs["id"]){
+			widget.extraArgs["id"] = widget.extraArgs["ID"];
+		}
+		// FIXME: the rest of this method is very slow!
+		if(widget.widgetId == ""){
+			if(widget["id"]){
+				widget.widgetId = widget["id"];
+			}else if(widget.extraArgs["id"]){
+				widget.widgetId = widget.extraArgs["id"];
+			}else{
+				widget.widgetId = this.getUniqueId(widget.widgetType);
+			}
+		}
+		if(this.widgetIds[widget.widgetId]){
+			dojo.debug("widget ID collision on ID: "+widget.widgetId);
+		}
+		this.widgetIds[widget.widgetId] = widget;
+		// Widget.destroy already calls removeById(), so we don't need to
+		// connect() it here
+		//dojo.profile.end("dojo.widget.manager.add");
+	}
+
+	this.destroyAll = function(){
+		for(var x=this.widgets.length-1; x>=0; x--){
+			try{
+				// this.widgets[x].destroyChildren();
+				this.widgets[x].destroy(true);
+				delete this.widgets[x];
+			}catch(e){ }
+		}
+	}
+
+	// FIXME: we should never allow removal of the root widget until all others
+	// are removed!
+	this.remove = function(widgetIndex){
+		if(dojo.lang.isNumber(widgetIndex)){
+			var tw = this.widgets[widgetIndex].widgetId;
+			delete this.widgetIds[tw];
+			this.widgets.splice(widgetIndex, 1);
+		}else{
+			this.removeById(widgetIndex);
+		}
+	}
+	
+	// FIXME: suboptimal performance
+	this.removeById = function(id) {
+		if(!dojo.lang.isString(id)){
+			id = id["widgetId"];
+			if(!id){ dojo.debug("invalid widget or id passed to removeById"); return; }
+		}
+		for (var i=0; i<this.widgets.length; i++){
+			if(this.widgets[i].widgetId == id){
+				this.remove(i);
+				break;
+			}
+		}
+	}
+
+	this.getWidgetById = function(id){
+		if(dojo.lang.isString(id)){
+			return this.widgetIds[id];
+		}
+		return id;
+	}
+
+	this.getWidgetsByType = function(type){
+		var lt = type.toLowerCase();
+		var getType = (type.indexOf(":") < 0 ? 
+			function(x) { return x.widgetType.toLowerCase(); } :
+			function(x) { return x.getNamespacedType(); }
+		);
+		var ret = [];
+		dojo.lang.forEach(this.widgets, function(x){
+			if(getType(x) == lt){ret.push(x);}
+		});
+		return ret;
+	}
+
+	this.getWidgetsByFilter = function(unaryFunc, onlyOne){
+		var ret = [];
+		dojo.lang.every(this.widgets, function(x){
+			if(unaryFunc(x)){
+				ret.push(x);
+				if(onlyOne){return false;}
+			}
+			return true;
+		});
+		return (onlyOne ? ret[0] : ret);
+	}
+
+	this.getAllWidgets = function() {
+		return this.widgets.concat();
+	}
+
+	//	added, trt 2006-01-20
+	this.getWidgetByNode = function(/* DOMNode */ node){
+		var w=this.getAllWidgets();
+		node = dojo.byId(node);
+		for(var i=0; i<w.length; i++){
+			if(w[i].domNode==node){
+				return w[i];
+			}
+		}
+		return null;
+	}
+
+	// shortcuts, baby
+	this.byId = this.getWidgetById;
+	this.byType = this.getWidgetsByType;
+	this.byFilter = this.getWidgetsByFilter;
+	this.byNode = this.getWidgetByNode;
+
+	// map of previousally discovered implementation names to constructors
+	var knownWidgetImplementations = {};
+
+	// support manually registered widget packages
+	var widgetPackages = ["dojo.widget"];
+	for (var i=0; i<widgetPackages.length; i++) {
+		// convenience for checking if a package exists (reverse lookup)
+		widgetPackages[widgetPackages[i]] = true;
+	}
+
+	this.registerWidgetPackage = function(pname) {
+		if(!widgetPackages[pname]){
+			widgetPackages[pname] = true;
+			widgetPackages.push(pname);
+		}
+	}
+	
+	this.getWidgetPackageList = function() {
+		return dojo.lang.map(widgetPackages, function(elt) { return(elt!==true ? elt : undefined); });
+	}
+	
+	this.getImplementation = function(widgetName, ctorObject, mixins, ns){
+		// try and find a name for the widget
+		var impl = this.getImplementationName(widgetName, ns);
+		if(impl){ 
+			// var tic = new Date();
+			var ret = ctorObject ? new impl(ctorObject) : new impl();
+			// dojo.debug(new Date() - tic);
+			return ret;
+		}
+	}
+
+	function buildPrefixCache() {
+		for(var renderer in dojo.render){
+			if(dojo.render[renderer]["capable"] === true){
+				var prefixes = dojo.render[renderer].prefixes;
+				for(var i=0; i<prefixes.length; i++){
+					renderPrefixCache.push(prefixes[i].toLowerCase());
+				}
+			}
+		}
+		// make sure we don't HAVE to prefix widget implementation names
+		// with anything to get them to render
+		//renderPrefixCache.push("");
+		// empty prefix is included automatically
+	}
+	
+	findImplementationInModule = function(lowerCaseWidgetName, module){
+		if(!module){return null;}
+		for(var i=0, l=renderPrefixCache.length, widgetModule; i<=l; i++){
+			widgetModule = (i<l ? module[renderPrefixCache[i]] : module);
+			if(!widgetModule){continue;}
+			for(var name in widgetModule){
+				if(name.toLowerCase() == lowerCaseWidgetName){
+					return widgetModule[name];
+				}
+			}
+		}
+		return null;
+	}
+
+	findImplementation = function(lowerCaseWidgetName, moduleName){
+		// locate registered widget module
+		var module = dojo.evalObjPath(moduleName, false);
+		// locate a widget implementation in the registered module for our current rendering environment
+		return (module ? findImplementationInModule(lowerCaseWidgetName, module) : null);
+	}
+
+	this.getImplementationName = function(widgetName, ns){
+		/*
+		 * Locate an implementation (constructor) for 'widgetName' in namespace 'ns' 
+		 * widgetNames are case INSENSITIVE
+		 * 
+		 * 1. Return value from implementation cache, if available, for quick turnaround.
+		 * 2. Locate a namespace registration for 'ns'
+		 * 3. If no namespace found, register the conventional one (ns.widget)
+		 * 4. Allow the namespace resolver (if any) to load a module for this widget.
+		 * 5. Permute the widget name and capable rendering prefixes to locate, cache, and return 
+		 *    an appropriate widget implementation.
+		 * 6. If no implementation is found, attempt to load the namespace manifest,
+		 *    and then look again for an implementation to cache and return.
+		 * 7. Use the deprecated widgetPackages registration system to attempt to locate the widget
+		 * 8. Fail
+		 */
+		var lowerCaseWidgetName = widgetName.toLowerCase();
+
+		// default to dojo namespace
+		ns=ns||"dojo";
+		// use cache if available
+		var imps = knownWidgetImplementations[ns] || (knownWidgetImplementations[ns]={});
+		//if(!knownWidgetImplementations[ns]){knownWidgetImplementations[ns]={};}
+		var impl = imps[lowerCaseWidgetName];
+		if(impl){
+			return impl;
+		}
+		
+		// (one time) store a list of the render prefixes we are capable of rendering
+		if(!renderPrefixCache.length){
+			buildPrefixCache();
+		}
+
+		// lookup namespace
+		var nsObj = dojo["namespace"].get(ns);
+		if(!nsObj){
+			// default to <ns>.widget by convention
+			dojo.namespace.register(ns, ns + '.widget');
+			nsObj = dojo["namespace"].get(ns);
+		}
+		
+		// allow the namespace to resolve the widget module
+		if(nsObj){nsObj.resolve(widgetName);}
+
+		// locate a widget implementation in the registered module for our current rendering environment
+		impl = findImplementation(lowerCaseWidgetName, nsObj.module);
+		if(impl){return(imps[lowerCaseWidgetName] = impl)};
+
+		// try to load a manifest to resolve this implemenation
+		nsObj = dojo["namespace"].require(ns);
+		if((nsObj)&&(nsObj.resolver)){
+			nsObj.resolve(widgetName);
+			impl = findImplementation(lowerCaseWidgetName, nsObj.module);
+			if(impl){return(imps[lowerCaseWidgetName] = impl)};
+		}
+	
+		// this is an error condition under new rules
+		dojo.deprecated('dojo.widget.Manager.getImplementationName', 
+			'Could not locate widget implementation for "' + widgetName + '" in "' + nsObj.module + '" registered to namespace "' + nsObj.name + '". '										
+			+ "Developers must specify correct namespaces for all non-Dojo widgets", "0.5");
+
+		// backward compat: if the user has not specified any namespace and their widget is not in dojo.widget.*
+		// search registered widget packages [sic]
+		// note: registerWidgetPackage itself is now deprecated 
+		for(var i=0; i<widgetPackages.length; i++){
+			impl = findImplementation(lowerCaseWidgetName, widgetPackages[i]);
+			if(impl){return(imps[lowerCaseWidgetName] = impl)};
+		}
+		
+		throw new Error('Could not locate widget implementation for "' + widgetName + '" in "' + nsObj.module + '" registered to namespace "' + nsObj.name + '"');
+	}
+
+	// FIXME: does it even belong in this module?
+	// NOTE: this method is implemented by DomWidget.js since not all
+	// hostenv's would have an implementation.
+	/*this.getWidgetFromPrimitive = function(baseRenderType){
+		dojo.unimplemented("dojo.widget.manager.getWidgetFromPrimitive");
+	}
+
+	this.getWidgetFromEvent = function(nativeEvt){
+		dojo.unimplemented("dojo.widget.manager.getWidgetFromEvent");
+	}*/
+
+	// Catch window resize events and notify top level widgets
+	this.resizing=false;
+	this.onWindowResized = function(){
+		if(this.resizing){
+			return;	// duplicate event
+		}
+		try{
+			this.resizing=true;
+			for(var id in this.topWidgets){
+				var child = this.topWidgets[id];
+				if(child.checkSize ){
+					child.checkSize();
+				}
+			}
+		}catch(e){
+		}finally{
+			this.resizing=false;
+		}
+	}
+	if(typeof window != "undefined") {
+		dojo.addOnLoad(this, 'onWindowResized');							// initial sizing
+		dojo.event.connect(window, 'onresize', this, 'onWindowResized');	// window resize
+	}
+
+	// FIXME: what else?
+};
+
+(function(){
+	var dw = dojo.widget;
+	var dwm = dw.manager;
+	var h = dojo.lang.curry(dojo.lang, "hitch", dwm);
+	var g = function(oldName, newName){
+		dw[(newName||oldName)] = h(oldName);
+	}
+	// copy the methods from the default manager (this) to the widget namespace
+	g("add", "addWidget");
+	g("destroyAll", "destroyAllWidgets");
+	g("remove", "removeWidget");
+	g("removeById", "removeWidgetById");
+	g("getWidgetById");
+	g("getWidgetById", "byId");
+	g("getWidgetsByType");
+	g("getWidgetsByFilter");
+	g("getWidgetsByType", "byType");
+	g("getWidgetsByFilter", "byFilter");
+	g("getWidgetByNode", "byNode");
+	dw.all = function(n){
+		var widgets = dwm.getAllWidgets.apply(dwm, arguments);
+		if(arguments.length > 0) {
+			return widgets[n];
+		}
+		return widgets;
+	}
+	g("registerWidgetPackage");
+	g("getImplementation", "getWidgetImplementation");
+	g("getImplementationName", "getWidgetImplementationName");
+
+	dw.widgets = dwm.widgets;
+	dw.widgetIds = dwm.widgetIds;
+	dw.root = dwm.root;
+})();

Propchange: tapestry/tapestry4/trunk/tapestry-framework/src/js/dojo/src/widget/Manager.js
------------------------------------------------------------------------------
    svn:eol-style = native

Added: tapestry/tapestry4/trunk/tapestry-framework/src/js/dojo/src/widget/Menu2.js
URL: http://svn.apache.org/viewvc/tapestry/tapestry4/trunk/tapestry-framework/src/js/dojo/src/widget/Menu2.js?view=auto&rev=449122
==============================================================================
--- tapestry/tapestry4/trunk/tapestry-framework/src/js/dojo/src/widget/Menu2.js (added)
+++ tapestry/tapestry4/trunk/tapestry-framework/src/js/dojo/src/widget/Menu2.js Fri Sep 22 16:22:30 2006
@@ -0,0 +1,700 @@
+/*
+	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.Menu2");
+
+dojo.require("dojo.widget.PopupContainer");
+
+dojo.widget.defineWidget(
+	"dojo.widget.PopupMenu2",
+	dojo.widget.PopupContainer,
+	function(){
+		this.targetNodeIds = []; // fill this with nodeIds upon widget creation and it becomes context menu for those nodes
+	
+		this.eventNames =  {
+			open: ""
+		};
+	},
+{
+	templateCssString: "",
+	currentSubmenuTrigger: null,
+	snarfChildDomOutput: true,
+
+	eventNaming: "default",
+
+	templateString: '<table class="dojoPopupMenu2" border=0 cellspacing=0 cellpadding=0 style="display: none;"><tbody dojoAttachPoint="containerNode"></tbody></table>',
+	templateCssPath: dojo.uri.dojoUri("src/widget/templates/Menu2.css"),
+
+	submenuDelay: 500,
+	submenuOverlap: 5,
+	contextMenuForWindow: false,
+	openEvent: null,
+
+	_highlighted_option: null,
+
+	initialize: function(args, frag) {
+		if (this.eventNaming == "default") {
+			for (var eventName in this.eventNames) {
+				this.eventNames[eventName] = this.widgetId+"/"+eventName;
+			}
+		}
+	},
+
+	postCreate: function(){
+		if (this.contextMenuForWindow){
+			var doc = dojo.body();
+			this.bindDomNode(doc);
+		} else if ( this.targetNodeIds.length > 0 ){
+			dojo.lang.forEach(this.targetNodeIds, this.bindDomNode, this);
+		}
+
+		this.subscribeSubitemsOnOpen();
+	},
+
+	subscribeSubitemsOnOpen: function() {
+		var subItems = this.getChildrenOfType(dojo.widget.MenuItem2);
+
+		for(var i=0; i<subItems.length; i++) {
+			dojo.event.topic.subscribe(this.eventNames.open, subItems[i], "menuOpen")
+		}
+	},
+
+	// get open event for current menu
+	getTopOpenEvent: function() {
+		var menu = this;
+		while (menu.parentPopup){ menu = menu.parentPopup; }
+		return menu.openEvent;
+	},
+
+	// attach menu to given node
+	bindDomNode: function(node){
+		node = dojo.byId(node);
+
+		var win = dojo.html.getElementWindow(node);
+		if(dojo.html.isTag(node,'iframe') == 'iframe'){
+			win = dojo.html.iframeContentWindow(node);
+			node = dojo.withGlobal(win, dojo.body);
+		}
+		// fixes node so that it supports oncontextmenu if not natively supported, Konqueror, Opera more?
+		dojo.widget.Menu2.OperaAndKonqFixer.fixNode(node);
+
+		dojo.event.kwConnect({
+			srcObj:     node,
+			srcFunc:    "oncontextmenu",
+			targetObj:  this,
+			targetFunc: "onOpen",
+			once:       true
+		});
+
+		//normal connect does not work if document.designMode is on in FF, use addListener instead
+		if(dojo.render.html.moz && win.document.designMode.toLowerCase() == 'on'){
+			dojo.event.browser.addListener(node, "contextmenu", dojo.lang.hitch(this, "onOpen"));
+		}
+		dojo.widget.PopupManager.registerWin(win);
+	},
+
+	// detach menu from given node
+	unBindDomNode: function(nodeName){
+		var node = dojo.byId(nodeName);
+		dojo.event.kwDisconnect({
+			srcObj:     node,
+			srcFunc:    "oncontextmenu",
+			targetObj:  this,
+			targetFunc: "onOpen",
+			once:       true
+		});
+
+		// cleans a fixed node, konqueror and opera
+		dojo.widget.Menu2.OperaAndKonqFixer.cleanNode(node);
+	},
+
+	moveToNext: function(evt){
+		this.highlightOption(1);
+		return true; //do not pass to parent menu
+	},
+
+	moveToPrevious: function(evt){
+		this.highlightOption(-1);
+		return true; //do not pass to parent menu
+	},
+
+	moveToParentMenu: function(evt){
+		if(this._highlighted_option && this.parentPopup){
+			//only process event in the focused menu
+			//and its immediate parentPopup to support
+			//MenuBar2
+			if(evt._menu2UpKeyProcessed){
+				return true; //do not pass to parent menu
+			}else{
+				this._highlighted_option.onUnhover();
+				this.closeSubpopup();
+				evt._menu2UpKeyProcessed = true;
+			}
+		}
+		return false;
+	},
+
+	moveToChildMenu: function(evt){
+		if(this._highlighted_option && this._highlighted_option.submenuId){
+			this._highlighted_option._onClick(true);
+			return true; //do not pass to parent menu
+		}
+		return false;
+	},
+
+	selectCurrentItem: function(evt){
+		if(this._highlighted_option){
+			this._highlighted_option._onClick();
+			return true;
+		}
+		return false;
+	},
+
+	//return true to stop the event being processed by the
+	//parent popupmenu
+	processKey: function(evt){
+		if(evt.ctrlKey || evt.altKey || !evt.key){ return false; }
+
+		var rval = false;
+		switch(evt.key){
+ 			case evt.KEY_DOWN_ARROW:
+				rval = this.moveToNext(evt);
+				break;
+			case evt.KEY_UP_ARROW:
+				rval = this.moveToPrevious(evt);
+				break;
+			case evt.KEY_RIGHT_ARROW:
+				rval = this.moveToChildMenu(evt);
+				break;
+			case evt.KEY_LEFT_ARROW:
+				rval = this.moveToParentMenu(evt);
+				break;
+			case " ": //fall through
+			case evt.KEY_ENTER: 
+				if(rval = this.selectCurrentItem(evt)){
+					break;
+				}
+				//fall through
+			case evt.KEY_ESCAPE:
+				dojo.widget.PopupManager.currentMenu.close();
+				rval = true;
+				break;
+		}
+
+		return rval;
+	},
+
+	findValidItem: function(dir, curItem){
+		if(curItem){
+			curItem = dir>0 ? curItem.getNextSibling() : curItem.getPreviousSibling();
+		}
+
+		for(var i=0; i < this.children.length; ++i){
+			if(!curItem){
+				curItem = dir>0 ? this.children[0] : this.children[this.children.length-1];
+			}
+			//find next/previous visible menu item, not including separators
+			if(curItem.onHover && curItem.isShowing()){
+				return curItem;
+			}
+			curItem = dir>0 ? curItem.getNextSibling() : curItem.getPreviousSibling();
+		}
+	},
+	
+	highlightOption: function(dir){
+		var item;
+		// || !this._highlighted_option.parentNode
+		if((!this._highlighted_option)){
+			item = this.findValidItem(dir);
+		}else{
+			item = this.findValidItem(dir, this._highlighted_option);
+		}
+		if(item){
+			if(this._highlighted_option) {
+				this._highlighted_option.onUnhover();
+			}
+			item.onHover();
+			dojo.html.scrollIntoView(item.domNode);
+			// navigate into the item table and select the first caption tag
+			try {
+				var node = dojo.html.getElementsByClass("dojoMenuItem2Label", item.domNode)[0];
+				node.focus();
+			} catch(e) { }
+		}
+	},
+
+	// User defined function to handle clicks on an item
+	onItemClick: function(item) {},
+
+	close: function(force){
+		if(this.animationInProgress){
+			dojo.widget.PopupMenu2.superclass.close.apply(this, arguments);
+			return;
+		}
+
+		if(this._highlighted_option){
+			this._highlighted_option.onUnhover();
+		}
+
+		dojo.widget.PopupMenu2.superclass.close.apply(this, arguments);
+	},
+
+	//overwrite the default one
+	closeSubpopup: function(force){
+		if (this.currentSubpopup == null){ return; }
+
+		this.currentSubpopup.close(force);
+		this.currentSubpopup = null;
+
+		this.currentSubmenuTrigger.is_open = false;
+		this.currentSubmenuTrigger.closedSubmenu(force);
+		this.currentSubmenuTrigger = null;
+	},
+
+	// open the menu to the right of the current menu item
+	openSubmenu: function(submenu, from_item){
+		var fromPos = dojo.html.getAbsolutePosition(from_item.domNode, true);
+		var our_w = dojo.html.getMarginBox(this.domNode).width;
+		var x = fromPos.x + our_w - this.submenuOverlap;
+		var y = fromPos.y;
+
+		//the following is set in open, so we do not need it
+		//this.currentSubpopup = submenu;
+		submenu.open(x, y, this, from_item.domNode);
+
+		this.currentSubmenuTrigger = from_item;
+		this.currentSubmenuTrigger.is_open = true;
+	},
+
+	onOpen: function(e){
+		this.openEvent = e;
+		if(e["target"]){
+			this.openedForWindow = dojo.html.getElementWindow(e.target);
+		}else{
+			this.openedForWindow = null;
+		}
+		var x = e.pageX, y = e.pageY;
+
+		var win = dojo.html.getElementWindow(e.target);
+		var iframe = win._frameElement || win.frameElement;
+		if(iframe){
+			var cood = dojo.html.abs(iframe, true);
+			x += cood.x - dojo.withGlobal(win, dojo.html.getScroll).left;
+			y += cood.y - dojo.withGlobal(win, dojo.html.getScroll).top;
+		}
+		this.open(x, y, null, [x, y]);
+
+		e.preventDefault();
+		e.stopPropagation();
+	}
+});
+
+dojo.widget.defineWidget(
+	"dojo.widget.MenuItem2",
+	dojo.widget.HtmlWidget,
+	function(){
+		this.eventNames = {
+			engage: ""
+		};
+	},
+{
+	// Make 4 columns
+	//   icon, label, accelerator-key, and right-arrow indicating sub-menu
+	templateString:
+		 '<tr class="dojoMenuItem2" dojoAttachEvent="onMouseOver: onHover; onMouseOut: onUnhover; onClick: _onClick; onKey:onKey;">'
+		+'<td><div class="${this.iconClass}" style="${this.iconStyle}"></div></td>'
+		+'<td tabIndex="-1" class="dojoMenuItem2Label">${this.caption}</td>'
+		+'<td class="dojoMenuItem2Accel">${this.accelKey}</td>'
+		+'<td><div class="dojoMenuItem2Submenu" style="display:${this.arrowDisplay};"></div></td>'
+		+'</tr>',
+
+	//
+	// internal settings
+	//
+
+	is_hovering: false,
+	hover_timer: null,
+	is_open: false,
+	topPosition: 0,
+
+	//
+	// options
+	//
+
+	caption: 'Untitled',
+	accelKey: '',
+	iconSrc: '',
+	iconClass: 'dojoMenuItem2Icon',
+	submenuId: '',
+	disabled: false,
+	eventNaming: "default",
+	highlightClass: 'dojoMenuItem2Hover',
+
+	postMixInProperties: function(){
+		this.iconStyle="";
+		if (this.iconSrc){
+			if ((this.iconSrc.toLowerCase().substring(this.iconSrc.length-4) == ".png") && (dojo.render.html.ie55 || dojo.render.html.ie60)){
+				this.iconStyle="filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='"+this.iconSrc+"', sizingMethod='image')";
+			}else{
+				this.iconStyle="background-image: url("+this.iconSrc+")";
+			}
+		}
+		this.arrowDisplay = this.submenuId ? 'block' : 'none';
+		dojo.widget.MenuItem2.superclass.postMixInProperties.apply(this, arguments);
+	},
+
+	fillInTemplate: function(){
+		dojo.html.disableSelection(this.domNode);
+
+		if (this.disabled){
+			this.setDisabled(true);
+		}
+
+		if (this.eventNaming == "default") {
+			for (var eventName in this.eventNames) {
+				this.eventNames[eventName] = this.widgetId+"/"+eventName;
+			}
+		}
+	},
+
+	onHover: function(){
+		//this is to prevent some annoying behavior when both mouse and keyboard are used
+		this.onUnhover();
+
+		if (this.is_hovering){ return; }
+		if (this.is_open){ return; }
+
+		if(this.parent._highlighted_option){
+			this.parent._highlighted_option.onUnhover();
+		}
+		this.parent.closeSubpopup();
+		this.parent._highlighted_option = this;
+		dojo.widget.PopupManager.setFocusedMenu(this.parent);
+
+		this.highlightItem();
+
+		if (this.is_hovering){ this.stopSubmenuTimer(); }
+		this.is_hovering = true;
+		this.startSubmenuTimer();
+	},
+
+	onUnhover: function(){
+		if(!this.is_open){ this.unhighlightItem(); }
+
+		this.is_hovering = false;
+
+		this.parent._highlighted_option = null;
+
+		if(this.parent.parentPopup){
+			dojo.widget.PopupManager.setFocusedMenu(this.parent.parentPopup);
+		}
+
+		this.stopSubmenuTimer();
+	},
+
+	// Internal function for clicks
+	_onClick: function(focus){
+		var displayingSubMenu = false;
+		if (this.disabled){ return false; }
+
+		if (this.submenuId){
+			if (!this.is_open){
+				this.stopSubmenuTimer();
+				this.openSubmenu();
+			}
+			displayingSubMenu = true;
+		}else{
+			// for some browsers the onMouseOut doesn't get called (?), so call it manually
+			this.onUnhover(); //only onUnhover when no submenu is available
+			this.parent.closeAll(true);
+		}
+
+		// user defined handler for click
+		this.onClick();
+
+		dojo.event.topic.publish(this.eventNames.engage, this);
+
+		if(displayingSubMenu && focus){
+			dojo.widget.getWidgetById(this.submenuId).highlightOption(1);
+		}
+		return;
+	},
+
+	// User defined function to handle clicks
+	// this default function call the parent
+	// menu's onItemClick
+	onClick: function() {
+		this.parent.onItemClick(this);
+	},
+
+	highlightItem: function(){
+		dojo.html.addClass(this.domNode, this.highlightClass);
+	},
+
+	unhighlightItem: function(){
+		dojo.html.removeClass(this.domNode, this.highlightClass);
+	},
+
+	startSubmenuTimer: function(){
+		this.stopSubmenuTimer();
+
+		if (this.disabled){ return; }
+
+		var self = this;
+		var closure = function(){ return function(){ self.openSubmenu(); } }();
+
+		this.hover_timer = dojo.lang.setTimeout(closure, this.parent.submenuDelay);
+	},
+
+	stopSubmenuTimer: function(){
+		if (this.hover_timer){
+			dojo.lang.clearTimeout(this.hover_timer);
+			this.hover_timer = null;
+		}
+	},
+
+	openSubmenu: function(){
+		// first close any other open submenu
+		this.parent.closeSubpopup();
+
+		var submenu = dojo.widget.getWidgetById(this.submenuId);
+		if (submenu){
+			this.parent.openSubmenu(submenu, this);
+		}
+	},
+
+	closedSubmenu: function(){
+		this.onUnhover();
+	},
+
+	setDisabled: function(value){
+		this.disabled = value;
+
+		if (this.disabled){
+			dojo.html.addClass(this.domNode, 'dojoMenuItem2Disabled');
+		}else{
+			dojo.html.removeClass(this.domNode, 'dojoMenuItem2Disabled');
+		}
+	},
+
+	enable: function(){
+		this.setDisabled(false);
+	},
+
+	disable: function(){
+		this.setDisabled(true);
+	},
+
+	menuOpen: function(message) {
+	}
+
+});
+
+dojo.widget.defineWidget(
+	"dojo.widget.MenuSeparator2",
+	dojo.widget.HtmlWidget,
+{
+	templateString: '<tr class="dojoMenuSeparator2"><td colspan=4>'
+			+'<div class="dojoMenuSeparator2Top"></div>'
+			+'<div class="dojoMenuSeparator2Bottom"></div>'
+			+'</td></tr>',
+
+	postCreate: function(){
+		dojo.html.disableSelection(this.domNode);
+	}
+});
+
+dojo.widget.defineWidget(
+	"dojo.widget.MenuBar2",
+	dojo.widget.PopupMenu2,
+{
+	menuOverlap: 2,
+
+	templateString: '<div class="dojoMenuBar2" tabIndex="0"><table class="dojoMenuBar2Client"><tr dojoAttachPoint="containerNode"></tr></table></div>',
+
+	close: function(force){
+		if(this._highlighted_option){
+			this._highlighted_option.onUnhover();
+		}
+
+		this.closeSubpopup(force);
+	},
+
+	processKey: function(evt){
+		if(evt.ctrlKey || evt.altKey){ return false; }
+
+		if (!dojo.html.hasClass(evt.target,"dojoMenuBar2")) { return false; }
+		var rval = false;
+
+		switch(evt.key){
+ 			case evt.KEY_DOWN_ARROW:
+				rval = this.moveToChildMenu(evt);
+				break;
+			case evt.KEY_UP_ARROW:
+				rval = this.moveToParentMenu(evt);
+				break;
+			case evt.KEY_RIGHT_ARROW:
+				rval = this.moveToNext(evt);
+				break;
+			case evt.KEY_LEFT_ARROW:
+				rval = this.moveToPrevious(evt);
+				break;
+			default:
+				rval = this.inherited("processKey", [evt]);
+				break;
+		}
+
+		return rval;
+	},
+
+	postCreate: function(){
+		this.inherited("postCreate");
+		dojo.widget.PopupManager.opened(this);
+		this.isShowingNow = true;
+	},
+
+	/*
+	 * override PopupMenu2 to open the submenu below us rather than to our right
+	 */
+	openSubmenu: function(submenu, from_item){
+		var fromPos = dojo.html.getAbsolutePosition(from_item.domNode, true);
+		var ourPos = dojo.html.getAbsolutePosition(this.domNode, true);
+		var our_h = dojo.html.getBorderBox(this.domNode).height;
+		var x = fromPos.x;
+		var y = ourPos.y + our_h - this.menuOverlap;
+
+		submenu.open(x, y, this, from_item.domNode);
+
+		this.currentSubmenuTrigger = from_item;
+		this.currentSubmenuTrigger.is_open = true;
+	}
+});
+
+dojo.widget.defineWidget(
+	"dojo.widget.MenuBarItem2",
+	dojo.widget.MenuItem2,
+{
+	templateString:
+		 '<td class="dojoMenuBarItem2" dojoAttachEvent="onMouseOver: onHover; onMouseOut: onUnhover; onClick: _onClick;">'
+		+'<span><span>${this.caption}</span>${this.caption}</span>'
+		+'</td>',
+
+	highlightClass: 'dojoMenuBarItem2Hover',
+
+	setDisabled: function(value){
+		this.disabled = value;
+		if (this.disabled){
+			dojo.html.addClass(this.domNode, 'dojoMenuBarItem2Disabled');
+		}else{
+			dojo.html.removeClass(this.domNode, 'dojoMenuBarItem2Disabled');
+		}
+	}
+});
+
+
+// ************************** make contextmenu work in konqueror and opera *********************
+dojo.widget.Menu2.OperaAndKonqFixer = new function(){
+ 	var implement = true;
+ 	var delfunc = false;
+
+ 	/** 	dom event check
+ 	*
+ 	*	make a event and dispatch it and se if it calls function below,
+ 	*	if it indeed is supported and we dont need to implement our own
+ 	*/
+
+ 	// gets called if we have support for oncontextmenu
+ 	if (!dojo.lang.isFunction(dojo.doc().oncontextmenu)){
+ 		dojo.doc().oncontextmenu = function(){
+ 			implement = false;
+ 			delfunc = true;
+ 		}
+ 	}
+
+ 	if (dojo.doc().createEvent){ // moz, safari has contextmenu event, need to do livecheck on this env.
+ 		try {
+ 			var e = dojo.doc().createEvent("MouseEvents");
+ 			e.initMouseEvent("contextmenu", 1, 1, dojo.global(), 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, null);
+ 			dojo.doc().dispatchEvent(e);
+ 		} catch (e) {/* assume not supported */}
+ 	} else {
+ 		// IE no need to implement custom contextmenu
+ 		implement = false;
+ 	}
+
+ 	// clear this one if it wasn't there before
+ 	if (delfunc){
+ 		delete dojo.doc().oncontextmenu;
+ 	}
+ 	/***** end dom event check *****/
+
+
+ 	/**
+ 	*	this fixes a dom node by attaching a custom oncontextmenu function that gets called when apropriate
+ 	*	@param	node	a dom node
+ 	*
+ 	*	no returns
+ 	*/
+ 	this.fixNode = function(node){
+ 		if (implement){
+ 			// attach stub oncontextmenu function
+ 			if (!dojo.lang.isFunction(node.oncontextmenu)){
+ 				node.oncontextmenu = function(e){/*stub*/}
+ 			}
+
+ 			// attach control function for oncontextmenu
+ 			if (dojo.render.html.opera){
+ 				// opera
+ 				// listen to ctrl-click events
+ 				node._menufixer_opera = function(e){
+ 					if (e.ctrlKey){
+ 						this.oncontextmenu(e);
+ 					}
+ 				};
+
+ 				dojo.event.connect(node, "onclick", node, "_menufixer_opera");
+
+ 			} else {
+ 				// konqueror
+ 				// rightclick, listen to mousedown events
+ 				node._menufixer_konq = function(e){
+ 					if (e.button==2 ){
+ 						e.preventDefault(); // need to prevent browsers menu
+ 						this.oncontextmenu(e);
+ 					}
+ 				};
+
+ 				dojo.event.connect(node, "onmousedown", node, "_menufixer_konq");
+ 			}
+ 		}
+ 	}
+
+ 	/**
+ 	*	this cleans up a fixed node, prevent memoryleak?
+ 	*	@param node	node to clean
+ 	*
+ 	*	no returns
+ 	*/
+ 	this.cleanNode = function(node){
+ 		if (implement){
+ 			// checks needed if we gets a non fixed node
+ 			if (node._menufixer_opera){
+ 				dojo.event.disconnect(node, "onclick", node, "_menufixer_opera");
+ 				delete node._menufixer_opera;
+ 			} else if(node._menufixer_konq){
+ 				dojo.event.disconnect(node, "onmousedown", node, "_menufixer_konq");
+ 				delete node._menufixer_konq;
+ 			}
+ 			if (node.oncontextmenu){
+ 				delete node.oncontextmenu;
+ 			}
+ 		}
+ 	}
+};
\ No newline at end of file

Propchange: tapestry/tapestry4/trunk/tapestry-framework/src/js/dojo/src/widget/Menu2.js
------------------------------------------------------------------------------
    svn:eol-style = native

Added: tapestry/tapestry4/trunk/tapestry-framework/src/js/dojo/src/widget/MonthlyCalendar.js
URL: http://svn.apache.org/viewvc/tapestry/tapestry4/trunk/tapestry-framework/src/js/dojo/src/widget/MonthlyCalendar.js?view=auto&rev=449122
==============================================================================
--- tapestry/tapestry4/trunk/tapestry-framework/src/js/dojo/src/widget/MonthlyCalendar.js (added)
+++ tapestry/tapestry4/trunk/tapestry-framework/src/js/dojo/src/widget/MonthlyCalendar.js Fri Sep 22 16:22:30 2006
@@ -0,0 +1,181 @@
+/*
+	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.MonthlyCalendar");
+dojo.require("dojo.date.common");
+dojo.require("dojo.date.format");
+dojo.require("dojo.widget.*");
+dojo.require("dojo.widget.DatePicker");
+dojo.require("dojo.event.*");
+dojo.require("dojo.html.*");
+
+dojo.widget.defineWidget(
+	"dojo.widget.MonthlyCalendar",
+	dojo.widget.DatePicker,
+	function(){
+		this.iCalendars = [];
+	},
+{
+	dayWidth: 'wide',
+
+	templatePath: dojo.uri.dojoUri("src/widget/templates/MonthlyCalendar.html"),
+	templateCssPath: dojo.uri.dojoUri("src/widget/templates/MonthlyCalendar.css"),
+
+	cache: function() {
+	},
+
+	addCalendar: function(/* dojo.iCalendar */ cal) {
+		dojo.debug("Adding Calendar");
+		this.iCalendars.push(cal);
+		dojo.debug("Starting init");
+		this.initUI();
+		dojo.debug("done init");
+	},
+
+	createDayContents: function(node,mydate) {
+		dojo.html.removeChildren(node);
+		node.appendChild(document.createTextNode(mydate.getDate()));	
+			for(var x=0; x<this.iCalendars.length; x++) {
+				var evts = this.iCalendars[x].getEvents(mydate);
+				if ((dojo.lang.isArray(evts)) && (evts.length>0)) {
+				for(var y=0;y<evts.length;y++) {
+					var el = document.createElement("div");
+					dojo.html.addClass(el, "dojoMonthlyCalendarEvent");          
+					el.appendChild(document.createTextNode(evts[y].summary.value));
+					el.width = dojo.html.getContentBox(node).width;
+					node.appendChild(el);
+				}
+			}
+		}
+	},
+
+	initUI: function() {
+		var dayLabels = dojo.date.getNames('days', this.dayWidth, 'standAlone', this.lang);
+		var dayLabelNodes = this.dayLabelsRow.getElementsByTagName("td");
+		for(var i=0; i<7; i++) {
+			dayLabelNodes.item(i).innerHTML = dayLabels[i];
+		}
+
+		this.selectedIsUsed = false;
+		this.currentIsUsed = false;
+		var currentClassName = "";
+		var previousDate = new Date();
+		var calendarNodes = this.calendarDatesContainerNode.getElementsByTagName("td");
+		var currentCalendarNode;
+		// set hours of date such that there is no chance of rounding error due to 
+		// time change in local time zones
+		previousDate.setHours(8);
+		var nextDate = new Date(this.firstSaturday.year, this.firstSaturday.month, this.firstSaturday.date, 8);
+		var lastDay = new Date(this.firstSaturday.year, this.firstSaturday.month, this.firstSaturday.date + 42, 8);
+		
+		if (this.iCalendars.length > 0) {
+			for (var x=0; x<this.iCalendars.length;x++) {
+				this.iCalendars[x].preComputeRecurringEvents(lastDay);
+			}
+		}
+
+		if(this.firstSaturday.date < 7) {
+			// this means there are days to show from the previous month
+			var dayInWeek = 6;
+			for (var i=this.firstSaturday.date; i>0; i--) {
+				currentCalendarNode = calendarNodes.item(dayInWeek);
+				this.createDayContents(currentCalendarNode, nextDate);
+				
+				dojo.html.setClass(currentCalendarNode, this.getDateClassName(nextDate, "current"));
+				dayInWeek--;
+				previousDate = nextDate;
+				nextDate = this.incrementDate(nextDate, false);
+			}
+			for(var i=dayInWeek; i>-1; i--) {
+				currentCalendarNode = calendarNodes.item(i);
+
+				this.createDayContents(currentCalendarNode, nextDate);
+
+				dojo.html.setClass(currentCalendarNode, this.getDateClassName(nextDate, "previous"));
+				previousDate = nextDate;
+				nextDate = this.incrementDate(nextDate, false);				
+			}
+		} else {
+			nextDate.setDate(1);
+			for(var i=0; i<7; i++) {
+				currentCalendarNode = calendarNodes.item(i);
+				this.createDayContents(currentCalendarNode, nextDate);
+				dojo.html.setClass(currentCalendarNode, this.getDateClassName(nextDate, "current"));
+				previousDate = nextDate;
+				nextDate = this.incrementDate(nextDate, true);				
+			}
+		}
+		previousDate.setDate(this.firstSaturday.date);
+		previousDate.setMonth(this.firstSaturday.month);
+		previousDate.setFullYear(this.firstSaturday.year);
+		nextDate = this.incrementDate(previousDate, true);
+		var count = 7;
+		currentCalendarNode = calendarNodes.item(count);
+		while((nextDate.getMonth() == previousDate.getMonth()) && (count<42)) {
+			this.createDayContents(currentCalendarNode, nextDate);
+			dojo.html.setClass(currentCalendarNode, this.getDateClassName(nextDate, "current"));
+			currentCalendarNode = calendarNodes.item(++count);
+			previousDate = nextDate;
+			nextDate = this.incrementDate(nextDate, true);
+		}
+		
+		while(count < 42) {
+			this.createDayContents(currentCalendarNode, nextDate);
+			dojo.html.setClass(currentCalendarNode, this.getDateClassName(nextDate, "next"));
+			currentCalendarNode = calendarNodes.item(++count);
+			previousDate = nextDate;
+			nextDate = this.incrementDate(nextDate, true);
+		}
+		this.setMonthLabel(this.firstSaturday.month);
+		this.setYearLabels(this.firstSaturday.year);
+	}	
+});
+
+dojo.widget.MonthlyCalendar.util= new function() {
+
+	this.toRfcDate = function(jsDate) {
+		if(!jsDate) {
+			jsDate = this.today;
+		}
+		var year = jsDate.getFullYear();
+		var month = jsDate.getMonth() + 1;
+		if (month < 10) {
+			month = "0" + month.toString();
+		}
+		var date = jsDate.getDate();
+		if (date < 10) {
+			date = "0" + date.toString();
+		}
+		// because this is a date picker and not a time picker, we treat time 
+		// as zero
+		return year + "-" + month + "-" + date + "T00:00:00+00:00";
+	}
+	
+	this.fromRfcDate = function(rfcDate) {
+		var tempDate = rfcDate.split("-");
+		if(tempDate.length < 3) {
+			return new Date();
+		}
+		// fullYear, month, date
+		return new Date(parseInt(tempDate[0]), (parseInt(tempDate[1], 10) - 1), parseInt(tempDate[2].substr(0,2), 10));
+	}
+
+//Note: redundant with dojo.widget.DatePicker.util	
+	this.initFirstSaturday = function(month, year) {
+		if(!month) {
+			month = this.date.getMonth();
+		}
+		if(!year) {
+			year = this.date.getFullYear();
+		}
+		var firstOfMonth = new Date(year, month, 1);
+		return {year: year, month: month, date: 7 - firstOfMonth.getDay()};
+	}
+}

Propchange: tapestry/tapestry4/trunk/tapestry-framework/src/js/dojo/src/widget/MonthlyCalendar.js
------------------------------------------------------------------------------
    svn:eol-style = native

Added: tapestry/tapestry4/trunk/tapestry-framework/src/js/dojo/src/widget/PageContainer.js
URL: http://svn.apache.org/viewvc/tapestry/tapestry4/trunk/tapestry-framework/src/js/dojo/src/widget/PageContainer.js?view=auto&rev=449122
==============================================================================
--- tapestry/tapestry4/trunk/tapestry-framework/src/js/dojo/src/widget/PageContainer.js (added)
+++ tapestry/tapestry4/trunk/tapestry-framework/src/js/dojo/src/widget/PageContainer.js Fri Sep 22 16:22:30 2006
@@ -0,0 +1,182 @@
+/*
+	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.PageContainer");
+
+dojo.require("dojo.lang.func");
+dojo.require("dojo.widget.*");
+dojo.require("dojo.event.*");
+dojo.require("dojo.html.selection");
+
+// A PageContainer is a container that has multiple panes, but shows only
+// one pane at a time.
+//
+// Publishes topics <widgetId>-addPane, <widgetId>-removePane, and <widgetId>-selectPane
+//
+// Can be base class for TabContainer, Wizard, etc.
+dojo.widget.defineWidget("dojo.widget.PageContainer", dojo.widget.HtmlWidget, {
+	isContainer: true,
+
+	// Boolean
+	//  if true, change the size of my currently displayed child to match my size
+	doLayout: true,
+
+	templateString: "<div dojoAttachPoint='containerNode'></div>",
+
+	// String
+	//   id of the initially shown page
+	selectedPage: "",
+
+	fillInTemplate: function(args, frag) {
+		// Copy style info from input node to output node
+		var source = this.getFragNodeRef(frag);
+		dojo.html.copyStyle(this.domNode, source);
+		dojo.widget.PageContainer.superclass.fillInTemplate.call(this, args, frag);
+	},
+
+	postCreate: function(args, frag) {
+		// Setup each page panel
+		dojo.lang.forEach(this.children, this._setupPage, this);
+
+		// Display the selected page
+		if(this.selectedPageWidget){
+			this.selectPage(this.selectedPageWidget, true);
+		}
+	},
+
+	addChild: function(child, overrideContainerNode, pos, ref, insertIndex){
+		this._setupPage(child);
+		dojo.widget.PageContainer.superclass.addChild.call(this,child, overrideContainerNode, pos, ref, insertIndex);
+
+		// in case the page labels have overflowed from one line to two lines
+		this.onResized();
+	},
+
+	_setupPage: function(page){
+		// Summary: Add the given pane to this page container
+		page.domNode.style.display="none";
+
+		if(!this.selectedPageWidget || this.selectedPage==page.widgetId || page.selected || (this.children.length==0)){
+			// Deselect old page and select new one
+			// We do this instead of calling selectPage in this case, because other wise other widgets
+			// listening for addChild and selectPage can run into a race condition
+			if(this.selectedPageWidget){
+				this._hidePage(this.selectedPageWidget);
+			}
+			this.selectedPageWidget = page;
+			this._showPage(page);
+
+		} else {
+			this._hidePage(page);
+		}
+
+		dojo.html.addClass(page.domNode, "selected");
+
+		// publish the addPane event for panes added via addChild(), and the original panes too
+		dojo.event.topic.publish(this.widgetId+"-addPane", page);
+	},
+
+	removeChild: function(/* Widget */page){
+		dojo.widget.PageContainer.superclass.removeChild.call(this, page);
+
+		// this will notify any tablists to remove a button; do this first because it may affect sizing
+		dojo.event.topic.publish(this.widgetId+"-removePane", page);
+
+		if (this.selectedPageWidget === page) {
+			this.selectedPageWidget = undefined;
+			if (this.children.length > 0) {
+				this.selectPage(this.children[0], true);
+			}
+		}
+	},
+
+	selectPage: function(/* Widget */ page, /* Boolean */ _noRefresh, /* Widget */ callingWidget){
+		// summary
+		//	Show the given widget (which must be one of my children)
+		page = dojo.widget.byId(page);
+		this.correspondingPageButton = callingWidget;
+
+		// Deselect old page and select new one
+		if(this.selectedPageWidget){
+			this._hidePage(this.selectedPageWidget);
+		}
+		this.selectedPageWidget = page;
+		this._showPage(page, _noRefresh);
+		page.isFirstPage = (page == this.children[0]);
+		page.isLastPage = (page == this.children[this.children.length-1]);
+		dojo.event.topic.publish(this.widgetId+"-selectPane", page);
+	},
+
+	nextPage: function(){
+		// Summary: advance to next page
+		var index = dojo.lang.find(this.children, this.selectedPageWidget);
+		this.selectPage(this.children[index+1]);
+	},
+
+	previousPage: function(){
+		// Summary: go back to previous page
+		var index = dojo.lang.find(this.children, this.selectedPageWidget);
+		this.selectPage(this.children[index-1]);
+	},
+
+	onResized: function(){
+		// Summary: called when any page is shown, to make it fit the container correctly
+		if(this.doLayout && this.selectedPageWidget){
+			with(this.selectedPageWidget.domNode.style){
+				top = dojo.html.getPixelValue(this.containerNode, "padding-top", true);
+				left = dojo.html.getPixelValue(this.containerNode, "padding-left", true);
+			}
+			var content = dojo.html.getContentBox(this.containerNode);
+			this.selectedPageWidget.resizeTo(content.width, content.height);
+		}
+	},
+
+	_showPage: function(page, _noRefresh) {
+		page.selected=true;
+
+		// size the current page (in case this is the first time it's being shown, or I have been resized)
+		this.onResized();
+
+		// make sure we dont refresh onClose and on postCreate
+		// speeds up things a bit when using refreshOnShow and fixes #646
+		if(_noRefresh && page.refreshOnShow){
+			var tmp = page.refreshOnShow;
+			page.refreshOnShow = false;
+			page.show();
+			page.refreshOnShow = tmp;
+		}else{
+			page.show();
+		}
+	},
+
+	_hidePage: function(page) {
+		page.selected=false;
+		page.hide();
+	},
+
+	closePage: function(page) {
+		// Summary:	callback when user tries to remove page from PageContainer
+		var onc = page.extraArgs.onClose || page.extraArgs.onclose;
+		var fcn = dojo.lang.isFunction(onc) ? onc : window[onc];
+		var remove = dojo.lang.isFunction(fcn) ? fcn(this,page) : true;
+		if(remove) {
+			this.removeChild(page);
+			// makes sure we can clean up executeScripts in ContentPane onUnLoad
+			page.destroy();
+		}
+	},
+
+	destroy: function(){
+		dojo.event.topic.destroy(this.widgetId+"-addPane");
+		dojo.event.topic.destroy(this.widgetId+"-removePane");
+		dojo.event.topic.destroy(this.widgetId+"-selectPane");
+		this.inherited("destroy");
+	}
+});

Propchange: tapestry/tapestry4/trunk/tapestry-framework/src/js/dojo/src/widget/PageContainer.js
------------------------------------------------------------------------------
    svn:eol-style = native

Added: tapestry/tapestry4/trunk/tapestry-framework/src/js/dojo/src/widget/Parse.js
URL: http://svn.apache.org/viewvc/tapestry/tapestry4/trunk/tapestry-framework/src/js/dojo/src/widget/Parse.js?view=auto&rev=449122
==============================================================================
--- tapestry/tapestry4/trunk/tapestry-framework/src/js/dojo/src/widget/Parse.js (added)
+++ tapestry/tapestry4/trunk/tapestry-framework/src/js/dojo/src/widget/Parse.js Fri Sep 22 16:22:30 2006
@@ -0,0 +1,333 @@
+/*
+	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.Parse");
+
+dojo.require("dojo.widget.Manager");
+dojo.require("dojo.dom");
+dojo.require("dojo.namespace");
+
+//
+// dojoML parser should be moved out of 'widget', codifying the difference between a 'component'
+// and a 'widget'. A 'component' being anything that can be generated from a tag.
+//
+// a particular dojoML tag would be handled by a registered tagHandler with a hook for a default handler
+// if the widget system is loaded, a widget builder would be attach itself as the default handler
+// 
+// widget tags are no longer registered themselves:
+// they are now arbitrarily namespaced, so we cannot register them all, and the non-prefixed portions 
+// are no longer guaranteed unique 
+// 
+// therefore dojo.widget.tags should go with this parser code out of the widget module
+//
+
+dojo.widget.Parse = function(fragment){
+	this.propertySetsList = [];
+	this.fragment = fragment;
+	
+	this.createComponents = function(frag, parentComp){
+		var comps = [];
+		var built = false;
+		// if we have items to parse/create at this level, do it!
+		try{
+			if((frag)&&(frag["tagName"])&&(frag!=frag["nodeRef"])){
+				
+				// these are in fact, not ever for widgets per-se anymore, 
+				// but for other markup elements (aka components)
+				var djTags = dojo.widget.tags;
+				
+				// we split so that you can declare multiple 
+				// non-destructive components from the same ctor node
+				var tna = String(frag["tagName"]).split(";");
+				for(var x=0; x<tna.length; x++){
+					var ltn = (tna[x].replace(/^\s+|\s+$/g, "")).toLowerCase();
+					// FIXME: unsure what this does
+					frag.tagName = ltn;
+					if(djTags[ltn]){
+						built = true;
+						var ret = djTags[ltn](frag, this, parentComp, frag["index"]);
+						comps.push(ret);
+					} else {
+						// we require a namespace prefix, default to dojo:
+						if (ltn.indexOf(":") == -1){
+							ltn = "dojo:"+ltn;
+						}
+						// FIXME: handling failure condition correctly?
+						//var ret = djTags[ltn](frag, this, parentComp, frag["index"]);
+						var ret = dojo.widget.buildWidgetFromParseTree(ltn, frag, this, parentComp, frag["index"]);
+						if (ret) {
+							built = true;
+							comps.push(ret);
+						}
+					}
+				}
+			}
+		}catch(e){
+		//	dojo.debug("dojo.widget.Parse: error:" + e);
+			 throw e;
+			// IE is such a bitch sometimes
+		}
+		// if there's a sub-frag, build widgets from that too
+		if(!built){
+			comps = comps.concat(this.createSubComponents(frag, parentComp));
+		}
+		return comps;
+	}
+
+	/*	createSubComponents recurses over a raw JavaScript object structure,
+			and calls the corresponding handler for its normalized tagName if it exists
+	*/
+	this.createSubComponents = function(fragment, parentComp){
+		var frag, comps = [];
+		for(var item in fragment){
+			frag = fragment[item];
+			if ((frag)&&(typeof frag == "object")&&(frag!=fragment.nodeRef)&&(frag!=fragment["tagName"])){
+				comps = comps.concat(this.createComponents(frag, parentComp));
+			}
+		}
+		return comps;
+	}
+
+	/*  parsePropertySets checks the top level of a raw JavaScript object
+			structure for any propertySets.  It stores an array of references to 
+			propertySets that it finds.
+	*/
+	this.parsePropertySets = function(fragment){
+		return [];
+		/*
+		var propertySets = [];
+		for(var item in fragment){
+			if((fragment[item]["tagName"] == "dojo:propertyset")){
+				propertySets.push(fragment[item]);
+			}
+		}
+		// FIXME: should we store these propertySets somewhere for later retrieval
+		this.propertySetsList.push(propertySets);
+		return propertySets;
+		*/
+	}
+	
+	/*  parseProperties checks a raw JavaScript object structure for
+			properties, and returns an array of properties that it finds.
+	*/
+	this.parseProperties = function(fragment){
+		var properties = {};
+		for(var item in fragment){
+			// FIXME: need to check for undefined?
+			// case: its a tagName or nodeRef
+			if((fragment[item] == fragment["tagName"])||(fragment[item] == fragment.nodeRef)){
+				// do nothing
+			}else{
+				if((fragment[item]["tagName"])&&
+					(dojo.widget.tags[fragment[item].tagName.toLowerCase()])){
+					// TODO: it isn't a property or property set, it's a fragment, 
+					// so do something else
+					// FIXME: needs to be a better/stricter check
+					// TODO: handle xlink:href for external property sets
+				}else if((fragment[item][0])&&(fragment[item][0].value!="")&&(fragment[item][0].value!=null)){
+					try{
+						// FIXME: need to allow more than one provider
+						if(item.toLowerCase() == "dataprovider") {
+							var _this = this;
+							this.getDataProvider(_this, fragment[item][0].value);
+							properties.dataProvider = this.dataProvider;
+						}
+						properties[item] = fragment[item][0].value;
+						var nestedProperties = this.parseProperties(fragment[item]);
+						// FIXME: this kind of copying is expensive and inefficient!
+						for(var property in nestedProperties){
+							properties[property] = nestedProperties[property];
+						}
+					}catch(e){ dojo.debug(e); }
+				}
+			}
+		}
+		return properties;
+	}
+
+	/* getPropertySetById returns the propertySet that matches the provided id
+	*/
+	
+	this.getDataProvider = function(objRef, dataUrl){
+		// FIXME: this is currently sync.  To make this async, we made need to move 
+		//this step into the widget ctor, so that it is loaded when it is needed 
+		// to populate the widget
+		dojo.io.bind({
+			url: dataUrl,
+			load: function(type, evaldObj){
+				if(type=="load"){
+					objRef.dataProvider = evaldObj;
+				}
+			},
+			mimetype: "text/javascript",
+			sync: true
+		});
+	}
+
+	
+	this.getPropertySetById = function(propertySetId){
+		for(var x = 0; x < this.propertySetsList.length; x++){
+			if(propertySetId == this.propertySetsList[x]["id"][0].value){
+				return this.propertySetsList[x];
+			}
+		}
+		return "";
+	}
+	
+	/* getPropertySetsByType returns the propertySet(s) that match(es) the
+	 * provided componentClass
+	 */
+	this.getPropertySetsByType = function(componentType){
+		var propertySets = [];
+		for(var x=0; x < this.propertySetsList.length; x++){
+			var cpl = this.propertySetsList[x];
+			var cpcc = cpl["componentClass"]||cpl["componentType"]||null;
+			var propertySetId = this.propertySetsList[x]["id"][0].value;
+			if((cpcc)&&(propertySetId == cpcc[0].value)){
+				propertySets.push(cpl);
+			}
+		}
+		return propertySets;
+	}
+	
+	/* getPropertySets returns the propertySet for a given component fragment
+	*/
+	this.getPropertySets = function(fragment){
+		var ppl = "dojo:propertyproviderlist";
+		var propertySets = [];
+		var tagname = fragment["tagName"];
+		if(fragment[ppl]){ 
+			var propertyProviderIds = fragment[ppl].value.split(" ");
+			// FIXME: should the propertyProviderList attribute contain #
+			// 		  syntax for reference to ids or not?
+			// FIXME: need a better test to see if this is local or external
+			// FIXME: doesn't handle nested propertySets, or propertySets that
+			// 		  just contain information about css documents, etc.
+			for(var propertySetId in propertyProviderIds){
+				if((propertySetId.indexOf("..")==-1)&&(propertySetId.indexOf("://")==-1)){
+					// get a reference to a propertySet within the current parsed structure
+					var propertySet = this.getPropertySetById(propertySetId);
+					if(propertySet != ""){
+						propertySets.push(propertySet);
+					}
+				}else{
+					// FIXME: add code to parse and return a propertySet from
+					// another document
+					// alex: is this even necessaray? Do we care? If so, why?
+				}
+			}
+		}
+		// we put the typed ones first so that the parsed ones override when
+		// iteration happens.
+		return (this.getPropertySetsByType(tagname)).concat(propertySets);
+	}
+	
+	/* 
+		nodeRef is the node to be replaced... in the future, we might want to add 
+		an alternative way to specify an insertion point
+
+		componentName is the expected dojo widget name, i.e. Button of ContextMenu
+
+		properties is an object of name value pairs
+		namespace is the namespace of the widget.  Defaults to "dojo"
+	*/
+	this.createComponentFromScript = function(nodeRef, componentName, properties, ns){
+		properties.fastMixIn = true;			
+		// FIXME: we pulled it apart and now we put it back together ... 
+		var ltn = (ns || "dojo") + ":" + componentName.toLowerCase();
+		if(dojo.widget.tags[ltn]){
+			return [dojo.widget.tags[ltn](properties, this, null, null, properties)];
+		}
+		return [dojo.widget.buildWidgetFromParseTree(ltn, properties, this, null, null, properties)];
+	}
+}
+
+dojo.widget._parser_collection = {"dojo": new dojo.widget.Parse() };
+dojo.widget.getParser = function(name){
+	if(!name){ name = "dojo"; }
+	if(!this._parser_collection[name]){
+		this._parser_collection[name] = new dojo.widget.Parse();
+	}
+	return this._parser_collection[name];
+}
+
+/**
+ * Creates widget.
+ *
+ * @param name     The name of the widget to create with optional namespace prefix,
+ *                 e.g."ns:widget", namespace defaults to "dojo".
+ * @param props    Key-Value pairs of properties of the widget
+ * @param refNode  If the position argument is specified, this node is used as
+ *                 a reference for inserting this node into a DOM tree; else
+ *                 the widget becomes the domNode
+ * @param position The position to insert this widget's node relative to the
+ *                 refNode argument
+ * @return The new Widget object
+ */
+
+dojo.widget.createWidget = function(name, props, refNode, position){
+	var isNode = false;
+	var isNameStr = (typeof name == "string");
+	if(isNameStr){
+		var pos = name.indexOf(":");
+		var ns = (pos > -1) ? name.substring(0,pos) : "dojo";
+		if(pos > -1){ name = name.substring(pos+1); }
+		var lowerCaseName = name.toLowerCase();
+		var namespacedName = ns + ":" + lowerCaseName;
+		isNode = (dojo.byId(name) && (!dojo.widget.tags[namespacedName])); 
+	}
+
+	if((arguments.length == 1) && ((isNode)||(!isNameStr))){
+		// we got a DOM node 
+		var xp = new dojo.xml.Parse(); 
+		// FIXME: we should try to find the parent! 
+		var tn = (isNode) ? dojo.byId(name) : name; 
+		return dojo.widget.getParser().createComponents(xp.parseElement(tn, null, true))[0]; 
+	}
+	
+	function fromScript(placeKeeperNode, name, props, ns){
+		props[namespacedName] = { 
+			dojotype: [{value: lowerCaseName}],
+			nodeRef: placeKeeperNode,
+			fastMixIn: true
+		};
+		props["namespace"] = ns;
+		return dojo.widget.getParser().createComponentFromScript(placeKeeperNode, name, props, ns);
+	}
+
+	props = props||{};
+	var notRef = false;
+	var tn = null;
+	var h = dojo.render.html.capable;
+	if(h){
+		tn = document.createElement("span");
+	}
+	if(!refNode){
+		notRef = true;
+		refNode = tn;
+		if(h){
+			dojo.body().appendChild(refNode);
+		}
+	}else if(position){
+		dojo.dom.insertAtPosition(tn, refNode, position);
+	}else{ // otherwise don't replace, but build in-place
+		tn = refNode;
+	}
+	var widgetArray = fromScript(tn, name.toLowerCase(), props, ns);
+	if (!widgetArray || !widgetArray[0] || typeof widgetArray[0].widgetType == "undefined") {
+		throw new Error("createWidget: Creation of \"" + name + "\" widget failed.");
+	}
+	if (notRef) {
+		if (widgetArray[0].domNode.parentNode) {
+			widgetArray[0].domNode.parentNode.removeChild(widgetArray[0].domNode);
+		}
+	}
+	return widgetArray[0]; // just return the widget
+}

Propchange: tapestry/tapestry4/trunk/tapestry-framework/src/js/dojo/src/widget/Parse.js
------------------------------------------------------------------------------
    svn:eol-style = native