summaryrefslogtreecommitdiff
path: root/lib/dijit/tree/ObjectStoreModel.js.uncompressed.js
diff options
context:
space:
mode:
Diffstat (limited to 'lib/dijit/tree/ObjectStoreModel.js.uncompressed.js')
-rw-r--r--lib/dijit/tree/ObjectStoreModel.js.uncompressed.js250
1 files changed, 250 insertions, 0 deletions
diff --git a/lib/dijit/tree/ObjectStoreModel.js.uncompressed.js b/lib/dijit/tree/ObjectStoreModel.js.uncompressed.js
new file mode 100644
index 000000000..901f85f1b
--- /dev/null
+++ b/lib/dijit/tree/ObjectStoreModel.js.uncompressed.js
@@ -0,0 +1,250 @@
+define("dijit/tree/ObjectStoreModel", [
+ "dojo/_base/array", // array.filter array.forEach array.indexOf array.some
+ "dojo/aspect", // aspect.before, aspect.after
+ "dojo/_base/declare", // declare
+ "dojo/_base/lang", // lang.hitch
+ "dojo/when"
+], function(array, aspect, declare, lang, when){
+
+ // module:
+ // dijit/tree/ObjectStoreModel
+
+ return declare("dijit.tree.ObjectStoreModel", null, {
+ // summary:
+ // Implements dijit/tree/model connecting dijit/Tree to a dojo/store/api/Store that implements
+ // getChildren().
+ //
+ // If getChildren() returns an array with an observe() method, then it will be leveraged to reflect
+ // store updates to the tree. So, this class will work best when:
+ //
+ // 1. the store implements dojo/store/Observable
+ // 2. getChildren() is implemented as a query to the server (i.e. it calls store.query())
+ //
+ // Drag and Drop: To support drag and drop, besides implementing getChildren()
+ // and dojo/store/Observable, the store must support the parent option to put().
+ // And in order to have child elements ordered according to how the user dropped them,
+ // put() must support the before option.
+
+ // store: dojo/store/api/Store
+ // Underlying store
+ store: null,
+
+ // labelAttr: String
+ // Get label for tree node from this attribute
+ labelAttr: "name",
+
+ // root: [readonly] Object
+ // Pointer to the root item from the dojo/store/api/Store (read only, not a parameter)
+ root: null,
+
+ // query: anything
+ // Specifies datastore query to return the root item for the tree.
+ // Must only return a single item. Alternately can just pass in pointer
+ // to root item.
+ // example:
+ // | {id:'ROOT'}
+ query: null,
+
+ constructor: function(/* Object */ args){
+ // summary:
+ // Passed the arguments listed above (store, etc)
+ // tags:
+ // private
+
+ lang.mixin(this, args);
+
+ this.childrenCache = {}; // map from id to array of children
+ },
+
+ destroy: function(){
+ // TODO: should cancel any in-progress processing of getRoot(), getChildren()
+ for(var id in this.childrenCache){
+ this.childrenCache[id].close && this.childrenCache[id].close();
+ }
+ },
+
+ // =======================================================================
+ // Methods for traversing hierarchy
+
+ getRoot: function(onItem, onError){
+ // summary:
+ // Calls onItem with the root item for the tree, possibly a fabricated item.
+ // Calls onError on error.
+ if(this.root){
+ onItem(this.root);
+ }else{
+ var res;
+ when(res = this.store.query(this.query),
+ lang.hitch(this, function(items){
+ //console.log("queried root: ", res);
+ if(items.length != 1){
+ throw new Error("dijit.tree.ObjectStoreModel: root query returned " + items.length +
+ " items, but must return exactly one");
+ }
+ this.root = items[0];
+ onItem(this.root);
+
+ // Setup listener to detect if root item changes
+ if(res.observe){
+ res.observe(lang.hitch(this, function(obj){
+ // Presumably removedFrom == insertedInto == 1, and this call indicates item has changed.
+ //console.log("root changed: ", obj);
+ this.onChange(obj);
+ }), true); // true to listen for updates to obj
+ }
+ }),
+ onError
+ );
+ }
+ },
+
+ mayHaveChildren: function(/*===== item =====*/){
+ // summary:
+ // Tells if an item has or may have children. Implementing logic here
+ // avoids showing +/- expando icon for nodes that we know don't have children.
+ // (For efficiency reasons we may not want to check if an element actually
+ // has children until user clicks the expando node).
+ //
+ // Application code should override this method based on the data, for example
+ // it could be `return item.leaf == true;`.
+ // item: Object
+ // Item from the dojo/store
+ return true;
+ },
+
+ getChildren: function(/*Object*/ parentItem, /*function(items)*/ onComplete, /*function*/ onError){
+ // summary:
+ // Calls onComplete() with array of child items of given parent item.
+ // parentItem:
+ // Item from the dojo/store
+
+ var id = this.store.getIdentity(parentItem);
+ if(this.childrenCache[id]){
+ when(this.childrenCache[id], onComplete, onError);
+ return;
+ }
+
+ var res = this.childrenCache[id] = this.store.getChildren(parentItem);
+
+ // User callback
+ when(res, onComplete, onError);
+
+ // Setup listener in case children list changes, or the item(s) in the children list are
+ // updated in some way.
+ if(res.observe){
+ res.observe(lang.hitch(this, function(obj, removedFrom, insertedInto){
+ //console.log("observe on children of ", id, ": ", obj, removedFrom, insertedInto);
+
+ // If removedFrom == insertedInto, this call indicates that the item has changed.
+ // Even if removedFrom != insertedInto, the item may have changed.
+ this.onChange(obj);
+
+ if(removedFrom != insertedInto){
+ // Indicates an item was added, removed, or re-parented. The children[] array (returned from
+ // res.then(...)) has already been updated (like a live collection), so just use it.
+ when(res, lang.hitch(this, "onChildrenChange", parentItem));
+ }
+ }), true); // true means to notify on item changes
+ }
+ },
+
+ // =======================================================================
+ // Inspecting items
+
+ isItem: function(/*===== something =====*/){
+ return true; // Boolean
+ },
+
+ fetchItemByIdentity: function(/* object */ keywordArgs){
+ this.store.get(keywordArgs.identity).then(
+ lang.hitch(keywordArgs.scope, keywordArgs.onItem),
+ lang.hitch(keywordArgs.scope, keywordArgs.onError)
+ );
+ },
+
+ getIdentity: function(/* item */ item){
+ return this.store.getIdentity(item); // Object
+ },
+
+ getLabel: function(/*dojo/data/Item*/ item){
+ // summary:
+ // Get the label for an item
+ return item[this.labelAttr]; // String
+ },
+
+ // =======================================================================
+ // Write interface, for DnD
+
+ newItem: function(/* dijit/tree/dndSource.__Item */ args, /*Item*/ parent, /*int?*/ insertIndex, /*Item*/ before){
+ // summary:
+ // Creates a new item. See `dojo/data/api/Write` for details on args.
+ // Used in drag & drop when item from external source dropped onto tree.
+
+ return this.store.put(args, {
+ parent: parent,
+ before: before
+ });
+ },
+
+ pasteItem: function(/*Item*/ childItem, /*Item*/ oldParentItem, /*Item*/ newParentItem,
+ /*Boolean*/ bCopy, /*int?*/ insertIndex, /*Item*/ before){
+ // summary:
+ // Move or copy an item from one parent item to another.
+ // Used in drag & drop
+
+ if(!bCopy){
+ // In order for DnD moves to work correctly, childItem needs to be orphaned from oldParentItem
+ // before being adopted by newParentItem. That way, the TreeNode is moved rather than
+ // an additional TreeNode being created, and the old TreeNode subsequently being deleted.
+ // The latter loses information such as selection and opened/closed children TreeNodes.
+ // Unfortunately simply calling this.store.put() will send notifications in a random order, based
+ // on when the TreeNodes in question originally appeared, and not based on the drag-from
+ // TreeNode vs. the drop-onto TreeNode.
+
+ var oldParentChildren = [].concat(this.childrenCache[this.getIdentity(oldParentItem)]), // concat to make copy
+ index = array.indexOf(oldParentChildren, childItem);
+ oldParentChildren.splice(index, 1);
+ this.onChildrenChange(oldParentItem, oldParentChildren);
+ }
+
+ return this.store.put(childItem, {
+ overwrite: true,
+ parent: newParentItem,
+ before: before
+ });
+ },
+
+ // =======================================================================
+ // Callbacks
+
+ onChange: function(/*dojo/data/Item*/ /*===== item =====*/){
+ // summary:
+ // Callback whenever an item has changed, so that Tree
+ // can update the label, icon, etc. Note that changes
+ // to an item's children or parent(s) will trigger an
+ // onChildrenChange() so you can ignore those changes here.
+ // tags:
+ // callback
+ },
+
+ onChildrenChange: function(/*===== parent, newChildrenList =====*/){
+ // summary:
+ // Callback to do notifications about new, updated, or deleted items.
+ // parent: dojo/data/Item
+ // newChildrenList: Object[]
+ // Items from the store
+ // tags:
+ // callback
+ },
+
+ onDelete: function(/*dojo/data/Item*/ /*===== item =====*/){
+ // summary:
+ // Callback when an item has been deleted.
+ // Actually we have no way of knowing this with the new dojo.store API,
+ // so this method is never called (but it's left here since Tree connects
+ // to it).
+ // tags:
+ // callback
+ }
+ });
+});