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