]> git.wh0rd.org - tt-rss.git/blame - lib/dijit/tree/ObjectStoreModel.js.uncompressed.js
modify dojo rebuild script to remove uncompressed files
[tt-rss.git] / lib / dijit / tree / ObjectStoreModel.js.uncompressed.js
CommitLineData
f0cfe83e
AD
1define("dijit/tree/ObjectStoreModel", [
2 "dojo/_base/array", // array.filter array.forEach array.indexOf array.some
3 "dojo/aspect", // aspect.before, aspect.after
4 "dojo/_base/declare", // declare
5 "dojo/_base/lang", // lang.hitch
6 "dojo/when"
7], function(array, aspect, declare, lang, when){
8
9 // module:
10 // dijit/tree/ObjectStoreModel
11
12 return declare("dijit.tree.ObjectStoreModel", null, {
13 // summary:
14 // Implements dijit/tree/model connecting dijit/Tree to a dojo/store/api/Store that implements
15 // getChildren().
16 //
17 // If getChildren() returns an array with an observe() method, then it will be leveraged to reflect
18 // store updates to the tree. So, this class will work best when:
19 //
20 // 1. the store implements dojo/store/Observable
21 // 2. getChildren() is implemented as a query to the server (i.e. it calls store.query())
22 //
23 // Drag and Drop: To support drag and drop, besides implementing getChildren()
24 // and dojo/store/Observable, the store must support the parent option to put().
25 // And in order to have child elements ordered according to how the user dropped them,
26 // put() must support the before option.
27
28 // store: dojo/store/api/Store
29 // Underlying store
30 store: null,
31
32 // labelAttr: String
33 // Get label for tree node from this attribute
34 labelAttr: "name",
35
36 // root: [readonly] Object
37 // Pointer to the root item from the dojo/store/api/Store (read only, not a parameter)
38 root: null,
39
40 // query: anything
41 // Specifies datastore query to return the root item for the tree.
42 // Must only return a single item. Alternately can just pass in pointer
43 // to root item.
44 // example:
45 // | {id:'ROOT'}
46 query: null,
47
48 constructor: function(/* Object */ args){
49 // summary:
50 // Passed the arguments listed above (store, etc)
51 // tags:
52 // private
53
54 lang.mixin(this, args);
55
56 this.childrenCache = {}; // map from id to array of children
57 },
58
59 destroy: function(){
60 // TODO: should cancel any in-progress processing of getRoot(), getChildren()
61 for(var id in this.childrenCache){
62 this.childrenCache[id].close && this.childrenCache[id].close();
63 }
64 },
65
66 // =======================================================================
67 // Methods for traversing hierarchy
68
69 getRoot: function(onItem, onError){
70 // summary:
71 // Calls onItem with the root item for the tree, possibly a fabricated item.
72 // Calls onError on error.
73 if(this.root){
74 onItem(this.root);
75 }else{
76 var res;
77 when(res = this.store.query(this.query),
78 lang.hitch(this, function(items){
79 //console.log("queried root: ", res);
80 if(items.length != 1){
81 throw new Error("dijit.tree.ObjectStoreModel: root query returned " + items.length +
82 " items, but must return exactly one");
83 }
84 this.root = items[0];
85 onItem(this.root);
86
87 // Setup listener to detect if root item changes
88 if(res.observe){
89 res.observe(lang.hitch(this, function(obj){
90 // Presumably removedFrom == insertedInto == 1, and this call indicates item has changed.
91 //console.log("root changed: ", obj);
92 this.onChange(obj);
93 }), true); // true to listen for updates to obj
94 }
95 }),
96 onError
97 );
98 }
99 },
100
101 mayHaveChildren: function(/*===== item =====*/){
102 // summary:
103 // Tells if an item has or may have children. Implementing logic here
104 // avoids showing +/- expando icon for nodes that we know don't have children.
105 // (For efficiency reasons we may not want to check if an element actually
106 // has children until user clicks the expando node).
107 //
108 // Application code should override this method based on the data, for example
109 // it could be `return item.leaf == true;`.
110 // item: Object
111 // Item from the dojo/store
112 return true;
113 },
114
115 getChildren: function(/*Object*/ parentItem, /*function(items)*/ onComplete, /*function*/ onError){
116 // summary:
117 // Calls onComplete() with array of child items of given parent item.
118 // parentItem:
119 // Item from the dojo/store
120
121 var id = this.store.getIdentity(parentItem);
122 if(this.childrenCache[id]){
123 when(this.childrenCache[id], onComplete, onError);
124 return;
125 }
126
127 var res = this.childrenCache[id] = this.store.getChildren(parentItem);
128
129 // User callback
130 when(res, onComplete, onError);
131
132 // Setup listener in case children list changes, or the item(s) in the children list are
133 // updated in some way.
134 if(res.observe){
135 res.observe(lang.hitch(this, function(obj, removedFrom, insertedInto){
136 //console.log("observe on children of ", id, ": ", obj, removedFrom, insertedInto);
137
138 // If removedFrom == insertedInto, this call indicates that the item has changed.
139 // Even if removedFrom != insertedInto, the item may have changed.
140 this.onChange(obj);
141
142 if(removedFrom != insertedInto){
143 // Indicates an item was added, removed, or re-parented. The children[] array (returned from
144 // res.then(...)) has already been updated (like a live collection), so just use it.
145 when(res, lang.hitch(this, "onChildrenChange", parentItem));
146 }
147 }), true); // true means to notify on item changes
148 }
149 },
150
151 // =======================================================================
152 // Inspecting items
153
154 isItem: function(/*===== something =====*/){
155 return true; // Boolean
156 },
157
158 fetchItemByIdentity: function(/* object */ keywordArgs){
159 this.store.get(keywordArgs.identity).then(
160 lang.hitch(keywordArgs.scope, keywordArgs.onItem),
161 lang.hitch(keywordArgs.scope, keywordArgs.onError)
162 );
163 },
164
165 getIdentity: function(/* item */ item){
166 return this.store.getIdentity(item); // Object
167 },
168
169 getLabel: function(/*dojo/data/Item*/ item){
170 // summary:
171 // Get the label for an item
172 return item[this.labelAttr]; // String
173 },
174
175 // =======================================================================
176 // Write interface, for DnD
177
178 newItem: function(/* dijit/tree/dndSource.__Item */ args, /*Item*/ parent, /*int?*/ insertIndex, /*Item*/ before){
179 // summary:
180 // Creates a new item. See `dojo/data/api/Write` for details on args.
181 // Used in drag & drop when item from external source dropped onto tree.
182
183 return this.store.put(args, {
184 parent: parent,
185 before: before
186 });
187 },
188
189 pasteItem: function(/*Item*/ childItem, /*Item*/ oldParentItem, /*Item*/ newParentItem,
190 /*Boolean*/ bCopy, /*int?*/ insertIndex, /*Item*/ before){
191 // summary:
192 // Move or copy an item from one parent item to another.
193 // Used in drag & drop
194
195 if(!bCopy){
196 // In order for DnD moves to work correctly, childItem needs to be orphaned from oldParentItem
197 // before being adopted by newParentItem. That way, the TreeNode is moved rather than
198 // an additional TreeNode being created, and the old TreeNode subsequently being deleted.
199 // The latter loses information such as selection and opened/closed children TreeNodes.
200 // Unfortunately simply calling this.store.put() will send notifications in a random order, based
201 // on when the TreeNodes in question originally appeared, and not based on the drag-from
202 // TreeNode vs. the drop-onto TreeNode.
203
204 var oldParentChildren = [].concat(this.childrenCache[this.getIdentity(oldParentItem)]), // concat to make copy
205 index = array.indexOf(oldParentChildren, childItem);
206 oldParentChildren.splice(index, 1);
207 this.onChildrenChange(oldParentItem, oldParentChildren);
208 }
209
210 return this.store.put(childItem, {
211 overwrite: true,
212 parent: newParentItem,
213 before: before
214 });
215 },
216
217 // =======================================================================
218 // Callbacks
219
220 onChange: function(/*dojo/data/Item*/ /*===== item =====*/){
221 // summary:
222 // Callback whenever an item has changed, so that Tree
223 // can update the label, icon, etc. Note that changes
224 // to an item's children or parent(s) will trigger an
225 // onChildrenChange() so you can ignore those changes here.
226 // tags:
227 // callback
228 },
229
230 onChildrenChange: function(/*===== parent, newChildrenList =====*/){
231 // summary:
232 // Callback to do notifications about new, updated, or deleted items.
233 // parent: dojo/data/Item
234 // newChildrenList: Object[]
235 // Items from the store
236 // tags:
237 // callback
238 },
239
240 onDelete: function(/*dojo/data/Item*/ /*===== item =====*/){
241 // summary:
242 // Callback when an item has been deleted.
243 // Actually we have no way of knowing this with the new dojo.store API,
244 // so this method is never called (but it's left here since Tree connects
245 // to it).
246 // tags:
247 // callback
248 }
249 });
250});