You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@sling.apache.org by fm...@apache.org on 2008/12/22 08:58:06 UTC

svn commit: r728626 - in /incubator/sling/trunk/extensions/dojo-sling/src/main/resources: SLING-INF/content/dojox/data/demo/demo4.html dojox/data/SlingNodeStore.js dojox/data/SlingPropertyStore.js

Author: fmeschbe
Date: Sun Dec 21 23:58:06 2008
New Revision: 728626

URL: http://svn.apache.org/viewvc?rev=728626&view=rev
Log:
SLING-792 Apply patch by Rory Douglas (thanks for providing)

Added:
    incubator/sling/trunk/extensions/dojo-sling/src/main/resources/SLING-INF/content/dojox/data/demo/demo4.html
Modified:
    incubator/sling/trunk/extensions/dojo-sling/src/main/resources/dojox/data/SlingNodeStore.js
    incubator/sling/trunk/extensions/dojo-sling/src/main/resources/dojox/data/SlingPropertyStore.js

Added: incubator/sling/trunk/extensions/dojo-sling/src/main/resources/SLING-INF/content/dojox/data/demo/demo4.html
URL: http://svn.apache.org/viewvc/incubator/sling/trunk/extensions/dojo-sling/src/main/resources/SLING-INF/content/dojox/data/demo/demo4.html?rev=728626&view=auto
==============================================================================
--- incubator/sling/trunk/extensions/dojo-sling/src/main/resources/SLING-INF/content/dojox/data/demo/demo4.html (added)
+++ incubator/sling/trunk/extensions/dojo-sling/src/main/resources/SLING-INF/content/dojox/data/demo/demo4.html Sun Dec 21 23:58:06 2008
@@ -0,0 +1,145 @@
+<!-- 
+  Licensed to the Apache Software Foundation (ASF) under one or more
+  contributor license agreements.  See the NOTICE file distributed with
+  this work for additional information regarding copyright ownership.
+  The ASF licenses this file to You under the Apache License, Version 2.0
+  (the "License"); you may not use this file except in compliance with
+  the License.  You may obtain a copy of the License at
+ 
+       http://www.apache.org/licenses/LICENSE-2.0
+ 
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+
+ -->
+<html>
+<head>
+	<style type="text/css">
+		@import "../../../dijit/themes/tundra/tundra.css";
+		@import "../../../dojo/resources/dojo.css";
+		@import "../../../dijit/tests/css/dijitTests.css";
+		@import "../../../dojox/grid/resources/tundraGrid.css";
+		@import "../../../dojox/grid/resources/Grid.css";
+		
+		.dojoxGrid table {
+			margin: 0;
+		}
+
+	</style>
+
+	<script type="text/javascript" src="../../../dojo/dojo.js" djConfig="isDebug: true, parseOnLoad: true, usePlainJson: true"></script>
+	<script type="text/javascript">
+		dojo.require("dijit.form.Form");
+		dojo.require("dijit.form.Button");
+		dojo.require("dijit.form.ComboBox");
+		dojo.require("dijit.form.TextBox");
+		dojo.require("dijit.form.FilteringSelect");
+		dojo.require("dijit.Tree");
+		dojo.require("dojox.data.SlingPropertyStore");
+		dojo.require("dojox.data.SlingNodeStore");
+		dojo.require("dojox.grid.DataGrid");
+		dojo.require("dijit.layout.StackContainer");
+		dojo.require("dijit.layout.TabContainer");
+		dojo.require("dijit.layout.ContentPane");
+		dojo.require("dijit.layout.BorderContainer");
+		
+		var nodeLayout = [
+			[
+				{ field: "name", name: "Name", width: 20 },
+				{ field: "value", name: "Value", width: 40, editable: true}
+		    ]
+		];
+
+	</script>
+</head>
+<body class="tundra">
+  <!-- the data stores -->
+  <div dojoType="dojox.data.SlingPropertyStore" url="/samplenodes" jsId="propertyStore"></div>
+  <div dojoType="dojox.data.SlingNodeStore" url="/samplenodes" jsId="nodeStore"></div>
+  <div dojoType="dojox.data.SlingNodeStore" url="/samplenodes" jsId="nodeStoreLevel2" overrideDepth="{depth: 2}"></div>
+  <div dojoType="dojox.data.SlingNodeStore" url="/samplenodes" jsId="nodeStoreLevel2NotDeep" overrideDepth="{depth: 2}" overrideDeep="{deep: false}"></div>
+  <div dojoType="dojox.data.SlingNodeStore" url="/samplenodes" jsId="nodeStoreAll3" overrideDeep="{deep: true}" overrideDepth="{depth: 3}"></div>
+  <div dojoType="dojox.data.SlingNodeStore" url="/" statement="//*[sling:resourceType='sample/node']" searchprops="['title','jcr:created']" jsId="nodeStoreSearch"></div>
+  <div dojoType="dojox.data.SlingNodeStore" url="/samplenodes" jsId="nodeStoreTreeLimit" overrideDepth="{treeDepth: 3}"></div>
+  
+  <!-- Models for the Trees -->
+  <div dojoType="dijit.tree.TreeStoreModel" jsId="treeModel" store="nodeStore"></div>
+  <div dojoType="dijit.tree.ForestStoreModel" jsId="forestModel" store="nodeStoreLevel2" rootId="fakeRoot" rootLabel="Fake Root"></div>
+  <div dojoType="dijit.tree.TreeStoreModel" jsId="treeModelLimit" store="nodeStoreTreeLimit"></div>
+  
+  <!--<div dojoType="dijit.layout.StackController" containerId="demoStack"></div>-->
+  <div dojoType="dijit.layout.TabContainer" id="demoStack" style="height: 100%">
+	<div title="Tree 1" dojoType="dijit.layout.ContentPane">
+		<h4>Tree of /samplenodes, all defaults</h4>
+		<div dojoType="dijit.Tree" model="treeModel" persist="false"></div>
+	</div>
+	<div title="Tree 2" dojoType="dijit.layout.ContentPane">
+		<h4>Tree of /samplenodes, depth=2, using forest model</h4>
+		<div dojoType="dijit.Tree" model="forestModel" persist="false"></div>
+	</div>
+	<div title="Tree 3" dojoType="dijit.layout.ContentPane">
+		<h4>Tree of /samplenodes, treedepth=3</h4>
+		<div dojoType="dijit.Tree" model="treeModelLimit" persist="false"></div>
+	</div>
+	<div title="ComboBox 1" dojoType="dijit.layout.ContentPane">
+		<h4>ComboBox of /samplenodes, all defaults</h4>
+		<div dojoType="dijit.form.ComboBox" store="nodeStore" searchAttr="title"></div>
+	</div>
+	<div title="ComboBox 2" dojoType="dijit.layout.ContentPane">
+		<h4>ComboBox of /samplenodes, depth=2</h4>
+		<div dojoType="dijit.form.ComboBox" store="nodeStoreLevel2" searchAttr="title"></div>
+	</div>
+	<div title="ComboBox 3" dojoType="dijit.layout.ContentPane">
+		<h4>ComboBox of /samplenodes, depth=2, deep=false</h4>
+		<div dojoType="dijit.form.ComboBox" store="nodeStoreLevel2NotDeep" searchAttr="title"></div>
+	</div>
+	<div title="FilteringSelect 1" dojoType="dijit.layout.ContentPane">
+		<h4>FilteringSelect of /samplenodes, using search statement: //*[sling:resourceType='sample/node']</h4>
+		<div dojoType="dijit.form.FilteringSelect" store="nodeStoreSearch" searchAttr="title"></div>
+	</div>
+	<div title="Complete" dojoType="dijit.layout.ContentPane">
+		<div dojoType="dijit.layout.BorderContainer" design="sidebar" gutters="true" liveSplitters="true" id="borderContainer">
+			<div dojoType="dijit.layout.ContentPane" splitter="true" region="leading" style="width: 20%;">
+				<div dojoType="dijit.Tree" model="treeModel" persist="false">
+					<script type="dojo/connect" event="onClick" args="nodeItem,nodeWidget">
+						propertyStore.setUrl(nodeItem.uri);
+						dijit.byId("nodePropGrid").setStore(propertyStore);
+					</script>
+				</div>
+			</div>
+			<div id="propGrid" dojoType="dijit.layout.ContentPane" region="center">
+				<div dojoType="dijit.layout.BorderContainer" gutters="true" liveSplitters="true" id="propContainer">
+					<div dojoType="dijit.layout.ContentPane" region="top">
+						<input id="newPropertyName" dojoType="dijit.form.TextBox" value=""/>
+						<input id="newPropertyValue" dojoType="dijit.form.TextBox" value=""/>
+						<div dojoType="dijit.form.Button" label="Add Property">
+							<script type="dojo/connect" event="onClick">
+								var newItem= {name: dijit.byId('newPropertyName').getValue(),value: dijit.byId('newPropertyValue').getValue()};
+								propertyStore.newItem(newItem);
+								dijit.byId("nodePropGrid").setStore(propertyStore);
+							</script>
+						</div>
+					</div>
+					<div dojoType="dijit.layout.ContentPane" region="center">
+						<div id="nodePropGrid"
+							    dojoType="dojox.grid.DataGrid"
+								store="propertyStore"
+								structure="nodeLayout"
+							    rowsPerPage="40">
+							<script type="dojo/connect" event="onApplyCellEdit">
+								// necessary because v1.2.3 grid keeps internal item cache & fetchItemByIdentity returns new item not ref to existing
+								dijit.byId("nodePropGrid").setStore(propertyStore);
+							</script>
+						</div>
+					</div>
+				</div>
+			</div>
+		</div>
+	</div>
+</body>
+</html>
+
+

Modified: incubator/sling/trunk/extensions/dojo-sling/src/main/resources/dojox/data/SlingNodeStore.js
URL: http://svn.apache.org/viewvc/incubator/sling/trunk/extensions/dojo-sling/src/main/resources/dojox/data/SlingNodeStore.js?rev=728626&r1=728625&r2=728626&view=diff
==============================================================================
--- incubator/sling/trunk/extensions/dojo-sling/src/main/resources/dojox/data/SlingNodeStore.js (original)
+++ incubator/sling/trunk/extensions/dojo-sling/src/main/resources/dojox/data/SlingNodeStore.js Sun Dec 21 23:58:06 2008
@@ -18,23 +18,72 @@
 dojo._hasResource["dojox.data.SlingNodeStore"] = true;
 
 dojo.require("dojo.data.util.simpleFetch");
+dojo.require("dojo.data.util.filter");
 dojo.provide("dojox.data.SlingNodeStore");
 
 dojo.declare("dojox.data.SlingNodeStore", null, {
   url:"",
+  statement:"",
   query:null,
-  
+  searchprops:null,
+  overrideDeep:null,
+  overrideDepth:null,
 	/* summary:
 	 *   The SlingNodeStore implements the dojo.data.api.Read API.  
 	 */
 	constructor: function(/* Object */ keywordParameters){
-    this.uri = keywordParameters.url;
+	    this.uri = keywordParameters.url;
+	    this.statement = keywordParameters.statement;
+	    
+	    if(keywordParameters.query) {
+	    	this.query = keywordParameters.query;
+	    }
+	    
+    	if (dojo.isArray(keywordParameters.searchprops)) {
+			this.searchprops = keywordParameters.searchprops;
+		}else{
+			if (dojo.isString(keywordParameters.searchprops)) {
+				this.searchprops = keywordParameters.searchprops.split(",");
+			}
+		}
+	    
+	    if(keywordParameters.overrideDeep) {
+	    	this.overrideDeep = keywordParameters.overrideDeep;
+	    }
+	    
+	    if(keywordParameters.overrideDepth) {
+	    	this.overrideDepth = keywordParameters.overrideDepth;
+	    }
 	},
   
+  setUrl: function(/* String */ url) {
+	this.uri = url;
+  },
+  setStatement: function(/* String */ statement) {
+	this.statement = statement;
+  },
+  setSearchProps: function(/* Array|String */ props) {
+	  if (dojo.isArray(props)) {
+			this.searchprops = props;
+		}else{
+			if (dojo.isString(props)) {
+				this.searchprops = props.split(",");
+			}
+		}
+  },
+  setOverrideDeep: function(/* Object */ overrideDeep) {
+	  this.overrideDeep = overrideDeep;
+  },
+  setOverrideDepth: function(/* Object */ overrideDepth) {
+	  this.overrideDepth = overrideDepth;
+  },
+  setQuery: function(/* Object */ query) {
+	  this.query = query;
+  },
   getValue: function(	/* item */ item, 
 						/* attribute-name-string */ attribute, 
 						/* value? */ defaultValue){
-    console.log("getValue " + attribute);
+    //console.log("getValue " + attribute);
     if (!this.isItem(item)) {
       throw new Error(item + " is not an item");
     }
@@ -62,6 +111,9 @@
     if (!dojo.isString(attribute)) {
       throw new Error(attribute + " is not a string");
     }
+    if (attribute=="sling:uri") {
+    	return [item.uri];
+    }
     if (attribute=="children"&&this._hasChildren(item)) {
       return this._getChildren(item);
     }
@@ -82,10 +134,14 @@
     
     for (var property in item.node) {
       if (dojo.isObject(item.node[property])) {
-        if (item.node[property]["jcr:primaryType"]&&this.accept(item.node[property], item.query)) {
-          var childuri = item.uri=="/" ? "/" + property : item.uri + "/" + property;
-          var child = {uri: childuri, query: item.query }
-          children.push(child);
+        if (item.node[property]["jcr:primaryType"]) {
+        	var childuri = item.uri=="/" ? "/" + property : item.uri + "/" + property;
+            var checkChild = {uri: childuri, node: item.node[property], depth: item.depth+1};
+            
+        	if(this.accept(checkChild, item.query)) {
+        		var child = {uri: childuri, query: item.query, depth: item.depth+1 };
+        		children.push(child);
+        	}
         }
       }
     }
@@ -95,7 +151,7 @@
   },
   
   getAttributes: function(/* item */ item){
-    console.log("getAttributes");
+    //console.log("getAttributes");
     if (!this.isItem(item)) {
       return [];
     }
@@ -129,6 +185,9 @@
     if (attribute=="children") {
       return this._hasChildren(item);
     }
+    if (attribute=="sling:uri") {
+    	return true;
+    }
     if (item.node[attribute]) {
       return true;
     }
@@ -137,11 +196,19 @@
   
   _hasChildren: function(/* item */ item) {
     //children are all properties of a node that are objects
+	if(this.overrideDepth && this.overrideDepth.treeDepth && item.depth && item.depth >= this.overrideDepth.treeDepth  ) {
+		return false;
+	}
     for (var property in item.node) {
       if (dojo.isObject(item.node[property])) {
-        if (item.node[property]["jcr:primaryType"]&&this.accept(item.node[property], item.query)) {
-          //console.log("there are children");
-          return true;
+        if (item.node[property]["jcr:primaryType"]) {
+        	var childuri = item.uri=="/" ? "/" + property : item.uri + "/" + property;
+            var checkChild = {uri: childuri, node: item.node[property], depth: item.depth+1};
+            
+        	if(this.accept(checkChild, item.query)) {
+	          	//console.log("there are children");
+	          	return true;
+			}
         }
       }
     }
@@ -251,29 +318,100 @@
         xhr.abort();
       }
     };
-    var query = keywordArgs.query;
     
-    var depth = 1;
-    if (query&&query.level) {
-      depth = depth + query.level;
+    var query = keywordArgs.query;
+    var queryOptions = keywordArgs.queryOptions;
+    //var startVal = keywordArgs.start;
+    //var countVal = keywordArgs.count;
+    	
+    var depth = 0;
+    var isDeep = false;
+    var isSearch = false;
+    
+    // is this a deep query? (store setting overrides queryOption)
+    if (this.overrideDeep) {
+    	isDeep = this.overrideDeep.deep;
+    } else if(queryOptions&&queryOptions.deep) {
+   		isDeep = queryOptions.deep; 
+    }
+    
+    // query depth/level specified? (store setting overrides queryOption)
+    // deep = true & no depth => depth is infinite
+    if(this.overrideDepth&&this.overrideDepth.depth) {
+    	depth = this.overrideDepth.depth;
+    } else if (queryOptions&&queryOptions.depth) {
+    	depth = queryOptions.depth;
+    } else if (isDeep){
+    	depth = "infinity";
+    }
+    
+    // mixin store query with caller-provided query
+    // won't work well if two queries share an attribute
+    if(this.query) {
+    	if(!query) {
+    		query = {};
+    	}
+    	dojo.mixin(query,this.query);
+    }
+    
+    var url = this.uri + "."+(depth == "infinity" ? depth : depth+1)+".json";
+    
+    // was a statement provided? if so, doing search
+    if(this.statement) {
+    	isSearch = true;
+    	
+    	// to make descend behave properly
+    	depth = "infinity";
+    	isDeep = true;
+    	
+    	// construct search URL
+    	url = this.uri + ".query.json?statement=" + this.statement;
+    	
+    	/*
+    	if(startVal != 0){
+			url = url + "&offset=" + startVal;
+		}
+		if(countVal && typeof countVal == "number"){
+			if(isFinite(countVal)) {
+				url = url + "&rows=" + countVal;
+			}
+		}
+		*/
+    	
+		if(dojo.isArray(this.searchprops)) {
+			dojo.forEach(this.searchprops,function(prop)  {
+				url = url + "&property=" + prop;
+			});
+		}
     }
-    var url = this.uri + "."+depth+".json";
+    
     var that = this;
     
     xhr = dojo.xhrGet({
         url: url,
         handleAs: "json-comment-optional",
         load: function(response, ioargs) {
-          var item = { node: response, uri: that.uri};
+          var item = { node: response, uri: that.uri, depth: 0};
           
           var items = [];
           if (request.onComplete) {
-            if (query&&query.level) {
+        	if (isSearch || dojo.isArray(response)) {
+        		var checkitems = [];
+        		dojo.forEach(response, function(item,index,array) {
+        			var anItem = {};
+        			anItem.node = item;
+        			anItem.uri = item['jcr:path'];
+        			anItem.depth = 0;
+        			checkitems.push(anItem);
+        		});
+        		
+        		items = that.descend(checkitems, query, depth, isDeep);
+        	} else if (depth == "infinity" || depth > 0) {
               //console.log("hehe. got a level");
-              var checkitems = [ { node: item.node, uri: that.uri } ];
-              items = that.descend(checkitems, query.level);
+              var checkitems = [ { node: item.node, uri: that.uri, depth: 0} ];
+              items = that.descend(checkitems, query, depth, isDeep );
             } else {
-              if (that.accept(item.node, query)) {
+              if (that.accept(item, query)) {
                 item.query = query;
                 items.push(item);
               }
@@ -284,101 +422,87 @@
     });
   },
   
-  descend: function(items, level) {
+  descend: function(items, query, level, isDeep) {
     var allitems = [];
-    console.log(level);
-    if (level==0) {
-      allitems = allitems.concat(items);
-    } else {
+    //console.log(level);
+    if (level==0 || isDeep) {
+    	 for (var i=0;i<items.length;i++) {
+    		 var checkItem = items[i];
+    		 if(this.accept(checkItem,query)) {
+    			 checkItem.query = query;
+    			 allitems.push(checkItem);
+    		 }
+    	 }
+      //allitems = allitems.concat(items);
+    } 
+    
+    var objFound = false;
+    
+    if(level != 0) {
       var newitems = [];
       for (var i=0;i<items.length;i++) {
         var item = items[i];
+                
         for (var property in item.node) {
-          if (dojo.isObject(item.node[property])) {
-            var newitem = { node: item.node[property], uri: ( item.uri == "/" ? "" : item.uri ) + "/" + property };
+          if (!dojo.isArray(item.node[property])&&dojo.isObject(item.node[property])) {
+        	objFound = true;
+            var newitem = { node: item.node[property], uri: ( item.uri == "/" ? "" : item.uri ) + "/" + property, depth: item.depth+1};
             newitems.push(newitem);
           }
         }
       }
-      allitems = allitems.concat(this.descend(newitems, level - 1));
-    }
-    console.dir(allitems);
-    return allitems;
-  },
-  
-  _nofetch: function(/* object */ keywordArgs) {
-    var request = keywordArgs;
-    
-    var xhr;
-    
-    request.abort = function() {
-      if (xhr.abort) {
-        xhr.abort();
+      
+      if(level == "infinity" && objFound) {
+   		  allitems = allitems.concat(this.descend(newitems, query, "infinity", isDeep));
+      } else if (level >= 1) {
+    	  allitems = allitems.concat(this.descend(newitems, query, level - 1, isDeep));
       }
-    };
-    
-    
-    var query = keywordArgs.query;
-    
-    var depth = 1;
-    if (query.level) {
-      depth = depth + query.level;
     }
-    var url = this.uri + "."+depth+".json";
-    var that = this;
-    
-    xhr = dojo.xhrGet({
-        url: url,
-        handleAs: "json-comment-optional",
-        load: function(response, ioargs) {
-          var item = { node: response, uri: that.uri};
-          
-          if (request.onComplete) {
-            if (query.level) {
-              
-            } else {
-              if (that.accept(item.node, query)) {
-                item.query = query;
-                request.onComplete([ item ], request);
-              }
-            }
-          }
-        }
-    });
-    //TODO: implement
-    //alert(this.url);
-    return request;
+    //console.dir(allitems);
+    return allitems;
   },
-  
-  accept: function(node, query) {
+   
+  accept: function(item, query) {
     //TODO: handle querying for arrays
     if (!query) {
       return true;
     }
-    if (!query.query) {
-      return true;
-    }
-    for (var property in query.query) {
+       
+    var ignoreCase = true;
+
+	//See if there are any string values that can be regexp parsed first to avoid multiple regexp gens on the
+	//same value for each item examined.  Much more efficient.
+	var regexpList = {};
+	for(var key in query){
+		var value = query[key];
+		if(typeof value === "string"){
+			regexpList[key] = dojo.data.util.filter.patternToRegExp(value, ignoreCase);
+		}
+	}
+
+	for (var property in query) {
       //console.log(property);
-      if (node[property]) {
-        if (dojo.isArray(query.query[property])) {
+      if (item.node[property]) {
+    	var checkItem = item;
+        if (dojo.isArray(query[property])) {
           //console.log("multiple values possible");
           var onematch = false;
-          for (var value in query.query[property]) {
-            //console.log("checking value " + query.query[property][value]);
-            if (node[property]==query.query[property][value]) {
-              onematch = true;
-            }
+			
+          for (var value in query[property]) {
+            //console.log("checking value " + query[property][value]);
+        	  if (!this._containsValue(checkItem, property, checkItem.node[property], regexpList[property])){
+        		  onematch = false;
+  			  }
           }
           if (!onematch) {
-            //console.log("required property " + property + " has wrong value "+ node[property]);
+            //console.log("required property " + property + " has wrong value "+ item.node[property]);
             return false;
           }
         } else {
-          if (node[property]!=query.query[property]) {
-            //console.log("required property " + property + " has wrong value "+ node[property]);
-            return false;
-          }
+        	 if (!this._containsValue(checkItem, property, checkItem.node[property], regexpList[property])){
+        		//console.log("required property " + property + " has wrong value "+ item.node[property]);
+       		  	return false;
+ 			  }
         }
       } else {
         //console.log("required property " + property + " missing");
@@ -388,6 +512,37 @@
     return true;
   },
   
+  _containsValue: function(	/* item */ item, 
+			/* attribute-name-string */ attribute, 
+			/* anything */ value,
+			/* RegExp?*/ regexp){
+	//	summary: 
+	//		Internal function for looking at the values contained by the item.
+	//	description: 
+	//		Internal function for looking at the values contained by the item.  This 
+	//		function allows for denoting if the comparison should be case sensitive for
+	//		strings or not (for handling filtering cases where string case should not matter)
+	//	
+	//	item:
+	//		The data item to examine for attribute values.
+	//	attribute:
+	//		The attribute to inspect.
+	//	value:	
+	//		The value to match.
+	//	regexp:
+	//		Optional regular expression generated off value if value was of string type to handle wildcarding.
+	//		If present and attribute values are string, then it can be used for comparison instead of 'value'
+	  return dojo.some(this.getValues(item, attribute), function(possibleValue){
+		if(possibleValue !== null && !dojo.isObject(possibleValue) && regexp){
+			if(possibleValue.toString().match(regexp)){
+				return true; // Boolean
+			}
+		}else if(value === possibleValue){
+			return true; // Boolean
+		}
+	  });
+	},
+
   getFeatures: function() {
     return {
       "dojo.data.api.Read": true,
@@ -435,7 +590,7 @@
   getIdentityAttributes: function(/* item */ item) {
     //console.log("getIdentityAttributes");
     //identity depends on the URI, not the representation
-    return null;
+    return ["sling:uri"];
   },
   
   fetchItemByIdentity: function(/* object */ keywordArgs) {
@@ -449,7 +604,28 @@
 		//			scope: object
 		//		}
     
-    //TODO: implement
+	 var request = keywordArgs;
+	 
+	 var url = keywordArgs.identity + ".1.json";
+	 
+	 var that = this;
+	    
+	    xhr = dojo.xhrGet({
+	        url: url,
+	        handleAs: "json-comment-optional",
+	        load: function(response, ioargs) {
+	          var item = { node: response, uri: request.identity};
+	          
+	          if (request.onItem) {
+	        	request.onItem(item);
+	          }
+	        },
+	        error: function(response, ioargs) {
+	        	if(request.onError) {
+	        		request.onError(response);
+	        	}
+	        }
+	    });
   },
   
   
@@ -498,8 +674,7 @@
   
   
   setValues: function(item, attribute, values) { console.log("setValues");
-    throw new Error('Unimplemented API: dojo.data.api.Write.setValues');
-    this.onSet(item, attribute, oldvalues, values);
+    this.setValue(item, attribute, values);
   },
   
   unsetAttribute: function(	/* item */ item, 

Modified: incubator/sling/trunk/extensions/dojo-sling/src/main/resources/dojox/data/SlingPropertyStore.js
URL: http://svn.apache.org/viewvc/incubator/sling/trunk/extensions/dojo-sling/src/main/resources/dojox/data/SlingPropertyStore.js?rev=728626&r1=728625&r2=728626&view=diff
==============================================================================
--- incubator/sling/trunk/extensions/dojo-sling/src/main/resources/dojox/data/SlingPropertyStore.js (original)
+++ incubator/sling/trunk/extensions/dojo-sling/src/main/resources/dojox/data/SlingPropertyStore.js Sun Dec 21 23:58:06 2008
@@ -18,6 +18,7 @@
 dojo._hasResource["dojox.data.SlingPropertyStore"] = true;
 
 dojo.require("dojo.data.util.simpleFetch");
+dojo.require("dojo.data.util.filter");
 dojo.provide("dojox.data.SlingPropertyStore");
 
 dojo.declare("dojox.data.SlingPropertyStore", null, {
@@ -29,9 +30,17 @@
    *   It will return one data item for every property found
 	 */
 	constructor: function(/* Object */ keywordParameters){ console.log("constructor");
-    this.uri = keywordParameters.url;
+	    this.uri = keywordParameters.url;
+	    if(keywordParameters.query) {
+	    	this.query = keywordParameters.query;
+	    }
 	},
-  
+  setUrl: function(/* String */ url) {
+		this.uri = url;
+  },
+  setQuery: function(/* Object */ query) {
+	  this.query = query;
+  },
   getValue: function(	/* item */ item,  /* attribute-name-string */ attribute,  /* value? */ defaultValue){
     //console.log("getValue " + attribute + " " + item.name);
     if (!this.isItem(item)) {
@@ -51,8 +60,17 @@
     if (!dojo.isString(attribute)) {
       throw new Error(attribute + " is not a string");
     }
-    return item[attribute];
-	},
+    if (item[attribute]) {
+      if (dojo.isArray(item[attribute])) {
+        return item[attribute]
+      } else {
+        return [item[attribute]];
+      }
+    } else {
+      var array = [];
+      return array; // an array that may contain literals and items
+    }
+  },
   
   getAttributes: function(/* item */ item){ //console.log("getAttributes");
     //console.log("getAttributes");
@@ -116,30 +134,44 @@
   _fetchItems: function(	/* Object */ keywordArgs, 
 							/* Function */ findCallback, 
 							/* Function */ errorCallback) {
-    var request = keywordArgs;
-    
+	  var request = keywordArgs;
+	    
     var xhr;
     
     request.abort = function() {
-      errorCallback.("XHR aborted", keywordArgs)
+      if (xhr.abort) {
+        xhr.abort();
+      }
     };
     
-    var depth = 1;
+    var query = keywordArgs.query;
+    
+    var depth = 0;
     
     var url = this.uri + "."+depth+".json";
     var that = this;
     
-    var query = keywordArgs.query;
-  
+    // mixin store query with caller-provided query
+    // won't work well if two queries share an attribute
+    if(this.query) {
+    	if(!query) {
+    		query = {};
+    	}
+    	dojo.mixin(query,this.query);
+    }
+    
     xhr = dojo.xhrGet({
         url: url,
         handleAs: "json-comment-optional",
         load: function(response, ioargs) {
           var items = [];
           for (var property in response) {
-            if (!dojo.isObject(response[property])) {
+            if (dojo.isArray(response[property]) || !dojo.isObject(response[property])) {
               //console.debug(property);
-              items.push({ uri: that.uri, name: property, value: response[property]});
+            	var checkitem = { uri: that.uri, name: property, value: response[property]};
+            	if(that.accept(checkitem,query)) {
+            		items.push(checkitem);
+            	}
             }
           }
           findCallback(items, keywordArgs);
@@ -148,59 +180,86 @@
     
   },
   
-  _nofetch: function(/* object */ keywordArgs) { console.log("fetch");
-    var request = keywordArgs;
-    
-    var xhr;
-    
-    request.abort = function() {
-      if (xhr.abort) {
-        xhr.abort();
-      }
-    };
-    
-    var depth = 1;
-    
-    /*
-    if (keywordArgs.count) {
-      depth = keywordArgs.count;
+  accept: function(item, query) {
+	  // TODO: handle querying for arrays
+    if (!query) {
+      return true;
     }
-    */
-    
-    var url = this.uri + "."+depth+".json";
-    var that = this;
-    
-    var query = keywordArgs.query;
-    
-    xhr = dojo.xhrGet({
-        url: url,
-        handleAs: "json-comment-optional",
-        load: function(response, ioargs) { console.log("load");
-          //console.dir(response);
-          var items = [];
-          
-          for (var property in response) {
-            if (!dojo.isObject(response[property])) {
-              //console.debug(property);
-              items.push({ uri: that.uri, name: property, value: response[property]});
-            }
+       
+    var ignoreCase = true;
+
+	//See if there are any string values that can be regexp parsed first to avoid multiple regexp gens on the
+	//same value for each item examined.  Much more efficient.
+	var regexpList = {};
+	for(var key in query){
+		var value = query[key];
+		if(typeof value === "string"){
+			regexpList[key] = dojo.data.util.filter.patternToRegExp(value, ignoreCase);
+		}
+	}
+
+	for (var property in query) {
+      //console.log(property);
+      if (item[property]) {
+    	var checkItem = item;
+        if (dojo.isArray(query[property])) {
+          //console.log("multiple values possible");
+          var onematch = false;
+			
+          for (var value in query[property]) {
+            //console.log("checking value " + query[property][value]);
+        	  if (!this._containsValue(checkItem, property, checkItem[property], regexpList[property])){
+        		  onematch = false;
+  			  }
           }
-          
-          if (request.onComplete) {
-            if (request.scope) {
-              request.onComplete.call(request.scope, item. request)
-            } else {
-              request.onComplete(items, request);
-            }
-            //request.onComplete(items, request);
+          if (!onematch) {
+            //console.log("required property " + property + " has wrong value "+ item.node[property]);
+            return false;
           }
+        } else {
+        	 if (!this._containsValue(checkItem, property, checkItem[property], regexpList[property])){
+        		//console.log("required property " + property + " has wrong value "+ item.node[property]);
+       		  	return false;
+ 			  }
         }
-    });
-    //TODO: implement
-    //alert(this.url);
-    return request;
+      } else {
+        //console.log("required property " + property + " missing");
+        return false;
+      }
+    }
+    return true;
   },
- 
+	  
+  _containsValue: function(	/* item */ item, 
+			/* attribute-name-string */ attribute, 
+			/* anything */ value,
+			/* RegExp?*/ regexp){
+	//	summary: 
+	//		Internal function for looking at the values contained by the item.
+	//	description: 
+	//		Internal function for looking at the values contained by the item.  This 
+	//		function allows for denoting if the comparison should be case sensitive for
+	//		strings or not (for handling filtering cases where string case should not matter)
+	//	
+	//	item:
+	//		The data item to examine for attribute values.
+	//	attribute:
+	//		The attribute to inspect.
+	//	value:	
+	//		The value to match.
+	//	regexp:
+	//		Optional regular expression generated off value if value was of string type to handle wildcarding.
+	//		If present and attribute values are string, then it can be used for comparison instead of 'value'
+	  return dojo.some(this.getValues(item, attribute), function(possibleValue){
+		if(possibleValue !== null && !dojo.isObject(possibleValue) && regexp){
+			if(possibleValue.toString().match(regexp)){
+				return true; // Boolean
+			}
+		}else if(value === possibleValue){
+			return true; // Boolean
+		}
+	  });
+	},
   
   getFeatures: function() { console.log("getFeatures");
     console.log("getFeatures");
@@ -237,7 +296,7 @@
       console.log("error: not an item");
       throw new Error(item + " is not an item");
     }
-    return item.uri + "[" + item.name + "]";
+    return this.uri + "[" + item.name + "]";
   },
   
   getIdentityAttributes: function(/* item */ item) { console.log("getIdentityAttributes");
@@ -256,8 +315,37 @@
 		//			onError: Function,
 		//			scope: object
 		//		}
+    var request = keywordArgs;
     
-    //TODO: implement
+  	var itemId = keywordArgs.identity;
+  	var idParts = itemId.split('['); 
+  	var itemUri = idParts[0];
+  	var itemName = idParts[1].substring(0,idParts[1].length-1);
+  	var url = itemUri + "/" + itemName + ".0.json";
+	 
+	 var that = this;
+	    
+	    xhr = dojo.xhrGet({
+	        url: url,
+	        handleAs: "json-comment-optional",
+	        load: function(response, ioargs) {
+	          
+	          if (request.onItem) {
+	        	  for (var property in response) {
+	                  if (dojo.isArray(response[property]) || !dojo.isObject(response[property])) {
+	                  	var checkitem = { uri: itemUri, name: property, value: response[property]};
+	                  	request.onItem(checkitem);
+	                  	break;
+	                  }
+	        	  }
+	          }
+	        },
+	        error: function(response, ioargs) {
+	        	if(request.onError) {
+	        		request.onError(response);
+	        	}
+	        }
+	    });
   },
   
   
@@ -322,11 +410,7 @@
   
   setValues: function(item, attribute, values) { console.log("setValues");
     console.log("setValues");
-    var oldvalues = item.values;
-    item.value = values;
-    item.dirty = true;
-    
-    this.onSet(item, attribute, oldvalues, values);
+    this.setValue(item, attribute, values);
   },
   
   unsetAttribute: function(	/* item */ item,