You are viewing a plain text version of this content. The canonical link for it is here.
Posted to xap-commits@incubator.apache.org by mt...@apache.org on 2007/03/14 20:37:27 UTC

svn commit: r518313 [26/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...

Added: incubator/xap/trunk/codebase/src/dojo/src/validate/datetime.js
URL: http://svn.apache.org/viewvc/incubator/xap/trunk/codebase/src/dojo/src/validate/datetime.js?view=auto&rev=518313
==============================================================================
--- incubator/xap/trunk/codebase/src/dojo/src/validate/datetime.js (added)
+++ incubator/xap/trunk/codebase/src/dojo/src/validate/datetime.js Wed Mar 14 13:36:44 2007
@@ -0,0 +1,172 @@
+/*
+	Copyright (c) 2004-2006, The Dojo Foundation
+	All Rights Reserved.
+
+	Licensed under the Academic Free License version 2.1 or above OR the
+	modified BSD license. For more information on Dojo licensing, see:
+
+		http://dojotoolkit.org/community/licensing.shtml
+*/
+
+dojo.provide("dojo.validate.datetime");
+dojo.require("dojo.validate.common");
+
+/**
+  Validates a time value in any International format.
+  The value can be validated against one format or one of multiple formats.
+
+  Format
+  h        12 hour, no zero padding.
+  hh       12 hour, has leading zero.
+  H        24 hour, no zero padding.
+  HH       24 hour, has leading zero.
+  m        minutes, no zero padding.
+  mm       minutes, has leading zero.
+  s        seconds, no zero padding.
+  ss       seconds, has leading zero.
+  All other characters must appear literally in the expression.
+
+  Example
+    "h:m:s t"  ->   2:5:33 PM
+    "HH:mm:ss" ->  14:05:33
+
+  @param value  A string.
+  @param flags  An object.
+    flags.format  A string or an array of strings.  Default is "h:mm:ss t".
+    flags.amSymbol  The symbol used for AM.  Default is "AM".
+    flags.pmSymbol  The symbol used for PM.  Default is "PM".
+  @return  true or false
+*/
+dojo.validate.isValidTime = function(value, flags) {
+	dojo.deprecated("dojo.validate.datetime", "use dojo.date.parse instead", "0.5");
+	var re = new RegExp("^" + dojo.regexp.time(flags) + "$", "i");
+	return re.test(value);
+}
+
+/**
+  Validates 12-hour time format.
+  Zero-padding is not allowed for hours, required for minutes and seconds.
+  Seconds are optional.
+
+  @param value  A string.
+  @return  true or false
+*/
+dojo.validate.is12HourTime = function(value) {
+	dojo.deprecated("dojo.validate.datetime", "use dojo.date.parse instead", "0.5");
+	return dojo.validate.isValidTime(value, {format: ["h:mm:ss t", "h:mm t"]});
+}
+
+/**
+  Validates 24-hour military time format.
+  Zero-padding is required for hours, minutes, and seconds.
+  Seconds are optional.
+
+  @param value  A string.
+  @return  true or false
+*/
+dojo.validate.is24HourTime = function(value) {
+	dojo.deprecated("dojo.validate.datetime", "use dojo.date.parse instead", "0.5");
+	return dojo.validate.isValidTime(value, {format: ["HH:mm:ss", "HH:mm"]} );
+}
+
+/**
+  Returns true if the date conforms to the format given and is a valid date. Otherwise returns false.
+
+  @param dateValue  A string for the date.
+  @param format  A string, default is  "MM/DD/YYYY".
+  @return  true or false
+
+  Accepts any type of format, including ISO8601.
+  All characters in the format string are treated literally except the following tokens:
+
+  YYYY - matches a 4 digit year
+  M - matches a non zero-padded month
+  MM - matches a zero-padded month
+  D -  matches a non zero-padded date
+  DD -  matches a zero-padded date
+  DDD -  matches an ordinal date, 001-365, and 366 on leapyear
+  ww - matches week of year, 01-53
+  d - matches day of week, 1-7
+
+  Examples: These are all today's date.
+
+  Date          Format
+  2005-W42-3    YYYY-Www-d
+  2005-292      YYYY-DDD
+  20051019      YYYYMMDD
+  10/19/2005    M/D/YYYY
+  19.10.2005    D.M.YYYY
+*/
+dojo.validate.isValidDate = function(dateValue, format) {
+	dojo.deprecated("dojo.validate.datetime", "use dojo.date.parse instead", "0.5");
+	// Default is the American format
+	if (typeof format == "object" && typeof format.format == "string"){ format = format.format; }
+	if (typeof format != "string") { format = "MM/DD/YYYY"; }
+
+	// Create a literal regular expression based on format
+	var reLiteral = format.replace(/([$^.*+?=!:|\/\\\(\)\[\]\{\}])/g, "\\$1");
+
+	// Convert all the tokens to RE elements
+	reLiteral = reLiteral.replace( "YYYY", "([0-9]{4})" );
+	reLiteral = reLiteral.replace( "MM", "(0[1-9]|10|11|12)" );
+	reLiteral = reLiteral.replace( "M", "([1-9]|10|11|12)" );
+	reLiteral = reLiteral.replace( "DDD", "(00[1-9]|0[1-9][0-9]|[12][0-9][0-9]|3[0-5][0-9]|36[0-6])" );
+	reLiteral = reLiteral.replace( "DD", "(0[1-9]|[12][0-9]|30|31)" );
+	reLiteral = reLiteral.replace( "D", "([1-9]|[12][0-9]|30|31)" );
+	reLiteral = reLiteral.replace( "ww", "(0[1-9]|[1-4][0-9]|5[0-3])" );
+	reLiteral = reLiteral.replace( "d", "([1-7])" );
+
+	// Anchor pattern to begining and end of string
+	reLiteral = "^" + reLiteral + "$";
+
+	// Dynamic RE that parses the original format given
+	var re = new RegExp(reLiteral);
+	
+	// Test if date is in a valid format
+	if (!re.test(dateValue))  return false;
+
+	// Parse date to get elements and check if date is valid
+	// Assume valid values for date elements not given.
+	var year = 0, month = 1, date = 1, dayofyear = 1, week = 1, day = 1;
+
+	// Capture tokens
+	var tokens = format.match( /(YYYY|MM|M|DDD|DD|D|ww|d)/g );
+
+	// Capture date values
+	var values = re.exec(dateValue);
+
+	// Match up tokens with date values
+	for (var i = 0; i < tokens.length; i++) {
+		switch (tokens[i]) {
+		case "YYYY":
+			year = Number(values[i+1]); break;
+		case "M":
+		case "MM":
+			month = Number(values[i+1]); break;
+		case "D":
+		case "DD":
+			date = Number(values[i+1]); break;
+		case "DDD":
+			dayofyear = Number(values[i+1]); break;
+		case "ww":
+			week = Number(values[i+1]); break;
+		case "d":
+			day = Number(values[i+1]); break;
+		}
+	}
+
+	// Leap years are divisible by 4, but not by 100, unless by 400
+	var leapyear = (year % 4 == 0 && (year % 100 != 0 || year % 400 == 0));
+
+	// 31st of a month with 30 days
+	if (date == 31 && (month == 4 || month == 6 || month == 9 || month == 11)) return false; 
+
+	// February 30th or 31st
+	if (date >= 30 && month == 2) return false; 
+
+	// February 29th outside a leap year
+	if (date == 29 && month == 2 && !leapyear) return false; 
+	if (dayofyear == 366 && !leapyear)  return false;
+
+	return true;
+}

Added: incubator/xap/trunk/codebase/src/dojo/src/validate/de.js
URL: http://svn.apache.org/viewvc/incubator/xap/trunk/codebase/src/dojo/src/validate/de.js?view=auto&rev=518313
==============================================================================
--- incubator/xap/trunk/codebase/src/dojo/src/validate/de.js (added)
+++ incubator/xap/trunk/codebase/src/dojo/src/validate/de.js Wed Mar 14 13:36:44 2007
@@ -0,0 +1,26 @@
+/*
+	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.validate.de");
+dojo.require("dojo.validate.common");
+
+dojo.validate.isGermanCurrency = function(/*String*/value) {
+	//summary: checks to see if 'value' is a valid representation of German currency (Euros)
+	var flags = {
+		symbol: "\u20AC",
+		placement: "after",
+		signPlacement: "begin", //TODO: this is really locale-dependent.  Will get fixed in v0.5 currency rewrite. 
+		decimal: ",",
+		separator: "."
+	};
+	return dojo.validate.isCurrency(value, flags); // Boolean
+}
+
+

Added: incubator/xap/trunk/codebase/src/dojo/src/validate/jp.js
URL: http://svn.apache.org/viewvc/incubator/xap/trunk/codebase/src/dojo/src/validate/jp.js?view=auto&rev=518313
==============================================================================
--- incubator/xap/trunk/codebase/src/dojo/src/validate/jp.js (added)
+++ incubator/xap/trunk/codebase/src/dojo/src/validate/jp.js Wed Mar 14 13:36:44 2007
@@ -0,0 +1,23 @@
+/*
+	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.validate.jp");
+dojo.require("dojo.validate.common");
+
+dojo.validate.isJapaneseCurrency = function(/*String*/value) {
+	//summary: checks to see if 'value' is a valid representation of Japanese currency
+	var flags = {
+		symbol: "\u00a5",
+		fractional: false
+	};
+	return dojo.validate.isCurrency(value, flags); // Boolean
+}
+
+

Added: incubator/xap/trunk/codebase/src/dojo/src/validate/us.js
URL: http://svn.apache.org/viewvc/incubator/xap/trunk/codebase/src/dojo/src/validate/us.js?view=auto&rev=518313
==============================================================================
--- incubator/xap/trunk/codebase/src/dojo/src/validate/us.js (added)
+++ incubator/xap/trunk/codebase/src/dojo/src/validate/us.js Wed Mar 14 13:36:44 2007
@@ -0,0 +1,84 @@
+/*
+	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.validate.us");
+dojo.require("dojo.validate.common");
+
+dojo.validate.us.isCurrency = function(/*String*/value, /*Object?*/flags){
+	// summary: Validates U.S. currency
+	// value: the representation to check
+	// flags: flags in validate.isCurrency can be applied.
+	return dojo.validate.isCurrency(value, flags); // Boolean
+}
+
+
+dojo.validate.us.isState = function(/*String*/value, /*Object?*/flags){
+	// summary: Validates US state and territory abbreviations.
+	//
+	// value: A two character string
+	// flags: An object
+	//    flags.allowTerritories  Allow Guam, Puerto Rico, etc.  Default is true.
+	//    flags.allowMilitary  Allow military 'states', e.g. Armed Forces Europe (AE).  Default is true.
+
+	var re = new RegExp("^" + dojo.regexp.us.state(flags) + "$", "i");
+	return re.test(value); // Boolean
+}
+
+dojo.validate.us.isPhoneNumber = function(/*String*/value){
+	// summary: Validates 10 US digit phone number for several common formats
+	// value: The telephone number string
+
+	var flags = {
+		format: [
+			"###-###-####",
+			"(###) ###-####",
+			"(###) ### ####",
+			"###.###.####",
+			"###/###-####",
+			"### ### ####",
+			"###-###-#### x#???",
+			"(###) ###-#### x#???",
+			"(###) ### #### x#???",
+			"###.###.#### x#???",
+			"###/###-#### x#???",
+			"### ### #### x#???",
+			"##########"
+		]
+	};
+
+	return dojo.validate.isNumberFormat(value, flags); // Boolean
+}
+
+dojo.validate.us.isSocialSecurityNumber = function(/*String*/value){
+// summary: Validates social security number
+	var flags = {
+		format: [
+			"###-##-####",
+			"### ## ####",
+			"#########"
+		]
+	};
+
+	return dojo.validate.isNumberFormat(value, flags); // Boolean
+}
+
+dojo.validate.us.isZipCode = function(/*String*/value){
+// summary: Validates U.S. zip-code
+	var flags = {
+		format: [
+			"#####-####",
+			"##### ####",
+			"#########",
+			"#####"
+		]
+	};
+
+	return dojo.validate.isNumberFormat(value, flags); // Boolean
+}

Added: incubator/xap/trunk/codebase/src/dojo/src/validate/web.js
URL: http://svn.apache.org/viewvc/incubator/xap/trunk/codebase/src/dojo/src/validate/web.js?view=auto&rev=518313
==============================================================================
--- incubator/xap/trunk/codebase/src/dojo/src/validate/web.js (added)
+++ incubator/xap/trunk/codebase/src/dojo/src/validate/web.js Wed Mar 14 13:36:44 2007
@@ -0,0 +1,95 @@
+/*
+	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.validate.web");
+dojo.require("dojo.validate.common");
+
+dojo.validate.isIpAddress = function(/*String*/value, /*Object?*/flags) {
+	// summary: Validates an IP address
+	//
+	// description:
+	//  Supports 5 formats for IPv4: dotted decimal, dotted hex, dotted octal, decimal and hexadecimal.
+	//  Supports 2 formats for Ipv6.
+	//
+	// value  A string.
+	// flags  An object.  All flags are boolean with default = true.
+	//    flags.allowDottedDecimal  Example, 207.142.131.235.  No zero padding.
+	//    flags.allowDottedHex  Example, 0x18.0x11.0x9b.0x28.  Case insensitive.  Zero padding allowed.
+	//    flags.allowDottedOctal  Example, 0030.0021.0233.0050.  Zero padding allowed.
+	//    flags.allowDecimal  Example, 3482223595.  A decimal number between 0-4294967295.
+	//    flags.allowHex  Example, 0xCF8E83EB.  Hexadecimal number between 0x0-0xFFFFFFFF.
+	//      Case insensitive.  Zero padding allowed.
+	//    flags.allowIPv6   IPv6 address written as eight groups of four hexadecimal digits.
+	//    flags.allowHybrid   IPv6 address written as six groups of four hexadecimal digits
+	//      followed by the usual 4 dotted decimal digit notation of IPv4. x:x:x:x:x:x:d.d.d.d
+
+	var re = new RegExp("^" + dojo.regexp.ipAddress(flags) + "$", "i");
+	return re.test(value); // Boolean
+}
+
+
+dojo.validate.isUrl = function(/*String*/value, /*Object?*/flags) {
+	// summary: Checks if a string could be a valid URL
+	// value: A string
+	// flags: An object
+	//    flags.scheme  Can be true, false, or [true, false]. 
+	//      This means: required, not allowed, or either.
+	//    flags in regexp.host can be applied.
+	//    flags in regexp.ipAddress can be applied.
+	//    flags in regexp.tld can be applied.
+
+	var re = new RegExp("^" + dojo.regexp.url(flags) + "$", "i");
+	return re.test(value); // Boolean
+}
+
+dojo.validate.isEmailAddress = function(/*String*/value, /*Object?*/flags) {
+	// summary: Checks if a string could be a valid email address
+	//
+	// value: A string
+	// flags: An object
+	//    flags.allowCruft  Allow address like <ma...@yahoo.com>.  Default is false.
+	//    flags in regexp.host can be applied.
+	//    flags in regexp.ipAddress can be applied.
+	//    flags in regexp.tld can be applied.
+
+	var re = new RegExp("^" + dojo.regexp.emailAddress(flags) + "$", "i");
+	return re.test(value); // Boolean
+}
+
+dojo.validate.isEmailAddressList = function(/*String*/value, /*Object?*/flags) {
+	// summary: Checks if a string could be a valid email address list.
+	//
+	// value  A string.
+	// flags  An object.
+	//    flags.listSeparator  The character used to separate email addresses.  Default is ";", ",", "\n" or " ".
+	//    flags in regexp.emailAddress can be applied.
+	//    flags in regexp.host can be applied.
+	//    flags in regexp.ipAddress can be applied.
+	//    flags in regexp.tld can be applied.
+
+	var re = new RegExp("^" + dojo.regexp.emailAddressList(flags) + "$", "i");
+	return re.test(value); // Boolean
+}
+
+dojo.validate.getEmailAddressList = function(/*String*/value, /*Object?*/flags) {
+	// summary: Check if value is an email address list. If an empty list
+	//  is returned, the value didn't pass the test or it was empty.
+	//
+	// value: A string
+	// flags: An object (same as dojo.validate.isEmailAddressList)
+
+	if(!flags) { flags = {}; }
+	if(!flags.listSeparator) { flags.listSeparator = "\\s;,"; }
+
+	if ( dojo.validate.isEmailAddressList(value, flags) ) {
+		return value.split(new RegExp("\\s*[" + flags.listSeparator + "]\\s*")); // Array
+	}
+	return []; // Array
+}

Added: incubator/xap/trunk/codebase/src/dojo/src/widget/AccordionContainer.js
URL: http://svn.apache.org/viewvc/incubator/xap/trunk/codebase/src/dojo/src/widget/AccordionContainer.js?view=auto&rev=518313
==============================================================================
--- incubator/xap/trunk/codebase/src/dojo/src/widget/AccordionContainer.js (added)
+++ incubator/xap/trunk/codebase/src/dojo/src/widget/AccordionContainer.js Wed Mar 14 13:36:44 2007
@@ -0,0 +1,274 @@
+/*
+	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.AccordionContainer");
+
+dojo.require("dojo.widget.*");
+dojo.require("dojo.html.*");
+dojo.require("dojo.lfx.html");
+dojo.require("dojo.html.selection");
+dojo.require("dojo.widget.html.layout");
+dojo.require("dojo.widget.PageContainer");
+
+
+/**
+ * description
+ *	Front view (3 panes, pane #2 open)
+ *	------------------------
+ *	|:::Pane#1 title:::    |
+ * 	|:::Pane#2 title:::    |
+ *	|                      |
+ *	|    pane#2 contents   |
+ *	|                      |
+ *	|:::Pane#3 title:::    |
+ *	------------------------
+ *
+ *	Side view (showing implementation):
+ *
+ *         viewport    pane#3     pane#2     pane#1
+ *            =                                
+ *            |                                =
+ *            |                      =         |
+ *	front     |                      |         |
+ *            |                      |         =
+ *            |                      =
+ *            |          =
+ *            =          |
+ *                       |
+ *                       =
+ *
+ *	Panes are stacked by z-index like a stack of cards, so they can be slid correctly.
+ *	The panes on the bottom extend past the bottom of the viewport (but are hidden).
+ *
+ * usage
+ *	<div dojoType="AccordionContainer">
+ *		<div dojoType="ContentPane" label="pane 1">...</div>
+ *		...
+ *	</div>
+ *
+ * TODO:
+ *	* this widget should extend PageContainer
+ */
+ dojo.widget.defineWidget(
+	"dojo.widget.AccordionContainer",
+	dojo.widget.HtmlWidget,
+	{
+		// summary: 
+		//		Holds a set of panes where every pane's title is visible, but only one pane's content is visible at a time,
+		//		and switching between panes is visualized by sliding the other panes up/down.
+
+		isContainer: true,
+		
+		// labelNodeClass: String
+		//		CSS class name for dom node w/the title
+		labelNodeClass: "label",
+		
+		// containerNodeClass: String
+		//		CSS class name for dom node holding the content
+		containerNodeClass: "accBody",
+
+		// duration: Integer
+		//		Amount of time (in ms) it takes to slide panes
+		duration: 250,
+
+		fillInTemplate: function(){
+			with(this.domNode.style){
+				// position must be either relative or absolute
+				if(position!="absolute"){
+					position="relative";
+				}
+				overflow="hidden";
+			}
+		},
+
+		addChild: function(/*Widget*/ widget){
+			var child = this._addChild(widget);
+			this._setSizes();
+			return child;	// Widget
+		},
+		
+		_addChild: function(/*Widget*/ widget){
+			// summary
+			//		Internal call to add child, used during postCreate() and by the real addChild() call
+			if(widget.open){
+				dojo.deprecated("open parameter deprecated, use 'selected=true' instead will be removed in ", "0.5");
+				dojo.debug(widget.widgetId + ": open == " + widget.open);
+				widget.selected=true;
+			}
+			if (widget.widgetType != "AccordionPane") {
+				var wrapper=dojo.widget.createWidget("AccordionPane",{label: widget.label, selected: widget.selected, labelNodeClass: this.labelNodeClass, containerNodeClass: this.containerNodeClass, allowCollapse: this.allowCollapse });
+				wrapper.addChild(widget);
+				this.addWidgetAsDirectChild(wrapper);
+				this.registerChild(wrapper, this.children.length);
+				return wrapper;	// Widget
+			} else {
+				dojo.html.addClass(widget.containerNode, this.containerNodeClass);
+				dojo.html.addClass(widget.labelNode, this.labelNodeClass);
+				this.addWidgetAsDirectChild(widget);
+				this.registerChild(widget, this.children.length);	
+				return widget;	// Widget
+			}
+		},
+	
+		postCreate: function() {
+			var tmpChildren = this.children;
+			this.children=[];
+			dojo.html.removeChildren(this.domNode);
+			dojo.lang.forEach(tmpChildren, dojo.lang.hitch(this,"_addChild"));
+			this._setSizes();
+		},
+	
+		removeChild: function(/*Widget*/ widget) {
+			dojo.widget.AccordionContainer.superclass.removeChild.call(this, widget);
+			this._setSizes();
+		},
+		
+		onResized: function(){
+			this._setSizes();
+		},
+
+		_setSizes: function() {
+			// summary
+			//		Set panes' size/position based on my size, and the current open node.
+
+			// get cumulative height of all the title bars, and figure out which pane is open
+			var totalCollapsedHeight = 0;
+			var openIdx = 0;
+			dojo.lang.forEach(this.children, function(child, idx){
+				totalCollapsedHeight += child.getLabelHeight();
+				if(child.selected){ openIdx=idx; }
+			});
+
+			// size and position each pane
+			var mySize=dojo.html.getContentBox(this.domNode);
+			var y = 0;
+			dojo.lang.forEach(this.children, function(child, idx){
+				var childCollapsedHeight = child.getLabelHeight();
+				child.resizeTo(mySize.width, mySize.height-totalCollapsedHeight+childCollapsedHeight);
+				child.domNode.style.zIndex=idx+1;
+				child.domNode.style.position="absolute";
+				child.domNode.style.top = y+"px";
+				y += (idx==openIdx) ? dojo.html.getBorderBox(child.domNode).height : childCollapsedHeight;
+			});
+		},
+
+		selectChild: function(/*Widget*/ page){
+			// summary
+			//		close the current page and select a new one
+			dojo.lang.forEach(this.children, function(child){child.setSelected(child==page);});
+
+			// slide each pane that needs to be moved
+			var y = 0;
+			var anims = [];
+			dojo.lang.forEach(this.children, function(child, idx){
+				if(child.domNode.style.top != (y+"px")){
+					anims.push(dojo.lfx.html.slideTo(child.domNode, {top: y, left: 0}, this.duration));
+				}
+				y += child.selected ? dojo.html.getBorderBox(child.domNode).height : child.getLabelHeight();
+			}, this);
+			dojo.lfx.combine(anims).play();
+		}
+	}
+);
+
+dojo.widget.defineWidget(
+	"dojo.widget.AccordionPane",
+	dojo.widget.HtmlWidget,
+{
+	// summary
+	//		AccordionPane is a box with a title that contains another widget (often a ContentPane).
+	//		It's a widget used internally by AccordionContainer.
+	// label: String
+	//		label to print on top of AccordionPane
+	label: "",
+
+	// class: String
+	//	CSS class name for the AccordionPane's dom node
+	"class": "dojoAccordionPane",
+
+	// labelNodeClass: String
+	//	CSS class name for the AccordionPane's label node
+	labelNodeClass: "label",
+
+	// containerNodeClass: String
+	//	CSS class name for the AccordionPane's container node
+	containerNodeClass: "accBody",
+	
+	// selected: Boolean
+	//	if true, this is the open pane
+	selected: false,
+
+	templatePath: dojo.uri.dojoUri("src/widget/templates/AccordionPane.html"),
+	templateCssPath: dojo.uri.dojoUri("src/widget/templates/AccordionPane.css"),
+
+	isContainer: true,
+
+	fillInTemplate: function() {
+		dojo.html.addClass(this.domNode, this["class"]);
+		dojo.widget.AccordionPane.superclass.fillInTemplate.call(this);
+		dojo.html.disableSelection(this.labelNode);
+		this.setSelected(this.selected);
+	},
+
+	setLabel: function(/*String*/ label) {
+		// summary: set the  title of the node
+		this.labelNode.innerHTML=label;
+	},
+	
+	resizeTo: function(width, height){
+		dojo.html.setMarginBox(this.domNode, {width: width, height: height});
+		var children = [
+			{domNode: this.labelNode, layoutAlign: "top"},
+			{domNode: this.containerNode, layoutAlign: "client"}
+		];
+		dojo.widget.html.layout(this.domNode, children);
+		var childSize = dojo.html.getContentBox(this.containerNode);
+		this.children[0].resizeTo(childSize.width, childSize.height);
+	},
+
+	getLabelHeight: function() {
+		// summary: returns the height of the title dom node
+		return dojo.html.getMarginBox(this.labelNode).height;	// Integer
+	},
+
+	onLabelClick: function() {
+		// summary: callback when someone clicks my label
+		this.parent.selectChild(this);
+	},
+	
+	setSelected: function(/*Boolean*/ isSelected){
+		this.selected=isSelected;
+		(isSelected ? dojo.html.addClass : dojo.html.removeClass)(this.domNode, this["class"]+"-selected");
+
+		// make sure child is showing (lazy load), and also that onShow()/onHide() is called
+		var child = this.children[0];
+		if(child){
+			if(isSelected){
+				if(!child.isShowing()){
+					child.show();
+				}else{
+					child.onShow();
+				}
+			}else{
+				child.onHide();
+			}
+		}
+	}
+});
+
+// These arguments can be specified for the children of an AccordionContainer
+// Since any widget can be specified as a child, mix them
+// into the base widget class.  (This is a hack, but it's effective.)
+dojo.lang.extend(dojo.widget.Widget, {
+	// open: String
+	//	is this the selected child?
+	//	DEPRECATED: will be removed in 0.5.  Used "selected" attribute instead.
+	open: false
+});

Added: incubator/xap/trunk/codebase/src/dojo/src/widget/AnimatedPng.js
URL: http://svn.apache.org/viewvc/incubator/xap/trunk/codebase/src/dojo/src/widget/AnimatedPng.js?view=auto&rev=518313
==============================================================================
--- incubator/xap/trunk/codebase/src/dojo/src/widget/AnimatedPng.js (added)
+++ incubator/xap/trunk/codebase/src/dojo/src/widget/AnimatedPng.js Wed Mar 14 13:36:44 2007
@@ -0,0 +1,98 @@
+/*
+	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.AnimatedPng");
+
+dojo.require("dojo.widget.*");
+dojo.require("dojo.widget.HtmlWidget");
+
+// usage
+//	<img dojoType="AnimatedPng"
+//		src="images/animatedpng_static.gif"		(for degradation; in case javascript is disabled)
+//		aniSrc="images/animatedpng_frames.gif"
+//		width="20"
+//		height="20"
+//		interval="50"
+//	/>
+//
+//	var params = {src: "images/animatedpng_static.gif", aniSrc: "images/animatedpng_frames.gif", width: 20, height: 20, interval: 50};
+//	var widget = dojo.widget.createWidget("AnimatedPng", params, document.getElementById("pngContainer"));
+//
+dojo.widget.defineWidget(
+	"dojo.widget.AnimatedPng",
+	dojo.widget.HtmlWidget,
+	{
+		// summary
+		//	PNGs have great tranparency, but lack animation.
+		//	This widget lets you point an img tag at an animated gif for graceful degrading,
+		//	while letting you specify a png containing a grid of cells to animate between.
+
+		isContainer: false,
+
+		// width: Integer
+		//	width (of each frame) in pixels
+		width: 0,
+		
+		// height: Integer
+		//	height (of each frame) in pixels
+		height: 0,
+		
+		// aniSrc: String
+		//	pathname to png file containing frames to be animated (ie, displayed sequentially)
+		aniSrc: '',
+		
+		// interval: Integer
+		//	time to display each frame
+		interval: 100,
+
+		_blankSrc: dojo.uri.dojoUri("src/widget/templates/images/blank.gif"),
+
+		templateString: '<img class="dojoAnimatedPng" />',
+
+		postCreate: function(){
+			this.cellWidth = this.width;
+			this.cellHeight = this.height;
+
+			var img = new Image();
+			var self = this;
+
+			img.onload = function(){ self._initAni(img.width, img.height); };
+			img.src = this.aniSrc;
+		},
+
+		_initAni: function(w, h){
+			this.domNode.src = this._blankSrc;
+			this.domNode.width = this.cellWidth;
+			this.domNode.height = this.cellHeight;
+			this.domNode.style.backgroundImage = 'url('+this.aniSrc+')';
+			this.domNode.style.backgroundRepeat = 'no-repeat';
+
+			this.aniCols = Math.floor(w/this.cellWidth);
+			this.aniRows = Math.floor(h/this.cellHeight);
+			this.aniCells = this.aniCols * this.aniRows;
+			this.aniFrame = 0;
+
+			window.setInterval(dojo.lang.hitch(this, '_tick'), this.interval);
+		},
+
+		_tick: function(){
+			this.aniFrame++;
+			if (this.aniFrame == this.aniCells) this.aniFrame = 0;
+
+			var col = this.aniFrame % this.aniCols;
+			var row = Math.floor(this.aniFrame / this.aniCols);
+
+			var bx = -1 * col * this.cellWidth;
+			var by = -1 * row * this.cellHeight;
+
+			this.domNode.style.backgroundPosition = bx+'px '+by+'px';
+		}
+	}
+);

Added: incubator/xap/trunk/codebase/src/dojo/src/widget/Button.js
URL: http://svn.apache.org/viewvc/incubator/xap/trunk/codebase/src/dojo/src/widget/Button.js?view=auto&rev=518313
==============================================================================
--- incubator/xap/trunk/codebase/src/dojo/src/widget/Button.js (added)
+++ incubator/xap/trunk/codebase/src/dojo/src/widget/Button.js Wed Mar 14 13:36:44 2007
@@ -0,0 +1,431 @@
+/*
+	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.Button");
+
+dojo.require("dojo.lang.extras");
+dojo.require("dojo.html.*");
+dojo.require("dojo.html.selection");
+dojo.require("dojo.widget.*");
+
+/*
+ * usage
+ *	<button dojoType="button" onClick="...">Hello world</button>
+ *
+ *  var button1 = dojo.widget.createWidget("Button", {caption: "hello world", onClick: foo});
+ *	document.body.appendChild(button1.domNode);
+ */
+dojo.widget.defineWidget(
+	"dojo.widget.Button",
+	dojo.widget.HtmlWidget,
+	{
+		// summary
+		//	Basically the same thing as a normal HTML button, but with special styling.
+
+		isContainer: true,
+
+		// caption: String
+		//	text to display in button
+		caption: "",
+		
+		templatePath: dojo.uri.dojoUri("src/widget/templates/ButtonTemplate.html"),
+		templateCssPath: dojo.uri.dojoUri("src/widget/templates/ButtonTemplate.css"),
+		
+		// inactiveImg: Url
+		//	prefix of filename holding images (left, center, right) for button in normal state
+		inactiveImg: "src/widget/templates/images/soriaButton-",
+		
+		// activeImg: Url
+		//	prefix of filename holding images (left, center, right) for button when it's being hovered over
+		activeImg: "src/widget/templates/images/soriaActive-",
+
+		// pressedImg: Url
+		//	prefix of filename holding images (left, center, right) for button between mouse-down and mouse-up
+		pressedImg: "src/widget/templates/images/soriaPressed-",
+
+		// disabledImg: Url
+		//	prefix of filename holding images (left, center, right) for button when it's disabled (aka, grayed-out)
+		disabledImg: "src/widget/templates/images/soriaDisabled-",
+		
+		// widget2height: Number
+		//	shape of the button's end pieces;
+		//	the height of the end pieces is a function of the button's height (which in turn is a function of the button's content),
+		//	and then the width of the end pieces is relative to their height.
+		width2height: 1.0/3.0,
+
+		fillInTemplate: function(){
+			if(this.caption){
+				this.containerNode.appendChild(document.createTextNode(this.caption));
+			}
+			dojo.html.disableSelection(this.containerNode);
+		},
+
+		postCreate: function(){
+			this._sizeMyself();
+		},
+	
+		_sizeMyself: function(){
+			// we cannot size correctly if any of our ancestors are hidden (display:none),
+			// so temporarily attach to document.body
+			if(this.domNode.parentNode){
+				var placeHolder = document.createElement("span");
+				dojo.html.insertBefore(placeHolder, this.domNode);
+			}
+			dojo.body().appendChild(this.domNode);
+			
+			this._sizeMyselfHelper();
+			
+			// Put this.domNode back where it was originally
+			if(placeHolder){
+				dojo.html.insertBefore(this.domNode, placeHolder);
+				dojo.html.removeNode(placeHolder);
+			}
+		},
+
+		_sizeMyselfHelper: function(){
+			var mb = dojo.html.getMarginBox(this.containerNode);
+			this.height = mb.height;
+			this.containerWidth = mb.width;
+			var endWidth= this.height * this.width2height;
+	
+			this.containerNode.style.left=endWidth+"px";
+	
+			this.leftImage.height = this.rightImage.height = this.centerImage.height = this.height;
+			this.leftImage.width = this.rightImage.width = endWidth+1;
+			this.centerImage.width = this.containerWidth;
+			this.centerImage.style.left=endWidth+"px";
+			this._setImage(this.disabled ? this.disabledImg : this.inactiveImg);
+
+			if ( this.disabled ) {
+				dojo.html.prependClass(this.domNode, "dojoButtonDisabled");
+				this.domNode.removeAttribute("tabIndex");
+				dojo.widget.wai.setAttr(this.domNode, "waiState", "disabled", true);
+			} else {
+				dojo.html.removeClass(this.domNode, "dojoButtonDisabled");
+				this.domNode.setAttribute("tabIndex", "0");
+				dojo.widget.wai.setAttr(this.domNode, "waiState", "disabled", false);
+			}
+				
+			this.domNode.style.height=this.height + "px";
+			this.domNode.style.width= (this.containerWidth+2*endWidth) + "px";
+		},
+	
+		onMouseOver: function(/*Event*/ e){
+			// summary: callback when user mouses-over the button
+			if( this.disabled ){ return; }
+			dojo.html.prependClass(this.buttonNode, "dojoButtonHover");
+			this._setImage(this.activeImg);
+		},
+	
+		onMouseDown: function(/*Event*/ e){
+			// summary: callback when user starts to click the button
+			if( this.disabled ){ return; }
+			dojo.html.prependClass(this.buttonNode, "dojoButtonDepressed");
+			dojo.html.removeClass(this.buttonNode, "dojoButtonHover");
+			this._setImage(this.pressedImg);
+		},
+
+		onMouseUp: function(/*Event*/ e){
+			// summary: callback when the user finishes clicking
+			if( this.disabled ){ return; }
+			dojo.html.prependClass(this.buttonNode, "dojoButtonHover");
+			dojo.html.removeClass(this.buttonNode, "dojoButtonDepressed");
+			this._setImage(this.activeImg);
+		},
+	
+		onMouseOut: function(/*Event*/ e){
+			// summary: callback when the user moves the mouse off the button
+			if( this.disabled ){ return; }
+			if( e.toElement && dojo.html.isDescendantOf(e.toElement, this.buttonNode) ){
+				return; // Ignore IE mouseOut events that dont actually leave button - Prevents hover image flicker in IE
+			}
+			dojo.html.removeClass(this.buttonNode, "dojoButtonHover");
+			dojo.html.removeClass(this.buttonNode, "dojoButtonDepressed");
+			this._setImage(this.inactiveImg);
+		},
+
+		onKey: function(/*Event*/ e){
+			// summary: callback when the user presses a key (on key-down)
+			if (!e.key) { return; }
+			var menu = dojo.widget.getWidgetById(this.menuId);
+			if (e.key == e.KEY_ENTER || e.key == " "){
+				this.onMouseDown(e);
+				this.buttonClick(e);
+				dojo.lang.setTimeout(this, "onMouseUp", 75, e);
+				dojo.event.browser.stopEvent(e);
+			}
+			if(menu && menu.isShowingNow && e.key == e.KEY_DOWN_ARROW){
+				// disconnect onBlur when focus moves into menu
+				dojo.event.disconnect(this.domNode, "onblur", this, "onBlur");
+				// allow event to propagate to menu
+			}
+		},
+
+		onFocus: function(/*Event*/ e){
+			// summary: callback on focus to the button
+			var menu = dojo.widget.getWidgetById(this.menuId);
+			if (menu){
+				dojo.event.connectOnce(this.domNode, "onblur", this, "onBlur");
+			}
+		},
+
+		onBlur: function(/*Event*/ e){
+			// summary: callback when button loses focus
+			var menu = dojo.widget.getWidgetById(this.menuId);
+			if ( !menu ) { return; }
+	
+			if ( menu.close && menu.isShowingNow ){
+				menu.close();
+			}
+		},
+
+		buttonClick: function(/*Event*/ e){
+			// summary: internal function for handling button clicks
+			if(!this.disabled){ 
+				// focus may fail when tabIndex is not supported on div's
+				// by the browser, or when the node is disabled
+				try { this.domNode.focus(); } catch(e2) {};
+				this.onClick(e); 
+			}
+		},
+
+		onClick: function(/*Event*/ e) {
+			// summary: callback for when button is clicked; user can override this function
+		},
+
+		_setImage: function(/*String*/ prefix){
+			this.leftImage.src=dojo.uri.dojoUri(prefix + "l.gif");
+			this.centerImage.src=dojo.uri.dojoUri(prefix + "c.gif");
+			this.rightImage.src=dojo.uri.dojoUri(prefix + "r.gif");
+		},
+		
+		_toggleMenu: function(/*String*/ menuId){
+			var menu = dojo.widget.getWidgetById(menuId); 
+			if ( !menu ) { return; }
+			if ( menu.open && !menu.isShowingNow) {
+				var pos = dojo.html.getAbsolutePosition(this.domNode, false);
+				menu.open(pos.x, pos.y+this.height, this);
+			} else if ( menu.close && menu.isShowingNow ){
+				menu.close();
+			} else {
+				menu.toggle();
+			}
+		},
+		
+		setCaption: function(/*String*/ content){
+			// summary: reset the caption (text) of the button; takes an HTML string
+			this.caption=content;
+			this.containerNode.innerHTML=content;
+			this._sizeMyself();
+		},
+		
+		setDisabled: function(/*Boolean*/ disabled){
+			// summary: set disabled state of button
+			this.disabled=disabled;
+			this._sizeMyself();
+		}
+	});
+
+/*
+ * usage
+ *	<button dojoType="DropDownButton" menuId="mymenu">Hello world</button>
+ *
+ *  var button1 = dojo.widget.createWidget("DropDownButton", {caption: "hello world", menuId: foo});
+ *	document.body.appendChild(button1.domNode);
+ */
+dojo.widget.defineWidget(
+	"dojo.widget.DropDownButton",
+	dojo.widget.Button,
+	{
+		// summary
+		//		push the button and a menu shows up
+		// menuId: String
+		//	widget id of the menu that this button should activate
+		menuId: "",
+
+		// downArrow: Url
+		//	path of arrow image to display to the right of the button text
+		downArrow: "src/widget/templates/images/whiteDownArrow.gif",
+
+		// disabledDownArray: Url
+		//	path of arrow image to display to the right of the button text, when the button is disabled
+		disabledDownArrow: "src/widget/templates/images/whiteDownArrow.gif",
+	
+		fillInTemplate: function(){
+			dojo.widget.DropDownButton.superclass.fillInTemplate.apply(this, arguments);
+	
+			this.arrow = document.createElement("img");
+			dojo.html.setClass(this.arrow, "downArrow");
+
+			dojo.widget.wai.setAttr(this.domNode, "waiState", "haspopup", this.menuId);
+		},
+
+		_sizeMyselfHelper: function(){
+			// draw the arrow (todo: why is the arror in containerNode rather than outside it?)
+			this.arrow.src = dojo.uri.dojoUri(this.disabled ? this.disabledDownArrow : this.downArrow);
+			this.containerNode.appendChild(this.arrow);
+
+			dojo.widget.DropDownButton.superclass._sizeMyselfHelper.call(this);
+		},
+
+		onClick: function(/*Event*/ e){
+			// summary: callback when button is clicked; user shouldn't override this function or else the menu won't toggle
+			this._toggleMenu(this.menuId);
+		}
+	});
+
+/*
+ * usage
+ *	<button dojoType="ComboButton" onClick="..." menuId="mymenu">Hello world</button>
+ *
+ *  var button1 = dojo.widget.createWidget("DropDownButton", {caption: "hello world", onClick: foo, menuId: "myMenu"});
+ *	document.body.appendChild(button1.domNode);
+ */
+dojo.widget.defineWidget(
+	"dojo.widget.ComboButton",
+	dojo.widget.Button,
+	{
+		// summary
+		//		left side is normal button, right side displays menu
+		// menuId: String
+		//	widget id of the menu that this button should activate
+		menuId: "",
+	
+		templatePath: dojo.uri.dojoUri("src/widget/templates/ComboButtonTemplate.html"),
+	
+		// splitWidth: Integer
+		//	# of pixels between left & right part of button
+		splitWidth: 2,
+		
+		// arrowWidth: Integer
+		//	width of segment holding down arrow
+		arrowWidth: 5,
+	
+		_sizeMyselfHelper: function(/*Event*/ e){
+			var mb = dojo.html.getMarginBox(this.containerNode);
+			this.height = mb.height;
+			this.containerWidth = mb.width;
+
+			var endWidth= this.height/3;
+
+			if(this.disabled){
+				dojo.widget.wai.setAttr(this.domNode, "waiState", "disabled", true);
+				this.domNode.removeAttribute("tabIndex");
+			}
+			else {
+				dojo.widget.wai.setAttr(this.domNode, "waiState", "disabled", false);
+				this.domNode.setAttribute("tabIndex", "0");
+			}
+	
+			// left part
+			this.leftImage.height = this.rightImage.height = this.centerImage.height = 
+				this.arrowBackgroundImage.height = this.height;
+			this.leftImage.width = endWidth+1;
+			this.centerImage.width = this.containerWidth;
+			this.buttonNode.style.height = this.height + "px";
+			this.buttonNode.style.width = endWidth + this.containerWidth + "px";
+			this._setImage(this.disabled ? this.disabledImg : this.inactiveImg);
+
+			// right part
+			this.arrowBackgroundImage.width=this.arrowWidth;
+			this.rightImage.width = endWidth+1;
+			this.rightPart.style.height = this.height + "px";
+			this.rightPart.style.width = this.arrowWidth + endWidth + "px";
+			this._setImageR(this.disabled ? this.disabledImg : this.inactiveImg);
+	
+			// outer container
+			this.domNode.style.height=this.height + "px";
+			var totalWidth = this.containerWidth+this.splitWidth+this.arrowWidth+2*endWidth;
+			this.domNode.style.width= totalWidth + "px";
+		},
+	
+		_setImage: function(prefix){
+			this.leftImage.src=dojo.uri.dojoUri(prefix + "l.gif");
+			this.centerImage.src=dojo.uri.dojoUri(prefix + "c.gif");
+		},
+	
+		/*** functions on right part of button ***/
+		rightOver: function(/*Event*/ e){
+			// summary:
+			//	callback when mouse-over right part of button;
+			//	onMouseOver() is the callback for the left side of the button.
+			if( this.disabled ){ return; }
+			dojo.html.prependClass(this.rightPart, "dojoButtonHover");
+			this._setImageR(this.activeImg);
+		},
+	
+		rightDown: function(/*Event*/ e){
+			// summary:
+			//	callback when mouse-down right part of button;
+			//	onMouseDown() is the callback for the left side of the button.
+			if( this.disabled ){ return; }
+			dojo.html.prependClass(this.rightPart, "dojoButtonDepressed");
+			dojo.html.removeClass(this.rightPart, "dojoButtonHover");
+			this._setImageR(this.pressedImg);
+		},
+
+		rightUp: function(/*Event*/ e){
+			// summary:
+			//	callback when mouse-up right part of button;
+			//	onMouseUp() is the callback for the left side of the button.
+			if( this.disabled ){ return; }
+			dojo.html.prependClass(this.rightPart, "dojoButtonHover");
+			dojo.html.removeClass(this.rightPart, "dojoButtonDepressed");
+			this._setImageR(this.activeImg);
+		},
+	
+		rightOut: function(/*Event*/ e){
+			// summary:
+			//	callback when moving the mouse off of the right part of button;
+			//	onMouseOut() is the callback for the left side of the button.
+			if( this.disabled ){ return; }
+			dojo.html.removeClass(this.rightPart, "dojoButtonHover");
+			dojo.html.removeClass(this.rightPart, "dojoButtonDepressed");
+			this._setImageR(this.inactiveImg);
+		},
+
+		rightClick: function(/*Event*/ e){
+			// summary:
+			//	callback when clicking the right part of button;
+			//	onClick() is the callback for the left side of the button.
+			if( this.disabled ){ return; }
+			// focus may fail when tabIndex is not supported on div's
+			// by the browser, or when the node is disabled
+			try { this.domNode.focus(); } catch(e2) {};
+			this._toggleMenu(this.menuId);
+		},
+	
+		_setImageR: function(prefix){
+			this.arrowBackgroundImage.src=dojo.uri.dojoUri(prefix + "c.gif");
+			this.rightImage.src=dojo.uri.dojoUri(prefix + "r.gif");
+		},
+
+		/*** keyboard functions ***/
+		
+		onKey: function(/*Event*/ e){
+			if (!e.key) { return; }
+			var menu = dojo.widget.getWidgetById(this.menuId);
+			if(e.key== e.KEY_ENTER || e.key == " "){
+				this.onMouseDown(e);
+				this.buttonClick(e);
+				dojo.lang.setTimeout(this, "onMouseUp", 75, e);
+				dojo.event.browser.stopEvent(e);
+			} else if (e.key == e.KEY_DOWN_ARROW && e.altKey){
+				this.rightDown(e);
+				this.rightClick(e);
+				dojo.lang.setTimeout(this, "rightUp", 75, e);
+				dojo.event.browser.stopEvent(e);
+			} else if(menu && menu.isShowingNow && e.key == e.KEY_DOWN_ARROW){
+				// disconnect onBlur when focus moves into menu
+				dojo.event.disconnect(this.domNode, "onblur", this, "onBlur");
+				// allow event to propagate to menu
+			}
+		}
+	});

Added: incubator/xap/trunk/codebase/src/dojo/src/widget/Chart.js
URL: http://svn.apache.org/viewvc/incubator/xap/trunk/codebase/src/dojo/src/widget/Chart.js?view=auto&rev=518313
==============================================================================
--- incubator/xap/trunk/codebase/src/dojo/src/widget/Chart.js (added)
+++ incubator/xap/trunk/codebase/src/dojo/src/widget/Chart.js Wed Mar 14 13:36:44 2007
@@ -0,0 +1,257 @@
+/*
+	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.Chart");
+
+dojo.require("dojo.widget.*");
+dojo.require("dojo.gfx.color");
+dojo.require("dojo.gfx.color.hsl");
+
+dojo.declare(
+	"dojo.widget.Chart",
+	null,
+	function(){
+		// summary: Base class for svg and vml implementations of Chart
+		this.series = [];
+	},
+{
+	isContainer: false,
+
+	assignColors: function(){
+		//	summary
+		//	Assigns/generates a color for a data series.
+		var hue=30;
+		var sat=120;
+		var lum=120;
+		var steps = Math.round(330/this.series.length);
+
+		for(var i=0; i<this.series.length; i++){
+			var c=dojo.gfx.color.hsl2rgb(hue,sat,lum);
+			if(!this.series[i].color){
+				this.series[i].color = dojo.gfx.color.rgb2hex(c[0],c[1],c[2]);
+			}
+			hue += steps;
+		}
+	},
+	parseData: function(table){
+		var thead=table.getElementsByTagName("thead")[0];
+		var tbody=table.getElementsByTagName("tbody")[0];
+		if(!(thead&&tbody)) dojo.raise("dojo.widget.Chart: supplied table must define a head and a body.");
+
+		//	set up the series.
+		var columns=thead.getElementsByTagName("tr")[0].getElementsByTagName("th");	//	should be <tr><..>
+		
+		//	assume column 0 == X
+		for (var i=1; i<columns.length; i++){
+			var key="column"+i;
+			var label=columns[i].innerHTML;
+			var plotType=columns[i].getAttribute("plotType")||"line";
+			var color=columns[i].getAttribute("color");
+			var ds=new dojo.widget.Chart.DataSeries(key,label,plotType,color);
+			this.series.push(ds);
+		}
+
+		//	ok, get the values.
+		var rows=tbody.rows;
+		var xMin=Number.MAX_VALUE,xMax=Number.MIN_VALUE;
+		var yMin=Number.MAX_VALUE,yMax=Number.MIN_VALUE;
+		var ignore = [
+			"accesskey","align","bgcolor","class",
+			"colspan","height","id","nowrap",
+			"rowspan","style","tabindex","title",
+			"valign","width"
+		];
+
+		for(var i=0; i<rows.length; i++){
+			var row=rows[i];
+			var cells=row.cells;
+			var x=Number.MIN_VALUE;
+			for (var j=0; j<cells.length; j++){
+				if (j==0){
+					x=parseFloat(cells[j].innerHTML);
+					xMin=Math.min(xMin, x);
+					xMax=Math.max(xMax, x);
+				} else {
+					var ds=this.series[j-1];
+					var y=parseFloat(cells[j].innerHTML);
+					yMin=Math.min(yMin,y);
+					yMax=Math.max(yMax,y);
+					var o={x:x, value:y};
+					var attrs=cells[j].attributes;
+					for(var k=0; k<attrs.length; k++){
+						var attr=attrs.item(k);
+						var bIgnore=false;
+						for (var l=0; l<ignore.length; l++){
+							if (attr.nodeName.toLowerCase()==ignore[l]){
+								bIgnore=true;
+								break;
+							}
+						}
+						if(!bIgnore) o[attr.nodeName]=attr.nodeValue;
+					}
+					ds.add(o);
+				}
+			}
+		}
+		return { x:{ min:xMin, max:xMax}, y:{ min:yMin, max:yMax} };
+	}
+});
+
+dojo.declare(
+	"dojo.widget.Chart.DataSeries",
+	null,
+	function(key, label, plotType, color){
+		//	summary:
+		//		Every chart has a set of data series; this is the series.  Note that each
+		//		member of value is an object and in the minimum has 2 properties: .x and
+		//		.value.
+		//
+		this.id = "DataSeries"+dojo.widget.Chart.DataSeries.count++;
+		this.key = key;
+		this.label = label||this.id;
+		this.plotType = plotType||"line";	//	let line be the default.
+		this.color = color;
+		this.values = [];
+	},
+{
+	add: function(v){
+		if(v.x==null||v.value==null){
+			dojo.raise("dojo.widget.Chart.DataSeries.add: v must have both an 'x' and 'value' property.");
+		}
+		this.values.push(v);
+	},
+
+	clear: function(){
+		this.values=[];
+	},
+
+	createRange: function(len){
+		var idx = this.values.length-1;
+		var length = (len||this.values.length);
+		return { "index": idx, "length": length, "start":Math.max(idx-length,0) };
+	},
+
+	//	trend values
+	getMean: function(len){
+		var range = this.createRange(len);
+		if(range.index<0){ return 0; }
+		var t = 0;
+		var c = 0;
+		for(var i=range.index; i>=range.start; i--){
+			var n = parseFloat(this.values[i].value);
+			if(!isNaN(n)){ t += n; c++; }
+		}
+		t /= Math.max(c,1);
+		return t;
+	},
+
+	getMovingAverage: function(len){
+		var range = this.createRange(len);
+		if(range.index<0){ return 0; }
+		var t = 0;
+		var c = 0;
+		for(var i=range.index; i>=range.start; i--){
+			var n = parseFloat(this.values[i].value);
+			if(!isNaN(n)){ t += n; c++; }
+		}
+		t /= Math.max(c,1);
+		return t;
+	},
+
+	getVariance: function(len){
+		var range = this.createRange(len);
+		if(range.index < 0){ return 0; }
+		var t = 0; // FIXME: for tom: wtf are t, c, and s?
+		var s = 0;
+		var c = 0;
+		for(var i=range.index; i>=range.start; i--){
+			var n = parseFloat(this.values[i].value);
+			if(!isNaN(n)){
+				t += n;
+				s += Math.pow(n,2);
+				c++;
+			}
+		}
+		return (s/c)-Math.pow(t/c,2);
+	},
+
+	getStandardDeviation: function(len){
+		return Math.sqrt(this.getVariance(len));
+	},
+
+	getMax: function(len){
+		var range = this.createRange(len);
+		if(range.index < 0){ return 0; }
+		var t = 0;
+		for (var i=range.index; i>=range.start; i--){
+			var n=parseFloat(this.values[i].value);
+			if (!isNaN(n)){
+				t=Math.max(n,t);
+			}
+		}
+		return t;
+	},
+
+	getMin: function(len){
+		var range=this.createRange(len);
+		if(range.index < 0){ return 0; }
+		var t = 0;
+		for(var i=range.index; i>=range.start; i--){
+			var n = parseFloat(this.values[i].value);
+			if(!isNaN(n)){
+				t=Math.min(n,t);
+			}
+		}
+		return t;
+	},
+
+	getMedian: function(len){
+		var range = this.createRange(len);
+
+		if(range.index<0){ return 0; }
+
+		var a = [];
+		for (var i=range.index; i>=range.start; i--){
+			var n=parseFloat(this.values[i].value);
+			if (!isNaN(n)){
+				var b=false;
+				for(var j=0; j<a.length&&!b; j++){
+					if (n==a[j]) b=true; 
+				}
+				if(!b){ a.push(n); }
+			}
+		}
+		a.sort();
+		if(a.length>0){ return a[Math.ceil(a.length/2)]; }
+		return 0;
+	},
+
+	getMode: function(len){
+		var range=this.createRange(len);
+		if(range.index<0){ return 0; }
+		var o = {};
+		var ret = 0
+		var m = 0;
+		for(var i=range.index; i>=range.start; i--){
+			var n=parseFloat(this.values[i].value);
+			if(!isNaN(n)){
+				if (!o[this.values[i].value]) o[this.values[i].value] = 1;
+				else o[this.values[i].value]++;
+			}
+		}
+		for(var p in o){
+			if(m<o[p]){ m=o[p]; ret=p; }
+		}
+		return parseFloat(ret);
+	}
+});
+
+dojo["requireIf"](dojo.render.svg.capable, "dojo.widget.svg.Chart");
+dojo["requireIf"](!dojo.render.svg.capable && dojo.render.vml.capable, "dojo.widget.vml.Chart");

Added: incubator/xap/trunk/codebase/src/dojo/src/widget/Checkbox.js
URL: http://svn.apache.org/viewvc/incubator/xap/trunk/codebase/src/dojo/src/widget/Checkbox.js?view=auto&rev=518313
==============================================================================
--- incubator/xap/trunk/codebase/src/dojo/src/widget/Checkbox.js (added)
+++ incubator/xap/trunk/codebase/src/dojo/src/widget/Checkbox.js Wed Mar 14 13:36:44 2007
@@ -0,0 +1,187 @@
+/*
+	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.Checkbox");
+
+dojo.require("dojo.widget.*");
+dojo.require("dojo.widget.HtmlWidget");
+dojo.require("dojo.event.*");
+dojo.require("dojo.html.style");
+dojo.require("dojo.html.selection");
+
+dojo.widget.defineWidget(
+	"dojo.widget.Checkbox",
+	dojo.widget.HtmlWidget,
+	{
+		// summary
+		//	Same as an HTML checkbox, but with fancy styling
+
+		templatePath: dojo.uri.dojoUri('src/widget/templates/Checkbox.html'),
+		templateCssPath: dojo.uri.dojoUri('src/widget/templates/Checkbox.css'),
+
+		// name: String
+		//	name used when submitting form; same as "name" attribute or plain HTML elements
+		name: "",
+
+		// id: String
+		//	id attached to the checkbox, used when submitting form
+		id: "",
+
+		// checked: Boolean
+		//	if true, checkbox is initially marked turned on;
+		//	in markup, specified as "checked='checked'" or just "checked"
+		checked: false,
+		
+		// tabIndex: Integer
+		//	order fields are traversed when user hits the tab key
+		tabIndex: "",
+
+		// value: Value
+		//	equivalent to value field on normal checkbox (if checked, the value is passed as
+		//	the value when form is submitted)
+		value: "on",
+
+		postMixInProperties: function(){
+			dojo.widget.Checkbox.superclass.postMixInProperties.apply(this, arguments);
+			
+			// set tabIndex="0" because if tabIndex=="" user won't be able to tab to the field
+			if(!this.disabled && this.tabIndex==""){ this.tabIndex="0"; }
+		},
+
+		fillInTemplate: function(){
+			this._setInfo();
+		},
+
+		postCreate: function(){
+			// find any associated label and create a labelled-by relationship
+			// assumes <label for="inputId">label text </label> rather than
+			// <label><input type="xyzzy">label text</label>
+			var notcon = true;
+			this.id = this.id !="" ? this.id : this.widgetId;
+			if(this.id != ""){
+				var labels = document.getElementsByTagName("label");
+				if (labels != null && labels.length > 0){
+					for(var i=0; i<labels.length; i++){
+						if (labels[i].htmlFor == this.id){
+							labels[i].id = (labels[i].htmlFor + "label");
+							this._connectEvents(labels[i]);
+							dojo.widget.wai.setAttr(this.domNode, "waiState", "labelledby", labels[i].id);
+							break;
+						}
+					}
+				}
+			}
+			this._connectEvents(this.domNode);
+			// this is needed here for IE
+			this.inputNode.checked=this.checked;
+		},
+
+		_connectEvents: function(/*DomNode*/ node){
+			dojo.event.connect(node, "onmouseover", this, "mouseOver");
+			dojo.event.connect(node, "onmouseout", this, "mouseOut");
+			dojo.event.connect(node, "onkey", this, "onKey");
+			dojo.event.connect(node, "onclick", this, "_onClick");
+			dojo.html.disableSelection(node);
+		},
+
+		_onClick: function(/*Event*/ e){
+			if(this.disabled == false){
+				this.checked = !this.checked;
+				this._setInfo();
+			}
+			e.preventDefault();
+			e.stopPropagation();
+			this.onClick();
+		},
+
+		setValue: function(/*boolean*/ bool){
+			// summary: set the checkbox state
+			if(this.disabled == false){
+				this.checked = bool;
+				this._setInfo();
+			}
+		},
+
+		onClick: function(){
+			// summary: user overridable callback function for checkbox being clicked
+		},
+
+		onKey: function(/*Event*/ e){
+			// summary: callback when user hits a key
+			var k = dojo.event.browser.keys;
+			if(e.key == " "){
+	 			this._onClick(e);
+	 		}
+		},
+
+		mouseOver: function(/*Event*/ e){
+			// summary: callback when user moves mouse over checkbox
+			this._hover(e, true);
+		},
+
+		mouseOut: function(/*Event*/ e){
+			// summary: callback when user moves mouse off of checkbox
+			this._hover(e, false);
+		},
+
+		_hover: function(/*Event*/ e, /*Boolean*/ isOver){
+			if (this.disabled == false){
+				var state = this.checked ? "On" : "Off";
+				var style = "dojoHtmlCheckbox" + state + "Hover";
+				if (isOver){
+					dojo.html.addClass(this.imageNode, style);
+				}else{
+					dojo.html.removeClass(this.imageNode,style);
+				}
+			}
+		},
+
+		_setInfo: function(){
+			// summary:
+			//	set state of hidden checkbox node to correspond to displayed value.
+			//	also set CSS class string according to checked/unchecked and disabled/enabled state
+			var state = "dojoHtmlCheckbox" + (this.disabled ? "Disabled" : "") + (this.checked ? "On" : "Off");
+			dojo.html.setClass(this.imageNode, "dojoHtmlCheckbox " + state);
+			this.inputNode.checked = this.checked;
+			if(this.disabled){
+				this.inputNode.setAttribute("disabled",true);
+			}else{
+				this.inputNode.removeAttribute("disabled");
+			}
+			dojo.widget.wai.setAttr(this.domNode, "waiState", "checked", this.checked);
+		}
+	}
+);
+
+dojo.widget.defineWidget(
+	"dojo.widget.a11y.Checkbox",
+	dojo.widget.Checkbox,
+	{
+		// summary
+		//	variation on Checkbox widget to be display on monitors in high-contrast mode (that don't display CSS background images)
+
+		templatePath: dojo.uri.dojoUri('src/widget/templates/CheckboxA11y.html'),
+
+		fillInTemplate: function(){
+		},
+
+		postCreate: function(args, frag){
+			this.inputNode.checked=this.checked;
+			//only set disabled if true since FF interprets any value for disabled as true
+			if (this.disabled){
+				this.inputNode.setAttribute("disabled",true);
+			} 
+		},
+
+		_onClick: function(){
+			this.onClick();
+		}
+	}
+);
\ No newline at end of file

Added: incubator/xap/trunk/codebase/src/dojo/src/widget/Clock.js
URL: http://svn.apache.org/viewvc/incubator/xap/trunk/codebase/src/dojo/src/widget/Clock.js?view=auto&rev=518313
==============================================================================
--- incubator/xap/trunk/codebase/src/dojo/src/widget/Clock.js (added)
+++ incubator/xap/trunk/codebase/src/dojo/src/widget/Clock.js Wed Mar 14 13:36:44 2007
@@ -0,0 +1,233 @@
+/*
+	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.Clock");
+
+dojo.require("dojo.widget.*");
+dojo.require("dojo.gfx.*");
+dojo.require("dojo.uri.Uri");
+dojo.require("dojo.lang.common");
+dojo.require("dojo.lang.timing.Timer");
+
+dojo.widget.defineWidget(
+	"dojo.widget.Clock",
+	dojo.widget.HtmlWidget,
+	function(){
+		// summary: A basic clock that supports offset and labels
+		// description:
+		//		Uses SVG and Internet Explorer's VML implementation to render a clock
+		//		using the gfx module.
+		// timeZoneOffset: Integer
+		//		Amount (in hours) to offset the clock, relative to local time.
+		// date: Date
+		// image: String
+		//		Location of the background image
+		var self=this;
+		this.timeZoneOffset=0;	//	this is fun.
+		this.label="";		//	optional label.
+		
+		this.date=new Date();
+		
+		this.handColor="#788598";
+		this.handStroke="#6f7b8c";
+	//	this.secondHandColor="#c90405";
+		this.secondHandColor=[201, 4, 5, 0.8];
+		this.topLabelColor="#efefef";
+		this.labelColor="#fff";
+
+		//	timer
+		this.timer = new dojo.lang.timing.Timer(1000);
+
+		//	shapes
+		this.center={ x:75, y:75 };
+		this.hands={
+			hour:null,
+			minute:null,
+			second:null
+		};
+		this.shadows={
+			hour:{ shadow:null, shift:{ dx:2, dy:2} },
+			minute:{ shadow:null, shift:{ dx:2, dy:3} },
+			second:{ shadow:null, shift:{ dx:4, dy:4} }
+		};
+		this.image = dojo.uri.dojoUri("src/widget/templates/images/clock.png");
+		this.surface=null;
+		this.labelNode=null;
+		this.topLabelNode=null;
+
+		this.draw=function(){
+			//	summary: Moves the hands of the clock to the proper position based on the current date.
+			self.date=new Date();
+			var h=(self.date.getHours()+self.timeZoneOffset) % 12;
+			var m=self.date.getMinutes();
+			var s=self.date.getSeconds();
+
+			self.placeHour(h, m, s);
+			self.placeMinute(m, s);
+			self.placeSecond(s);
+
+			self.topLabelNode.innerHTML=((self.date.getHours()+self.timeZoneOffset)>11)?"PM":"AM";
+		};
+
+		this.timer.onTick=self.draw;
+	},
+	{
+		set:function(/* Date */dt){
+			// summary: Set the date object manually
+			this.date=dt;
+			if(!this.timer.isRunning){
+				this.draw();
+			}
+		},
+		start:function(){ 
+			// summary: start the clock.
+			this.timer.start(); 
+		},
+		stop:function(){ 
+			// summary: stop the clock.
+			this.timer.stop(); 
+		},
+
+		_initPoly:function(parent, points){
+			var path = parent.createPath();
+			var first = true;
+			dojo.lang.forEach(points, function(c){
+				if(first){
+					path.moveTo(c.x, c.y);
+					first=false;
+				} else {
+					path.lineTo(c.x, c.y);
+				}
+			});
+			return path;
+		},
+		_placeHand:function(shape, angle, shift){
+			var move = { dx:this.center.x + (shift?shift.dx:0), dy:this.center.y+(shift?shift.dy:0) };
+			return shape.setTransform([move, dojo.gfx.matrix.rotateg(-angle)]);
+		},
+		placeHour:function(/* Number */h, /* Number */m, /* number */s){
+			// summary: place the hour hand at the proper point and rotation.
+			var angle=30 *(h + m/60 + s/3600);
+			this._placeHand(this.hands.hour, angle);
+			this._placeHand(this.shadows.hour.shadow, angle, this.shadows.hour.shift);
+		},
+		placeMinute:function(/* Number */m, /* Number */s){
+			// summary: place the minute hand at the proper point and rotation.
+			var angle=6 * (m + s/60);
+			this._placeHand(this.hands.minute, angle);
+			this._placeHand(this.shadows.minute.shadow, angle, this.shadows.minute.shift);
+		},
+		placeSecond:function(/* Number */s){
+			// summary: place the second hand at the proper point and rotation.
+			var angle=6 * s;
+			this._placeHand(this.hands.second, angle);
+			this._placeHand(this.shadows.second.shadow, angle, this.shadows.second.shift);
+		},
+		
+		init:function(){
+			// summary: initialize the widget by creating the initial shapes.
+			//	start by setting up the domNode
+			if(this.domNode.style.position != "absolute"){
+				this.domNode.style.position = "relative";
+			}
+
+			//	clean out any children
+			while(this.domNode.childNodes.length>0){
+				this.domNode.removeChild(this.domNode.childNodes[0]);
+			}
+			
+			//	set ourselves up.
+			this.domNode.style.width="150px";
+			this.domNode.style.height="150px";
+
+			this.surface=dojo.gfx.createSurface(this.domNode, 150, 150);
+			this.surface.createRect({width: 150, height: 150});
+			this.surface.createImage({width: 150, height: 150, src: this.image+""});
+			
+			var hP=[ {x: -3, y: -4}, {x: 3, y: -4}, {x: 1, y: -27}, { x:-1, y:-27}, {x: -3, y: -4} ];
+			var mP=[ {x: -3, y: -4}, {x: 3, y: -4}, {x: 1, y: -38}, {x:-1, y:-38}, {x: -3, y: -4} ];
+			var sP=[ {x: -2, y: -2}, {x: 2, y: -2}, {x: 1, y: -45}, {x: -1, y: -45}, {x: -2, y: -2} ];
+			
+			this.shadows.hour.shadow = this._initPoly(this.surface, hP)
+				.setFill([0, 0, 0, 0.1]);
+			this.hands.hour = this._initPoly(this.surface, hP)
+				.setStroke({color: this.handStroke, width:1 })
+				.setFill({ 
+					type:"linear", 
+					x1:0, y1:0, x2:0, y2:-27, 
+					colors:[{offset:0, color:"#fff"}, {offset:0.33, color:this.handColor}]
+				});
+			this.shadows.minute.shadow = this._initPoly(this.surface, mP)
+				.setFill([0, 0, 0, 0.1]);
+			this.hands.minute = this._initPoly(this.surface, mP)
+				.setStroke({color: this.handStroke, width:1 })
+				.setFill({ 
+					type:"linear", 
+					x1:0, y1:0, x2:0, y2:-38, 
+					colors:[{offset:0, color:"#fff"}, {offset:0.33, color:this.handColor}]
+				});
+
+			this.surface.createCircle({r: 6})
+				.setStroke({color: this.handStroke, width:2 })
+				.setFill("#fff")
+				.setTransform({dx: 75, dy: 75});
+
+			this.shadows.second.shadow = this._initPoly(this.surface, sP)
+				.setFill([0, 0, 0, 0.1]);
+			this.hands.second = this._initPoly(this.surface, sP)
+				.setFill(this.secondHandColor);
+
+			//	clock centers, doesn't move.
+			this.surface.createCircle({r: 4})
+				.setFill(this.secondHandColor)
+				.setTransform({dx: 75, dy: 75});
+
+			//	labels
+			this.topLabelNode=document.createElement("div");
+			with(this.topLabelNode.style){
+				position="absolute";
+				top="3px";
+				left="0px";
+				color=this.topLabelColor;
+				textAlign="center";
+				width="150px";
+				fontFamily="sans-serif";
+				fontSize="11px";
+				textTransform="uppercase";
+				fontWeight="bold";
+			}
+			this.topLabelNode.innerHTML=((this.date.getHours()+this.timeZoneOffset)>11)?"PM":"AM";
+			this.domNode.appendChild(this.topLabelNode);
+
+			this.labelNode=document.createElement("div");
+			with(this.labelNode.style){
+				position="absolute";
+				top="134px";
+				left="0px";
+				color=this.labelColor;
+				textAlign="center";
+				width="150px";
+				fontFamily="sans-serif";
+				fontSize="10px";
+				textTransform="uppercase";
+				fontWeight="bold";
+			}
+			this.labelNode.innerHTML=this.label||"&nbsp;";
+			this.domNode.appendChild(this.labelNode);
+			
+			this.draw();
+		},
+		postCreate:function(){
+			// summary: Create the clock and start the timer.
+			this.init();
+			this.start();
+		}
+	}
+);

Added: incubator/xap/trunk/codebase/src/dojo/src/widget/ColorPalette.js
URL: http://svn.apache.org/viewvc/incubator/xap/trunk/codebase/src/dojo/src/widget/ColorPalette.js?view=auto&rev=518313
==============================================================================
--- incubator/xap/trunk/codebase/src/dojo/src/widget/ColorPalette.js (added)
+++ incubator/xap/trunk/codebase/src/dojo/src/widget/ColorPalette.js Wed Mar 14 13:36:44 2007
@@ -0,0 +1,91 @@
+/*
+	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.ColorPalette");
+dojo.require("dojo.widget.*");
+dojo.require("dojo.html.layout");
+dojo.require("dojo.html.display");
+dojo.require("dojo.html.selection");
+
+dojo.widget.defineWidget(
+	"dojo.widget.ColorPalette",
+	dojo.widget.HtmlWidget,
+{
+	// summary
+	//		Grid showing various colors, so the user pick a certain color
+	
+	// palette: String
+	//		Size of grid, either "7x10" or "3x4".
+	palette: "7x10",
+
+	_palettes: {
+		"7x10": [["fff", "fcc", "fc9", "ff9", "ffc", "9f9", "9ff", "cff", "ccf", "fcf"],
+			["ccc", "f66", "f96", "ff6", "ff3", "6f9", "3ff", "6ff", "99f", "f9f"],
+			["c0c0c0", "f00", "f90", "fc6", "ff0", "3f3", "6cc", "3cf", "66c", "c6c"],
+			["999", "c00", "f60", "fc3", "fc0", "3c0", "0cc", "36f", "63f", "c3c"],
+			["666", "900", "c60", "c93", "990", "090", "399", "33f", "60c", "939"],
+			["333", "600", "930", "963", "660", "060", "366", "009", "339", "636"],
+			["000", "300", "630", "633", "330", "030", "033", "006", "309", "303"]],
+
+		"3x4": [["ffffff"/*white*/, "00ff00"/*lime*/, "008000"/*green*/, "0000ff"/*blue*/],
+			["c0c0c0"/*silver*/, "ffff00"/*yellow*/, "ff00ff"/*fuchsia*/, "000080"/*navy*/],
+			["808080"/*gray*/, "ff0000"/*red*/, "800080"/*purple*/, "000000"/*black*/]]
+			//["00ffff"/*aqua*/, "808000"/*olive*/, "800000"/*maroon*/, "008080"/*teal*/]];
+	},
+
+	buildRendering: function () {
+		this.domNode = document.createElement("table");
+		dojo.html.disableSelection(this.domNode);
+		dojo.event.connect(this.domNode, "onmousedown", function (e) {
+			e.preventDefault();
+		});
+		with (this.domNode) { // set the table's properties
+			cellPadding = "0"; cellSpacing = "1"; border = "1";
+			style.backgroundColor = "white";
+		}
+		var colors = this._palettes[this.palette];
+		for (var i = 0; i < colors.length; i++) {
+			var tr = this.domNode.insertRow(-1);
+			for (var j = 0; j < colors[i].length; j++) {
+				if (colors[i][j].length == 3) {
+					colors[i][j] = colors[i][j].replace(/(.)(.)(.)/, "$1$1$2$2$3$3");
+				}
+
+				var td = tr.insertCell(-1);
+				with (td.style) {
+					backgroundColor = "#" + colors[i][j];
+					border = "1px solid gray";
+					width = height = "15px";
+					fontSize = "1px";
+				}
+
+				td.color = "#" + colors[i][j];
+
+				td.onmouseover = function (e) { this.style.borderColor = "white"; }
+				td.onmouseout = function (e) { this.style.borderColor = "gray"; }
+				dojo.event.connect(td, "onmousedown", this, "onClick");
+
+				td.innerHTML = "&nbsp;";
+			}
+		}
+	},
+
+	onClick: function(/*Event*/ e) {
+		this.onColorSelect(e.currentTarget.color);
+		e.currentTarget.style.borderColor = "gray";
+	},
+
+	onColorSelect: function(color){
+		// summary:
+		//		Callback when a color is selected.
+		// color: String
+		//		Hex value corresponding to color.
+	}
+});