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

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

Added: jackrabbit/trunk/contrib/jcr-browser/src/main/webapp/dojo/src/widget/PopupContainer.js
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/contrib/jcr-browser/src/main/webapp/dojo/src/widget/PopupContainer.js?view=auto&rev=473755
==============================================================================
--- jackrabbit/trunk/contrib/jcr-browser/src/main/webapp/dojo/src/widget/PopupContainer.js (added)
+++ jackrabbit/trunk/contrib/jcr-browser/src/main/webapp/dojo/src/widget/PopupContainer.js Sat Nov 11 08:44:22 2006
@@ -0,0 +1,442 @@
+dojo.provide("dojo.widget.PopupContainer");
+
+dojo.require("dojo.html.style");
+dojo.require("dojo.html.layout");
+dojo.require("dojo.html.selection");
+dojo.require("dojo.html.iframe");
+dojo.require("dojo.event.*");
+dojo.require("dojo.widget.*");
+dojo.require("dojo.widget.HtmlWidget");
+
+// summary:
+//		PopupContainerBase is the mixin class which provide popup behaviors:
+//		it can open in a given position x,y or around a given node.
+//		In addition, it handles animation and IE bleed through workaround.
+// description:
+//		This class can not be used standalone: it should be mixed-in to a
+//		dojo.widget.HtmlWidget. Use PopupContainer instead if you want a
+//		a standalone popup widget
+dojo.declare(
+	"dojo.widget.PopupContainerBase",
+	null,
+	function(){
+		this.queueOnAnimationFinish = [];
+	},
+{
+	isContainer: true,
+	templateString: '<div dojoAttachPoint="containerNode" style="display:none;position:absolute;" class="dojoPopupContainer" ></div>',
+
+	// Boolean: whether this popup is shown
+	isShowingNow: false,
+
+	// Widget: the shown sub popup if any
+	currentSubpopup: null,
+
+	// Int: the minimal popup zIndex
+	beginZIndex: 1000,
+
+	// Widget: parent popup widget
+	parentPopup: null,
+	// Widget: parent Widget
+	parent: null,
+	// Int: level of sub popup
+	popupIndex: 0,
+
+	// dojo.html.boxSizing: which bounding box to use for open aroundNode. By default use BORDER box of the aroundNode
+	aroundBox: dojo.html.boxSizing.BORDER_BOX,
+
+	// Object: in which window, the open() is triggered
+	openedForWindow: null,
+
+	processKey: function(/*Event*/evt){
+		// summary: key event handler
+		return false;
+	},
+
+	applyPopupBasicStyle: function(){
+		// summary: apply necessary css rules to the top domNode
+		// description:
+		//		this function should be called in sub class where a custom
+		//		templateString/templateStringPath is used (see Tooltip widget)
+		with(this.domNode.style){
+			display = 'none';
+			position = 'absolute';
+		}
+	},
+
+	aboutToShow: function() {
+		// summary: connect to this stub to modify the content of the popup
+	},
+
+	open: function(/*Integer*/x, /*Integer*/y, /*DomNode*/parent, /*Object*/explodeSrc, /*String?*/orient, /*Array?*/padding){
+		// summary:
+		//		Open the popup at position (x,y), relative to dojo.body()
+	 	//		Or open(node, parent, explodeSrc, aroundOrient) to open
+	 	//		around node
+		if (this.isShowingNow){ return; }
+
+		this.aboutToShow();
+
+		// if I click right button and menu is opened, then it gets 2 commands: close -> open
+		// so close enables animation and next "open" is put to queue to occur at new location
+		if(this.animationInProgress){
+			this.queueOnAnimationFinish.push(this.open, arguments);
+			return;
+		}
+
+		// save this so that the focus can be returned
+		this.parent = parent;
+
+		var around = false, node, aroundOrient;
+		if(typeof x == 'object'){
+			node = x;
+			aroundOrient = explodeSrc;
+			explodeSrc = parent;
+			parent = y;
+			around = true;
+		}
+
+		// for unknown reasons even if the domNode is attached to the body in postCreate(),
+		// it's not attached here, so have to attach it here.
+		dojo.body().appendChild(this.domNode);
+
+		// if explodeSrc isn't specified then explode from my parent widget
+		explodeSrc = explodeSrc || parent["domNode"] || [];
+
+		//keep track of parent popup to decided whether this is a top level popup
+		var parentPopup = null;
+		this.isTopLevel = true;
+		while(parent){
+			if(parent !== this && (parent.setOpenedSubpopup != undefined && parent.applyPopupBasicStyle != undefined)){
+				parentPopup = parent;
+				this.isTopLevel = false;
+				parentPopup.setOpenedSubpopup(this);
+				break;
+			}
+			parent = parent.parent;
+		}
+
+		this.parentPopup = parentPopup;
+		this.popupIndex = parentPopup ? parentPopup.popupIndex + 1 : 1;
+
+		if(this.isTopLevel){
+			var button = dojo.html.isNode(explodeSrc) ? explodeSrc : null;
+			dojo.widget.PopupManager.opened(this, button);
+		}
+
+		//Store the current selection and restore it before the action for a menu item
+		//is executed. This is required as clicking on an menu item deselects current selection
+		if(this.isTopLevel && !dojo.withGlobal(this.openedForWindow||dojo.global(), dojo.html.selection.isCollapsed)){
+			this._bookmark = dojo.withGlobal(this.openedForWindow||dojo.global(), dojo.html.selection.getBookmark);
+		}else{
+			this._bookmark = null;
+		}
+
+		//convert explodeSrc from format [x, y] to
+		//{left: x, top: y, width: 0, height: 0} which is the new
+		//format required by dojo.html.toCoordinateObject
+		if(explodeSrc instanceof Array){
+			explodeSrc = {left: explodeSrc[0], top: explodeSrc[1], width: 0, height: 0};
+		}
+
+		// display temporarily, and move into position, then hide again
+		with(this.domNode.style){
+			display="";
+			zIndex = this.beginZIndex + this.popupIndex;
+		}
+
+		if(around){
+			this.move(node, padding, aroundOrient);
+		}else{
+			this.move(x, y, padding, orient);
+		}
+		this.domNode.style.display="none";
+
+		this.explodeSrc = explodeSrc;
+
+		// then use the user defined method to display it
+		this.show();
+
+		this.isShowingNow = true;
+	},
+
+	// TODOC: move(node, padding, aroundOrient) how to do this?
+	move: function(/*Int*/x, /*Int*/y, /*Integer?*/padding, /*String?*/orient){
+		// summary: calculate where to place the popup
+
+		var around = (typeof x == "object");
+		if(around){
+			var aroundOrient=padding;
+			var node=x;
+			padding=y;
+			if(!aroundOrient){ //By default, attempt to open above the aroundNode, or below
+				aroundOrient = {'BL': 'TL', 'TL': 'BL'};
+			}
+			dojo.html.placeOnScreenAroundElement(this.domNode, node, padding, this.aroundBox, aroundOrient);
+		}else{
+			if(!orient){ orient = 'TL,TR,BL,BR';}
+			dojo.html.placeOnScreen(this.domNode, x, y, padding, true, orient);
+		}
+	},
+
+	close: function(/*Boolean?*/force){
+		// summary: hide the popup
+		if(force){
+			this.domNode.style.display="none";
+		}
+
+		// If we are in the process of opening the menu and we are asked to close it
+		if(this.animationInProgress){
+			this.queueOnAnimationFinish.push(this.close, []);
+			return;
+		}
+
+		this.closeSubpopup(force);
+		this.hide();
+		if(this.bgIframe){
+			this.bgIframe.hide();
+			this.bgIframe.size({left: 0, top: 0, width: 0, height: 0});
+		}
+		if(this.isTopLevel){
+			dojo.widget.PopupManager.closed(this);
+		}
+		this.isShowingNow = false;
+		// return focus to the widget that opened the menu
+		try {
+			this.parent.domNode.focus();
+		} catch(e) {}
+
+		//do not need to restore if current selection is not empty
+		//(use keyboard to select a menu item)
+		if(this._bookmark && dojo.withGlobal(this.openedForWindow||dojo.global(), dojo.html.selection.isCollapsed)){
+			if(this.openedForWindow){
+				this.openedForWindow.focus()
+			}
+			dojo.withGlobal(this.openedForWindow||dojo.global(), "moveToBookmark", dojo.html.selection, [this._bookmark]);
+		}
+		this._bookmark = null;
+	},
+
+	closeAll: function(/*Boolean?*/force){
+		// summary: hide all popups including sub ones
+		if (this.parentPopup){
+			this.parentPopup.closeAll(force);
+		}else{
+			this.close(force);
+		}
+	},
+
+	setOpenedSubpopup: function(/*Widget*/popup) {
+		// summary: used by sub popup to set currentSubpopup in the parent popup
+		this.currentSubpopup = popup;
+	},
+
+	closeSubpopup: function(/*Boolean?*/force) {
+		// summary: close opened sub popup
+		if(this.currentSubpopup == null){ return; }
+
+		this.currentSubpopup.close(force);
+		this.currentSubpopup = null;
+	},
+
+	onShow: function() {
+		dojo.widget.PopupContainer.superclass.onShow.apply(this, arguments);
+		// With some animation (wipe), after close, the size of the domnode is 0
+		// and next time when shown, the open() function can not determine
+		// the correct place to popup, so we store the opened size here and
+		// set it after close (in function onHide())
+		this.openedSize={w: this.domNode.style.width, h: this.domNode.style.height};
+		// prevent IE bleed through
+		if(dojo.render.html.ie){
+			if(!this.bgIframe){
+				this.bgIframe = new dojo.html.BackgroundIframe();
+				this.bgIframe.setZIndex(this.domNode);
+			}
+
+			this.bgIframe.size(this.domNode);
+			this.bgIframe.show();
+		}
+		this.processQueue();
+	},
+
+	processQueue: function() {
+		// summary: do events from queue
+		if (!this.queueOnAnimationFinish.length) return;
+
+		var func = this.queueOnAnimationFinish.shift();
+		var args = this.queueOnAnimationFinish.shift();
+
+		func.apply(this, args);
+	},
+
+	onHide: function() {
+		dojo.widget.HtmlWidget.prototype.onHide.call(this);
+
+		//restore size of the domnode, see comment in
+		//function onShow()
+		if(this.openedSize){
+			with(this.domNode.style){
+				width=this.openedSize.w;
+				height=this.openedSize.h;
+			}
+		}
+
+		this.processQueue();
+	}
+});
+
+// summary: dojo.widget.PopupContainer is the widget version of dojo.widget.PopupContainerBase
+dojo.widget.defineWidget(
+	"dojo.widget.PopupContainer",
+	[dojo.widget.HtmlWidget, dojo.widget.PopupContainerBase], {});
+
+
+// summary:
+//		the popup manager makes sure we don't have several popups
+//		open at once. the root popup in an opening sequence calls
+//		opened(). when a root menu closes it calls closed(). then
+//		everything works. lovely.
+dojo.widget.PopupManager = new function(){
+	this.currentMenu = null;
+	this.currentButton = null;		// button that opened current menu (if any)
+	this.currentFocusMenu = null;	// the (sub)menu which receives key events
+	this.focusNode = null;
+	this.registeredWindows = [];
+
+	this.registerWin = function(/*Window*/win){
+		// summary: register a window so that when clicks/scroll in it, the popup can be closed automatically
+		if(!win.__PopupManagerRegistered)
+		{
+			dojo.event.connect(win.document, 'onmousedown', this, 'onClick');
+			dojo.event.connect(win, "onscroll", this, "onClick");
+			dojo.event.connect(win.document, "onkey", this, 'onKey');
+			win.__PopupManagerRegistered = true;
+			this.registeredWindows.push(win);
+		}
+	};
+
+	/*
+
+	*/
+	this.registerAllWindows = function(/*Window*/targetWindow){
+		// summary:
+		//		This function register all the iframes and the top window,
+		//		so that whereever the user clicks in the page, the popup
+		//		menu will be closed
+		//		In case you add an iframe after onload event, please call
+		//		dojo.widget.PopupManager.registerWin manually
+
+		//starting from window.top, clicking everywhere in this page
+		//should close popup menus
+		if(!targetWindow) { //see comment below
+			targetWindow = dojo.html.getDocumentWindow(window.top && window.top.document || window.document);
+		}
+
+		this.registerWin(targetWindow);
+
+		for (var i = 0; i < targetWindow.frames.length; i++){
+			try{
+				//do not remove  dojo.html.getDocumentWindow, see comment in it
+				var win = dojo.html.getDocumentWindow(targetWindow.frames[i].document);
+				if(win){
+					this.registerAllWindows(win);
+				}
+			}catch(e){ /* squelch error for cross domain iframes */ }
+		}
+	};
+
+	this.unRegisterWin = function(/*Window*/win){
+		// summary: remove listeners on the registered window
+		if(win.__PopupManagerRegistered)
+		{
+			dojo.event.disconnect(win.document, 'onmousedown', this, 'onClick');
+			dojo.event.disconnect(win, "onscroll", this, "onClick");
+			dojo.event.disconnect(win.document, "onkey", this, 'onKey');
+			win.__PopupManagerRegistered = false;
+		}
+	};
+
+	this.unRegisterAllWindows = function(){
+		// summary: remove listeners on all the registered windows
+		for(var i=0;i<this.registeredWindows.length;++i){
+			this.unRegisterWin(this.registeredWindows[i]);
+		}
+		this.registeredWindows = [];
+	};
+
+	dojo.addOnLoad(this, "registerAllWindows");
+	dojo.addOnUnload(this, "unRegisterAllWindows");
+
+	this.closed = function(/*Widget*/menu){
+		// summary: notify the manager that menu is closed
+		if (this.currentMenu == menu){
+			this.currentMenu = null;
+			this.currentButton = null;
+			this.currentFocusMenu = null;
+		}
+	};
+
+	this.opened = function(/*Widget*/menu, /*DomNode*/button){
+		// summary: sets the current opened popup
+		if (menu == this.currentMenu){ return; }
+
+		if (this.currentMenu){
+			this.currentMenu.close();
+		}
+
+		this.currentMenu = menu;
+		this.currentFocusMenu = menu;
+		this.currentButton = button;
+	};
+
+	this.setFocusedMenu = function(/*Widget*/menu){
+		// summary:
+		// 		Set the current focused popup, This is used by popups which supports keyboard navigation
+		this.currentFocusMenu = menu;
+	};
+
+	this.onKey = function(/*Event*/e){
+		if (!e.key) { return; }
+		if(!this.currentMenu || !this.currentMenu.isShowingNow){ return; }
+
+		var m = this.currentFocusMenu;
+		while (m){
+			if(m.processKey(e)){
+				e.preventDefault();
+				e.stopPropagation();
+				break;
+			}
+			m = m.parentPopup;
+		}
+	},
+
+	this.onClick = function(/*Event*/e){
+		if (!this.currentMenu){ return; }
+
+		var scrolloffset = dojo.html.getScroll().offset;
+
+		// starting from the base menu, perform a hit test
+		// and exit when one succeeds
+
+		var m = this.currentMenu;
+
+		while (m){
+			if(dojo.html.overElement(m.domNode, e) || dojo.html.isDescendantOf(e.target, m.domNode)){
+				return;
+			}
+			m = m.currentSubpopup;
+		}
+
+		// Also, if user clicked the button that opened this menu, then
+		// that button will send the menu a close() command, so this code
+		// shouldn't try to close the menu.  Closing twice messes up animation.
+		if (this.currentButton && dojo.html.overElement(this.currentButton, e)){
+			return;
+		}
+
+		// the click didn't fall within the open menu tree
+		// so close it
+
+		this.currentMenu.close();
+	};
+}
\ No newline at end of file

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

Added: jackrabbit/trunk/contrib/jcr-browser/src/main/webapp/dojo/src/widget/ProgressBar.js
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/contrib/jcr-browser/src/main/webapp/dojo/src/widget/ProgressBar.js?view=auto&rev=473755
==============================================================================
--- jackrabbit/trunk/contrib/jcr-browser/src/main/webapp/dojo/src/widget/ProgressBar.js (added)
+++ jackrabbit/trunk/contrib/jcr-browser/src/main/webapp/dojo/src/widget/ProgressBar.js Sat Nov 11 08:44:22 2006
@@ -0,0 +1,279 @@
+dojo.provide("dojo.widget.ProgressBar");
+
+// requires here
+dojo.require("dojo.widget.*"); // necessary
+dojo.require("dojo.event");
+dojo.require("dojo.dom.*");
+dojo.require("dojo.html.style");
+dojo.require("dojo.string.*");
+dojo.require("dojo.lfx.*");
+
+dojo.widget.defineWidget(
+	"dojo.widget.ProgressBar",
+	dojo.widget.HtmlWidget,
+	{
+		// Constructor arguments
+		progressValue: "0",
+		maxProgressValue: 100,
+		width: 300,
+		height: 30,
+		frontPercentClass: "frontPercent",
+		backPercentClass: "backPercent",
+		frontBarClass: "frontBar",
+		backBarClass: "backBar",
+		hasText: "false",
+		isVertical:"false",
+		showOnlyIntegers: "false",
+		dataSource: "",
+		pollInterval: "3000",
+		duration: "1000",
+//		leftImage: null,
+//		centerImage: null,
+//		rightImage: null,
+		templatePath: dojo.uri.dojoUri("src/widget/templates/ProgressBar.html"),
+		templateCssPath: dojo.uri.dojoUri("src/widget/templates/ProgressBar.css"),
+		
+	
+		// attach points
+		containerNode: null,
+		internalProgress: null,
+	
+		// private members
+		_pixelUnitRatio: 0.0,
+		// _pixelRatio := width/100
+		_pixelPercentRatio: 0.0,
+		_unitPercentRatio: 0.0,
+		_unitPixelRatio: 0.0,
+		_floatDimension: 0.0,
+		_intDimension: 0,
+		_progressPercentValue: "0%",
+		_floatMaxProgressValue: 0.0,
+		_dimension: "width",
+		_pixelValue: 0,
+		_oInterval: null,
+		_animation: null,
+		_animationStopped: true,
+		_progressValueBak: false,
+		_hasTextBak: false,
+		// public functions
+		fillInTemplate: function(args, frag){
+			this.internalProgress.className = this.frontBarClass;
+			this.containerNode.className = this.backBarClass;
+			if (this.isVertical == "true"){
+				this.internalProgress.style.bottom="0px";
+				this.internalProgress.style.left="0px";
+				this._dimension = "height";
+			} else {
+				this.internalProgress.style.top="0px";
+				this.internalProgress.style.left="0px";
+				this._dimension = "width";
+			}
+			this.frontPercentLabel.className = this.frontPercentClass;
+			this.backPercentLabel.className = this.backPercentClass;
+			this.progressValue = "" + this.progressValue; 
+			this.domNode.style.height = this.height; 
+			this.domNode.style.width = this.width;
+			this._intDimension = parseInt("0" + eval("this." + this._dimension));
+			this._floatDimension = parseFloat("0" + eval("this."+this._dimension));
+			this._pixelPercentRatio = this._floatDimension/100;
+			this.setMaxProgressValue(this.maxProgressValue, true);
+			this.setProgressValue(dojo.string.trim(this.progressValue), true);
+			dojo.debug("float dimension: " + this._floatDimension);
+			dojo.debug("this._unitPixelRatio: " + this._unitPixelRatio);
+			this.showText(this.hasText);
+		},
+		showText: function(visible){
+			if (visible == "true"){
+				this.backPercentLabel.style.display="block";
+				this.frontPercentLabel.style.display="block";
+			} else {
+				this.backPercentLabel.style.display="none";
+				this.frontPercentLabel.style.display="none";
+			}
+			this.hasText = visible;
+		},
+		postCreate: function(args, frag){
+			// labels position
+			this.render();
+		},
+		_backupValues: function(){
+			this._progressValueBak = this.progressValue;
+			this._hasTextBak = this.hasText;
+		},
+		_restoreValues: function(){
+				this.setProgressValue(this._progressValueBak);
+				this.showText(this._hasTextBak);
+		},
+		_setupAnimation: function(){
+			var _self = this;
+			dojo.debug("internalProgress width: " + this.internalProgress.style.width);
+			this._animation = dojo.lfx.html.slideTo(this.internalProgress, 
+				{top: 0, left: this.width-parseInt(this.internalProgress.style.width)}, parseInt(this.duration), null, 
+					function(){
+						var _backAnim = dojo.lfx.html.slideTo(_self.internalProgress, 
+						{ top: 0, left: 0 }, parseInt(_self.duration));
+						dojo.event.connect(_backAnim, "onEnd", function(){
+							if (!_self._animationStopped){
+								_self._animation.play();
+							}
+							});
+						if (!_self._animationStopped){
+							_backAnim.play();
+						}
+						_backAnim = null; // <-- to avoid memory leaks in IE
+					}
+				);
+		},
+		getMaxProgressValue: function(){
+			return this.maxProgressValue;
+		},
+		setMaxProgressValue: function(maxValue, noRender){
+			if (!this._animationStopped){
+				return;
+			}
+			this.maxProgressValue = maxValue;
+			this._floatMaxProgressValue = parseFloat("0" + this.maxProgressValue);
+			this._pixelUnitRatio = this._floatDimension/this.maxProgressValue;
+			this._unitPercentRatio = this._floatMaxProgressValue/100;
+			this._unitPixelRatio = this._floatMaxProgressValue/this._floatDimension;
+			this.setProgressValue(this.progressValue, true);
+			if (!noRender){
+				this.render();
+			}
+		},
+		setProgressValue: function(value, noRender){
+			if (!this._animationStopped){
+				return;
+			}
+			// transformations here
+			this._progressPercentValue = "0%";
+			var _value=dojo.string.trim("" + value);
+			var _floatValue = parseFloat("0" + _value);
+			var _intValue = parseInt("0" + _value);
+			var _pixelValue = 0;
+			if (dojo.string.endsWith(_value, "%", false)){
+				this._progressPercentValue = Math.min(_floatValue.toFixed(1), 100) + "%";
+				_value = Math.min((_floatValue)*this._unitPercentRatio, this.maxProgressValue);
+				_pixelValue = Math.min((_floatValue)*this._pixelPercentRatio, eval("this."+this._dimension));
+			} else {
+				this.progressValue = Math.min(_floatValue, this.maxProgressValue);
+				this._progressPercentValue = Math.min((_floatValue/this._unitPercentRatio).toFixed(1), 100) + "%";
+				_pixelValue = Math.min(_floatValue/this._unitPixelRatio, eval("this."+this._dimension));
+			}
+			this.progressValue = dojo.string.trim(_value);
+			this._pixelValue = _pixelValue;
+			if (!noRender){
+				this.render();
+			}
+		},
+		setCurrentPercentProgress: function(percentProgress){
+			this._setCurrentPixelProgress(percentProgress);
+		},
+		getProgressValue: function(){
+			return this.progressValue;
+		},
+		getProgressPercentValue: function(){
+			return this._progressPercentValue;
+		},
+		setDataSource: function(dataSource){
+			this.dataSource = dataSource;
+		},
+		setPollInterval: function(pollInterval){
+			this.pollInterval = pollInterval;
+		},
+		start: function(){
+			var _showFunction = dojo.lang.hitch(this, this._showRemoteProgress);
+			this._oInterval = setInterval(_showFunction, this.pollInterval);
+		},
+		startAnimation: function(){
+			if (this._animationStopped) {
+				this._backupValues();
+				this.setProgressValue("10%");
+				this._animationStopped = false;
+				this._setupAnimation();
+				this.showText(false);
+				this.internalProgress.style.height="105%";
+				this._animation.play();
+			}
+		},
+		stopAnimation: function(){
+			if (this._animation) {
+				this._animationStopped = true;
+				this._animation.stop();
+				this.internalProgress.style.height="100%";
+				this.internalProgress.style.left = "0px";
+				this._restoreValues();
+				this._setLabelPosition();
+			}
+		},
+		_showRemoteProgress: function(){
+			var _self = this;
+//			dojo.debug("getMax: "+this.getMaxProgressValue()+" getprval: "+this.getProgressValue());
+			if ( (this.getMaxProgressValue() == this.getProgressValue()) &&
+				this._oInterval){
+				clearInterval(this._oInterval);
+				this._oInterval = null;
+				this.setProgressValue("100%");
+				return;	
+			}
+			var bArgs = {
+				url: _self.dataSource,
+				method: "POST",
+				mimetype: "text/json",
+				error: function(type, errorObj){
+					dojo.debug("[ProgressBar] showRemoteProgress error");
+				},
+				load: function(type, data, evt){
+					//dojo.debug(data["progress"]);
+					_self.setProgressValue(
+						(_self._oInterval ? data["progress"] : "100%")
+					);
+//				dojo.debug("_oInterval: "+_self._oInterval);
+				}
+			};
+			dojo.io.bind(bArgs);
+		},
+		render: function(){
+			this._setPercentLabel(dojo.string.trim(this._progressPercentValue));
+			this._setPixelValue(this._pixelValue);
+			this._setLabelPosition();
+		},
+		// private functions
+		_setLabelPosition: function(){
+			var _widthFront = 
+				dojo.html.getContentBox(this.frontPercentLabel).width;
+			var _heightFront = 
+				dojo.html.getContentBox(this.frontPercentLabel).height;
+			var _widthBack = 
+				dojo.html.getContentBox(this.backPercentLabel).width;
+			var _heightBack = 
+				dojo.html.getContentBox(this.backPercentLabel).height;
+			var _leftFront = (this.width - _widthFront)/2 + "px";
+			var _bottomFront = (parseInt(this.height) - parseInt(_heightFront))/2 + "px";
+			var _leftBack = (this.width - _widthBack)/2 + "px";
+			var _bottomBack = (parseInt(this.height) - parseInt(_heightBack))/2 + "px";
+			this.frontPercentLabel.style.left = _leftFront;
+			this.backPercentLabel.style.left = _leftBack; 
+			this.frontPercentLabel.style.bottom = _bottomFront;
+			this.backPercentLabel.style.bottom = _bottomBack; 
+//			dojo.debug("bottom: "+this.backPercentLabel.style.bottom);
+//			dojo.debug("BOTTOM: "+_bottom);
+		},
+		_setPercentLabel: function(percentValue){
+			dojo.dom.removeChildren(this.frontPercentLabel);
+			dojo.dom.removeChildren(this.backPercentLabel);
+			var _percentValue = this.showOnlyIntegers == "false" ? 
+				percentValue : parseInt(percentValue) + "%";
+			this.frontPercentLabel.
+				appendChild(document.createTextNode(_percentValue));
+			this.backPercentLabel.
+				appendChild(document.createTextNode(_percentValue));
+		},
+		_setPixelValue: function(value){
+			eval("this.internalProgress.style." + this._dimension + " = " + value + " + 'px'");
+			this.onChange();
+		},
+		onChange: function(){
+		}
+	});
+	

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

Added: jackrabbit/trunk/contrib/jcr-browser/src/main/webapp/dojo/src/widget/RadioGroup.js
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/contrib/jcr-browser/src/main/webapp/dojo/src/widget/RadioGroup.js?view=auto&rev=473755
==============================================================================
--- jackrabbit/trunk/contrib/jcr-browser/src/main/webapp/dojo/src/widget/RadioGroup.js (added)
+++ jackrabbit/trunk/contrib/jcr-browser/src/main/webapp/dojo/src/widget/RadioGroup.js Sat Nov 11 08:44:22 2006
@@ -0,0 +1,184 @@
+dojo.provide("dojo.widget.RadioGroup");
+
+dojo.require("dojo.lang.common");
+dojo.require("dojo.event.browser");
+dojo.require("dojo.html.selection");
+dojo.require("dojo.widget.*");
+dojo.require("dojo.widget.HtmlWidget");
+
+// Widget that provides useful/common functionality that may be desirable
+// when interacting with ul/ol html lists.
+//
+// This widget was mostly developed under supervision/guidance from Tom Trenka.
+dojo.widget.defineWidget(
+	"dojo.widget.RadioGroup", 
+	dojo.widget.HtmlWidget,
+	function(){
+		this.selectedItem=null; //currently selected li, if any
+		this.listNode=null; //the containing ul or ol
+		this.items=[]; //the individual li's
+		this.selected=[];
+		
+		//	CSS classes as attributes.
+		this.groupCssClass="radioGroup";
+		this.selectedCssClass="selected";
+		this.itemContentCssClass="itemContent";
+	},
+	{
+		isContainer:false,
+		templatePath: null,
+		templateCssPath: null,
+		
+		//	overridden from HtmlWidget
+		postCreate:function(){
+			this.parseStructure();
+			dojo.html.addClass(this.listNode, this.groupCssClass);
+			this.setupChildren();
+			dojo.event.browser.addListener(this.listNode, "onclick", dojo.lang.hitch(this, "onSelect"));
+			if (this.selectedItem){
+				this.selectItem(this.selectedItem);
+			}
+		},
+		
+		/* 
+		 * Sets local radioGroup and items properties, also validates
+		 * that domNode contains an expected list.
+		 *
+		 * exception: If a ul or ol node can't be found in this widgets domNode
+		 */
+		parseStructure:function() {
+			var listNode = dojo.dom.firstElement(this.domNode, "ul");
+			if (!listNode) { listNode = dojo.dom.firstElement(this.domNode, "ol");}
+			
+			if (listNode) {
+				this.listNode = listNode;
+				this.items=[];	//	reset the items.
+				var nl=listNode.getElementsByTagName("li");
+				for (var i=0; i<nl.length; i++){
+					if(nl[i].parentNode==listNode){
+						this.items.push(nl[i]);
+					}
+				}
+				return;
+			}
+			dojo.raise("RadioGroup: Expected ul or ol content.");
+		},
+		
+		/*
+		 * Allows the app to add a node on the fly, finishing up
+		 * the setup so that we don't need to deal with it on a
+		 * widget-wide basis.
+		 */
+		add:function(node){
+			if(node.parentNode!=this.listNode){
+				this.listNode.appendChild(node);
+			}
+			this.items.push(node);
+			this.setup(node);
+		},
+		
+		// removes the specified node from this group, if it exists
+		remove:function(node){
+			var idx=-1;
+			for(var i=0; i<this.items.length; i++){
+				if(this.items[i]==node){
+					idx=i;
+					break;
+				}
+			}
+			if(idx<0) {return;}
+			this.items.splice(idx,1);
+			node.parentNode.removeChild(node);
+		},
+		
+		// removes all items in this list
+		clear:function(){
+			for(var i=0; i<this.items.length; i++){
+				this.listNode.removeChild(this.items[i]);
+			}
+			this.items=[];
+		},
+		
+		// clears any selected items from being selected
+		clearSelections:function(){
+			for(var i=0; i<this.items.length; i++){
+				dojo.html.removeClass(this.items[i], this.selectedCssClass);
+			}
+			this.selectedItem=null;
+		},
+		
+		setup:function(node){
+			var span = document.createElement("span");
+			dojo.html.disableSelection(span);
+			dojo.html.addClass(span, this.itemContentCssClass);
+			dojo.dom.moveChildren(node, span);
+			node.appendChild(span);
+			
+			if (this.selected.length > 0) {
+				var uid = dojo.html.getAttribute(node, "id");
+				if (uid && uid == this.selected){
+					this.selectedItem = node;
+				}
+			}
+			dojo.event.browser.addListener(node, "onclick", dojo.lang.hitch(this, "onItemSelect"));
+			if (dojo.html.hasAttribute(node, "onitemselect")) {
+				var tn = dojo.lang.nameAnonFunc(new Function(dojo.html.getAttribute(node, "onitemselect")), 
+												this);
+				dojo.event.browser.addListener(node, "onclick", dojo.lang.hitch(this, tn));
+			}
+		},
+		
+		/*
+		 * Iterates over the items li nodes and manipulates their
+		 * dom structures to handle things like span tag insertion
+		 * and selecting a default item.
+		 */
+		setupChildren:function(){
+			for (var i=0; i<this.items.length; i++){
+				this.setup(this.items[i]);
+			}
+		},
+		
+		// Sets the selectedItem to passed in node, applies
+		// css selection class on new item
+		selectItem:function(node, event, nofire){
+			if(this.selectedItem){
+				dojo.html.removeClass(this.selectedItem, this.selectedCssClass);
+			}
+			
+			this.selectedItem = node;
+			dojo.html.addClass(this.selectedItem, this.selectedCssClass);
+			
+			// if this is the result of an event, stop here.
+			if (!dj_undef("currentTarget", event)){
+				return;
+			}
+			
+			//	if there's no nofire flag, passed when this is nailed internally.
+			if(!nofire){
+				if(dojo.render.html.ie){
+					this.selectedItem.fireEvent("onclick");
+				}else{
+					var e = document.createEvent("MouseEvents");
+					e.initEvent("click", true, false);
+					this.selectedItem.dispatchEvent(e);
+				}
+			}
+		},
+		
+		// gets the currently selected item
+		getValue:function() {
+			return this.selectedItem;
+		},
+		
+		// when the ul or ol contained by this widget is selected
+		onSelect:function(e) { },
+		
+		// when an individual li is selected
+		onItemSelect:function(e) {
+			if (!dj_undef("currentTarget", e)){
+				this.selectItem(e.currentTarget, e);
+			}
+		}
+	}
+);

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

Added: jackrabbit/trunk/contrib/jcr-browser/src/main/webapp/dojo/src/widget/RealNumberTextbox.js
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/contrib/jcr-browser/src/main/webapp/dojo/src/widget/RealNumberTextbox.js?view=auto&rev=473755
==============================================================================
--- jackrabbit/trunk/contrib/jcr-browser/src/main/webapp/dojo/src/widget/RealNumberTextbox.js (added)
+++ jackrabbit/trunk/contrib/jcr-browser/src/main/webapp/dojo/src/widget/RealNumberTextbox.js Sat Nov 11 08:44:22 2006
@@ -0,0 +1,63 @@
+dojo.provide("dojo.widget.RealNumberTextbox");
+
+dojo.require("dojo.widget.IntegerTextbox");
+dojo.require("dojo.validate.common");
+
+/*
+  ****** RealNumberTextbox ******
+
+  A subclass that extends IntegerTextbox.
+  Over-rides isValid/isInRange to test for real number input.
+  Has 5 new properties that can be specified as attributes in the markup.
+
+  @attr places    The exact number of decimal places.  If omitted, it's unlimited and optional.
+  @attr exponent  Can be true or false.  If omitted the exponential part is optional.
+  @attr eSigned   Is the exponent signed?  Can be true or false, if omitted the sign is optional.
+  @attr min  Minimum signed value.  Default is -Infinity
+  @attr max  Maximum signed value.  Default is +Infinity
+*/
+dojo.widget.defineWidget(
+	"dojo.widget.RealNumberTextbox",
+	dojo.widget.IntegerTextbox,
+	{
+		mixInProperties: function(localProperties, frag){
+			// First initialize properties in super-class.
+			dojo.widget.RealNumberTextbox.superclass.mixInProperties.apply(this, arguments);
+	
+			// Get properties from markup attributes, and assign to flags object.
+			if (localProperties.places){ 
+				this.flags.places = Number(localProperties.places);
+			}
+			if((localProperties.exponent == "true")||
+				(localProperties.exponent == "always")){
+				this.flags.exponent = true;
+			}else if((localProperties.exponent == "false")||(localProperties.exponent == "never")){
+				this.flags.exponent = false;
+			}else{
+				this.flags.exponent = [ true, false ]; // optional
+			}
+			if((localProperties.esigned == "true")||(localProperties.esigned == "always")){
+				this.flags.eSigned = true;
+			}else if((localProperties.esigned == "false")||(localProperties.esigned == "never")){
+				this.flags.eSigned = false;
+			}else{
+				this.flags.eSigned = [ true, false ]; // optional
+			}
+			if(localProperties.min){ 
+				this.flags.min = parseFloat(localProperties.min);
+			}
+			if(localProperties.max){ 
+				this.flags.max = parseFloat(localProperties.max);
+			}
+		},
+
+		// Over-ride for real number validation
+		isValid: function(){
+			return dojo.validate.isRealNumber(this.textbox.value, this.flags);
+		},
+		isInRange: function(){
+			return dojo.validate.isInRange(this.textbox.value, this.flags);
+		}
+
+	}
+);

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

Added: jackrabbit/trunk/contrib/jcr-browser/src/main/webapp/dojo/src/widget/RegexpTextbox.js
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/contrib/jcr-browser/src/main/webapp/dojo/src/widget/RegexpTextbox.js?view=auto&rev=473755
==============================================================================
--- jackrabbit/trunk/contrib/jcr-browser/src/main/webapp/dojo/src/widget/RegexpTextbox.js (added)
+++ jackrabbit/trunk/contrib/jcr-browser/src/main/webapp/dojo/src/widget/RegexpTextbox.js Sat Nov 11 08:44:22 2006
@@ -0,0 +1,38 @@
+dojo.provide("dojo.widget.RegexpTextbox");
+
+dojo.require("dojo.widget.ValidationTextbox");
+
+/*
+  ****** RegexpTextbox ******
+
+  A subclass of ValidationTextbox.
+  Over-rides isValid to test input based on a regular expression.
+  Has a new property that can be specified as attributes in the markup. 
+
+  @attr regexp     The regular expression string to use
+  @attr flags      Flags to pass to the regular expression (e.g. 'i', 'g', etc)
+*/
+dojo.widget.defineWidget(
+	"dojo.widget.RegexpTextbox",
+	dojo.widget.ValidationTextbox,
+	{
+	    mixInProperties: function(localProperties, frag){
+	        // First initialize properties in super-class.
+	        dojo.widget.RegexpTextbox.superclass.mixInProperties.apply(this, arguments);
+
+	        // Get properties from markup attibutes, and assign to flags object.
+	        if(localProperties.regexp){
+	            this.flags.regexp = localProperties.regexp;
+	        }
+	        if(localProperties.flags){
+	            this.flags.flags = localProperties.flags;
+	        }
+	    },
+
+	    // Over-ride for integer validation
+	    isValid: function(){
+	        var regexp = new RegExp(this.flags.regexp, this.flags.flags);
+	        return regexp.test(this.textbox.value);
+	    }
+	}
+);

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

Added: jackrabbit/trunk/contrib/jcr-browser/src/main/webapp/dojo/src/widget/RemoteTabController.js
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/contrib/jcr-browser/src/main/webapp/dojo/src/widget/RemoteTabController.js?view=auto&rev=473755
==============================================================================
--- jackrabbit/trunk/contrib/jcr-browser/src/main/webapp/dojo/src/widget/RemoteTabController.js (added)
+++ jackrabbit/trunk/contrib/jcr-browser/src/main/webapp/dojo/src/widget/RemoteTabController.js Sat Nov 11 08:44:22 2006
@@ -0,0 +1,40 @@
+dojo.provide("dojo.widget.RemoteTabController");
+
+//Summary
+//Remote Tab Controller widget.  Can be located independently of a tab
+//container and control the selection of its tabs
+dojo.require("dojo.widget.*");
+dojo.require("dojo.widget.TabContainer");
+dojo.require("dojo.event.*");
+
+dojo.deprecated("dojo.widget.RemoteTabController is slated for removal in 0.5; use PageController or TabController instead.", "0.5");
+
+dojo.widget.defineWidget(
+    "dojo.widget.RemoteTabController",
+    dojo.widget.TabController,
+	{
+        templateCssPath: dojo.uri.dojoUri("src/widget/templates/RemoteTabControl.css"),
+		templateString: '<div dojoAttachPoint="domNode" wairole="tablist"></div>',
+
+		"class": "dojoRemoteTabController",
+
+		// String
+		//	ID of page container that I connect to
+		tabContainer: "",
+	
+		postMixInProperties: function(){
+			this.containerId = this.tabContainer;
+			dojo.widget.RemoteTabController.superclass.postMixInProperties.apply(this, arguments);
+		},
+			
+		fillInTemplate: function() {
+			dojo.html.addClass(this.domNode, this["class"]);  // "class" is a reserved word in JS
+
+			if (this.tabContainer) {
+				dojo.addOnLoad(dojo.lang.hitch(this, "setupTabs"));
+			}
+
+			dojo.widget.RemoteTabController.superclass.fillInTemplate.apply(this, arguments);
+		}
+	}
+);

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

Added: jackrabbit/trunk/contrib/jcr-browser/src/main/webapp/dojo/src/widget/Repeater.js
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/contrib/jcr-browser/src/main/webapp/dojo/src/widget/Repeater.js?view=auto&rev=473755
==============================================================================
--- jackrabbit/trunk/contrib/jcr-browser/src/main/webapp/dojo/src/widget/Repeater.js (added)
+++ jackrabbit/trunk/contrib/jcr-browser/src/main/webapp/dojo/src/widget/Repeater.js Sat Nov 11 08:44:22 2006
@@ -0,0 +1,130 @@
+dojo.provide("dojo.widget.Repeater");
+dojo.require("dojo.widget.HtmlWidget");
+dojo.require("dojo.string");
+dojo.require("dojo.event.*");
+dojo.require("dojo.experimental");
+dojo.experimental("dojo.widget.Repeater");
+
+dojo.widget.defineWidget("dojo.widget.Repeater", dojo.widget.HtmlWidget,
+	{
+		name: "",
+		rowTemplate: "",
+		myObject: null,
+		pattern: "",
+		useDnd: false,
+		isContainer: true,
+
+		initialize: function(args,frag) {
+			var node = this.getFragNodeRef(frag);
+			node.removeAttribute("dojotype");
+			this.setRow(dojo.string.trim(node.innerHTML), {});
+			node.innerHTML="";
+			frag=null;
+		},
+
+		postCreate: function(args,frag){
+			if (this.useDnd) {
+				dojo.require("dojo.dnd.*");
+				var dnd = new dojo.dnd.HtmlDropTarget(this.domNode, [this.widgetId]);
+			}
+		},
+
+		reIndexRows: function() {
+			for(var i=0,len=this.domNode.childNodes.length; i<len;i++) {
+				var elems = ["INPUT", "SELECT", "TEXTAREA"];
+				for (var k=0; k < elems.length; k++) {
+					var list = this.domNode.childNodes[i].getElementsByTagName(elems[k]);
+					for (var j=0,len2=list.length; j<len2; j++) {
+						var name = list[j].name;
+						var index=dojo.string.escape("regexp", this.pattern);
+						index = index.replace(/%\\{index\\}/g,"%{index}");
+						var nameRegexp = dojo.string.substituteParams(index, {"index": "[0-9]*"});
+						var newName= dojo.string.substituteParams(this.pattern, {"index": "" + i});
+						var re=new RegExp(nameRegexp,"g");
+						list[j].name = name.replace(re,newName);
+					}
+				}
+			}
+		},
+
+		onDeleteRow: function(e) {
+			var index=dojo.string.escape("regexp", this.pattern);
+			index = index.replace(/%\\{index\\}/g,"%{index}");
+			var nameRegexp = dojo.string.substituteParams(index, {"index": "([0-9]*)"});
+			var re=new RegExp(nameRegexp,"g");
+			this.deleteRow(re.exec(e.target.name)[1]);
+		},
+		hasRows: function() {
+			if (this.domNode.childNodes.length > 0) {
+				return true;
+			}
+			return false;
+		},
+
+		getRowCount: function() {
+			return this.domNode.childNodes.length;
+		},
+
+		deleteRow: function(idx) {
+			this.domNode.removeChild(this.domNode.childNodes[idx]);
+			this.reIndexRows();
+		},
+
+		changeRowPosition: function(e) {
+			if (e.dragStatus == "dropFailure") {
+				this.domNode.removeChild(e["dragSource"].domNode);
+			} else if (e.dragStatus == "dropSuccess") {
+				//  nothing to do
+			} // else-if
+			this.reIndexRows();
+		},
+		setRow: function(template, myObject) {
+			template = dojo.string.substituteParams(template, {"index": "0"});
+			this.rowTemplate=template;
+			this.myObject = myObject;
+		},
+		getRow: function() {
+			return this.rowTemplate;
+		},
+		onAddRow: function(e) {
+		},
+		addRow: function() {
+			var node = document.createElement('span');
+			node.innerHTML=this.getRow();
+			if (node.childNodes.length == 1) {
+				node=node.childNodes[0];
+			}
+			this.domNode.appendChild(node);
+			var parser = new dojo.xml.Parse();
+			var frag = parser.parseElement(node, null, true);
+			dojo.widget.getParser().createSubComponents(frag, this);
+			var elems = ["INPUT", "SELECT", "IMG"];
+			for (var k=0; k < elems.length; k++) {
+				var list = node.getElementsByTagName(elems[k]);
+				for(var i=0, len=list.length; i<len; i++) {
+					var child = list[i];
+					if(child.nodeType != 1) {continue};
+					if (child.getAttribute("rowFunction") != null) {
+						if(typeof(this.myObject[child.getAttribute("rowFunction")]) == "undefined") {
+							dojo.debug("Function " + child.getAttribute("rowFunction") + " not found");
+						} else { 
+							this.myObject[child.getAttribute("rowFunction")](child);
+						}
+					} else if (child.getAttribute("rowAction") != null) {
+						if(child.getAttribute("rowAction") == "delete") {
+							child.name=dojo.string.substituteParams(this.pattern, {"index": "0"});
+							dojo.event.connect(child, "onclick", this, "onDeleteRow");
+						} // if
+					} // else-if
+				} // for
+			} // for
+			this.reIndexRows();
+			if (this.useDnd) { // bind to DND
+				node=new dojo.dnd.HtmlDragSource(node, this.widgetId);
+				dojo.event.connect(node, "onDragEnd", this, "changeRowPosition");
+			}
+			this.onAddRow();
+		}
+});
+
+

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

Added: jackrabbit/trunk/contrib/jcr-browser/src/main/webapp/dojo/src/widget/ResizableTextarea.js
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/contrib/jcr-browser/src/main/webapp/dojo/src/widget/ResizableTextarea.js?view=auto&rev=473755
==============================================================================
--- jackrabbit/trunk/contrib/jcr-browser/src/main/webapp/dojo/src/widget/ResizableTextarea.js (added)
+++ jackrabbit/trunk/contrib/jcr-browser/src/main/webapp/dojo/src/widget/ResizableTextarea.js Sat Nov 11 08:44:22 2006
@@ -0,0 +1,92 @@
+dojo.provide("dojo.widget.ResizableTextarea");
+dojo.require("dojo.widget.*");
+dojo.require("dojo.widget.LayoutContainer");
+dojo.require("dojo.widget.ResizeHandle");
+
+dojo.widget.defineWidget(
+	"dojo.widget.ResizableTextarea",
+	dojo.widget.HtmlWidget,
+{
+	templatePath: dojo.uri.dojoUri("src/widget/templates/ResizableTextarea.html"),
+	templateCssPath: dojo.uri.dojoUri("src/widget/templates/ResizableTextarea.css"),
+	isContainer: false,
+	textAreaNode: null,
+	textAreaContainer: null,
+	textAreaContainerNode: null,
+	statusBar: null,
+	statusBarContainerNode: null,
+	statusLabelNode: null,
+	statusLabel: null,
+	rootLayoutNode: null,
+	resizeHandleNode: null,
+	resizeHandle: null,
+
+	fillInTemplate: function(args, frag){
+		this.textAreaNode = this.getFragNodeRef(frag).cloneNode(true);
+
+		// FIXME: Safari apparently needs this!
+		dojo.body().appendChild(this.domNode);
+
+		this.rootLayout = dojo.widget.createWidget(
+			"LayoutContainer",
+			{
+				minHeight: 50,
+				minWidth: 100
+			},
+			this.rootLayoutNode
+		);
+
+
+		this.textAreaContainer = dojo.widget.createWidget(
+			"LayoutContainer",
+			{ layoutAlign: "client" },
+			this.textAreaContainerNode
+		);
+		this.rootLayout.addChild(this.textAreaContainer);
+
+		this.textAreaContainer.domNode.appendChild(this.textAreaNode);
+		with(this.textAreaNode.style){
+			width="100%";
+			height="100%";
+		}
+
+		this.statusBar = dojo.widget.createWidget(
+			"LayoutContainer",
+			{ 
+				layoutAlign: "bottom", 
+				minHeight: 28
+			},
+			this.statusBarContainerNode
+		);
+		this.rootLayout.addChild(this.statusBar);
+
+		this.statusLabel = dojo.widget.createWidget(
+			"LayoutContainer",
+			{ 
+				layoutAlign: "client", 
+				minWidth: 50
+			},
+			this.statusLabelNode
+		);
+		this.statusBar.addChild(this.statusLabel);
+
+		this.resizeHandle = dojo.widget.createWidget(
+			"ResizeHandle", 
+			{ targetElmId: this.rootLayout.widgetId },
+			this.resizeHandleNode
+		);
+		this.statusBar.addChild(this.resizeHandle);
+		// dojo.debug(this.rootLayout.widgetId);
+
+		// dojo.event.connect(this.resizeHandle, "beginSizing", this, "hideContent");
+		// dojo.event.connect(this.resizeHandle, "endSizing", this, "showContent");
+	},
+
+	hideContent: function(){
+		this.textAreaNode.style.display = "none";
+	},
+
+	showContent: function(){
+		this.textAreaNode.style.display = "";
+	}
+});

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

Added: jackrabbit/trunk/contrib/jcr-browser/src/main/webapp/dojo/src/widget/ResizeHandle.js
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/contrib/jcr-browser/src/main/webapp/dojo/src/widget/ResizeHandle.js?view=auto&rev=473755
==============================================================================
--- jackrabbit/trunk/contrib/jcr-browser/src/main/webapp/dojo/src/widget/ResizeHandle.js (added)
+++ jackrabbit/trunk/contrib/jcr-browser/src/main/webapp/dojo/src/widget/ResizeHandle.js Sat Nov 11 08:44:22 2006
@@ -0,0 +1,93 @@
+dojo.provide("dojo.widget.ResizeHandle");
+
+dojo.require("dojo.widget.*");
+dojo.require("dojo.html.layout");
+dojo.require("dojo.event.*");
+
+dojo.widget.defineWidget(
+	"dojo.widget.ResizeHandle",
+	dojo.widget.HtmlWidget,
+{
+	isSizing: false,
+	startPoint: null,
+	startSize: null,
+	minSize: null,
+
+	targetElmId: '',
+
+	templateCssPath: dojo.uri.dojoUri("src/widget/templates/ResizeHandle.css"),
+	templateString: '<div class="dojoHtmlResizeHandle"><div></div></div>',
+
+	postCreate: function(){
+		dojo.event.connect(this.domNode, "onmousedown", this, "beginSizing");
+	},
+
+	beginSizing: function(e){
+		if (this.isSizing){ return false; }
+
+		// get the target dom node to adjust.  targetElmId can refer to either a widget or a simple node
+		this.targetWidget = dojo.widget.byId(this.targetElmId);
+		this.targetDomNode = this.targetWidget ? this.targetWidget.domNode : dojo.byId(this.targetElmId);
+		if (!this.targetDomNode){ return; }
+
+		this.isSizing = true;
+		this.startPoint  = {'x':e.clientX, 'y':e.clientY};
+		var mb = dojo.html.getMarginBox(this.targetDomNode);
+		this.startSize  = {'w':mb.width, 'h':mb.height};
+
+		dojo.event.kwConnect({
+			srcObj: dojo.body(), 
+			srcFunc: "onmousemove",
+			targetObj: this,
+			targetFunc: "changeSizing",
+			rate: 25
+		});
+		dojo.event.connect(dojo.body(), "onmouseup", this, "endSizing");
+
+		e.preventDefault();
+	},
+
+	changeSizing: function(e){
+		// On IE, if you move the mouse above/to the left of the object being resized,
+		// sometimes clientX/Y aren't set, apparently.  Just ignore the event.
+		try{
+			if(!e.clientX  || !e.clientY){ return; }
+		}catch(e){
+			// sometimes you get an exception accessing above fields...
+			return;
+		}
+		var dx = this.startPoint.x - e.clientX;
+		var dy = this.startPoint.y - e.clientY;
+		
+		var newW = this.startSize.w - dx;
+		var newH = this.startSize.h - dy;
+
+		// minimum size check
+		if (this.minSize) {
+			var mb = dojo.html.getMarginBox(this.targetDomNode);
+			if (newW < this.minSize.w) {
+				newW = mb.width;
+			}
+			if (newH < this.minSize.h) {
+				newH = mb.height;
+			}
+		}
+		
+		if(this.targetWidget){
+			this.targetWidget.resizeTo(newW, newH);
+		}else{
+			dojo.html.setMarginBox(this.targetDomNode, { width: newW, height: newH});
+		}
+		
+		e.preventDefault();
+	},
+
+	endSizing: function(e){
+		dojo.event.disconnect(dojo.body(), "onmousemove", this, "changeSizing");
+		dojo.event.disconnect(dojo.body(), "onmouseup", this, "endSizing");
+
+		this.isSizing = false;
+	}
+
+
+});

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