You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@jackrabbit.apache.org by ed...@apache.org on 2006/11/11 17:44:48 UTC

svn commit: r473755 [35/43] - in /jackrabbit/trunk/contrib/jcr-browser: ./ src/ src/main/ src/main/java/ src/main/java/org/ src/main/java/org/apache/ src/main/java/org/apache/jackrabbit/ src/main/java/org/apache/jackrabbit/browser/ src/main/resources/ ...

Added: jackrabbit/trunk/contrib/jcr-browser/src/main/webapp/dojo/src/widget/SplitContainer.js
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/contrib/jcr-browser/src/main/webapp/dojo/src/widget/SplitContainer.js?view=auto&rev=473755
==============================================================================
--- jackrabbit/trunk/contrib/jcr-browser/src/main/webapp/dojo/src/widget/SplitContainer.js (added)
+++ jackrabbit/trunk/contrib/jcr-browser/src/main/webapp/dojo/src/widget/SplitContainer.js Sat Nov 11 08:44:22 2006
@@ -0,0 +1,517 @@
+dojo.provide("dojo.widget.SplitContainer");
+
+//
+// TODO
+// make it prettier
+// active dragging upwards doesn't always shift other bars (direction calculation is wrong in this case)
+//
+
+dojo.require("dojo.widget.*");
+dojo.require("dojo.widget.ContentPane");
+dojo.require("dojo.widget.HtmlWidget");
+dojo.require("dojo.html.style");
+dojo.require("dojo.html.layout");
+dojo.require("dojo.html.selection");
+dojo.require("dojo.io.cookie");
+
+dojo.widget.defineWidget(
+	"dojo.widget.SplitContainer",
+	dojo.widget.HtmlWidget,
+	function(){
+		this.sizers = [];
+	},
+{
+	isContainer: true,
+
+	// variables
+	virtualSizer: null,
+	isHorizontal: null,
+	paneBefore: null,
+	paneAfter: null,
+	isSizing: false,
+	dragOffset: 0,
+	startPoint: 0,
+	lastPoint: 0,
+	sizingSplitter: null,
+	screenToClientOffset: 0,
+	isDraggingLeft: 0,
+	templateCssPath: dojo.uri.dojoUri("src/widget/templates/SplitContainer.css"),
+	originPos: 0,
+
+	// parameters (user settable)
+	activeSizing: false,
+	sizerWidth: 15,
+	orientation: 'horizontal',
+	persist: true,		// save splitter positions in a cookie
+
+	debugName: '',
+
+	fillInTemplate: function(){
+
+		dojo.html.insertCssFile(this.templateCssPath, null, true);
+		dojo.html.addClass(this.domNode, "dojoSplitContainer");
+		// overflow has to be explicitly hidden for splitContainers using gekko (trac #1435)
+		// to keep other combined css classes from inadvertantly making the overflow visible
+		if (dojo.render.html.moz) {
+		        this.domNode.style.overflow = '-moz-scrollbars-none'; // hidden doesn't work
+		}
+		
+		var content = dojo.html.getContentBox(this.domNode);
+		this.paneWidth = content.width;
+		this.paneHeight = content.height;
+
+		this.isHorizontal = (this.orientation == 'horizontal');
+
+		//dojo.debug("fillInTemplate for "+this.debugName);
+	},
+
+	onResized: function(e){
+		var content = dojo.html.getContentBox(this.domNode);
+		this.paneWidth = content.width;
+		this.paneHeight = content.height;
+		this.layoutPanels();
+	},
+
+	postCreate: function(args, fragment, parentComp){
+
+		// dojo.debug("post create for "+this.debugName);
+
+		// attach the children and create the draggers
+		for(var i=0; i<this.children.length; i++){
+            with(this.children[i].domNode.style){
+                position = "absolute";
+            }
+            dojo.html.addClass(this.children[i].domNode,
+                "dojoSplitPane");
+
+            if(i == this.children.length-1){
+                break;
+            }
+
+            this._addSizer();
+		}
+
+		// create the fake dragger
+		if (typeof this.sizerWidth == "object") { 
+			try {
+				this.sizerWidth = parseInt(this.sizerWidth.toString()); 
+			} catch(e) { this.sizerWidth = 15; }
+		}
+		this.virtualSizer = document.createElement('div');
+		this.virtualSizer.style.position = 'absolute';
+		this.virtualSizer.style.display = 'none';
+		//this.virtualSizer.style.backgroundColor = 'lime';
+		this.virtualSizer.style.zIndex = 10;
+		this.virtualSizer.className = this.isHorizontal ? 'dojoSplitContainerVirtualSizerH' : 'dojoSplitContainerVirtualSizerV';
+		this.domNode.appendChild(this.virtualSizer);
+
+		dojo.html.disableSelection(this.virtualSizer);
+
+		if(this.persist){
+			this.restoreState();
+		}
+
+		// size the panels once the browser has caught up
+		this.resizeSoon();
+	},
+
+    _injectChild: function(child) {
+        with(child.domNode.style){
+            position = "absolute";
+        }
+        dojo.html.addClass(child.domNode,
+            "dojoSplitPane");
+    },
+
+    _addSizer: function() {
+        var i = this.sizers.length;
+
+        this.sizers[i] = document.createElement('div');
+        this.sizers[i].style.position = 'absolute';
+        this.sizers[i].className = this.isHorizontal ? 'dojoSplitContainerSizerH' : 'dojoSplitContainerSizerV';
+
+        var self = this;
+        var handler = (function(){ var sizer_i = i; return function(e){ self.beginSizing(e, sizer_i); } })();
+        dojo.event.connect(this.sizers[i], "onmousedown", handler);
+
+        this.domNode.appendChild(this.sizers[i]);
+        dojo.html.disableSelection(this.sizers[i]);
+    },
+
+    removeChild: function(widget){
+        // Remove sizer, but only if widget is really our child and
+        // we have at least one sizer to throw away
+        if (this.sizers.length > 0) {
+            for(var x=0; x<this.children.length; x++){
+                if(this.children[x] === widget){
+                    var i = this.sizers.length - 1;
+                    this.domNode.removeChild(this.sizers[i]);
+                    this.sizers.length = i;
+                    break;
+                }
+            }
+        }
+
+        // Remove widget and repaint
+        dojo.widget.SplitContainer.superclass.removeChild.call(this, widget, arguments);
+        this.onResized();
+    },
+
+    addChild: function(widget, overrideContainerNode, pos, ref, insertIndex){
+        dojo.widget.SplitContainer.superclass.addChild.call(this, widget, overrideContainerNode, pos, ref, insertIndex);
+        this._injectChild(widget);
+
+        if (this.children.length > 1) {
+            this._addSizer();
+        }
+
+        this.layoutPanels();
+    },
+
+    layoutPanels: function(){
+        if (this.children.length == 0){ return; }
+
+		//
+		// calculate space
+		//
+
+		var space = this.isHorizontal ? this.paneWidth : this.paneHeight;
+
+		if (this.children.length > 1){
+
+			space -= this.sizerWidth * (this.children.length - 1);
+		}
+
+
+		//
+		// calculate total of SizeShare values
+		//
+
+		var out_of = 0;
+
+		for(var i=0; i<this.children.length; i++){
+
+			out_of += this.children[i].sizeShare;
+		}
+
+
+		//
+		// work out actual pixels per sizeshare unit
+		//
+
+		var pix_per_unit = space / out_of;
+
+
+		//
+		// set the SizeActual member of each pane
+		//
+
+		var total_size = 0;
+
+		for(var i=0; i<this.children.length-1; i++){
+
+			var size = Math.round(pix_per_unit * this.children[i].sizeShare);
+			this.children[i].sizeActual = size;
+			total_size += size;
+		}
+		this.children[this.children.length-1].sizeActual = space - total_size;
+
+		//
+		// make sure the sizes are ok
+		//
+
+		this.checkSizes();
+
+
+		//
+		// now loop, positioning each pane and letting children resize themselves
+		//
+
+		var pos = 0;
+		var size = this.children[0].sizeActual;
+		this.movePanel(this.children[0].domNode, pos, size);
+		this.children[0].position = pos;
+		this.children[0].checkSize();
+		pos += size;
+
+		for(var i=1; i<this.children.length; i++){
+
+			// first we position the sizing handle before this pane
+			this.movePanel(this.sizers[i-1], pos, this.sizerWidth);
+			this.sizers[i-1].position = pos;
+			pos += this.sizerWidth;
+
+			size = this.children[i].sizeActual;
+			this.movePanel(this.children[i].domNode, pos, size);
+			this.children[i].position = pos;
+			this.children[i].checkSize();
+			pos += size;
+		}
+	},
+
+	movePanel: function(panel, pos, size){
+		if (this.isHorizontal){
+			panel.style.left = pos + 'px';
+			panel.style.top = 0;
+
+			dojo.html.setMarginBox(panel, { width: size, height: this.paneHeight });
+		}else{
+			panel.style.left = 0;
+			panel.style.top = pos + 'px';
+
+			dojo.html.setMarginBox(panel, { width: this.paneWidth, height: size });
+		}
+	},
+
+	growPane: function(growth, pane){
+
+		if (growth > 0){
+			if (pane.sizeActual > pane.sizeMin){
+				if ((pane.sizeActual - pane.sizeMin) > growth){
+
+					// stick all the growth in this pane
+					pane.sizeActual = pane.sizeActual - growth;
+					growth = 0;
+				}else{
+					// put as much growth in here as we can
+					growth -= pane.sizeActual - pane.sizeMin;
+					pane.sizeActual = pane.sizeMin;
+				}
+			}
+		}
+		return growth;
+	},
+
+	checkSizes: function(){
+
+		var total_min_size = 0;
+		var total_size = 0;
+
+		for(var i=0; i<this.children.length; i++){
+
+			total_size += this.children[i].sizeActual;
+			total_min_size += this.children[i].sizeMin;
+		}
+
+		// only make adjustments if we have enough space for all the minimums
+
+		if (total_min_size <= total_size){
+
+			var growth = 0;
+
+			for(var i=0; i<this.children.length; i++){
+
+				if (this.children[i].sizeActual < this.children[i].sizeMin){
+
+					growth += this.children[i].sizeMin - this.children[i].sizeActual;
+					this.children[i].sizeActual = this.children[i].sizeMin;
+				}
+			}
+
+			if (growth > 0){
+				if (this.isDraggingLeft){
+					for(var i=this.children.length-1; i>=0; i--){
+						growth = this.growPane(growth, this.children[i]);
+					}
+				}else{
+					for(var i=0; i<this.children.length; i++){
+						growth = this.growPane(growth, this.children[i]);
+					}
+				}
+			}
+		}else{
+
+			for(var i=0; i<this.children.length; i++){
+				this.children[i].sizeActual = Math.round(total_size * (this.children[i].sizeMin / total_min_size));
+			}
+		}
+	},
+
+	beginSizing: function(e, i){
+		this.paneBefore = this.children[i];
+		this.paneAfter = this.children[i+1];
+
+		this.isSizing = true;
+		this.sizingSplitter = this.sizers[i];
+		this.originPos = dojo.html.getAbsolutePosition(this.children[0].domNode, true, dojo.html.boxSizing.MARGIN_BOX);
+		if (this.isHorizontal){
+			var client = (e.layerX ? e.layerX : e.offsetX);
+			var screen = e.pageX;
+			this.originPos = this.originPos.x;
+		}else{
+			var client = (e.layerY ? e.layerY : e.offsetY);
+			var screen = e.pageY;
+			this.originPos = this.originPos.y;
+		}
+		this.startPoint = this.lastPoint = screen;
+		this.screenToClientOffset = screen - client;
+		this.dragOffset = this.lastPoint - this.paneBefore.sizeActual - this.originPos - this.paneBefore.position;
+
+		if (!this.activeSizing){
+			this.showSizingLine();
+		}
+
+		//
+		// attach mouse events
+		//
+
+		dojo.event.connect(document.documentElement, "onmousemove", this, "changeSizing");
+		dojo.event.connect(document.documentElement, "onmouseup", this, "endSizing");
+		dojo.event.browser.stopEvent(e);
+	},
+
+	changeSizing: function(e){
+		this.lastPoint = this.isHorizontal ? e.pageX : e.pageY;
+		if (this.activeSizing){
+			this.movePoint();
+			this.updateSize();
+		}else{
+			this.movePoint();
+			this.moveSizingLine();
+		}
+		dojo.event.browser.stopEvent(e);
+	},
+
+	endSizing: function(e){
+
+		if (!this.activeSizing){
+			this.hideSizingLine();
+		}
+
+		this.updateSize();
+
+		this.isSizing = false;
+
+		dojo.event.disconnect(document.documentElement, "onmousemove", this, "changeSizing");
+		dojo.event.disconnect(document.documentElement, "onmouseup", this, "endSizing");
+		
+		if(this.persist){
+			this.saveState(this);
+		}
+	},
+
+	movePoint: function(){
+
+		// make sure lastPoint is a legal point to drag to
+		var p = this.lastPoint - this.screenToClientOffset;
+
+		var a = p - this.dragOffset;
+		a = this.legaliseSplitPoint(a);
+		p = a + this.dragOffset;
+
+		this.lastPoint = p + this.screenToClientOffset;
+	},
+
+	legaliseSplitPoint: function(a){
+
+		a += this.sizingSplitter.position;
+
+		this.isDraggingLeft = (a > 0) ? 1 : 0;
+
+		if (!this.activeSizing){
+
+			if (a < this.paneBefore.position + this.paneBefore.sizeMin){
+
+				a = this.paneBefore.position + this.paneBefore.sizeMin;
+			}
+
+			if (a > this.paneAfter.position + (this.paneAfter.sizeActual - (this.sizerWidth + this.paneAfter.sizeMin))){
+
+				a = this.paneAfter.position + (this.paneAfter.sizeActual - (this.sizerWidth + this.paneAfter.sizeMin));
+			}
+		}
+
+		a -= this.sizingSplitter.position;
+
+		this.checkSizes();
+
+		return a;
+	},
+
+	updateSize: function(){
+		var pos = this.lastPoint - this.dragOffset - this.originPos;
+
+		var start_region = this.paneBefore.position;
+		var end_region   = this.paneAfter.position + this.paneAfter.sizeActual;
+
+		this.paneBefore.sizeActual = pos - start_region;
+		this.paneAfter.position    = pos + this.sizerWidth;
+		this.paneAfter.sizeActual  = end_region - this.paneAfter.position;
+
+		for(var i=0; i<this.children.length; i++){
+
+			this.children[i].sizeShare = this.children[i].sizeActual;
+		}
+
+		this.layoutPanels();
+	},
+
+	showSizingLine: function(){
+
+		this.moveSizingLine();
+
+		if (this.isHorizontal){
+			dojo.html.setMarginBox(this.virtualSizer, { width: this.sizerWidth, height: this.paneHeight });
+		}else{
+			dojo.html.setMarginBox(this.virtualSizer, { width: this.paneWidth, height: this.sizerWidth });
+		}
+
+		this.virtualSizer.style.display = 'block';
+	},
+
+	hideSizingLine: function(){
+		this.virtualSizer.style.display = 'none';
+	},
+
+	moveSizingLine: function(){
+		var pos = this.lastPoint - this.startPoint + this.sizingSplitter.position;
+		if (this.isHorizontal){
+			this.virtualSizer.style.left = pos + 'px';
+		}else{
+			var pos = (this.lastPoint - this.startPoint) + this.sizingSplitter.position;
+			this.virtualSizer.style.top = pos + 'px';
+		}
+
+	},
+	
+	_getCookieName: function(i) {
+		return this.widgetId + "_" + i;
+	},
+
+	restoreState: function () {
+		for(var i=0; i<this.children.length; i++) {
+			var cookieName = this._getCookieName(i);
+			var cookieValue = dojo.io.cookie.getCookie(cookieName);
+			if (cookieValue != null) {
+				var pos = parseInt(cookieValue);
+				if (typeof pos == "number") {
+					this.children[i].sizeShare=pos;
+				}
+			}
+		}
+	},
+
+	saveState: function (){
+		for(var i=0; i<this.children.length; i++) {
+			var cookieName = this._getCookieName(i);
+			dojo.io.cookie.setCookie(cookieName, this.children[i].sizeShare, null, null, null, null);
+		}
+	}
+});
+
+// These arguments can be specified for the children of a SplitContainer.
+// Since any widget can be specified as a SplitContainer child, mix them
+// into the base widget class.  (This is a hack, but it's effective.)
+dojo.lang.extend(dojo.widget.Widget, {
+	sizeMin: 10,
+	sizeShare: 10
+});
+
+// Deprecated class for split pane children.
+// Actually any widget can be the child of a split pane
+dojo.widget.defineWidget(
+	"dojo.widget.SplitContainerPanel",
+	dojo.widget.ContentPane,
+	{}
+);
+

Propchange: jackrabbit/trunk/contrib/jcr-browser/src/main/webapp/dojo/src/widget/SplitContainer.js
------------------------------------------------------------------------------
    svn:eol-style = native

Added: jackrabbit/trunk/contrib/jcr-browser/src/main/webapp/dojo/src/widget/SvgButton.js
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/contrib/jcr-browser/src/main/webapp/dojo/src/widget/SvgButton.js?view=auto&rev=473755
==============================================================================
--- jackrabbit/trunk/contrib/jcr-browser/src/main/webapp/dojo/src/widget/SvgButton.js (added)
+++ jackrabbit/trunk/contrib/jcr-browser/src/main/webapp/dojo/src/widget/SvgButton.js Sat Nov 11 08:44:22 2006
@@ -0,0 +1,131 @@
+// FIXME: not yet functional
+
+dojo.provide("dojo.widget.SvgButton");
+
+dojo.require("dojo.widget.Button");
+
+dojo.widget.SvgButton = function(){
+	// FIXME: this is incomplete and doesn't work yet
+	// if DOMButton turns into a mixin, we should subclass Button instead and
+	// just mix in the DOMButton properties.
+
+	dojo.widget.DomButton.call(this);
+	dojo.widget.SvgWidget.call(this);
+
+	// FIXME: freaking implement this already!
+	this.onFoo = function(){ alert("bar"); }
+
+	this.label = "huzzah!";
+
+	this.setLabel = function(x, y, textSize, label, shape){
+		//var labelNode = this.domNode.ownerDocument.createTextNode(this.label);
+		//var textNode = this.domNode.ownerDocument.createElement("text");
+		var coords = dojo.widget.SvgButton.prototype.coordinates(x, y, textSize, label, shape);
+		var textString = "";
+		switch(shape) {
+			case "ellipse":
+				textString = "<text x='"+ coords[6] + "' y='"+ coords[7] + "'>"+ label + "</text>";
+				//textNode.setAttribute("x", coords[6]);
+				//textNode.setAttribute("y", coords[7]);
+				break;
+			case "rectangle":
+				//FIXME: implement
+				textString = "";
+				//textNode.setAttribute("x", coords[6]);
+				//textNode.setAttribute("y", coords[7]);
+				break;
+			case "circle":
+				//FIXME: implement
+				textString = "";
+				//textNode.setAttribute("x", coords[6]);
+				//textNode.setAttribute("y", coords[7]);
+				break;
+		}
+		//textNode.appendChild(labelNode);
+		//this.domNode.appendChild(textNode);
+		return textString;
+		//alert(textNode.getComputedTextLength());
+	}
+
+	this.fillInTemplate = function(x, y, textSize, label, shape){
+		// the idea is to set the text to the appropriate place given its length
+		// and the template shape
+		
+		// FIXME: For now, assuming text sizes are integers in SVG units
+		this.textSize = textSize || 12;
+		this.label = label;
+		// FIXEME: for now, I'm going to fake this... need to come up with a real way to 
+		// determine the actual width of the text, such as computedStyle
+		var textWidth = this.label.length*this.textSize ;
+		//this.setLabel();
+	}
+}
+
+dojo.inherits(dojo.widget.SvgButton, dojo.widget.DomButton);
+
+// FIXME
+dojo.widget.SvgButton.prototype.shapeString = function(x, y, textSize, label, shape) {
+	switch(shape) {
+		case "ellipse":
+			var coords = dojo.widget.SvgButton.prototype.coordinates(x, y, textSize, label, shape)
+			return "<ellipse cx='"+ coords[4]+"' cy='"+ coords[5]+"' rx='"+ coords[2]+"' ry='"+ coords[3]+"'/>";
+			break;
+		case "rect":
+			//FIXME: implement
+			return "";
+			//return "<rect x='110' y='45' width='70' height='30'/>";
+			break;
+		case "circle":
+			//FIXME: implement
+			return "";
+			//return "<circle cx='210' cy='60' r='23'/>";
+			break;
+	}
+}
+
+dojo.widget.SvgButton.prototype.coordinates = function(x, y, textSize, label, shape) {
+	switch(shape) {
+		case "ellipse":
+			var buttonWidth = label.length*textSize;
+			var buttonHeight = textSize*2.5
+			var rx = buttonWidth/2;
+			var ry = buttonHeight/2;
+			var cx = rx + x;
+			var cy = ry + y;
+			var textX = cx - rx*textSize/25;
+			var textY = cy*1.1;
+			return [buttonWidth, buttonHeight, rx, ry, cx, cy, textX, textY];
+			break;
+		case "rectangle":
+			//FIXME: implement
+			return "";
+			break;
+		case "circle":
+			//FIXME: implement
+			return "";
+			break;
+	}
+}
+
+dojo.widget.SvgButton.prototype.labelString = function(x, y, textSize, label, shape){
+	var textString = "";
+	var coords = dojo.widget.SvgButton.prototype.coordinates(x, y, textSize, label, shape);
+	switch(shape) {
+		case "ellipse":
+			textString = "<text x='"+ coords[6] + "' y='"+ coords[7] + "'>"+ label + "</text>";
+			break;
+		case "rectangle":
+			//FIXME: implement
+			textString = "";
+			break;
+		case "circle":
+			//FIXME: implement
+			textString = "";
+			break;
+	}
+	return textString;
+}
+
+dojo.widget.SvgButton.prototype.templateString = function(x, y, textSize, label, shape) {
+	return "<g class='dojoButton' dojoAttachEvent='onClick; onMouseMove: onFoo;' dojoAttachPoint='labelNode'>"+ dojo.widgets.SVGButton.prototype.shapeString(x, y, textSize, label, shape) + dojo.widget.SVGButton.prototype.labelString(x, y, textSize, label, shape) + "</g>";
+}

Propchange: jackrabbit/trunk/contrib/jcr-browser/src/main/webapp/dojo/src/widget/SvgButton.js
------------------------------------------------------------------------------
    svn:eol-style = native

Added: jackrabbit/trunk/contrib/jcr-browser/src/main/webapp/dojo/src/widget/SvgWidget.js
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/contrib/jcr-browser/src/main/webapp/dojo/src/widget/SvgWidget.js?view=auto&rev=473755
==============================================================================
--- jackrabbit/trunk/contrib/jcr-browser/src/main/webapp/dojo/src/widget/SvgWidget.js (added)
+++ jackrabbit/trunk/contrib/jcr-browser/src/main/webapp/dojo/src/widget/SvgWidget.js Sat Nov 11 08:44:22 2006
@@ -0,0 +1,79 @@
+dojo.require("dojo.widget.DomWidget");
+dojo.provide("dojo.widget.SvgWidget");
+dojo.provide("dojo.widget.SVGWidget"); // back compat
+
+dojo.require("dojo.dom");
+
+// SVGWidget is a mixin ONLY
+dojo.widget.declare(
+	"dojo.widget.SvgWidget",
+	dojo.widget.DomWidget,
+{
+	getContainerHeight: function(){
+		// NOTE: container height must be returned as the INNER height
+		dojo.unimplemented("dojo.widget.SvgWidget.getContainerHeight");
+	},
+
+	getContainerWidth: function(){
+		// return this.parent.domNode.offsetWidth;
+		dojo.unimplemented("dojo.widget.SvgWidget.getContainerWidth");
+	},
+
+	setNativeHeight: function(height){
+		// var ch = this.getContainerHeight();
+		dojo.unimplemented("dojo.widget.SVGWidget.setNativeHeight");
+	},
+
+	createNodesFromText: function(txt, wrap){
+		return dojo.dom.createNodesFromText(txt, wrap);
+	}
+});
+
+dojo.widget.SVGWidget = dojo.widget.SvgWidget;
+
+try{
+(function(){
+	var tf = function(){
+		// FIXME: fill this in!!!
+		var rw = new function(){
+			dojo.widget.SvgWidget.call(this);
+			this.buildRendering = function(){ return; }
+			this.destroyRendering = function(){ return; }
+			this.postInitialize = function(){ return; }
+			this.cleanUp = function(){ return; }
+			this.widgetType = "SVGRootWidget";
+			this.domNode = document.documentElement;
+		}
+		var wm = dojo.widget.manager;
+		wm.root = rw;
+		wm.add(rw);
+
+		// extend the widgetManager with a getWidgetFromNode method
+		wm.getWidgetFromNode = function(node){
+			var filter = function(x){
+				if(x.domNode == node){
+					return true;
+				}
+			}
+			var widgets = [];
+			while((node)&&(widgets.length < 1)){
+				widgets = this.getWidgetsByFilter(filter);
+				node = node.parentNode;
+			}
+			if(widgets.length > 0){
+				return widgets[0];
+			}else{
+				return null;
+			}
+		}
+
+		wm.getWidgetFromEvent = function(domEvt){
+			return this.getWidgetFromNode(domEvt.target);
+		}
+
+		wm.getWidgetFromPrimitive = wm.getWidgetFromNode;
+	}
+	// make sure we get called when the time is right
+	dojo.event.connect(dojo.hostenv, "loaded", tf);
+})();
+}catch(e){ alert(e); }

Propchange: jackrabbit/trunk/contrib/jcr-browser/src/main/webapp/dojo/src/widget/SvgWidget.js
------------------------------------------------------------------------------
    svn:eol-style = native

Added: jackrabbit/trunk/contrib/jcr-browser/src/main/webapp/dojo/src/widget/SwtWidget.js
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/contrib/jcr-browser/src/main/webapp/dojo/src/widget/SwtWidget.js?view=auto&rev=473755
==============================================================================
--- jackrabbit/trunk/contrib/jcr-browser/src/main/webapp/dojo/src/widget/SwtWidget.js (added)
+++ jackrabbit/trunk/contrib/jcr-browser/src/main/webapp/dojo/src/widget/SwtWidget.js Sat Nov 11 08:44:22 2006
@@ -0,0 +1,54 @@
+dojo.provide("dojo.widget.SwtWidget");
+
+dojo.require("dojo.event.*");
+dojo.require("dojo.widget.Widget");
+dojo.require("dojo.uri.*");
+dojo.require("dojo.lang.func");
+dojo.require("dojo.lang.extras");
+
+try{
+	importPackage(Packages.org.eclipse.swt.widgets);
+
+	dojo.declare("dojo.widget.SwtWidget", dojo.widget.Widget,
+		function() {
+			if((arguments.length>0)&&(typeof arguments[0] == "object")){
+				this.create(arguments[0]);
+			}
+		},
+	{
+		display: null,
+		shell: null,
+
+		show: function(){ },
+		hide: function(){ },
+
+		addChild: function(){ },
+		registerChild: function(){ },
+		addWidgetAsDirectChild: function(){ },
+		removeChild: function(){ },
+		cleanUp: function(){ },
+		destroyRendering: function(){ },
+		postInitialize: function(){ },
+	});
+
+	// initialize SWT runtime
+
+	dojo.widget.SwtWidget.prototype.display = new Display();
+	dojo.widget.SwtWidget.prototype.shell = new Shell(dojo.widget.SwtWidget.prototype.display);
+
+	dojo.widget.manager.startShell = function(){
+		var sh = dojo.widget.SwtWidget.prototype.shell;
+		var d = dojo.widget.SwtWidget.prototype.display;
+		sh.open();
+		while(!sh.isDisposed()){
+			dojo.widget.manager.doNext();
+			if(!d.readAndDispatch()){
+				d.sleep();
+			}
+		}
+		d.dispose();
+	};
+}catch(e){
+	// seems we didn't have the SWT classes in the environment. Log it.
+	dojo.debug("dojo.widget.SwtWidget not loaded. SWT classes not available");
+}

Propchange: jackrabbit/trunk/contrib/jcr-browser/src/main/webapp/dojo/src/widget/SwtWidget.js
------------------------------------------------------------------------------
    svn:eol-style = native

Added: jackrabbit/trunk/contrib/jcr-browser/src/main/webapp/dojo/src/widget/TabContainer.js
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/contrib/jcr-browser/src/main/webapp/dojo/src/widget/TabContainer.js?view=auto&rev=473755
==============================================================================
--- jackrabbit/trunk/contrib/jcr-browser/src/main/webapp/dojo/src/widget/TabContainer.js (added)
+++ jackrabbit/trunk/contrib/jcr-browser/src/main/webapp/dojo/src/widget/TabContainer.js Sat Nov 11 08:44:22 2006
@@ -0,0 +1,205 @@
+dojo.provide("dojo.widget.TabContainer");
+
+dojo.require("dojo.lang.func");
+dojo.require("dojo.widget.*");
+dojo.require("dojo.widget.PageContainer");
+dojo.require("dojo.event.*");
+dojo.require("dojo.html.selection");
+dojo.require("dojo.widget.html.layout");
+
+// summary
+//	A TabContainer is a container that has multiple panes, but shows only
+//	one pane at a time.  There are a set of tabs corresponding to each pane,
+//	where each tab has the title (aka label) of the pane, and optionally a close button.
+//
+//	Publishes topics <widgetId>-addChild, <widgetId>-removeChild, and <widgetId>-selectChild
+//	(where <widgetId> is the id of the TabContainer itself.
+dojo.widget.defineWidget("dojo.widget.TabContainer", dojo.widget.PageContainer, {
+
+	// String
+	//   Defines where tab labels go relative to tab content.
+	//   "top", "bottom", "left-h", "right-h"
+	labelPosition: "top",
+	
+	// String
+	//   If closebutton=="tab", then every tab gets a close button.
+	//   DEPRECATED:  Should just say closable=true on each
+	//   pane you want to be closable.
+	closeButton: "none",
+
+	templateString: null,	// override setting in PageContainer
+	templatePath: dojo.uri.dojoUri("src/widget/templates/TabContainer.html"),
+	templateCssPath: dojo.uri.dojoUri("src/widget/templates/TabContainer.css"),
+
+	// String
+	//	initially selected tab (widgetId)
+	//	DEPRECATED: use selectedChild instead.
+	selectedTab: "",
+
+	postMixInProperties: function() {
+		if(this.selectedTab){
+			dojo.deprecated("selectedTab deprecated, use selectedChild instead, will be removed in", "0.5");
+			this.selectedChild=this.selectedTab;
+		}
+		if(this.closeButton!="none"){
+			dojo.deprecated("closeButton deprecated, use closable='true' on each child instead, will be removed in", "0.5");
+		}
+		dojo.widget.TabContainer.superclass.postMixInProperties.apply(this, arguments);
+	},
+
+	fillInTemplate: function() {
+		// create the tab list that will have a tab (a.k.a. tab button) for each tab panel
+		this.tablist = dojo.widget.createWidget("TabController",
+			{
+				id: this.widgetId + "_tablist",
+				labelPosition: this.labelPosition,
+				doLayout: this.doLayout,
+				containerId: this.widgetId
+			}, this.tablistNode);
+		dojo.widget.TabContainer.superclass.fillInTemplate.apply(this, arguments);
+	},
+
+	postCreate: function(args, frag) {	
+		dojo.widget.TabContainer.superclass.postCreate.apply(this, arguments);
+
+		// size the container pane to take up the space not used by the tabs themselves
+		this.onResized();
+	},
+
+	_setupChild: function(tab){
+		if(this.closeButton=="tab" || this.closeButton=="pane"){
+			// TODO: remove in 0.5
+			tab.closable=true;
+		}
+		dojo.html.addClass(tab.domNode, "dojoTabPane");
+		dojo.widget.TabContainer.superclass._setupChild.apply(this, arguments);
+	},
+
+	onResized: function(){
+		// Summary: Configure the content pane to take up all the space except for where the tabs are
+		if(!this.doLayout){ return; }
+
+		// position the labels and the container node
+		var labelAlign=this.labelPosition.replace(/-h/,"");
+		var children = [
+			{domNode: this.tablist.domNode, layoutAlign: labelAlign},
+			{domNode: this.containerNode, layoutAlign: "client"}
+		];
+		dojo.widget.html.layout(this.domNode, children);
+
+		if(this.selectedChildWidget){
+			var containerSize = dojo.html.getContentBox(this.containerNode);
+			this.selectedChildWidget.resizeTo(containerSize.width, containerSize.height);
+		}
+	},
+
+	selectTab: function(tab, callingWidget){
+		dojo.deprecated("use selectChild() rather than selectTab(), selectTab() will be removed in", "0.5");
+		this.selectChild(tab, callingWidget);
+	},
+
+	onKey: function(e){
+		// summary
+		//	Keystroke handling for keystrokes on the tab panel itself (that were bubbled up to me)
+		//	Ctrl-up: focus is returned from the pane to the tab button
+		//	Alt-del: close tab
+		if(e.keyCode == e.KEY_UP_ARROW && e.ctrlKey){
+			// set focus to current tab
+			var button = this.correspondingTabButton || this.selectedTabWidget.tabButton;
+			button.focus();
+			dojo.event.browser.stopEvent(e);
+		}else if(e.keyCode == e.KEY_DELETE && e.altKey){
+			if (this.selectedChildWidget.closable){
+				this.closeChild(this.selectedChildWidget);
+				dojo.event.browser.stopEvent(e);
+			}
+		}
+	},
+
+	destroy: function(){
+		this.tablist.destroy();
+		dojo.widget.TabContainer.superclass.destroy.apply(this, arguments);
+	}
+});
+
+// summary
+// 	Set of tabs (the things with labels and a close button, that you click to show a tab panel).
+//	Lets the user select the currently shown pane in a TabContainer or PageContainer.
+//	TabController also monitors the TabContainer, and whenever a pane is
+//	added or deleted updates itself accordingly.
+dojo.widget.defineWidget(
+    "dojo.widget.TabController",
+    dojo.widget.PageController,
+	{
+		templateString: "<div wairole='tablist' dojoAttachEvent='onKey'></div>",
+
+		// String
+		//   Defines where tab labels go relative to tab content.
+		//   "top", "bottom", "left-h", "right-h"
+		labelPosition: "top",
+
+		doLayout: true,
+
+		// String
+		//	Class name to apply to the top dom node
+		"class": "",
+
+		// String
+		//	the name of the tab widget to create to correspond to each page
+		buttonWidget: "TabButton",
+
+		postMixInProperties: function() {
+			if(!this["class"]){
+				this["class"] = "dojoTabLabels-" + this.labelPosition + (this.doLayout ? "" : " dojoTabNoLayout");
+			}
+			dojo.widget.TabController.superclass.postMixInProperties.apply(this, arguments);
+		}
+	}
+);
+
+// summary
+//	A tab (the thing you click to select a pane).
+//	Contains the title (aka label) of the pane, and optionally a close-button to destroy the pane.
+//	This is an internal widget and should not be instantiated directly.
+dojo.widget.defineWidget("dojo.widget.TabButton", dojo.widget.PageButton,
+{
+	templateString: "<div class='dojoTab' dojoAttachEvent='onClick'>"
+						+"<div dojoAttachPoint='innerDiv'>"
+							+"<span dojoAttachPoint='titleNode' tabIndex='-1' waiRole='tab'>${this.label}</span>"
+							+"<span dojoAttachPoint='closeButtonNode' class='close closeImage' style='${this.closeButtonStyle}'"
+							+"    dojoAttachEvent='onMouseOver:onCloseButtonMouseOver; onMouseOut:onCloseButtonMouseOut; onClick:onCloseButtonClick'></span>"
+						+"</div>"
+					+"</div>",
+
+	postMixInProperties: function(){
+		this.closeButtonStyle = this.closeButton ? "" : "display: none";
+		dojo.widget.TabButton.superclass.postMixInProperties.apply(this, arguments);
+	},
+
+	fillInTemplate: function(){
+		dojo.html.disableSelection(this.titleNode);
+		dojo.widget.TabButton.superclass.fillInTemplate.apply(this, arguments);
+	}
+});
+
+
+// summary
+//	Tab for display in high-contrast mode (where background images don't show up).
+//	This is an internal widget and shouldn't be instantiated directly.
+dojo.widget.defineWidget(
+	"dojo.widget.a11y.TabButton",
+	dojo.widget.TabButton,
+	{
+		imgPath: dojo.uri.dojoUri("src/widget/templates/images/tab_close.gif"),
+		
+		templateString: "<div class='dojoTab' dojoAttachEvent='onClick;onKey'>"
+							+"<div dojoAttachPoint='innerDiv'>"
+								+"<span dojoAttachPoint='titleNode' tabIndex='-1' waiRole='tab'>${this.label}</span>"
+								+"<img class='close' src='${this.imgPath}' alt='[x]' style='${this.closeButtonStyle}'"
+								+"    dojoAttachEvent='onClick:onCloseButtonClick'>"
+							+"</div>"
+						+"</div>"
+	}
+);
+
+

Propchange: jackrabbit/trunk/contrib/jcr-browser/src/main/webapp/dojo/src/widget/TabContainer.js
------------------------------------------------------------------------------
    svn:eol-style = native

Added: jackrabbit/trunk/contrib/jcr-browser/src/main/webapp/dojo/src/widget/TaskBar.js
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/contrib/jcr-browser/src/main/webapp/dojo/src/widget/TaskBar.js?view=auto&rev=473755
==============================================================================
--- jackrabbit/trunk/contrib/jcr-browser/src/main/webapp/dojo/src/widget/TaskBar.js (added)
+++ jackrabbit/trunk/contrib/jcr-browser/src/main/webapp/dojo/src/widget/TaskBar.js Sat Nov 11 08:44:22 2006
@@ -0,0 +1,83 @@
+dojo.provide("dojo.widget.TaskBar");
+
+dojo.require("dojo.widget.*");
+dojo.require("dojo.widget.FloatingPane");
+dojo.require("dojo.widget.HtmlWidget");
+dojo.require("dojo.event.*");
+dojo.require("dojo.html.selection");
+
+// summary
+//	Widget used internally by the TaskBar;
+//	shows an icon associated w/a floating pane
+dojo.widget.defineWidget(
+	"dojo.widget.TaskBarItem",
+	dojo.widget.HtmlWidget,
+{
+	// String
+	//	path of icon for associated floating pane
+	iconSrc: '',
+	
+	// String
+	//	name of associated floating pane
+	caption: 'Untitled',
+
+	// String
+	//	widget id of associated floating pane
+	widgetId: "",
+
+	templatePath: dojo.uri.dojoUri("src/widget/templates/TaskBarItemTemplate.html"),
+	templateCssPath: dojo.uri.dojoUri("src/widget/templates/TaskBar.css"),
+
+	fillInTemplate: function() {
+		if (this.iconSrc) {
+			var img = document.createElement("img");
+			img.src = this.iconSrc;
+			this.domNode.appendChild(img);
+		}
+		this.domNode.appendChild(document.createTextNode(this.caption));
+		dojo.html.disableSelection(this.domNode);
+	},
+
+	postCreate: function() {
+		this.window=dojo.widget.getWidgetById(this.windowId);
+		this.window.explodeSrc = this.domNode;
+		dojo.event.connect(this.window, "destroy", this, "destroy")
+	},
+
+	onClick: function() {
+		this.window.toggleDisplay();
+	}
+});
+
+// summary:
+//	Displays an icon for each associated floating pane, like Windows task bar
+dojo.widget.defineWidget(
+	"dojo.widget.TaskBar",
+	dojo.widget.FloatingPane,
+	function(){
+		this._addChildStack = [];
+	},
+{
+	// TODO: this class extends floating pane merely to get the shadow;
+	//	it should extend HtmlWidget and then just call the shadow code directly
+	resizable: false,
+	titleBarDisplay: "none",
+
+	addChild: function(/*Widget*/ child) {
+		// summary: add taskbar item for specified FloatingPane
+		// TODO: this should not be called addChild(), as that has another meaning.
+		if(!this.containerNode){ 
+			this._addChildStack.push(child);
+		}else if(this._addChildStack.length > 0){
+			var oarr = this._addChildStack;
+			this._addChildStack = [];
+			dojo.lang.forEach(oarr, this.addChild, this);
+		}
+		var tbi = dojo.widget.createWidget("TaskBarItem",
+			{	windowId: child.widgetId, 
+				caption: child.title, 
+				iconSrc: child.iconSrc
+			});
+		dojo.widget.TaskBar.superclass.addChild.call(this,tbi);
+	}
+});

Propchange: jackrabbit/trunk/contrib/jcr-browser/src/main/webapp/dojo/src/widget/TaskBar.js
------------------------------------------------------------------------------
    svn:eol-style = native

Added: jackrabbit/trunk/contrib/jcr-browser/src/main/webapp/dojo/src/widget/Textbox.js
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/contrib/jcr-browser/src/main/webapp/dojo/src/widget/Textbox.js?view=auto&rev=473755
==============================================================================
--- jackrabbit/trunk/contrib/jcr-browser/src/main/webapp/dojo/src/widget/Textbox.js (added)
+++ jackrabbit/trunk/contrib/jcr-browser/src/main/webapp/dojo/src/widget/Textbox.js Sat Nov 11 08:44:22 2006
@@ -0,0 +1,84 @@
+dojo.provide("dojo.widget.Textbox");
+
+dojo.require("dojo.widget.*");
+dojo.require("dojo.widget.HtmlWidget");
+dojo.require("dojo.widget.Manager");
+dojo.require("dojo.widget.Parse");
+dojo.require("dojo.xml.Parse");
+dojo.require("dojo.lang.array");
+dojo.require("dojo.lang.common");
+
+dojo.require("dojo.i18n.common");
+dojo.requireLocalization("dojo.widget", "validate");
+
+/*
+  ****** Textbox ******
+
+  This widget is a generic textbox field.
+  Serves as a base class to derive more specialized functionality in subclasses.
+  Has the following properties that can be specified as attributes in the markup.
+
+  @attr id         The textbox id attribute.
+  @attr className  The textbox class attribute.
+  @attr name       The textbox name attribute.
+  @attr value      The textbox value attribute.
+  @attr trim       Removes leading and trailing whitespace if true.  Default is false.
+  @attr uppercase  Converts all characters to uppercase if true.  Default is false.
+  @attr lowercase  Converts all characters to lowercase if true.  Default is false.
+  @attr ucFirst    Converts the first character of each word to uppercase if true.
+  @attr lowercase  Removes all characters that are not digits if true.  Default is false.
+*/
+dojo.widget.defineWidget(
+	"dojo.widget.Textbox",
+	dojo.widget.HtmlWidget,
+	{
+		// default values for new subclass properties
+		className: "",
+		name: "",
+		value: "",
+		type: "",
+		trim: false,
+		uppercase: false,
+		lowercase: false,
+		ucFirst: false,
+		digit: false,
+		htmlfloat: "none",
+
+		templatePath: dojo.uri.dojoUri("src/widget/templates/Textbox.html"),
+	
+		// our DOM nodes
+		textbox: null,
+	
+		// Apply various filters to textbox value
+		filter: function() { 
+			if (this.trim) {
+				this.textbox.value = this.textbox.value.replace(/(^\s*|\s*$)/g, "");
+			} 
+			if (this.uppercase) {
+				this.textbox.value = this.textbox.value.toUpperCase();
+			} 
+			if (this.lowercase) {
+				this.textbox.value = this.textbox.value.toLowerCase();
+			} 
+			if (this.ucFirst) {
+				this.textbox.value = this.textbox.value.replace(/\b\w+\b/g, 
+					function(word) { return word.substring(0,1).toUpperCase() + word.substring(1).toLowerCase(); });
+			} 
+			if (this.digit) {
+				this.textbox.value = this.textbox.value.replace(/\D/g, "");
+			} 
+		},
+	
+		// event handlers, you can over-ride these in your own subclasses
+		onfocus: function() {},
+		onblur: function() { this.filter(); },
+	
+		// All functions below are called by create from dojo.widget.Widget
+		mixInProperties: function(localProperties, frag) {
+			dojo.widget.Textbox.superclass.mixInProperties.apply(this, arguments);
+			if ( localProperties["class"] ) { 
+				this.className = localProperties["class"];
+			}
+		}
+	}
+);

Propchange: jackrabbit/trunk/contrib/jcr-browser/src/main/webapp/dojo/src/widget/Textbox.js
------------------------------------------------------------------------------
    svn:eol-style = native

Added: jackrabbit/trunk/contrib/jcr-browser/src/main/webapp/dojo/src/widget/TimePicker.js
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/contrib/jcr-browser/src/main/webapp/dojo/src/widget/TimePicker.js?view=auto&rev=473755
==============================================================================
--- jackrabbit/trunk/contrib/jcr-browser/src/main/webapp/dojo/src/widget/TimePicker.js (added)
+++ jackrabbit/trunk/contrib/jcr-browser/src/main/webapp/dojo/src/widget/TimePicker.js Sat Nov 11 08:44:22 2006
@@ -0,0 +1,332 @@
+dojo.provide("dojo.widget.TimePicker");
+dojo.require("dojo.widget.*");
+dojo.require("dojo.widget.HtmlWidget");
+dojo.require("dojo.event.*");
+dojo.require("dojo.date.serialize");
+dojo.require("dojo.date.format");
+dojo.require("dojo.dom");
+dojo.require("dojo.html.style");
+
+dojo.requireLocalization("dojo.i18n.calendar", "gregorian");
+dojo.requireLocalization("dojo.widget", "TimePicker");
+
+dojo.widget.defineWidget(
+	"dojo.widget.TimePicker",
+	dojo.widget.HtmlWidget,
+	function(){
+		// selected time, JS Date object
+		this.time = "";
+		// set following flag to true if a default time should be set
+		this.useDefaultTime = false;
+		// set the following to true to set default minutes to current time, false to // use zero
+		this.useDefaultMinutes = false;
+		// rfc 3339 date
+		this.storedTime = "";
+		// time currently selected in the UI, stored in hours, minutes, seconds in the format that will be actually displayed
+		this.currentTime = {};
+		this.classNames = {
+			selectedTime: "selectedItem"
+		};
+		this.any = "any"; //FIXME: never used?
+		// dom node indecies for selected hour, minute, amPm, and "any time option"
+		this.selectedTime = {
+			hour: "",
+			minute: "",
+			amPm: "",
+			anyTime: false
+		};
+
+		// minutes are ordered as follows: ["12", "6", "1", "7", "2", "8", "3", "9", "4", "10", "5", "11"]
+		this.hourIndexMap = ["", 2, 4, 6, 8, 10, 1, 3, 5, 7, 9, 11, 0];
+		// minutes are ordered as follows: ["00", "30", "05", "35", "10", "40", "15", "45", "20", "50", "25", "55"]
+		this.minuteIndexMap = [0, 2, 4, 6, 8, 10, 1, 3, 5, 7, 9, 11];
+	},
+{
+	isContainer: false,
+	templatePath: dojo.uri.dojoUri("src/widget/templates/TimePicker.html"),
+	templateCssPath: dojo.uri.dojoUri("src/widget/templates/TimePicker.css"),
+
+	fillInTemplate: function(args, frag){
+		// Copy style info from input node to output node
+		var source = this.getFragNodeRef(frag);
+		dojo.html.copyStyle(this.domNode, source);
+
+		this.initData();
+		this.initUI();
+	},
+
+	postMixInProperties: function(localProperties, frag) {
+		dojo.widget.TimePicker.superclass.postMixInProperties.apply(this, arguments);
+		this.calendar = dojo.i18n.getLocalization("dojo.i18n.calendar", "gregorian", this.lang); // "am","pm"
+		this.widgetStrings = dojo.i18n.getLocalization("dojo.widget", "TimePicker", this.lang); // "any"
+	},
+
+	initData: function() {
+		// FIXME: doesn't currently validate the time before trying to set it
+		// Determine the date/time from stored info, or by default don't 
+		//  have a set time
+		// FIXME: should normalize against whitespace on storedTime... for now 
+		// just a lame hack
+		if(this.storedTime.indexOf("T")!=-1 && this.storedTime.split("T")[1] && this.storedTime!=" " && this.storedTime.split("T")[1]!="any") {
+			this.time = dojo.widget.TimePicker.util.fromRfcDateTime(this.storedTime, this.useDefaultMinutes, this.selectedTime.anyTime);
+		} else if (this.useDefaultTime) {
+			this.time = dojo.widget.TimePicker.util.fromRfcDateTime("", this.useDefaultMinutes, this.selectedTime.anyTime);
+		} else {
+			this.selectedTime.anyTime = true;
+			this.time = dojo.widget.TimePicker.util.fromRfcDateTime("", 0, 1);
+		}
+	},
+
+	initUI: function() {
+		// set UI to match the currently selected time
+		if(!this.selectedTime.anyTime && this.time) {
+			var amPmHour = dojo.widget.TimePicker.util.toAmPmHour(this.time.getHours());
+			var hour = amPmHour[0];
+			var isAm = amPmHour[1];
+			var minute = this.time.getMinutes();
+			var minuteIndex = parseInt(minute/5);
+			this.onSetSelectedHour(this.hourIndexMap[hour]);
+			this.onSetSelectedMinute(this.minuteIndexMap[minuteIndex]);
+			this.onSetSelectedAmPm(isAm);
+		} else {
+			this.onSetSelectedAnyTime();
+		}
+	},
+	
+	setTime: function(date) {
+		if(date) {
+			this.selectedTime.anyTime = false;
+			this.setDateTime(dojo.date.toRfc3339(date));
+		} else {
+			this.selectedTime.anyTime = true;
+		}
+		this.initData();
+		this.initUI();
+	},
+
+	setDateTime: function(rfcDate) {
+		this.storedTime = rfcDate;
+	},
+	
+	onClearSelectedHour: function(evt) {
+		this.clearSelectedHour();
+	},
+
+	onClearSelectedMinute: function(evt) {
+		this.clearSelectedMinute();
+	},
+
+	onClearSelectedAmPm: function(evt) {
+		this.clearSelectedAmPm();
+	},
+
+	onClearSelectedAnyTime: function(evt) {
+		this.clearSelectedAnyTime();
+		if(this.selectedTime.anyTime) {
+			this.selectedTime.anyTime = false;
+			this.time = dojo.widget.TimePicker.util.fromRfcDateTime("", this.useDefaultMinutes);
+			this.initUI();
+		}
+	},
+
+	clearSelectedHour: function() {
+		var hourNodes = this.hourContainerNode.getElementsByTagName("td");
+		for (var i=0; i<hourNodes.length; i++) {
+			dojo.html.setClass(hourNodes.item(i), "");
+		}
+	},
+
+	clearSelectedMinute: function() {
+		var minuteNodes = this.minuteContainerNode.getElementsByTagName("td");
+		for (var i=0; i<minuteNodes.length; i++) {
+			dojo.html.setClass(minuteNodes.item(i), "");
+		}
+	},
+
+	clearSelectedAmPm: function() {
+		var amPmNodes = this.amPmContainerNode.getElementsByTagName("td");
+		for (var i=0; i<amPmNodes.length; i++) {
+			dojo.html.setClass(amPmNodes.item(i), "");
+		}
+	},
+
+	clearSelectedAnyTime: function() {
+		dojo.html.setClass(this.anyTimeContainerNode, "anyTimeContainer");
+	},
+
+	onSetSelectedHour: function(evt) {
+		this.onClearSelectedAnyTime();
+		this.onClearSelectedHour();
+		this.setSelectedHour(evt);
+		this.onSetTime();
+	},
+
+	setSelectedHour: function(evt) {
+		if(evt && evt.target) {
+			if(evt.target.nodeType == dojo.dom.ELEMENT_NODE) {
+				var eventTarget = evt.target;
+			} else {
+				var eventTarget = evt.target.parentNode;
+			}
+			dojo.event.browser.stopEvent(evt);
+			dojo.html.setClass(eventTarget, this.classNames.selectedTime);
+			this.selectedTime["hour"] = eventTarget.innerHTML;
+		} else if (!isNaN(evt)) {
+			var hourNodes = this.hourContainerNode.getElementsByTagName("td");
+			if(hourNodes.item(evt)) {
+				dojo.html.setClass(hourNodes.item(evt), this.classNames.selectedTime);
+				this.selectedTime["hour"] = hourNodes.item(evt).innerHTML;
+			}
+		}
+		this.selectedTime.anyTime = false;
+	},
+
+	onSetSelectedMinute: function(evt) {
+		this.onClearSelectedAnyTime();
+		this.onClearSelectedMinute();
+		this.setSelectedMinute(evt);
+		this.selectedTime.anyTime = false;
+		this.onSetTime();
+	},
+
+	setSelectedMinute: function(evt) {
+		if(evt && evt.target) {
+			if(evt.target.nodeType == dojo.dom.ELEMENT_NODE) {
+				var eventTarget = evt.target;
+			} else {
+				var eventTarget = evt.target.parentNode;
+			}
+			dojo.event.browser.stopEvent(evt);
+			dojo.html.setClass(eventTarget, this.classNames.selectedTime);
+			this.selectedTime["minute"] = eventTarget.innerHTML;
+		} else if (!isNaN(evt)) {
+			var minuteNodes = this.minuteContainerNode.getElementsByTagName("td");
+			if(minuteNodes.item(evt)) {
+				dojo.html.setClass(minuteNodes.item(evt), this.classNames.selectedTime);
+				this.selectedTime["minute"] = minuteNodes.item(evt).innerHTML;
+			}
+		}
+	},
+
+	onSetSelectedAmPm: function(evt) {
+		this.onClearSelectedAnyTime();
+		this.onClearSelectedAmPm();
+		this.setSelectedAmPm(evt);
+		this.selectedTime.anyTime = false;
+		this.onSetTime();
+	},
+
+	setSelectedAmPm: function(evt) {
+		var eventTarget = evt.target;
+		if(evt && eventTarget) {
+			if(eventTarget.nodeType != dojo.dom.ELEMENT_NODE) {
+				eventTarget = eventTarget.parentNode;
+			}
+			dojo.event.browser.stopEvent(evt);
+			this.selectedTime.amPm = eventTarget.id;
+			dojo.html.setClass(eventTarget, this.classNames.selectedTime);
+		} else {
+			evt = evt ? 0 : 1;
+			var amPmNodes = this.amPmContainerNode.getElementsByTagName("td");
+			if(amPmNodes.item(evt)) {
+				this.selectedTime.amPm = amPmNodes.item(evt).id;
+				dojo.html.setClass(amPmNodes.item(evt), this.classNames.selectedTime);
+			}
+		}
+	},
+
+	onSetSelectedAnyTime: function(evt) {
+		this.onClearSelectedHour();
+		this.onClearSelectedMinute();
+		this.onClearSelectedAmPm();
+		this.setSelectedAnyTime();
+		this.onSetTime();
+	},
+
+	setSelectedAnyTime: function(evt) {
+		this.selectedTime.anyTime = true;
+		dojo.html.setClass(this.anyTimeContainerNode, this.classNames.selectedTime + " " + "anyTimeContainer");
+	},
+
+	onClick: function(evt) {
+		dojo.event.browser.stopEvent(evt);
+	},
+
+	onSetTime: function() {
+		if(this.selectedTime.anyTime) {
+			this.time = new Date();
+			var tempDateTime = dojo.widget.TimePicker.util.toRfcDateTime(this.time);
+			this.setDateTime(tempDateTime.split("T")[0]);
+		} else {
+			var hour = 12;
+			var minute = 0;
+			var isAm = false;
+			if(this.selectedTime["hour"]) {
+				hour = parseInt(this.selectedTime["hour"], 10);
+			}
+			if(this.selectedTime["minute"]) {
+				minute = parseInt(this.selectedTime["minute"], 10);
+			}
+			if(this.selectedTime["amPm"]) {
+				isAm = (this.selectedTime["amPm"].toLowerCase() == "am");
+			}
+			this.time = new Date();
+			this.time.setHours(dojo.widget.TimePicker.util.fromAmPmHour(hour, isAm));
+			this.time.setMinutes(minute);
+			this.setDateTime(dojo.widget.TimePicker.util.toRfcDateTime(this.time));
+		}
+	}
+});
+
+dojo.widget.TimePicker.util = new function() {
+	// utility functions
+	this.toRfcDateTime = function(jsDate) {
+		if(!jsDate) {
+			jsDate = new Date();
+		}
+		jsDate.setSeconds(0);
+		return dojo.date.strftime(jsDate, "%Y-%m-%dT%H:%M:00%z"); //FIXME: use dojo.date.toRfc3339 instead
+	}
+
+	this.fromRfcDateTime = function(rfcDate, useDefaultMinutes, isAnyTime) {
+		var tempDate = new Date();
+		if(!rfcDate || rfcDate.indexOf("T")==-1) {
+			if(useDefaultMinutes) {
+				tempDate.setMinutes(Math.floor(tempDate.getMinutes()/5)*5);
+			} else {
+				tempDate.setMinutes(0);
+			}
+		} else {
+			var tempTime = rfcDate.split("T")[1].split(":");
+			// fullYear, month, date
+			var tempDate = new Date();
+			tempDate.setHours(tempTime[0]);
+			tempDate.setMinutes(tempTime[1]);
+		}
+		return tempDate;
+	}
+
+	this.toAmPmHour = function(hour) {
+		var amPmHour = hour;
+		var isAm = true;
+		if (amPmHour == 0) {
+			amPmHour = 12;
+		} else if (amPmHour>12) {
+			amPmHour = amPmHour - 12;
+			isAm = false;
+		} else if (amPmHour == 12) {
+			isAm = false;
+		}
+		return [amPmHour, isAm];
+	}
+
+	this.fromAmPmHour = function(amPmHour, isAm) {
+		var hour = parseInt(amPmHour, 10);
+		if(isAm && hour == 12) {
+			hour = 0;
+		} else if (!isAm && hour<12) {
+			hour = hour + 12;
+		}
+		return hour;
+	}
+}

Propchange: jackrabbit/trunk/contrib/jcr-browser/src/main/webapp/dojo/src/widget/TimePicker.js
------------------------------------------------------------------------------
    svn:eol-style = native

Added: jackrabbit/trunk/contrib/jcr-browser/src/main/webapp/dojo/src/widget/TitlePane.js
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/contrib/jcr-browser/src/main/webapp/dojo/src/widget/TitlePane.js?view=auto&rev=473755
==============================================================================
--- jackrabbit/trunk/contrib/jcr-browser/src/main/webapp/dojo/src/widget/TitlePane.js (added)
+++ jackrabbit/trunk/contrib/jcr-browser/src/main/webapp/dojo/src/widget/TitlePane.js Sat Nov 11 08:44:22 2006
@@ -0,0 +1,51 @@
+dojo.provide("dojo.widget.TitlePane");
+dojo.require("dojo.widget.*");
+dojo.require("dojo.widget.ContentPane");
+dojo.require("dojo.html.style");
+dojo.require("dojo.lfx.*");
+
+dojo.widget.defineWidget(
+	"dojo.widget.TitlePane",
+	dojo.widget.ContentPane,
+{
+	labelNode: "",
+	labelNodeClass: "",
+	containerNodeClass: "",
+	label: "",
+	
+	open: true,
+	templatePath: dojo.uri.dojoUri("src/widget/templates/TitlePane.html"),
+
+	postCreate: function() {
+		if (this.label) {
+			this.labelNode.appendChild(document.createTextNode(this.label));
+		}
+
+		if (this.labelNodeClass) {
+			dojo.html.addClass(this.labelNode, this.labelNodeClass);
+		}	
+
+		if (this.containerNodeClass) {
+			dojo.html.addClass(this.containerNode, this.containerNodeClass);
+		}	
+
+		if (!this.open) {
+			dojo.html.hide(this.containerNode);
+		}
+		dojo.widget.TitlePane.superclass.postCreate.apply(this, arguments);
+	},
+
+	onLabelClick: function() {
+		if (this.open) {
+			dojo.lfx.wipeOut(this.containerNode, 250).play();
+			this.open=false;
+		} else {
+			dojo.lfx.wipeIn(this.containerNode, 250).play();
+			this.open=true;
+		}
+	},
+
+	setLabel: function(label) {
+		this.labelNode.innerHTML=label;
+	}
+});

Propchange: jackrabbit/trunk/contrib/jcr-browser/src/main/webapp/dojo/src/widget/TitlePane.js
------------------------------------------------------------------------------
    svn:eol-style = native

Added: jackrabbit/trunk/contrib/jcr-browser/src/main/webapp/dojo/src/widget/Toaster.js
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/contrib/jcr-browser/src/main/webapp/dojo/src/widget/Toaster.js?view=auto&rev=473755
==============================================================================
--- jackrabbit/trunk/contrib/jcr-browser/src/main/webapp/dojo/src/widget/Toaster.js (added)
+++ jackrabbit/trunk/contrib/jcr-browser/src/main/webapp/dojo/src/widget/Toaster.js Sat Nov 11 08:44:22 2006
@@ -0,0 +1,235 @@
+dojo.provide("dojo.widget.Toaster");
+
+dojo.require("dojo.widget.*");
+dojo.require("dojo.lfx.*");
+dojo.require("dojo.html.iframe");
+
+// This is mostly taken from Jesse Kuhnert's MessageNotifier.
+// Modified by Bryan Forbes to support topics and a variable delay.
+
+dojo.widget.defineWidget(
+	"dojo.widget.Toaster",
+	dojo.widget.HtmlWidget,
+	{
+		templateString: '<div dojoAttachPoint="clipNode"><div dojoAttachPoint="containerNode" dojoAttachEvent="onClick:onSelect"><div dojoAttachPoint="contentNode"></div></div></div>',
+		templateCssPath: dojo.uri.dojoUri("src/widget/templates/Toaster.css"),
+		
+		clipNode: null,
+
+		messageTopic: "",
+		contentNode: null,
+
+		_scrollConnected: false,
+		
+		// possible message types
+		messageTypes: {
+			MESSAGE: "MESSAGE",
+			WARNING: "WARNING",
+			ERROR: "ERROR",
+			FATAL: "FATAL"
+		},
+		defaultType: "MESSAGE",
+
+		// css classes
+		clipCssClass: "dojoToasterClip",
+		containerCssClass: "dojoToasterContainer",
+		contentCssClass: "dojoToasterContent",
+		messageCssClass: "dojoToasterMessage",
+		warningCssClass: "dojoToasterWarning",
+		errorCssClass: "dojoToasterError",
+		fatalCssClass: "dojoToasterFatal",
+		
+		positionDirection: "br-up",
+		positionDirectionTypes: ["br-up", "br-left", "bl-up", "bl-right", "tr-down", "tr-left", "tl-down", "tl-right"],
+		showDelay: 2000,
+
+		slideAnim: null,
+		fadeAnim: null,
+
+		bgIframe: null,
+
+		postCreate: function(){
+			this.hide();
+			dojo.html.setClass(this.clipNode, this.clipCssClass);
+			dojo.html.addClass(this.containerNode, this.containerCssClass);
+			dojo.html.setClass(this.contentNode, this.contentCssClass);
+			if(this.messageTopic){
+				dojo.event.topic.subscribe(this.messageTopic, this, "handleMessage");
+			}
+			if(!this.positionDirection || !dojo.lang.inArray(this.positionDirectionTypes, this.positionDirection)){
+				this.positionDirection = this.positionDirectionTypes.BRU;
+			}
+		},
+
+		handleMessage: function(msg){
+			if(dojo.lang.isString(msg)){
+				this.setContent(msg);
+			}else{
+				this.setContent(msg["message"], msg["type"], msg["delay"]);
+			}
+		},
+
+		setContent: function(msg, messageType, delay){
+			var delay = delay||this.showDelay;
+			// sync animations so there are no ghosted fades and such
+			if(this.slideAnim && this.slideAnim.status() == "playing"){
+				dojo.lang.setTimeout(50, dojo.lang.hitch(this, function(){
+					this.setContent(msg, messageType);
+				}));
+				return;
+			}else if(this.slideAnim){
+				this.slideAnim.stop();
+				if(this.fadeAnim) this.fadeAnim.stop();
+			}
+			if(!msg){
+				dojo.debug(this.widgetId + ".setContent() incoming content was null, ignoring.");
+				return;
+			}
+			if(!this.positionDirection || !dojo.lang.inArray(this.positionDirectionTypes, this.positionDirection)){
+				dojo.raise(this.widgetId + ".positionDirection is an invalid value: " + this.positionDirection);
+			}
+
+			// determine type of content and apply appropriately
+			dojo.html.removeClass(this.containerNode, this.messageCssClass);
+			dojo.html.removeClass(this.containerNode, this.warningCssClass);
+			dojo.html.removeClass(this.containerNode, this.errorCssClass);
+			dojo.html.removeClass(this.containerNode, this.fatalCssClass);
+
+			dojo.html.clearOpacity(this.containerNode);
+			
+			if(msg instanceof String || typeof msg == "string"){
+				this.contentNode.innerHTML = msg;
+			}else if(dojo.html.isNode(msg)){
+				this.contentNode.innerHTML = dojo.html.getContentAsString(msg);
+			}else{
+				dojo.raise("Toaster.setContent(): msg is of unknown type:" + msg);
+			}
+
+			switch(messageType){
+				case this.messageTypes.WARNING:
+					dojo.html.addClass(this.containerNode, this.warningCssClass);
+					break;
+				case this.messageTypes.ERROR:
+					dojo.html.addClass(this.containerNode, this.errorCssClass);
+					break
+				case this.messageTypes.FATAL:
+					dojo.html.addClass(this.containerNode, this.fatalCssClass);
+					break;
+				case this.messageTypes.MESSAGE:
+				default:
+					dojo.html.addClass(this.containerNode, this.messageCssClass);
+					break;
+			}
+
+			// now do funky animation of widget appearing from
+			// bottom right of page and up
+			this.show();
+
+			var nodeSize = dojo.html.getMarginBox(this.containerNode);
+
+			// sets up initial position of container node and slide-out direction
+			if(this.positionDirection.indexOf("-up") >= 0){
+				this.containerNode.style.left=0+"px";
+				this.containerNode.style.top=nodeSize.height + 10 + "px";
+			}else if(this.positionDirection.indexOf("-left") >= 0){
+				this.containerNode.style.left=nodeSize.width + 10 +"px";
+				this.containerNode.style.top=0+"px";
+			}else if(this.positionDirection.indexOf("-right") >= 0){
+				this.containerNode.style.left = 0 - nodeSize.width - 10 + "px";
+				this.containerNode.style.top = 0+"px";
+			}else if(this.positionDirection.indexOf("-down") >= 0){
+				this.containerNode.style.left = 0+"px";
+				this.containerNode.style.top = 0 - nodeSize.height - 10 + "px";
+			}else{
+				dojo.raise(this.widgetId + ".positionDirection is an invalid value: " + this.positionDirection);
+			}
+
+			this.slideAnim = dojo.lfx.html.slideTo(
+				this.containerNode,
+				{ top: 0, left: 0 },
+				450,
+				null,
+				dojo.lang.hitch(this, function(nodes, anim){
+					dojo.lang.setTimeout(dojo.lang.hitch(this, function(evt){
+						// we must hide the iframe in order to fade
+						// TODO: figure out how to fade with a BackgroundIframe
+						if(this.bgIframe){
+							this.bgIframe.hide();
+						}
+						// can't do a fadeHide because we're fading the
+						// inner node rather than the clipping node
+						this.fadeAnim = dojo.lfx.html.fadeOut(
+							this.containerNode,
+							1000,
+							null,
+							dojo.lang.hitch(this, function(evt){
+								this.hide();
+							})).play();
+					}), delay);
+				})).play();
+		},
+
+		placeClip: function(){
+			var scroll = dojo.html.getScroll();
+			var view = dojo.html.getViewport();
+
+			var nodeSize = dojo.html.getMarginBox(this.containerNode);
+
+			// sets up the size of the clipping node
+			this.clipNode.style.height = nodeSize.height+"px";
+			this.clipNode.style.width = nodeSize.width+"px";
+
+			// sets up the position of the clipping node
+			if(this.positionDirection.match(/^t/)){
+				this.clipNode.style.top = scroll.top+"px";
+			}else if(this.positionDirection.match(/^b/)){
+				this.clipNode.style.top = (view.height - nodeSize.height - 2 + scroll.top)+"px";
+			}
+			if(this.positionDirection.match(/^[tb]r-/)){
+				this.clipNode.style.left = (view.width - nodeSize.width - 1 - scroll.left)+"px";
+			}else if(this.positionDirection.match(/^[tb]l-/)){
+				this.clipNode.style.left = 0 + "px";
+			}
+
+			this.clipNode.style.clip = "rect(0px, " + nodeSize.width + "px, " + nodeSize.height + "px, 0px)";
+
+			if(dojo.render.html.ie){
+				if(!this.bgIframe){
+					this.bgIframe = new dojo.html.BackgroundIframe(this.containerNode);
+					this.bgIframe.setZIndex(this.containerNode);
+				}
+				this.bgIframe.onResized();
+				this.bgIframe.show();
+			}
+		},
+
+		onSelect: function(e) { },
+
+		onScroll: function(){
+			this.placeClip();
+		},
+
+		show: function(){
+			dojo.widget.Toaster.superclass.show.call(this);
+
+			this.placeClip();
+
+			if(!this._scrollConnected){
+				this._scrollConnected = true;
+				dojo.event.connect(window, "onscroll", this, "onScroll");
+			}
+		},
+
+		hide: function(){
+			dojo.widget.Toaster.superclass.hide.call(this);
+
+			if(this._scrollConnected){
+				this._scrollConnected = false;
+				dojo.event.disconnect(window, "onscroll", this, "onScroll");
+			}
+
+			dojo.html.setOpacity(this.containerNode, 1.0);
+		}
+	},
+	"html"
+);

Propchange: jackrabbit/trunk/contrib/jcr-browser/src/main/webapp/dojo/src/widget/Toaster.js
------------------------------------------------------------------------------
    svn:eol-style = native

Added: jackrabbit/trunk/contrib/jcr-browser/src/main/webapp/dojo/src/widget/Toggler.js
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/contrib/jcr-browser/src/main/webapp/dojo/src/widget/Toggler.js?view=auto&rev=473755
==============================================================================
--- jackrabbit/trunk/contrib/jcr-browser/src/main/webapp/dojo/src/widget/Toggler.js (added)
+++ jackrabbit/trunk/contrib/jcr-browser/src/main/webapp/dojo/src/widget/Toggler.js Sat Nov 11 08:44:22 2006
@@ -0,0 +1,24 @@
+dojo.provide("dojo.widget.Toggler");
+dojo.require("dojo.widget.*");
+dojo.require("dojo.event.*");
+
+// clicking on this node shows/hides another widget
+
+dojo.widget.defineWidget(
+	"dojo.widget.Toggler",
+	dojo.widget.HtmlWidget,
+{
+	// Associated widget 
+	targetId: '',
+	
+	fillInTemplate: function() {
+		dojo.event.connect(this.domNode, "onclick", this, "onClick");
+	},
+	
+	onClick: function() {
+		var pane = dojo.widget.byId(this.targetId);
+		if(!pane){ return; }
+		pane.explodeSrc = this.domNode;
+		pane.toggleShowing();
+	}
+});

Propchange: jackrabbit/trunk/contrib/jcr-browser/src/main/webapp/dojo/src/widget/Toggler.js
------------------------------------------------------------------------------
    svn:eol-style = native

Added: jackrabbit/trunk/contrib/jcr-browser/src/main/webapp/dojo/src/widget/Toolbar.js
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/contrib/jcr-browser/src/main/webapp/dojo/src/widget/Toolbar.js?view=auto&rev=473755
==============================================================================
--- jackrabbit/trunk/contrib/jcr-browser/src/main/webapp/dojo/src/widget/Toolbar.js (added)
+++ jackrabbit/trunk/contrib/jcr-browser/src/main/webapp/dojo/src/widget/Toolbar.js Sat Nov 11 08:44:22 2006
@@ -0,0 +1,936 @@
+dojo.provide("dojo.widget.Toolbar");
+
+dojo.require("dojo.widget.*");
+dojo.require("dojo.html.style");
+
+/* ToolbarContainer
+ *******************/
+dojo.widget.defineWidget(
+	"dojo.widget.ToolbarContainer",
+	dojo.widget.HtmlWidget,
+{
+	isContainer: true,
+
+	templateString: '<div class="toolbarContainer" dojoAttachPoint="containerNode"></div>',
+	templateCssPath: dojo.uri.dojoUri("src/widget/templates/Toolbar.css"),
+
+	getItem: function(name) {
+		if(name instanceof dojo.widget.ToolbarItem) { return name; }
+		for(var i = 0; i < this.children.length; i++) {
+			var child = this.children[i];
+			if(child instanceof dojo.widget.Toolbar) {
+				var item = child.getItem(name);
+				if(item) { return item; }
+			}
+		}
+		return null;
+	},
+
+	getItems: function() {
+		var items = [];
+		for(var i = 0; i < this.children.length; i++) {
+			var child = this.children[i];
+			if(child instanceof dojo.widget.Toolbar) {
+				items = items.concat(child.getItems());
+			}
+		}
+		return items;
+	},
+
+	enable: function() {
+		for(var i = 0; i < this.children.length; i++) {
+			var child = this.children[i];
+			if(child instanceof dojo.widget.Toolbar) {
+				child.enable.apply(child, arguments);
+			}
+		}
+	},
+
+	disable: function() {
+		for(var i = 0; i < this.children.length; i++) {
+			var child = this.children[i];
+			if(child instanceof dojo.widget.Toolbar) {
+				child.disable.apply(child, arguments);
+			}
+		}
+	},
+
+	select: function(name) {
+		for(var i = 0; i < this.children.length; i++) {
+			var child = this.children[i];
+			if(child instanceof dojo.widget.Toolbar) {
+				child.select(arguments);
+			}
+		}
+	},
+
+	deselect: function(name) {
+		for(var i = 0; i < this.children.length; i++) {
+			var child = this.children[i];
+			if(child instanceof dojo.widget.Toolbar) {
+				child.deselect(arguments);
+			}
+		}
+	},
+
+	getItemsState: function() {
+		var values = {};
+		for(var i = 0; i < this.children.length; i++) {
+			var child = this.children[i];
+			if(child instanceof dojo.widget.Toolbar) {
+				dojo.lang.mixin(values, child.getItemsState());
+			}
+		}
+		return values;
+	},
+
+	getItemsActiveState: function() {
+		var values = {};
+		for(var i = 0; i < this.children.length; i++) {
+			var child = this.children[i];
+			if(child instanceof dojo.widget.Toolbar) {
+				dojo.lang.mixin(values, child.getItemsActiveState());
+			}
+		}
+		return values;
+	},
+
+	getItemsSelectedState: function() {
+		var values = {};
+		for(var i = 0; i < this.children.length; i++) {
+			var child = this.children[i];
+			if(child instanceof dojo.widget.Toolbar) {
+				dojo.lang.mixin(values, child.getItemsSelectedState());
+			}
+		}
+		return values;
+	}
+});
+
+/* Toolbar
+ **********/
+
+dojo.widget.defineWidget(
+	"dojo.widget.Toolbar",
+	dojo.widget.HtmlWidget,
+{
+	isContainer: true,
+
+	templateString: '<div class="toolbar" dojoAttachPoint="containerNode" unselectable="on" dojoOnMouseover="_onmouseover" dojoOnMouseout="_onmouseout" dojoOnClick="_onclick" dojoOnMousedown="_onmousedown" dojoOnMouseup="_onmouseup"></div>',
+
+	// given a node, tries to find it's toolbar item
+	_getItem: function(node) {
+		var start = new Date();
+		var widget = null;
+		while(node && node != this.domNode) {
+			if(dojo.html.hasClass(node, "toolbarItem")) {
+				var widgets = dojo.widget.manager.getWidgetsByFilter(function(w) { return w.domNode == node; });
+				if(widgets.length == 1) {
+					widget = widgets[0];
+					break;
+				} else if(widgets.length > 1) {
+					dojo.raise("Toolbar._getItem: More than one widget matches the node");
+				}
+			}
+			node = node.parentNode;
+		}
+		return widget;
+	},
+
+	_onmouseover: function(e) {
+		var widget = this._getItem(e.target);
+		if(widget && widget._onmouseover) { widget._onmouseover(e); }
+	},
+
+	_onmouseout: function(e) {
+		var widget = this._getItem(e.target);
+		if(widget && widget._onmouseout) { widget._onmouseout(e); }
+	},
+
+	_onclick: function(e) {
+		var widget = this._getItem(e.target);
+		if(widget && widget._onclick){
+			widget._onclick(e);
+		}
+	},
+
+	_onmousedown: function(e) {
+		var widget = this._getItem(e.target);
+		if(widget && widget._onmousedown) { widget._onmousedown(e); }
+	},
+
+	_onmouseup: function(e) {
+		var widget = this._getItem(e.target);
+		if(widget && widget._onmouseup) { widget._onmouseup(e); }
+	},
+
+	addChild: function(item, pos, props) {
+		var widget = dojo.widget.ToolbarItem.make(item, null, props);
+		var ret = dojo.widget.Toolbar.superclass.addChild.call(this, widget, null, pos, null);
+		return ret;
+	},
+
+	push: function() {
+		for(var i = 0; i < arguments.length; i++) {
+			this.addChild(arguments[i]);
+		}
+	},
+
+	getItem: function(name) {
+		if(name instanceof dojo.widget.ToolbarItem) { return name; }
+		for(var i = 0; i < this.children.length; i++) {
+			var child = this.children[i];
+			if(child instanceof dojo.widget.ToolbarItem
+				&& child._name == name) { return child; }
+		}
+		return null;
+	},
+
+	getItems: function() {
+		var items = [];
+		for(var i = 0; i < this.children.length; i++) {
+			var child = this.children[i];
+			if(child instanceof dojo.widget.ToolbarItem) {
+				items.push(child);
+			}
+		}
+		return items;
+	},
+
+	getItemsState: function() {
+		var values = {};
+		for(var i = 0; i < this.children.length; i++) {
+			var child = this.children[i];
+			if(child instanceof dojo.widget.ToolbarItem) {
+				values[child._name] = {
+					selected: child._selected,
+					enabled: child._enabled
+				};
+			}
+		}
+		return values;
+	},
+
+	getItemsActiveState: function() {
+		var values = this.getItemsState();
+		for(var item in values) {
+			values[item] = values[item].enabled;
+		}
+		return values;
+	},
+
+	getItemsSelectedState: function() {
+		var values = this.getItemsState();
+		for(var item in values) {
+			values[item] = values[item].selected;
+		}
+		return values;
+	},
+
+	enable: function() {
+		var items = arguments.length ? arguments : this.children;
+		for(var i = 0; i < items.length; i++) {
+			var child = this.getItem(items[i]);
+			if(child instanceof dojo.widget.ToolbarItem) {
+				child.enable(false, true);
+			}
+		}
+	},
+
+	disable: function() {
+		var items = arguments.length ? arguments : this.children;
+		for(var i = 0; i < items.length; i++) {
+			var child = this.getItem(items[i]);
+			if(child instanceof dojo.widget.ToolbarItem) {
+				child.disable();
+			}
+		}
+	},
+
+	select: function() {
+		for(var i = 0; i < arguments.length; i++) {
+			var name = arguments[i];
+			var item = this.getItem(name);
+			if(item) { item.select(); }
+		}
+	},
+
+	deselect: function() {
+		for(var i = 0; i < arguments.length; i++) {
+			var name = arguments[i];
+			var item = this.getItem(name);
+			if(item) { item.disable(); }
+		}
+	},
+
+	setValue: function() {
+		for(var i = 0; i < arguments.length; i += 2) {
+			var name = arguments[i], value = arguments[i+1];
+			var item = this.getItem(name);
+			if(item) {
+				if(item instanceof dojo.widget.ToolbarItem) {
+					item.setValue(value);
+				}
+			}
+		}
+	}
+});
+
+/* ToolbarItem hierarchy:
+	- ToolbarItem
+		- ToolbarButton
+		- ToolbarDialog
+			- ToolbarMenu
+		- ToolbarSeparator
+			- ToolbarSpace
+				- ToolbarFlexibleSpace
+*/
+
+
+/* ToolbarItem
+ **************/
+dojo.widget.defineWidget(
+	"dojo.widget.ToolbarItem",
+	dojo.widget.HtmlWidget,
+{
+	templateString: '<span unselectable="on" class="toolbarItem"></span>',
+
+	_name: null,
+	getName: function() { return this._name; },
+	setName: function(value) { return (this._name = value); },
+	getValue: function() { return this.getName(); },
+	setValue: function(value) { return this.setName(value); },
+
+	_selected: false,
+	isSelected: function() { return this._selected; },
+	setSelected: function(is, force, preventEvent) {
+		if(!this._toggleItem && !force) { return; }
+		is = Boolean(is);
+		if(force || this._enabled && this._selected != is) {
+			this._selected = is;
+			this.update();
+			if(!preventEvent) {
+				this._fireEvent(is ? "onSelect" : "onDeselect");
+				this._fireEvent("onChangeSelect");
+			}
+		}
+	},
+	select: function(force, preventEvent) {
+		return this.setSelected(true, force, preventEvent);
+	},
+	deselect: function(force, preventEvent) {
+		return this.setSelected(false, force, preventEvent);
+	},
+
+	_toggleItem: false,
+	isToggleItem: function() { return this._toggleItem; },
+	setToggleItem: function(value) { this._toggleItem = Boolean(value); },
+
+	toggleSelected: function(force) {
+		return this.setSelected(!this._selected, force);
+	},
+
+	_enabled: true,
+	isEnabled: function() { return this._enabled; },
+	setEnabled: function(is, force, preventEvent) {
+		is = Boolean(is);
+		if(force || this._enabled != is) {
+			this._enabled = is;
+			this.update();
+			if(!preventEvent) {
+				this._fireEvent(this._enabled ? "onEnable" : "onDisable");
+				this._fireEvent("onChangeEnabled");
+			}
+		}
+		return this._enabled;
+	},
+	enable: function(force, preventEvent) {
+		return this.setEnabled(true, force, preventEvent);
+	},
+	disable: function(force, preventEvent) {
+		return this.setEnabled(false, force, preventEvent);
+	},
+	toggleEnabled: function(force, preventEvent) {
+		return this.setEnabled(!this._enabled, force, preventEvent);
+	},
+
+	_icon: null,
+	getIcon: function() { return this._icon; },
+	setIcon: function(value) {
+		var icon = dojo.widget.Icon.make(value);
+		if(this._icon) {
+			this._icon.setIcon(icon);
+		} else {
+			this._icon = icon;
+		}
+		var iconNode = this._icon.getNode();
+		if(iconNode.parentNode != this.domNode) {
+			if(this.domNode.hasChildNodes()) {
+				this.domNode.insertBefore(iconNode, this.domNode.firstChild);
+			} else {
+				this.domNode.appendChild(iconNode);
+			}
+		}
+		return this._icon;
+	},
+
+	// TODO: update the label node (this.labelNode?)
+	_label: "",
+	getLabel: function() { return this._label; },
+	setLabel: function(value) {
+		var ret = (this._label = value);
+		if(!this.labelNode) {
+			this.labelNode = document.createElement("span");
+			this.domNode.appendChild(this.labelNode);
+		}
+		this.labelNode.innerHTML = "";
+		this.labelNode.appendChild(document.createTextNode(this._label));
+		this.update();
+		return ret;
+	},
+
+	// fired from: setSelected, setEnabled, setLabel
+	update: function() {
+		if(this._enabled) {
+			dojo.html.removeClass(this.domNode, "disabled");
+			if(this._selected) {
+				dojo.html.addClass(this.domNode, "selected");
+			} else {
+				dojo.html.removeClass(this.domNode, "selected");
+			}
+		} else {
+			this._selected = false;
+			dojo.html.addClass(this.domNode, "disabled");
+			dojo.html.removeClass(this.domNode, "down");
+			dojo.html.removeClass(this.domNode, "hover");
+		}
+		this._updateIcon();
+	},
+
+	_updateIcon: function() {
+		if(this._icon) {
+			if(this._enabled) {
+				if(this._cssHover) {
+					this._icon.hover();
+				} else if(this._selected) {
+					this._icon.select();
+				} else {
+					this._icon.enable();
+				}
+			} else {
+				this._icon.disable();
+			}
+		}
+	},
+
+	_fireEvent: function(evt) {
+		if(typeof this[evt] == "function") {
+			var args = [this];
+			for(var i = 1; i < arguments.length; i++) {
+				args.push(arguments[i]);
+			}
+			this[evt].apply(this, args);
+		}
+	},
+
+	_onmouseover: function(e) {
+		if(!this._enabled) { return; }
+		dojo.html.addClass(this.domNode, "hover");
+		this._fireEvent("onMouseOver");
+	},
+
+	_onmouseout: function(e) {
+		dojo.html.removeClass(this.domNode, "hover");
+		dojo.html.removeClass(this.domNode, "down");
+		if(!this._selected) {
+			dojo.html.removeClass(this.domNode, "selected");
+		}
+		this._fireEvent("onMouseOut");
+	},
+
+	_onclick: function(e) {
+		// FIXME: buttons never seem to have this._enabled set to true on Opera 9
+		// dojo.debug("widget:", this.widgetType, ":", this.getName(), ", enabled:", this._enabled);
+		if(this._enabled && !this._toggleItem) {
+			this._fireEvent("onClick");
+		}
+	},
+
+	_onmousedown: function(e) {
+		if(e.preventDefault) { e.preventDefault(); }
+		if(!this._enabled) { return; }
+		dojo.html.addClass(this.domNode, "down");
+		if(this._toggleItem) {
+			if(this.parent.preventDeselect && this._selected) {
+				return;
+			}
+			this.toggleSelected();
+		}
+		this._fireEvent("onMouseDown");
+	},
+
+	_onmouseup: function(e) {
+		dojo.html.removeClass(this.domNode, "down");
+		this._fireEvent("onMouseUp");
+	},
+
+	onClick: function() { },
+	onMouseOver: function() { },
+	onMouseOut: function() { },
+	onMouseDown: function() { },
+	onMouseUp: function() { },
+
+	fillInTemplate: function(args, frag) {
+		if(args.name) { this._name = args.name; }
+		if(args.selected) { this.select(); }
+		if(args.disabled) { this.disable(); }
+		if(args.label) { this.setLabel(args.label); }
+		if(args.icon) { this.setIcon(args.icon); }
+		if(args.toggleitem||args.toggleItem) { this.setToggleItem(true); }
+	}
+});
+
+dojo.widget.ToolbarItem.make = function(wh, whIsType, props) {
+	var item = null;
+
+	if(wh instanceof Array) {
+		item = dojo.widget.createWidget("ToolbarButtonGroup", props);
+		item.setName(wh[0]);
+		for(var i = 1; i < wh.length; i++) {
+			item.addChild(wh[i]);
+		}
+	} else if(wh instanceof dojo.widget.ToolbarItem) {
+		item = wh;
+	} else if(wh instanceof dojo.uri.Uri) {
+		item = dojo.widget.createWidget("ToolbarButton",
+			dojo.lang.mixin(props||{}, {icon: new dojo.widget.Icon(wh.toString())}));
+	} else if(whIsType) {
+		item = dojo.widget.createWidget(wh, props);
+	} else if(typeof wh == "string" || wh instanceof String) {
+		switch(wh.charAt(0)) {
+			case "|":
+			case "-":
+			case "/":
+				item = dojo.widget.createWidget("ToolbarSeparator", props);
+				break;
+			case " ":
+				if(wh.length == 1) {
+					item = dojo.widget.createWidget("ToolbarSpace", props);
+				} else {
+					item = dojo.widget.createWidget("ToolbarFlexibleSpace", props);
+				}
+				break;
+			default:
+				if(/\.(gif|jpg|jpeg|png)$/i.test(wh)) {
+					item = dojo.widget.createWidget("ToolbarButton",
+						dojo.lang.mixin(props||{}, {icon: new dojo.widget.Icon(wh.toString())}));
+				} else {
+					item = dojo.widget.createWidget("ToolbarButton",
+						dojo.lang.mixin(props||{}, {label: wh.toString()}));
+				}
+		}
+	} else if(wh && wh.tagName && /^img$/i.test(wh.tagName)) {
+		item = dojo.widget.createWidget("ToolbarButton",
+			dojo.lang.mixin(props||{}, {icon: wh}));
+	} else {
+		item = dojo.widget.createWidget("ToolbarButton",
+			dojo.lang.mixin(props||{}, {label: wh.toString()}));
+	}
+	return item;
+}
+
+/* ToolbarButtonGroup
+ *********************/
+dojo.widget.defineWidget(
+	"dojo.widget.ToolbarButtonGroup",
+	dojo.widget.ToolbarItem,
+{
+	isContainer: true,
+
+	templateString: '<span unselectable="on" class="toolbarButtonGroup" dojoAttachPoint="containerNode"></span>',
+
+	// if a button has the same name, it will be selected
+	// if this is set to a number, the button at that index will be selected
+	defaultButton: "",
+
+    postCreate: function() {
+        for (var i = 0; i < this.children.length; i++) {
+            this._injectChild(this.children[i]);
+        }
+    },
+
+	addChild: function(item, pos, props) {
+		var widget = dojo.widget.ToolbarItem.make(item, null, dojo.lang.mixin(props||{}, {toggleItem:true}));
+		var ret = dojo.widget.ToolbarButtonGroup.superclass.addChild.call(this, widget, null, pos, null);
+        this._injectChild(widget);
+        return ret;
+    },
+
+    _injectChild: function(widget) {
+        dojo.event.connect(widget, "onSelect", this, "onChildSelected");
+        dojo.event.connect(widget, "onDeselect", this, "onChildDeSelected");
+        if(widget._name == this.defaultButton
+			|| (typeof this.defaultButton == "number"
+			&& this.children.length-1 == this.defaultButton)) {
+			widget.select(false, true);
+		}
+	},
+
+	getItem: function(name) {
+		if(name instanceof dojo.widget.ToolbarItem) { return name; }
+		for(var i = 0; i < this.children.length; i++) {
+			var child = this.children[i];
+			if(child instanceof dojo.widget.ToolbarItem
+				&& child._name == name) { return child; }
+		}
+		return null;
+	},
+
+	getItems: function() {
+		var items = [];
+		for(var i = 0; i < this.children.length; i++) {
+			var child = this.children[i];
+			if(child instanceof dojo.widget.ToolbarItem) {
+				items.push(child);
+			}
+		}
+		return items;
+	},
+
+	onChildSelected: function(e) {
+		this.select(e._name);
+	},
+
+	onChildDeSelected: function(e) {
+		this._fireEvent("onChangeSelect", this._value);
+	},
+
+	enable: function(force, preventEvent) {
+		for(var i = 0; i < this.children.length; i++) {
+			var child = this.children[i];
+			if(child instanceof dojo.widget.ToolbarItem) {
+				child.enable(force, preventEvent);
+				if(child._name == this._value) {
+					child.select(force, preventEvent);
+				}
+			}
+		}
+	},
+
+	disable: function(force, preventEvent) {
+		for(var i = 0; i < this.children.length; i++) {
+			var child = this.children[i];
+			if(child instanceof dojo.widget.ToolbarItem) {
+				child.disable(force, preventEvent);
+			}
+		}
+	},
+
+	_value: "",
+	getValue: function() { return this._value; },
+
+	select: function(name, force, preventEvent) {
+		for(var i = 0; i < this.children.length; i++) {
+			var child = this.children[i];
+			if(child instanceof dojo.widget.ToolbarItem) {
+				if(child._name == name) {
+					child.select(force, preventEvent);
+					this._value = name;
+				} else {
+					child.deselect(true, true);
+				}
+			}
+		}
+		if(!preventEvent) {
+			this._fireEvent("onSelect", this._value);
+			this._fireEvent("onChangeSelect", this._value);
+		}
+	},
+	setValue: this.select,
+
+	preventDeselect: false // if true, once you select one, you can't have none selected
+});
+
+/* ToolbarButton
+ ***********************/
+dojo.widget.defineWidget(
+	"dojo.widget.ToolbarButton",
+	dojo.widget.ToolbarItem,
+{
+	fillInTemplate: function(args, frag) {
+		dojo.widget.ToolbarButton.superclass.fillInTemplate.call(this, args, frag);
+		dojo.html.addClass(this.domNode, "toolbarButton");
+		if(this._icon) {
+			this.setIcon(this._icon);
+		}
+		if(this._label) {
+			this.setLabel(this._label);
+		}
+
+		if(!this._name) {
+			if(this._label) {
+				this.setName(this._label);
+			} else if(this._icon) {
+				var src = this._icon.getSrc("enabled").match(/[\/^]([^\.\/]+)\.(gif|jpg|jpeg|png)$/i);
+				if(src) { this.setName(src[1]); }
+			} else {
+				this._name = this._widgetId;
+			}
+		}
+	}
+});
+
+/* ToolbarDialog
+ **********************/
+dojo.widget.defineWidget(
+	"dojo.widget.ToolbarDialog",
+	dojo.widget.ToolbarButton,
+{
+	fillInTemplate: function (args, frag) {
+		dojo.widget.ToolbarDialog.superclass.fillInTemplate.call(this, args, frag);
+		dojo.event.connect(this, "onSelect", this, "showDialog");
+		dojo.event.connect(this, "onDeselect", this, "hideDialog");
+	},
+
+	showDialog: function (e) {
+		dojo.lang.setTimeout(dojo.event.connect, 1, document, "onmousedown", this, "deselect");
+	},
+
+	hideDialog: function (e) {
+		dojo.event.disconnect(document, "onmousedown", this, "deselect");
+	}
+
+});
+
+/* ToolbarMenu
+ **********************/
+dojo.widget.defineWidget(
+	"dojo.widget.ToolbarMenu",
+	dojo.widget.ToolbarDialog,
+	{}
+);
+
+/* ToolbarMenuItem
+ ******************/
+dojo.widget.ToolbarMenuItem = function() {
+}
+
+/* ToolbarSeparator
+ **********************/
+dojo.widget.defineWidget(
+	"dojo.widget.ToolbarSeparator",
+	dojo.widget.ToolbarItem,
+{
+	templateString: '<span unselectable="on" class="toolbarItem toolbarSeparator"></span>',
+
+	defaultIconPath: new dojo.uri.dojoUri("src/widget/templates/buttons/sep.gif"),
+
+	fillInTemplate: function(args, frag, skip) {
+		dojo.widget.ToolbarSeparator.superclass.fillInTemplate.call(this, args, frag);
+		this._name = this.widgetId;
+		if(!skip) {
+			if(!this._icon) {
+				this.setIcon(this.defaultIconPath);
+			}
+			this.domNode.appendChild(this._icon.getNode());
+		}
+	},
+
+	// don't want events!
+	_onmouseover: null,
+    _onmouseout: null,
+    _onclick: null,
+    _onmousedown: null,
+    _onmouseup: null
+});
+
+/* ToolbarSpace
+ **********************/
+dojo.widget.defineWidget(
+	"dojo.widget.ToolbarSpace",
+	dojo.widget.ToolbarSeparator,
+{
+	fillInTemplate: function(args, frag, skip) {
+		dojo.widget.ToolbarSpace.superclass.fillInTemplate.call(this, args, frag, true);
+		if(!skip) {
+			dojo.html.addClass(this.domNode, "toolbarSpace");
+		}
+	}
+});
+
+/* ToolbarSelect
+ ******************/
+
+dojo.widget.defineWidget(
+	"dojo.widget.ToolbarSelect",
+	dojo.widget.ToolbarItem,
+{
+	templateString: '<span class="toolbarItem toolbarSelect" unselectable="on"><select dojoAttachPoint="selectBox" dojoOnChange="changed"></select></span>',
+
+	fillInTemplate: function(args, frag) {
+		dojo.widget.ToolbarSelect.superclass.fillInTemplate.call(this, args, frag, true);
+		var keys = args.values;
+		var i = 0;
+		for(var val in keys) {
+			var opt = document.createElement("option");
+			opt.setAttribute("value", keys[val]);
+			opt.innerHTML = val;
+			this.selectBox.appendChild(opt);
+		}
+	},
+
+	changed: function(e) {
+		this._fireEvent("onSetValue", this.selectBox.value);
+	},
+
+	setEnabled: function(is, force, preventEvent) {
+		var ret = dojo.widget.ToolbarSelect.superclass.setEnabled.call(this, is, force, preventEvent);
+		this.selectBox.disabled = !this._enabled;
+		return ret;
+	},
+
+	// don't want events!
+	_onmouseover: null,
+    _onmouseout: null,
+    _onclick: null,
+    _onmousedown: null,
+    _onmouseup: null
+});
+
+/* Icon
+ *********/
+// arguments can be IMG nodes, Image() instances or URLs -- enabled is the only one required
+dojo.widget.Icon = function(enabled, disabled, hovered, selected){
+	if(!arguments.length){
+		// FIXME: should this be dojo.raise?
+		throw new Error("Icon must have at least an enabled state");
+	}
+	var states = ["enabled", "disabled", "hovered", "selected"];
+	var currentState = "enabled";
+	var domNode = document.createElement("img");
+
+	this.getState = function(){ return currentState; }
+	this.setState = function(value){
+		if(dojo.lang.inArray(states, value)){
+			if(this[value]){
+				currentState = value;
+				var img = this[currentState];
+				if ((dojo.render.html.ie55 || dojo.render.html.ie60) && img.src && img.src.match(/[.]png$/i) ) {
+					domNode.width = img.width||img.offsetWidth;
+					domNode.height = img.height||img.offsetHeight;
+					domNode.setAttribute("src", dojo.uri.dojoUri("src/widget/templates/images/blank.gif").uri);
+					domNode.style.filter="progid:DXImageTransform.Microsoft.AlphaImageLoader(src='"+img.src+"',sizingMethod='image')";
+				} else {
+					domNode.setAttribute("src", img.src);
+				}
+			}
+		}else{
+			throw new Error("Invalid state set on Icon (state: " + value + ")");
+		}
+	}
+
+	this.setSrc = function(state, value){
+		if(/^img$/i.test(value.tagName)){
+			this[state] = value;
+		}else if(typeof value == "string" || value instanceof String
+			|| value instanceof dojo.uri.Uri){
+			this[state] = new Image();
+			this[state].src = value.toString();
+		}
+		return this[state];
+	}
+
+	this.setIcon = function(icon){
+		for(var i = 0; i < states.length; i++){
+			if(icon[states[i]]){
+				this.setSrc(states[i], icon[states[i]]);
+			}
+		}
+		this.update();
+	}
+
+	this.enable = function(){ this.setState("enabled"); }
+	this.disable = function(){ this.setState("disabled"); }
+	this.hover = function(){ this.setState("hovered"); }
+	this.select = function(){ this.setState("selected"); }
+
+	this.getSize = function(){
+		return {
+			width: domNode.width||domNode.offsetWidth,
+			height: domNode.height||domNode.offsetHeight
+		};
+	}
+
+	this.setSize = function(w, h){
+		domNode.width = w;
+		domNode.height = h;
+		return { width: w, height: h };
+	}
+
+	this.getNode = function(){
+		return domNode;
+	}
+
+	this.getSrc = function(state){
+		if(state){ return this[state].src; }
+		return domNode.src||"";
+	}
+
+	this.update = function(){
+		this.setState(currentState);
+	}
+
+	for(var i = 0; i < states.length; i++){
+		var arg = arguments[i];
+		var state = states[i];
+		this[state] = null;
+		if(!arg){ continue; }
+		this.setSrc(state, arg);
+	}
+
+	this.enable();
+}
+
+dojo.widget.Icon.make = function(a,b,c,d){
+	for(var i = 0; i < arguments.length; i++){
+		if(arguments[i] instanceof dojo.widget.Icon){
+			return arguments[i];
+		}
+	}
+
+	return new dojo.widget.Icon(a,b,c,d);
+}
+
+/* ToolbarColorDialog
+ ******************/
+dojo.widget.defineWidget(
+	"dojo.widget.ToolbarColorDialog",
+	dojo.widget.ToolbarDialog,
+{
+ 	palette: "7x10",
+
+	fillInTemplate: function (args, frag) {
+		dojo.widget.ToolbarColorDialog.superclass.fillInTemplate.call(this, args, frag);
+		this.dialog = dojo.widget.createWidget("ColorPalette", {palette: this.palette});
+		this.dialog.domNode.style.position = "absolute";
+
+		dojo.event.connect(this.dialog, "onColorSelect", this, "_setValue");
+	},
+
+	_setValue: function(color) {
+		this._value = color;
+		this._fireEvent("onSetValue", color);
+	},
+
+	showDialog: function (e) {
+		dojo.widget.ToolbarColorDialog.superclass.showDialog.call(this, e);
+		var abs = dojo.html.getAbsolutePosition(this.domNode, true);
+		var y = abs.y + dojo.html.getBorderBox(this.domNode).height;
+		this.dialog.showAt(abs.x, y);
+	},
+
+	hideDialog: function (e) {
+		dojo.widget.ToolbarColorDialog.superclass.hideDialog.call(this, e);
+		this.dialog.hide();
+	}
+});
\ No newline at end of file

Propchange: jackrabbit/trunk/contrib/jcr-browser/src/main/webapp/dojo/src/widget/Toolbar.js
------------------------------------------------------------------------------
    svn:eol-style = native