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