You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
218 lines
6.7 KiB
JavaScript
218 lines
6.7 KiB
JavaScript
dojo.provide("dijit.tree.ForestStoreModel");
|
|
|
|
dojo.require("dijit.tree.TreeStoreModel");
|
|
|
|
dojo.declare("dijit.tree.ForestStoreModel", dijit.tree.TreeStoreModel, {
|
|
// summary:
|
|
// Interface between Tree and a dojo.store that doesn't have a root item,
|
|
// i.e. has multiple "top level" items.
|
|
//
|
|
// description
|
|
// Use this class to wrap a dojo.store, making all the items matching the specified query
|
|
// appear as children of a fabricated "root item". If no query is specified then all the
|
|
// items returned by fetch() on the underlying store become children of the root item.
|
|
// It allows dijit.Tree to assume a single root item, even if the store doesn't have one.
|
|
|
|
// Parameters to constructor
|
|
|
|
// rootId: String
|
|
// ID of fabricated root item
|
|
rootId: "$root$",
|
|
|
|
// rootLabel: String
|
|
// Label of fabricated root item
|
|
rootLabel: "ROOT",
|
|
|
|
// query: String
|
|
// Specifies the set of children of the root item.
|
|
// example:
|
|
// | {type:'continent'}
|
|
query: null,
|
|
|
|
// End of parameters to constructor
|
|
|
|
constructor: function(params){
|
|
// summary:
|
|
// Sets up variables, etc.
|
|
// tags:
|
|
// private
|
|
|
|
// Make dummy root item
|
|
this.root = {
|
|
store: this,
|
|
root: true,
|
|
id: params.rootId,
|
|
label: params.rootLabel,
|
|
children: params.rootChildren // optional param
|
|
};
|
|
},
|
|
|
|
// =======================================================================
|
|
// Methods for traversing hierarchy
|
|
|
|
mayHaveChildren: function(/*dojo.data.Item*/ 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)
|
|
// tags:
|
|
// extension
|
|
return item === this.root || this.inherited(arguments);
|
|
},
|
|
|
|
getChildren: function(/*dojo.data.Item*/ parentItem, /*function(items)*/ callback, /*function*/ onError){
|
|
// summary:
|
|
// Calls onComplete() with array of child items of given parent item, all loaded.
|
|
if(parentItem === this.root){
|
|
if(this.root.children){
|
|
// already loaded, just return
|
|
callback(this.root.children);
|
|
}else{
|
|
this.store.fetch({
|
|
query: this.query,
|
|
onComplete: dojo.hitch(this, function(items){
|
|
this.root.children = items;
|
|
callback(items);
|
|
}),
|
|
onError: onError
|
|
});
|
|
}
|
|
}else{
|
|
this.inherited(arguments);
|
|
}
|
|
},
|
|
|
|
// =======================================================================
|
|
// Inspecting items
|
|
|
|
getIdentity: function(/* item */ item){
|
|
return (item === this.root) ? this.root.id : this.inherited(arguments);
|
|
},
|
|
|
|
getLabel: function(/* item */ item){
|
|
return (item === this.root) ? this.root.label : this.inherited(arguments);
|
|
},
|
|
|
|
// =======================================================================
|
|
// Write interface
|
|
|
|
newItem: function(/* Object? */ args, /*Item*/ parent){
|
|
// 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.
|
|
if(parent===this.root){
|
|
this.onNewRootItem(args);
|
|
return this.store.newItem(args);
|
|
}else{
|
|
return this.inherited(arguments);
|
|
}
|
|
},
|
|
|
|
onNewRootItem: function(args){
|
|
// summary:
|
|
// User can override this method to modify a new element that's being
|
|
// added to the root of the tree, for example to add a flag like root=true
|
|
},
|
|
|
|
pasteItem: function(/*Item*/ childItem, /*Item*/ oldParentItem, /*Item*/ newParentItem, /*Boolean*/ bCopy, /*int?*/ insertIndex){
|
|
// summary:
|
|
// Move or copy an item from one parent item to another.
|
|
// Used in drag & drop
|
|
if(oldParentItem === this.root){
|
|
if(!bCopy){
|
|
// It's onLeaveRoot()'s responsibility to modify the item so it no longer matches
|
|
// this.query... thus triggering an onChildrenChange() event to notify the Tree
|
|
// that this element is no longer a child of the root node
|
|
this.onLeaveRoot(childItem);
|
|
}
|
|
}
|
|
dijit.tree.TreeStoreModel.prototype.pasteItem.call(this, childItem,
|
|
oldParentItem === this.root ? null : oldParentItem,
|
|
newParentItem === this.root ? null : newParentItem,
|
|
bCopy,
|
|
insertIndex
|
|
);
|
|
if(newParentItem === this.root){
|
|
// It's onAddToRoot()'s responsibility to modify the item so it matches
|
|
// this.query... thus triggering an onChildrenChange() event to notify the Tree
|
|
// that this element is now a child of the root node
|
|
this.onAddToRoot(childItem);
|
|
}
|
|
},
|
|
|
|
// =======================================================================
|
|
// Handling for top level children
|
|
|
|
onAddToRoot: function(/* item */ item){
|
|
// summary:
|
|
// Called when item added to root of tree; user must override this method
|
|
// to modify the item so that it matches the query for top level items
|
|
// example:
|
|
// | store.setValue(item, "root", true);
|
|
// tags:
|
|
// extension
|
|
console.log(this, ": item ", item, " added to root");
|
|
},
|
|
|
|
onLeaveRoot: function(/* item */ item){
|
|
// summary:
|
|
// Called when item removed from root of tree; user must override this method
|
|
// to modify the item so it doesn't match the query for top level items
|
|
// example:
|
|
// | store.unsetAttribute(item, "root");
|
|
// tags:
|
|
// extension
|
|
console.log(this, ": item ", item, " removed from root");
|
|
},
|
|
|
|
// =======================================================================
|
|
// Events from data store
|
|
|
|
_requeryTop: function(){
|
|
// reruns the query for the children of the root node,
|
|
// sending out an onSet notification if those children have changed
|
|
var oldChildren = this.root.children || [];
|
|
this.store.fetch({
|
|
query: this.query,
|
|
onComplete: dojo.hitch(this, function(newChildren){
|
|
this.root.children = newChildren;
|
|
|
|
// If the list of children or the order of children has changed...
|
|
if(oldChildren.length != newChildren.length ||
|
|
dojo.some(oldChildren, function(item, idx){ return newChildren[idx] != item;})){
|
|
this.onChildrenChange(this.root, newChildren);
|
|
}
|
|
})
|
|
});
|
|
},
|
|
|
|
_onNewItem: function(/* dojo.data.Item */ item, /* Object */ parentInfo){
|
|
// summary:
|
|
// Handler for when new items appear in the store.
|
|
|
|
// In theory, any new item could be a top level item.
|
|
// Do the safe but inefficient thing by requerying the top
|
|
// level items. User can override this function to do something
|
|
// more efficient.
|
|
this._requeryTop();
|
|
|
|
this.inherited(arguments);
|
|
},
|
|
|
|
_onDeleteItem: function(/*Object*/ item){
|
|
// summary:
|
|
// Handler for delete notifications from underlying store
|
|
|
|
// check if this was a child of root, and if so send notification that root's children
|
|
// have changed
|
|
if(dojo.indexOf(this.root.children, item) != -1){
|
|
this._requeryTop();
|
|
}
|
|
|
|
this.inherited(arguments);
|
|
}
|
|
});
|
|
|
|
|