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, 


Reply via email to