FileStore.js 12 KB

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