ForestStoreModel.js.uncompressed.js 9.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279
  1. define("dijit/tree/ForestStoreModel", [
  2. "dojo/_base/array", // array.indexOf array.some
  3. "dojo/_base/declare", // declare
  4. "dojo/_base/kernel", // global
  5. "dojo/_base/lang", // lang.hitch
  6. "./TreeStoreModel"
  7. ], function(array, declare, kernel, lang, TreeStoreModel){
  8. // module:
  9. // dijit/tree/ForestStoreModel
  10. return declare("dijit.tree.ForestStoreModel", TreeStoreModel, {
  11. // summary:
  12. // Interface between a dijit.Tree and a dojo.data store that doesn't have a root item,
  13. // a.k.a. a store that has multiple "top level" items.
  14. //
  15. // description:
  16. // Use this class to wrap a dojo.data store, making all the items matching the specified query
  17. // appear as children of a fabricated "root item". If no query is specified then all the
  18. // items returned by fetch() on the underlying store become children of the root item.
  19. // This class allows dijit.Tree to assume a single root item, even if the store doesn't have one.
  20. //
  21. // When using this class the developer must override a number of methods according to their app and
  22. // data, including:
  23. //
  24. // - onNewRootItem
  25. // - onAddToRoot
  26. // - onLeaveRoot
  27. // - onNewItem
  28. // - onSetItem
  29. // Parameters to constructor
  30. // rootId: String
  31. // ID of fabricated root item
  32. rootId: "$root$",
  33. // rootLabel: String
  34. // Label of fabricated root item
  35. rootLabel: "ROOT",
  36. // query: String
  37. // Specifies the set of children of the root item.
  38. // example:
  39. // | {type:'continent'}
  40. query: null,
  41. // End of parameters to constructor
  42. constructor: function(params){
  43. // summary:
  44. // Sets up variables, etc.
  45. // tags:
  46. // private
  47. // Make dummy root item
  48. this.root = {
  49. store: this,
  50. root: true,
  51. id: params.rootId,
  52. label: params.rootLabel,
  53. children: params.rootChildren // optional param
  54. };
  55. },
  56. // =======================================================================
  57. // Methods for traversing hierarchy
  58. mayHaveChildren: function(/*dojo/data/Item*/ item){
  59. // summary:
  60. // Tells if an item has or may have children. Implementing logic here
  61. // avoids showing +/- expando icon for nodes that we know don't have children.
  62. // (For efficiency reasons we may not want to check if an element actually
  63. // has children until user clicks the expando node)
  64. // tags:
  65. // extension
  66. return item === this.root || this.inherited(arguments);
  67. },
  68. getChildren: function(/*dojo/data/Item*/ parentItem, /*function(items)*/ callback, /*function*/ onError){
  69. // summary:
  70. // Calls onComplete() with array of child items of given parent item, all loaded.
  71. if(parentItem === this.root){
  72. if(this.root.children){
  73. // already loaded, just return
  74. callback(this.root.children);
  75. }else{
  76. this.store.fetch({
  77. query: this.query,
  78. onComplete: lang.hitch(this, function(items){
  79. this.root.children = items;
  80. callback(items);
  81. }),
  82. onError: onError
  83. });
  84. }
  85. }else{
  86. this.inherited(arguments);
  87. }
  88. },
  89. // =======================================================================
  90. // Inspecting items
  91. isItem: function(/* anything */ something){
  92. return (something === this.root) ? true : this.inherited(arguments);
  93. },
  94. fetchItemByIdentity: function(/* object */ keywordArgs){
  95. if(keywordArgs.identity == this.root.id){
  96. var scope = keywordArgs.scope || kernel.global;
  97. if(keywordArgs.onItem){
  98. keywordArgs.onItem.call(scope, this.root);
  99. }
  100. }else{
  101. this.inherited(arguments);
  102. }
  103. },
  104. getIdentity: function(/* item */ item){
  105. return (item === this.root) ? this.root.id : this.inherited(arguments);
  106. },
  107. getLabel: function(/* item */ item){
  108. return (item === this.root) ? this.root.label : this.inherited(arguments);
  109. },
  110. // =======================================================================
  111. // Write interface
  112. newItem: function(/* dijit/tree/dndSource.__Item */ args, /*Item*/ parent, /*int?*/ insertIndex){
  113. // summary:
  114. // Creates a new item. See dojo/data/api/Write for details on args.
  115. // Used in drag & drop when item from external source dropped onto tree.
  116. if(parent === this.root){
  117. this.onNewRootItem(args);
  118. return this.store.newItem(args);
  119. }else{
  120. return this.inherited(arguments);
  121. }
  122. },
  123. onNewRootItem: function(/* dijit/tree/dndSource.__Item */ /*===== args =====*/){
  124. // summary:
  125. // User can override this method to modify a new element that's being
  126. // added to the root of the tree, for example to add a flag like root=true
  127. },
  128. pasteItem: function(/*Item*/ childItem, /*Item*/ oldParentItem, /*Item*/ newParentItem, /*Boolean*/ bCopy, /*int?*/ insertIndex){
  129. // summary:
  130. // Move or copy an item from one parent item to another.
  131. // Used in drag & drop
  132. if(oldParentItem === this.root){
  133. if(!bCopy){
  134. // It's onLeaveRoot()'s responsibility to modify the item so it no longer matches
  135. // this.query... thus triggering an onChildrenChange() event to notify the Tree
  136. // that this element is no longer a child of the root node
  137. this.onLeaveRoot(childItem);
  138. }
  139. }
  140. this.inherited(arguments, [childItem,
  141. oldParentItem === this.root ? null : oldParentItem,
  142. newParentItem === this.root ? null : newParentItem,
  143. bCopy,
  144. insertIndex
  145. ]);
  146. if(newParentItem === this.root){
  147. // It's onAddToRoot()'s responsibility to modify the item so it matches
  148. // this.query... thus triggering an onChildrenChange() event to notify the Tree
  149. // that this element is now a child of the root node
  150. this.onAddToRoot(childItem);
  151. }
  152. },
  153. // =======================================================================
  154. // Handling for top level children
  155. onAddToRoot: function(/* item */ item){
  156. // summary:
  157. // Called when item added to root of tree; user must override this method
  158. // to modify the item so that it matches the query for top level items
  159. // example:
  160. // | store.setValue(item, "root", true);
  161. // tags:
  162. // extension
  163. console.log(this, ": item ", item, " added to root");
  164. },
  165. onLeaveRoot: function(/* item */ item){
  166. // summary:
  167. // Called when item removed from root of tree; user must override this method
  168. // to modify the item so it doesn't match the query for top level items
  169. // example:
  170. // | store.unsetAttribute(item, "root");
  171. // tags:
  172. // extension
  173. console.log(this, ": item ", item, " removed from root");
  174. },
  175. // =======================================================================
  176. // Events from data store
  177. _requeryTop: function(){
  178. // reruns the query for the children of the root node,
  179. // sending out an onSet notification if those children have changed
  180. var oldChildren = this.root.children || [];
  181. this.store.fetch({
  182. query: this.query,
  183. onComplete: lang.hitch(this, function(newChildren){
  184. this.root.children = newChildren;
  185. // If the list of children or the order of children has changed...
  186. if(oldChildren.length != newChildren.length ||
  187. array.some(oldChildren, function(item, idx){ return newChildren[idx] != item;})){
  188. this.onChildrenChange(this.root, newChildren);
  189. }
  190. })
  191. });
  192. },
  193. onNewItem: function(/* dojo/data/api/Item */ item, /* Object */ parentInfo){
  194. // summary:
  195. // Handler for when new items appear in the store. Developers should override this
  196. // method to be more efficient based on their app/data.
  197. // description:
  198. // Note that the default implementation requeries the top level items every time
  199. // a new item is created, since any new item could be a top level item (even in
  200. // addition to being a child of another item, since items can have multiple parents).
  201. //
  202. // If developers can detect which items are possible top level items (based on the item and the
  203. // parentInfo parameters), they should override this method to only call _requeryTop() for top
  204. // level items. Often all top level items have parentInfo==null, but
  205. // that will depend on which store you use and what your data is like.
  206. // tags:
  207. // extension
  208. this._requeryTop();
  209. this.inherited(arguments);
  210. },
  211. onDeleteItem: function(/*Object*/ item){
  212. // summary:
  213. // Handler for delete notifications from underlying store
  214. // check if this was a child of root, and if so send notification that root's children
  215. // have changed
  216. if(array.indexOf(this.root.children, item) != -1){
  217. this._requeryTop();
  218. }
  219. this.inherited(arguments);
  220. },
  221. onSetItem: function(/* item */ item,
  222. /* attribute-name-string */ attribute,
  223. /* Object|Array */ oldValue,
  224. /* Object|Array */ newValue){
  225. // summary:
  226. // Updates the tree view according to changes to an item in the data store.
  227. // Developers should override this method to be more efficient based on their app/data.
  228. // description:
  229. // Handles updates to an item's children by calling onChildrenChange(), and
  230. // other updates to an item by calling onChange().
  231. //
  232. // Also, any change to any item re-executes the query for the tree's top-level items,
  233. // since this modified item may have started/stopped matching the query for top level items.
  234. //
  235. // If possible, developers should override this function to only call _requeryTop() when
  236. // the change to the item has caused it to stop/start being a top level item in the tree.
  237. // tags:
  238. // extension
  239. this._requeryTop();
  240. this.inherited(arguments);
  241. }
  242. });
  243. });