source: Dev/branches/rest-dojo-ui/client/dojox/data/FileStore.js @ 256

Last change on this file since 256 was 256, checked in by hendrikvanantwerpen, 13 years ago

Reworked project structure based on REST interaction and Dojo library. As
soon as this is stable, the old jQueryUI branch can be removed (it's
kept for reference).

  • Property svn:executable set to *
File size: 11.8 KB
Line 
1define(["dojo/_base/declare", "dojo/_base/lang", "dojo/_base/window", "dojo/_base/json", "dojo/_base/xhr"],
2  function(declare, lang, winUtil, jsonUtil, xhr) {
3
4return declare("dojox.data.FileStore", null, {
5        constructor: function(/*Object*/args){
6                //      summary:
7                //              A simple store that provides a datastore interface to a filesystem.
8                //      description:
9                //              A simple store that provides a datastore interface to a filesystem.  It takes a few parameters
10                //              for initialization:
11                //                      url:    The URL of the service which provides the file store serverside implementation.
12                //                      label:  The attribute of the file to use as the huma-readable text.  Default is 'name'.
13                //              The purpose of this store is to represent a file as a datastore item.  The
14                //              datastore item by default has the following attributes that can be examined on it.
15                //                      directory:      Boolean indicating if the file item represents a directory.
16                //                      name:   The filename with no path informatiom.
17                //                      path:   The file complete file path including name, relative to the location the
18                //                                      file service scans from
19                //                      size:   The size of the file, in bytes.
20                //                      parentDir:      The parent directory path.
21                //                      children:       Any child files contained by a directory file item.
22                //
23                //              Note that the store's server call pattern is RESTlike.
24                //
25                //              The store also supports the passing of configurable options to the back end service, such as
26                //              expanding all child files (no lazy load), displaying hidden files, displaying only directories, and so on.
27                //              These are defined through a comma-separated list in declarative, or through setting the options array in programmatic.
28                //              example:        options="expand,dirsOnly,showHiddenFiles"
29                if(args && args.label){
30                        this.label = args.label;
31                }
32                if(args && args.url){
33                        this.url = args.url;
34                }
35                if(args && args.options){
36                        if(lang.isArray(args.options)){
37                                this.options = args.options;
38                        }else{
39                                if(lang.isString(args.options)){
40                                        this.options = args.options.split(",");
41                                }
42                        }
43                }
44                if(args && args.pathAsQueryParam){
45                        this.pathAsQueryParam = true;
46                }
47                if(args && "urlPreventCache" in args){
48                        this.urlPreventCache = args.urlPreventCache?true:false;
49                }
50        },
51
52        // url: [public] string
53        //              The URL to the file path service.
54        url: "",
55       
56        // _storeRef: [private] string
57        //              Internal variable used to denote an item came from this store instance.
58        _storeRef: "_S",
59
60        // label: [public] string
61        //              Default attribute to use to represent the item as a user-readable
62        //              string.  Public, so users can change it.
63        label: "name",
64
65        // _identifier: [private] string
66        //              Default attribute to use to represent the item's identifier.
67        //              Path should always be unique in the store instance.
68        _identifier: "path",
69
70        // _attributes: [private] string
71        //              Internal variable of attributes all file items should have.
72        _attributes: ["children", "directory", "name", "path", "modified", "size", "parentDir"], //
73       
74        // pathSeparator: [public] string
75        //              The path separator to use when chaining requests for children
76        //              Can be overriden by the server on initial load
77        pathSeparator: "/",
78
79        // options: [public] array
80        //              Array of options to always send when doing requests.
81        //              Back end service controls this, like 'dirsOnly', 'showHiddenFiles', 'expandChildren', etc.
82        options: [],
83
84        // failOk: [public] boolean
85        //              Flag to pass on to xhr functions to check if we are OK to fail the call silently
86        failOk: false,
87
88        // urlPreventCache: [public] string
89        //              Flag to dennote if preventCache should be passed to xhrGet.
90        urlPreventCache: true,
91
92        _assertIsItem: function(/* item */ item){
93                // summary:
94                //      This function tests whether the item passed in is indeed an item in the store.
95                // item:
96                //              The item to test for being contained by the store.
97                if(!this.isItem(item)){
98                        throw new Error("dojox.data.FileStore: a function was passed an item argument that was not an item");
99                }
100        },
101
102        _assertIsAttribute: function(/* attribute-name-string */ attribute){
103                // summary:
104                //              This function tests whether the item passed in is indeed a valid 'attribute' like type for the store.
105                // attribute:
106                //              The attribute to test for being contained by the store.
107                if(typeof attribute !== "string"){
108                        throw new Error("dojox.data.FileStore: a function was passed an attribute argument that was not an attribute name string");
109                }
110        },
111
112        pathAsQueryParam: false, //Function to switch between REST style URL lookups and passing the path to specific items as a query param: 'path'.
113
114        getFeatures: function(){
115                // summary:
116                //      See dojo.data.api.Read.getFeatures()
117                return {
118                        'dojo.data.api.Read': true, 'dojo.data.api.Identity':true
119                };
120        },
121
122        getValue: function(item, attribute, defaultValue){
123                // summary:
124                //      See dojo.data.api.Read.getValue()
125                var values = this.getValues(item, attribute);
126                if(values && values.length > 0){
127                        return values[0];
128                }
129                return defaultValue;
130        },
131
132        getAttributes: function(item){
133                // summary:
134                //      See dojo.data.api.Read.getAttributes()
135                return this._attributes;
136        },
137
138        hasAttribute: function(item, attribute){
139                // summary:
140                //      See dojo.data.api.Read.hasAttribute()
141                this._assertIsItem(item);
142                this._assertIsAttribute(attribute);
143                return (attribute in item);
144        },
145       
146        getIdentity: function(/* item */ item){
147                // summary:
148                //              See dojo.data.api.Identity.getIdentity()
149                return this.getValue(item, this._identifier);
150        },
151       
152        getIdentityAttributes: function(item){
153                // summary:
154                //      See dojo.data.api.Read.getLabelAttributes()
155                return [this._identifier];
156        },
157
158
159        isItemLoaded: function(item){
160                 //     summary:
161                 //      See dojo.data.api.Read.isItemLoaded()
162                 var loaded = this.isItem(item);
163                 if(loaded && typeof item._loaded == "boolean" && !item._loaded){
164                        loaded = false;
165                 }
166                 return loaded;
167        },
168
169        loadItem: function(keywordArgs){
170                // summary:
171                //      See dojo.data.api.Read.loadItem()
172                var item = keywordArgs.item;
173                var self = this;
174                var scope = keywordArgs.scope || winUtil.global;
175
176                var content = {};
177
178                if(this.options.length > 0){
179                        content.options = jsonUtil.toJson(this.options);
180                }
181
182                if(this.pathAsQueryParam){
183                        content.path = item.parentPath + this.pathSeparator + item.name;
184                }
185                var xhrData = {
186                        url: this.pathAsQueryParam? this.url : this.url + "/" + item.parentPath + "/" + item.name,
187                        handleAs: "json-comment-optional",
188                        content: content,
189                        preventCache: this.urlPreventCache,
190                        failOk: this.failOk
191                };
192
193                var deferred = xhr.get(xhrData);
194                deferred.addErrback(function(error){
195                                if(keywordArgs.onError){
196                                        keywordArgs.onError.call(scope, error);
197                                }
198                });
199               
200                deferred.addCallback(function(data){
201                        delete item.parentPath;
202                        delete item._loaded;
203                        lang.mixin(item, data);
204                        self._processItem(item);
205                        if(keywordArgs.onItem){
206                                keywordArgs.onItem.call(scope, item);
207                        }
208                });
209        },
210
211        getLabel: function(item){
212                // summary:
213                //      See dojo.data.api.Read.getLabel()
214                return this.getValue(item,this.label);
215        },
216       
217        getLabelAttributes: function(item){
218                // summary:
219                //      See dojo.data.api.Read.getLabelAttributes()
220                return [this.label];
221        },
222       
223        containsValue: function(item, attribute, value){
224                // summary:
225                //      See dojo.data.api.Read.containsValue()
226                var values = this.getValues(item,attribute);
227                for(var i = 0; i < values.length; i++){
228                        if(values[i] == value){
229                                return true;
230                        }
231                }
232                return false;
233        },
234
235        getValues: function(item, attribute){
236                // summary:
237                //      See dojo.data.api.Read.getValue()
238                this._assertIsItem(item);
239                this._assertIsAttribute(attribute);
240               
241                var value = item[attribute];
242                if(typeof value !== "undefined" && !lang.isArray(value)){
243                        value = [value];
244                }else if(typeof value === "undefined"){
245                        value = [];
246                }
247                return value;
248        },
249
250        isItem: function(item){
251                // summary:
252                //      See dojo.data.api.Read.isItem()
253                if(item && item[this._storeRef] === this){
254                        return true;
255                }
256                return false;
257        },
258       
259        close: function(request){
260                // summary:
261                //      See dojo.data.api.Read.close()
262        },
263
264        fetch: function(request){
265                // summary:
266                //              Fetch  items that match to a query
267                // request:
268                //              A request object
269
270                request = request || {};
271                if(!request.store){
272                        request.store = this;
273                }
274                var self = this;
275                var scope = request.scope || winUtil.global;
276
277                //Generate what will be sent over.
278                var reqParams = {};
279                if(request.query){
280                        reqParams.query = jsonUtil.toJson(request.query);
281                }
282
283                if(request.sort){
284                        reqParams.sort = jsonUtil.toJson(request.sort);
285                }
286
287                if(request.queryOptions){
288                        reqParams.queryOptions = jsonUtil.toJson(request.queryOptions);
289                }
290
291                if(typeof request.start == "number"){
292                        reqParams.start = "" + request.start;
293                }
294                if(typeof request.count == "number"){
295                        reqParams.count = "" + request.count;
296                }
297
298                if(this.options.length > 0){
299                        reqParams.options = jsonUtil.toJson(this.options);
300                }
301
302                var getArgs = {
303                        url: this.url,
304                        preventCache: this.urlPreventCache,
305                        failOk: this.failOk,
306                        handleAs: "json-comment-optional",
307                        content: reqParams
308                };
309
310
311                var deferred = xhr.get(getArgs);
312
313                deferred.addCallback(function(data){self._processResult(data, request);});
314                deferred.addErrback(function(error){
315                        if(request.onError){
316                                request.onError.call(scope, error, request);
317                        }
318                });
319        },
320
321        fetchItemByIdentity: function(keywordArgs){
322                // summary:
323                //      See dojo.data.api.Read.loadItem()
324                var path = keywordArgs.identity;
325                var self = this;
326                var scope = keywordArgs.scope || winUtil.global;
327
328                var content = {};
329
330                if(this.options.length > 0){
331                        content.options = jsonUtil.toJson(this.options);
332                }
333
334                if(this.pathAsQueryParam){
335                        content.path = path;
336                }
337                var xhrData = {
338                        url: this.pathAsQueryParam? this.url : this.url + "/" + path,
339                        handleAs: "json-comment-optional",
340                        content: content,
341                        preventCache: this.urlPreventCache,
342                        failOk: this.failOk
343                };
344
345                var deferred = xhr.get(xhrData);
346                deferred.addErrback(function(error){
347                                if(keywordArgs.onError){
348                                        keywordArgs.onError.call(scope, error);
349                                }
350                });
351               
352                deferred.addCallback(function(data){
353                        var item = self._processItem(data);
354                        if(keywordArgs.onItem){
355                                keywordArgs.onItem.call(scope, item);
356                        }
357                });
358        },
359
360        _processResult: function(data, request){
361                 var scope = request.scope || winUtil.global;
362                 try{
363                         //If the data contains a path separator, set ours
364                         if(data.pathSeparator){
365                                 this.pathSeparator = data.pathSeparator;
366                         }
367                         //Invoke the onBegin handler, if any, to return the
368                         //size of the dataset as indicated by the service.
369                         if(request.onBegin){
370                                 request.onBegin.call(scope, data.total, request);
371                         }
372                         //Now process all the returned items thro
373                         var items = this._processItemArray(data.items);
374                         if(request.onItem){
375                                var i;
376                                for(i = 0; i < items.length; i++){
377                                        request.onItem.call(scope, items[i], request);
378                                }
379                                items = null;
380                         }
381                         if(request.onComplete){
382                                 request.onComplete.call(scope, items, request);
383                         }
384                 }catch (e){
385                         if(request.onError){
386                                 request.onError.call(scope, e, request);
387                         }else{
388                                 console.log(e);
389                         }
390                 }
391        },
392       
393        _processItemArray: function(itemArray){
394                 //     summary:
395                 //             Internal function for processing an array of items for return.
396                 var i;
397                 for(i = 0; i < itemArray.length; i++){
398                        this._processItem(itemArray[i]);
399                 }
400                 return itemArray;
401        },
402       
403        _processItem: function(item){
404                //      summary:
405                //              Internal function for processing an item returned from the store.
406                //              It sets up the store ref as well as sets up the attributes necessary
407                //              to invoke a lazy load on a child, if there are any.
408                if(!item){return null;}
409                item[this._storeRef] = this;
410                if(item.children && item.directory){
411                        if(lang.isArray(item.children)){
412                                var children = item.children;
413                                var i;
414                                for(i = 0; i < children.length; i++ ){
415                                        var name = children[i];
416                                        if(lang.isObject(name)){
417                                                children[i] = this._processItem(name);
418                                        }else{
419                                                children[i] = {name: name, _loaded: false, parentPath: item.path};
420                                                children[i][this._storeRef] = this;
421                                        }
422                                }
423                        }else{
424                                delete item.children;
425                        }
426                }
427                return item;
428        }
429});
430});
Note: See TracBrowser for help on using the repository browser.