FileStore.js 12 KB

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