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