summaryrefslogtreecommitdiff
path: root/lib/dijit/tree
diff options
context:
space:
mode:
authorAndrew Dolgov <[email protected]>2012-08-14 18:59:10 +0400
committerAndrew Dolgov <[email protected]>2012-08-14 18:59:18 +0400
commit1354d17270961fff662d40f90521223f8fd0d73b (patch)
treee9266be71587e47c800303446e968a6d3565e2cf /lib/dijit/tree
parentd04f8c826f5283765f52cf6b98b42a1ed8f2d6bc (diff)
update dojo to 1.7.3
Diffstat (limited to 'lib/dijit/tree')
-rw-r--r--lib/dijit/tree/ForestStoreModel.js282
-rw-r--r--lib/dijit/tree/ForestStoreModel.js.uncompressed.js285
-rw-r--r--lib/dijit/tree/TreeStoreModel.js383
-rw-r--r--lib/dijit/tree/TreeStoreModel.js.uncompressed.js383
-rw-r--r--lib/dijit/tree/_dndContainer.js189
-rw-r--r--lib/dijit/tree/_dndContainer.js.uncompressed.js150
-rw-r--r--lib/dijit/tree/_dndSelector.js289
-rw-r--r--lib/dijit/tree/_dndSelector.js.uncompressed.js326
-rw-r--r--lib/dijit/tree/dndSource.js546
-rw-r--r--lib/dijit/tree/dndSource.js.uncompressed.js564
-rw-r--r--lib/dijit/tree/model.js136
-rw-r--r--lib/dijit/tree/model.js.uncompressed.js142
12 files changed, 1861 insertions, 1814 deletions
diff --git a/lib/dijit/tree/ForestStoreModel.js b/lib/dijit/tree/ForestStoreModel.js
index 5e1b25efb..d0b895335 100644
--- a/lib/dijit/tree/ForestStoreModel.js
+++ b/lib/dijit/tree/ForestStoreModel.js
@@ -1,280 +1,2 @@
-/*
- Copyright (c) 2004-2011, The Dojo Foundation All Rights Reserved.
- Available via Academic Free License >= 2.1 OR the modified BSD license.
- see: http://dojotoolkit.org/license for details
-*/
-
-
-if(!dojo._hasResource["dijit.tree.ForestStoreModel"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
-dojo._hasResource["dijit.tree.ForestStoreModel"] = true;
-dojo.provide("dijit.tree.ForestStoreModel");
-dojo.require("dijit.tree.TreeStoreModel");
-
-
-dojo.declare("dijit.tree.ForestStoreModel", dijit.tree.TreeStoreModel, {
- // summary:
- // Interface between a dijit.Tree and a dojo.data store that doesn't have a root item,
- // a.k.a. a store that has multiple "top level" items.
- //
- // description
- // Use this class to wrap a dojo.data 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.
- // This class allows dijit.Tree to assume a single root item, even if the store doesn't have one.
- //
- // When using this class the developer must override a number of methods according to their app and
- // data, including:
- // - onNewRootItem
- // - onAddToRoot
- // - onLeaveRoot
- // - onNewItem
- // - onSetItem
-
- // 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
-
- isItem: function(/* anything */ something){
- return (something === this.root) ? true : this.inherited(arguments);
- },
-
- fetchItemByIdentity: function(/* object */ keywordArgs){
- if(keywordArgs.identity == this.root.id){
- var scope = keywordArgs.scope?keywordArgs.scope:dojo.global;
- if(keywordArgs.onItem){
- keywordArgs.onItem.call(scope, this.root);
- }
- }else{
- this.inherited(arguments);
- }
- },
-
- 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(/* dojo.dnd.Item */ args, /*Item*/ parent, /*int?*/ insertIndex){
- // 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. Developers should override this
- // method to be more efficient based on their app/data.
- // description:
- // Note that the default implementation requeries the top level items every time
- // a new item is created, since any new item could be a top level item (even in
- // addition to being a child of another item, since items can have multiple parents).
- //
- // If developers can detect which items are possible top level items (based on the item and the
- // parentInfo parameters), they should override this method to only call _requeryTop() for top
- // level items. Often all top level items have parentInfo==null, but
- // that will depend on which store you use and what your data is like.
- // tags:
- // extension
- 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);
- },
-
- onSetItem: function(/* item */ item,
- /* attribute-name-string */ attribute,
- /* object | array */ oldValue,
- /* object | array */ newValue){
- // summary:
- // Updates the tree view according to changes to an item in the data store.
- // Developers should override this method to be more efficient based on their app/data.
- // description:
- // Handles updates to an item's children by calling onChildrenChange(), and
- // other updates to an item by calling onChange().
- //
- // Also, any change to any item re-executes the query for the tree's top-level items,
- // since this modified item may have started/stopped matching the query for top level items.
- //
- // If possible, developers should override this function to only call _requeryTop() when
- // the change to the item has caused it to stop/start being a top level item in the tree.
- // tags:
- // extension
-
- this._requeryTop();
- this.inherited(arguments);
- }
-
-});
-
-}
+//>>built
+define("dijit/tree/ForestStoreModel",["dojo/_base/array","dojo/_base/declare","dojo/_base/lang","dojo/_base/window","./TreeStoreModel"],function(_1,_2,_3,_4,_5){return _2("dijit.tree.ForestStoreModel",_5,{rootId:"$root$",rootLabel:"ROOT",query:null,constructor:function(_6){this.root={store:this,root:true,id:_6.rootId,label:_6.rootLabel,children:_6.rootChildren};},mayHaveChildren:function(_7){return _7===this.root||this.inherited(arguments);},getChildren:function(_8,_9,_a){if(_8===this.root){if(this.root.children){_9(this.root.children);}else{this.store.fetch({query:this.query,onComplete:_3.hitch(this,function(_b){this.root.children=_b;_9(_b);}),onError:_a});}}else{this.inherited(arguments);}},isItem:function(_c){return (_c===this.root)?true:this.inherited(arguments);},fetchItemByIdentity:function(_d){if(_d.identity==this.root.id){var _e=_d.scope?_d.scope:_4.global;if(_d.onItem){_d.onItem.call(_e,this.root);}}else{this.inherited(arguments);}},getIdentity:function(_f){return (_f===this.root)?this.root.id:this.inherited(arguments);},getLabel:function(_10){return (_10===this.root)?this.root.label:this.inherited(arguments);},newItem:function(_11,_12,_13){if(_12===this.root){this.onNewRootItem(_11);return this.store.newItem(_11);}else{return this.inherited(arguments);}},onNewRootItem:function(){},pasteItem:function(_14,_15,_16,_17,_18){if(_15===this.root){if(!_17){this.onLeaveRoot(_14);}}this.inherited(arguments,[_14,_15===this.root?null:_15,_16===this.root?null:_16,_17,_18]);if(_16===this.root){this.onAddToRoot(_14);}},onAddToRoot:function(_19){},onLeaveRoot:function(_1a){},_requeryTop:function(){var _1b=this.root.children||[];this.store.fetch({query:this.query,onComplete:_3.hitch(this,function(_1c){this.root.children=_1c;if(_1b.length!=_1c.length||_1.some(_1b,function(_1d,idx){return _1c[idx]!=_1d;})){this.onChildrenChange(this.root,_1c);}})});},onNewItem:function(_1e,_1f){this._requeryTop();this.inherited(arguments);},onDeleteItem:function(_20){if(_1.indexOf(this.root.children,_20)!=-1){this._requeryTop();}this.inherited(arguments);},onSetItem:function(_21,_22,_23,_24){this._requeryTop();this.inherited(arguments);}});}); \ No newline at end of file
diff --git a/lib/dijit/tree/ForestStoreModel.js.uncompressed.js b/lib/dijit/tree/ForestStoreModel.js.uncompressed.js
new file mode 100644
index 000000000..3531b0d10
--- /dev/null
+++ b/lib/dijit/tree/ForestStoreModel.js.uncompressed.js
@@ -0,0 +1,285 @@
+define("dijit/tree/ForestStoreModel", [
+ "dojo/_base/array", // array.indexOf array.some
+ "dojo/_base/declare", // declare
+ "dojo/_base/lang", // lang.hitch
+ "dojo/_base/window", // win.global
+ "./TreeStoreModel"
+], function(array, declare, lang, win, TreeStoreModel){
+
+/*=====
+var TreeStoreModel = dijit.tree.TreeStoreModel;
+=====*/
+
+// module:
+// dijit/tree/ForestStoreModel
+// summary:
+// Interface between a dijit.Tree and a dojo.data store that doesn't have a root item,
+// a.k.a. a store that has multiple "top level" items.
+
+return declare("dijit.tree.ForestStoreModel", TreeStoreModel, {
+ // summary:
+ // Interface between a dijit.Tree and a dojo.data store that doesn't have a root item,
+ // a.k.a. a store that has multiple "top level" items.
+ //
+ // description
+ // Use this class to wrap a dojo.data 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.
+ // This class allows dijit.Tree to assume a single root item, even if the store doesn't have one.
+ //
+ // When using this class the developer must override a number of methods according to their app and
+ // data, including:
+ // - onNewRootItem
+ // - onAddToRoot
+ // - onLeaveRoot
+ // - onNewItem
+ // - onSetItem
+
+ // 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: lang.hitch(this, function(items){
+ this.root.children = items;
+ callback(items);
+ }),
+ onError: onError
+ });
+ }
+ }else{
+ this.inherited(arguments);
+ }
+ },
+
+ // =======================================================================
+ // Inspecting items
+
+ isItem: function(/* anything */ something){
+ return (something === this.root) ? true : this.inherited(arguments);
+ },
+
+ fetchItemByIdentity: function(/* object */ keywordArgs){
+ if(keywordArgs.identity == this.root.id){
+ var scope = keywordArgs.scope?keywordArgs.scope:win.global;
+ if(keywordArgs.onItem){
+ keywordArgs.onItem.call(scope, this.root);
+ }
+ }else{
+ this.inherited(arguments);
+ }
+ },
+
+ 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(/* dojo.dnd.Item */ args, /*Item*/ parent, /*int?*/ insertIndex){
+ // 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(/* dojo.dnd.Item */ /*===== 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);
+ }
+ }
+ this.inherited(arguments, [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: lang.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 ||
+ array.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. Developers should override this
+ // method to be more efficient based on their app/data.
+ // description:
+ // Note that the default implementation requeries the top level items every time
+ // a new item is created, since any new item could be a top level item (even in
+ // addition to being a child of another item, since items can have multiple parents).
+ //
+ // If developers can detect which items are possible top level items (based on the item and the
+ // parentInfo parameters), they should override this method to only call _requeryTop() for top
+ // level items. Often all top level items have parentInfo==null, but
+ // that will depend on which store you use and what your data is like.
+ // tags:
+ // extension
+ 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(array.indexOf(this.root.children, item) != -1){
+ this._requeryTop();
+ }
+
+ this.inherited(arguments);
+ },
+
+ onSetItem: function(/* item */ item,
+ /* attribute-name-string */ attribute,
+ /* object | array */ oldValue,
+ /* object | array */ newValue){
+ // summary:
+ // Updates the tree view according to changes to an item in the data store.
+ // Developers should override this method to be more efficient based on their app/data.
+ // description:
+ // Handles updates to an item's children by calling onChildrenChange(), and
+ // other updates to an item by calling onChange().
+ //
+ // Also, any change to any item re-executes the query for the tree's top-level items,
+ // since this modified item may have started/stopped matching the query for top level items.
+ //
+ // If possible, developers should override this function to only call _requeryTop() when
+ // the change to the item has caused it to stop/start being a top level item in the tree.
+ // tags:
+ // extension
+
+ this._requeryTop();
+ this.inherited(arguments);
+ }
+
+});
+
+});
diff --git a/lib/dijit/tree/TreeStoreModel.js b/lib/dijit/tree/TreeStoreModel.js
index 5164176b7..f61977c2f 100644
--- a/lib/dijit/tree/TreeStoreModel.js
+++ b/lib/dijit/tree/TreeStoreModel.js
@@ -1,381 +1,2 @@
-/*
- Copyright (c) 2004-2011, The Dojo Foundation All Rights Reserved.
- Available via Academic Free License >= 2.1 OR the modified BSD license.
- see: http://dojotoolkit.org/license for details
-*/
-
-
-if(!dojo._hasResource["dijit.tree.TreeStoreModel"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
-dojo._hasResource["dijit.tree.TreeStoreModel"] = true;
-dojo.provide("dijit.tree.TreeStoreModel");
-
-
-dojo.declare(
- "dijit.tree.TreeStoreModel",
- null,
- {
- // summary:
- // Implements dijit.Tree.model connecting to a store with a single
- // root item. Any methods passed into the constructor will override
- // the ones defined here.
-
- // store: dojo.data.Store
- // Underlying store
- store: null,
-
- // childrenAttrs: String[]
- // One or more attribute names (attributes in the dojo.data item) that specify that item's children
- childrenAttrs: ["children"],
-
- // newItemIdAttr: String
- // Name of attribute in the Object passed to newItem() that specifies the id.
- //
- // If newItemIdAttr is set then it's used when newItem() is called to see if an
- // item with the same id already exists, and if so just links to the old item
- // (so that the old item ends up with two parents).
- //
- // Setting this to null or "" will make every drop create a new item.
- newItemIdAttr: "id",
-
- // labelAttr: String
- // If specified, get label for tree node from this attribute, rather
- // than by calling store.getLabel()
- labelAttr: "",
-
- // root: [readonly] dojo.data.Item
- // Pointer to the root item (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,
-
- // deferItemLoadingUntilExpand: Boolean
- // Setting this to true will cause the TreeStoreModel to defer calling loadItem on nodes
- // until they are expanded. This allows for lazying loading where only one
- // loadItem (and generally one network call, consequently) per expansion
- // (rather than one for each child).
- // This relies on partial loading of the children items; each children item of a
- // fully loaded item should contain the label and info about having children.
- deferItemLoadingUntilExpand: false,
-
- constructor: function(/* Object */ args){
- // summary:
- // Passed the arguments listed above (store, etc)
- // tags:
- // private
-
- dojo.mixin(this, args);
-
- this.connects = [];
-
- var store = this.store;
- if(!store.getFeatures()['dojo.data.api.Identity']){
- throw new Error("dijit.Tree: store must support dojo.data.Identity");
- }
-
- // if the store supports Notification, subscribe to the notification events
- if(store.getFeatures()['dojo.data.api.Notification']){
- this.connects = this.connects.concat([
- dojo.connect(store, "onNew", this, "onNewItem"),
- dojo.connect(store, "onDelete", this, "onDeleteItem"),
- dojo.connect(store, "onSet", this, "onSetItem")
- ]);
- }
- },
-
- destroy: function(){
- dojo.forEach(this.connects, dojo.disconnect);
- // TODO: should cancel any in-progress processing of getRoot(), getChildren()
- },
-
- // =======================================================================
- // 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{
- this.store.fetch({
- query: this.query,
- onComplete: dojo.hitch(this, function(items){
- if(items.length != 1){
- throw new Error(this.declaredClass + ": query " + dojo.toJson(this.query) + " returned " + items.length +
- " items, but must return exactly one item");
- }
- this.root = items[0];
- onItem(this.root);
- }),
- onError: onError
- });
- }
- },
-
- 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)
- return dojo.some(this.childrenAttrs, function(attr){
- return this.store.hasAttribute(item, attr);
- }, this);
- },
-
- getChildren: function(/*dojo.data.Item*/ parentItem, /*function(items)*/ onComplete, /*function*/ onError){
- // summary:
- // Calls onComplete() with array of child items of given parent item, all loaded.
-
- var store = this.store;
- if(!store.isItemLoaded(parentItem)){
- // The parent is not loaded yet, we must be in deferItemLoadingUntilExpand
- // mode, so we will load it and just return the children (without loading each
- // child item)
- var getChildren = dojo.hitch(this, arguments.callee);
- store.loadItem({
- item: parentItem,
- onItem: function(parentItem){
- getChildren(parentItem, onComplete, onError);
- },
- onError: onError
- });
- return;
- }
- // get children of specified item
- var childItems = [];
- for(var i=0; i<this.childrenAttrs.length; i++){
- var vals = store.getValues(parentItem, this.childrenAttrs[i]);
- childItems = childItems.concat(vals);
- }
-
- // count how many items need to be loaded
- var _waitCount = 0;
- if(!this.deferItemLoadingUntilExpand){
- dojo.forEach(childItems, function(item){ if(!store.isItemLoaded(item)){ _waitCount++; } });
- }
-
- if(_waitCount == 0){
- // all items are already loaded (or we aren't loading them). proceed...
- onComplete(childItems);
- }else{
- // still waiting for some or all of the items to load
- dojo.forEach(childItems, function(item, idx){
- if(!store.isItemLoaded(item)){
- store.loadItem({
- item: item,
- onItem: function(item){
- childItems[idx] = item;
- if(--_waitCount == 0){
- // all nodes have been loaded, send them to the tree
- onComplete(childItems);
- }
- },
- onError: onError
- });
- }
- });
- }
- },
-
- // =======================================================================
- // Inspecting items
-
- isItem: function(/* anything */ something){
- return this.store.isItem(something); // Boolean
- },
-
- fetchItemByIdentity: function(/* object */ keywordArgs){
- this.store.fetchItemByIdentity(keywordArgs);
- },
-
- getIdentity: function(/* item */ item){
- return this.store.getIdentity(item); // Object
- },
-
- getLabel: function(/*dojo.data.Item*/ item){
- // summary:
- // Get the label for an item
- if(this.labelAttr){
- return this.store.getValue(item,this.labelAttr); // String
- }else{
- return this.store.getLabel(item); // String
- }
- },
-
- // =======================================================================
- // Write interface
-
- newItem: function(/* dojo.dnd.Item */ args, /*Item*/ parent, /*int?*/ insertIndex){
- // 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.
- // description:
- // Developers will need to override this method if new items get added
- // to parents with multiple children attributes, in order to define which
- // children attribute points to the new item.
-
- var pInfo = {parent: parent, attribute: this.childrenAttrs[0]}, LnewItem;
-
- if(this.newItemIdAttr && args[this.newItemIdAttr]){
- // Maybe there's already a corresponding item in the store; if so, reuse it.
- this.fetchItemByIdentity({identity: args[this.newItemIdAttr], scope: this, onItem: function(item){
- if(item){
- // There's already a matching item in store, use it
- this.pasteItem(item, null, parent, true, insertIndex);
- }else{
- // Create new item in the tree, based on the drag source.
- LnewItem=this.store.newItem(args, pInfo);
- if (LnewItem && (insertIndex!=undefined)){
- // Move new item to desired position
- this.pasteItem(LnewItem, parent, parent, false, insertIndex);
- }
- }
- }});
- }else{
- // [as far as we know] there is no id so we must assume this is a new item
- LnewItem=this.store.newItem(args, pInfo);
- if (LnewItem && (insertIndex!=undefined)){
- // Move new item to desired position
- this.pasteItem(LnewItem, parent, parent, false, insertIndex);
- }
- }
- },
-
- 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
- var store = this.store,
- parentAttr = this.childrenAttrs[0]; // name of "children" attr in parent item
-
- // remove child from source item, and record the attribute that child occurred in
- if(oldParentItem){
- dojo.forEach(this.childrenAttrs, function(attr){
- if(store.containsValue(oldParentItem, attr, childItem)){
- if(!bCopy){
- var values = dojo.filter(store.getValues(oldParentItem, attr), function(x){
- return x != childItem;
- });
- store.setValues(oldParentItem, attr, values);
- }
- parentAttr = attr;
- }
- });
- }
-
- // modify target item's children attribute to include this item
- if(newParentItem){
- if(typeof insertIndex == "number"){
- // call slice() to avoid modifying the original array, confusing the data store
- var childItems = store.getValues(newParentItem, parentAttr).slice();
- childItems.splice(insertIndex, 0, childItem);
- store.setValues(newParentItem, parentAttr, childItems);
- }else{
- store.setValues(newParentItem, parentAttr,
- store.getValues(newParentItem, parentAttr).concat(childItem));
- }
- }
- },
-
- // =======================================================================
- // 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(/*dojo.data.Item*/ parent, /*dojo.data.Item[]*/ newChildrenList){
- // summary:
- // Callback to do notifications about new, updated, or deleted items.
- // tags:
- // callback
- },
-
- onDelete: function(/*dojo.data.Item*/ parent, /*dojo.data.Item[]*/ newChildrenList){
- // summary:
- // Callback when an item has been deleted.
- // description:
- // Note that there will also be an onChildrenChange() callback for the parent
- // of this item.
- // tags:
- // callback
- },
-
- // =======================================================================
- // Events from data store
-
- onNewItem: function(/* dojo.data.Item */ item, /* Object */ parentInfo){
- // summary:
- // Handler for when new items appear in the store, either from a drop operation
- // or some other way. Updates the tree view (if necessary).
- // description:
- // If the new item is a child of an existing item,
- // calls onChildrenChange() with the new list of children
- // for that existing item.
- //
- // tags:
- // extension
-
- // We only care about the new item if it has a parent that corresponds to a TreeNode
- // we are currently displaying
- if(!parentInfo){
- return;
- }
-
- // Call onChildrenChange() on parent (ie, existing) item with new list of children
- // In the common case, the new list of children is simply parentInfo.newValue or
- // [ parentInfo.newValue ], although if items in the store has multiple
- // child attributes (see `childrenAttr`), then it's a superset of parentInfo.newValue,
- // so call getChildren() to be sure to get right answer.
- this.getChildren(parentInfo.item, dojo.hitch(this, function(children){
- this.onChildrenChange(parentInfo.item, children);
- }));
- },
-
- onDeleteItem: function(/*Object*/ item){
- // summary:
- // Handler for delete notifications from underlying store
- this.onDelete(item);
- },
-
- onSetItem: function(/* item */ item,
- /* attribute-name-string */ attribute,
- /* object | array */ oldValue,
- /* object | array */ newValue){
- // summary:
- // Updates the tree view according to changes in the data store.
- // description:
- // Handles updates to an item's children by calling onChildrenChange(), and
- // other updates to an item by calling onChange().
- //
- // See `onNewItem` for more details on handling updates to an item's children.
- // tags:
- // extension
-
- if(dojo.indexOf(this.childrenAttrs, attribute) != -1){
- // item's children list changed
- this.getChildren(item, dojo.hitch(this, function(children){
- // See comments in onNewItem() about calling getChildren()
- this.onChildrenChange(item, children);
- }));
- }else{
- // item's label/icon/etc. changed.
- this.onChange(item);
- }
- }
- });
-
-}
+//>>built
+define("dijit/tree/TreeStoreModel",["dojo/_base/array","dojo/aspect","dojo/_base/declare","dojo/_base/json","dojo/_base/lang"],function(_1,_2,_3,_4,_5){return _3("dijit.tree.TreeStoreModel",null,{store:null,childrenAttrs:["children"],newItemIdAttr:"id",labelAttr:"",root:null,query:null,deferItemLoadingUntilExpand:false,constructor:function(_6){_5.mixin(this,_6);this.connects=[];var _7=this.store;if(!_7.getFeatures()["dojo.data.api.Identity"]){throw new Error("dijit.Tree: store must support dojo.data.Identity");}if(_7.getFeatures()["dojo.data.api.Notification"]){this.connects=this.connects.concat([_2.after(_7,"onNew",_5.hitch(this,"onNewItem"),true),_2.after(_7,"onDelete",_5.hitch(this,"onDeleteItem"),true),_2.after(_7,"onSet",_5.hitch(this,"onSetItem"),true)]);}},destroy:function(){var h;while(h=this.connects.pop()){h.remove();}},getRoot:function(_8,_9){if(this.root){_8(this.root);}else{this.store.fetch({query:this.query,onComplete:_5.hitch(this,function(_a){if(_a.length!=1){throw new Error(this.declaredClass+": query "+_4.stringify(this.query)+" returned "+_a.length+" items, but must return exactly one item");}this.root=_a[0];_8(this.root);}),onError:_9});}},mayHaveChildren:function(_b){return _1.some(this.childrenAttrs,function(_c){return this.store.hasAttribute(_b,_c);},this);},getChildren:function(_d,_e,_f){var _10=this.store;if(!_10.isItemLoaded(_d)){var _11=_5.hitch(this,arguments.callee);_10.loadItem({item:_d,onItem:function(_12){_11(_12,_e,_f);},onError:_f});return;}var _13=[];for(var i=0;i<this.childrenAttrs.length;i++){var _14=_10.getValues(_d,this.childrenAttrs[i]);_13=_13.concat(_14);}var _15=0;if(!this.deferItemLoadingUntilExpand){_1.forEach(_13,function(_16){if(!_10.isItemLoaded(_16)){_15++;}});}if(_15==0){_e(_13);}else{_1.forEach(_13,function(_17,idx){if(!_10.isItemLoaded(_17)){_10.loadItem({item:_17,onItem:function(_18){_13[idx]=_18;if(--_15==0){_e(_13);}},onError:_f});}});}},isItem:function(_19){return this.store.isItem(_19);},fetchItemByIdentity:function(_1a){this.store.fetchItemByIdentity(_1a);},getIdentity:function(_1b){return this.store.getIdentity(_1b);},getLabel:function(_1c){if(this.labelAttr){return this.store.getValue(_1c,this.labelAttr);}else{return this.store.getLabel(_1c);}},newItem:function(_1d,_1e,_1f){var _20={parent:_1e,attribute:this.childrenAttrs[0]},_21;if(this.newItemIdAttr&&_1d[this.newItemIdAttr]){this.fetchItemByIdentity({identity:_1d[this.newItemIdAttr],scope:this,onItem:function(_22){if(_22){this.pasteItem(_22,null,_1e,true,_1f);}else{_21=this.store.newItem(_1d,_20);if(_21&&(_1f!=undefined)){this.pasteItem(_21,_1e,_1e,false,_1f);}}}});}else{_21=this.store.newItem(_1d,_20);if(_21&&(_1f!=undefined)){this.pasteItem(_21,_1e,_1e,false,_1f);}}},pasteItem:function(_23,_24,_25,_26,_27){var _28=this.store,_29=this.childrenAttrs[0];if(_24){_1.forEach(this.childrenAttrs,function(_2a){if(_28.containsValue(_24,_2a,_23)){if(!_26){var _2b=_1.filter(_28.getValues(_24,_2a),function(x){return x!=_23;});_28.setValues(_24,_2a,_2b);}_29=_2a;}});}if(_25){if(typeof _27=="number"){var _2c=_28.getValues(_25,_29).slice();_2c.splice(_27,0,_23);_28.setValues(_25,_29,_2c);}else{_28.setValues(_25,_29,_28.getValues(_25,_29).concat(_23));}}},onChange:function(){},onChildrenChange:function(){},onDelete:function(){},onNewItem:function(_2d,_2e){if(!_2e){return;}this.getChildren(_2e.item,_5.hitch(this,function(_2f){this.onChildrenChange(_2e.item,_2f);}));},onDeleteItem:function(_30){this.onDelete(_30);},onSetItem:function(_31,_32){if(_1.indexOf(this.childrenAttrs,_32)!=-1){this.getChildren(_31,_5.hitch(this,function(_33){this.onChildrenChange(_31,_33);}));}else{this.onChange(_31);}}});}); \ No newline at end of file
diff --git a/lib/dijit/tree/TreeStoreModel.js.uncompressed.js b/lib/dijit/tree/TreeStoreModel.js.uncompressed.js
new file mode 100644
index 000000000..4e8087c27
--- /dev/null
+++ b/lib/dijit/tree/TreeStoreModel.js.uncompressed.js
@@ -0,0 +1,383 @@
+define("dijit/tree/TreeStoreModel", [
+ "dojo/_base/array", // array.filter array.forEach array.indexOf array.some
+ "dojo/aspect", // aspect.after
+ "dojo/_base/declare", // declare
+ "dojo/_base/json", // json.stringify
+ "dojo/_base/lang" // lang.hitch
+], function(array, aspect, declare, json, lang){
+
+ // module:
+ // dijit/tree/TreeStoreModel
+ // summary:
+ // Implements dijit.Tree.model connecting to a dojo.data store with a single
+ // root item.
+
+ return declare("dijit.tree.TreeStoreModel", null, {
+ // summary:
+ // Implements dijit.Tree.model connecting to a dojo.data store with a single
+ // root item. Any methods passed into the constructor will override
+ // the ones defined here.
+
+ // store: dojo.data.Store
+ // Underlying store
+ store: null,
+
+ // childrenAttrs: String[]
+ // One or more attribute names (attributes in the dojo.data item) that specify that item's children
+ childrenAttrs: ["children"],
+
+ // newItemIdAttr: String
+ // Name of attribute in the Object passed to newItem() that specifies the id.
+ //
+ // If newItemIdAttr is set then it's used when newItem() is called to see if an
+ // item with the same id already exists, and if so just links to the old item
+ // (so that the old item ends up with two parents).
+ //
+ // Setting this to null or "" will make every drop create a new item.
+ newItemIdAttr: "id",
+
+ // labelAttr: String
+ // If specified, get label for tree node from this attribute, rather
+ // than by calling store.getLabel()
+ labelAttr: "",
+
+ // root: [readonly] dojo.data.Item
+ // Pointer to the root item (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,
+
+ // deferItemLoadingUntilExpand: Boolean
+ // Setting this to true will cause the TreeStoreModel to defer calling loadItem on nodes
+ // until they are expanded. This allows for lazying loading where only one
+ // loadItem (and generally one network call, consequently) per expansion
+ // (rather than one for each child).
+ // This relies on partial loading of the children items; each children item of a
+ // fully loaded item should contain the label and info about having children.
+ deferItemLoadingUntilExpand: false,
+
+ constructor: function(/* Object */ args){
+ // summary:
+ // Passed the arguments listed above (store, etc)
+ // tags:
+ // private
+
+ lang.mixin(this, args);
+
+ this.connects = [];
+
+ var store = this.store;
+ if(!store.getFeatures()['dojo.data.api.Identity']){
+ throw new Error("dijit.Tree: store must support dojo.data.Identity");
+ }
+
+ // if the store supports Notification, subscribe to the notification events
+ if(store.getFeatures()['dojo.data.api.Notification']){
+ this.connects = this.connects.concat([
+ aspect.after(store, "onNew", lang.hitch(this, "onNewItem"), true),
+ aspect.after(store, "onDelete", lang.hitch(this, "onDeleteItem"), true),
+ aspect.after(store, "onSet", lang.hitch(this, "onSetItem"), true)
+ ]);
+ }
+ },
+
+ destroy: function(){
+ var h;
+ while(h = this.connects.pop()){ h.remove(); }
+ // TODO: should cancel any in-progress processing of getRoot(), getChildren()
+ },
+
+ // =======================================================================
+ // 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{
+ this.store.fetch({
+ query: this.query,
+ onComplete: lang.hitch(this, function(items){
+ if(items.length != 1){
+ throw new Error(this.declaredClass + ": query " + json.stringify(this.query) + " returned " + items.length +
+ " items, but must return exactly one item");
+ }
+ this.root = items[0];
+ onItem(this.root);
+ }),
+ onError: onError
+ });
+ }
+ },
+
+ 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)
+ return array.some(this.childrenAttrs, function(attr){
+ return this.store.hasAttribute(item, attr);
+ }, this);
+ },
+
+ getChildren: function(/*dojo.data.Item*/ parentItem, /*function(items)*/ onComplete, /*function*/ onError){
+ // summary:
+ // Calls onComplete() with array of child items of given parent item, all loaded.
+
+ var store = this.store;
+ if(!store.isItemLoaded(parentItem)){
+ // The parent is not loaded yet, we must be in deferItemLoadingUntilExpand
+ // mode, so we will load it and just return the children (without loading each
+ // child item)
+ var getChildren = lang.hitch(this, arguments.callee);
+ store.loadItem({
+ item: parentItem,
+ onItem: function(parentItem){
+ getChildren(parentItem, onComplete, onError);
+ },
+ onError: onError
+ });
+ return;
+ }
+ // get children of specified item
+ var childItems = [];
+ for(var i=0; i<this.childrenAttrs.length; i++){
+ var vals = store.getValues(parentItem, this.childrenAttrs[i]);
+ childItems = childItems.concat(vals);
+ }
+
+ // count how many items need to be loaded
+ var _waitCount = 0;
+ if(!this.deferItemLoadingUntilExpand){
+ array.forEach(childItems, function(item){ if(!store.isItemLoaded(item)){ _waitCount++; } });
+ }
+
+ if(_waitCount == 0){
+ // all items are already loaded (or we aren't loading them). proceed...
+ onComplete(childItems);
+ }else{
+ // still waiting for some or all of the items to load
+ array.forEach(childItems, function(item, idx){
+ if(!store.isItemLoaded(item)){
+ store.loadItem({
+ item: item,
+ onItem: function(item){
+ childItems[idx] = item;
+ if(--_waitCount == 0){
+ // all nodes have been loaded, send them to the tree
+ onComplete(childItems);
+ }
+ },
+ onError: onError
+ });
+ }
+ });
+ }
+ },
+
+ // =======================================================================
+ // Inspecting items
+
+ isItem: function(/* anything */ something){
+ return this.store.isItem(something); // Boolean
+ },
+
+ fetchItemByIdentity: function(/* object */ keywordArgs){
+ this.store.fetchItemByIdentity(keywordArgs);
+ },
+
+ getIdentity: function(/* item */ item){
+ return this.store.getIdentity(item); // Object
+ },
+
+ getLabel: function(/*dojo.data.Item*/ item){
+ // summary:
+ // Get the label for an item
+ if(this.labelAttr){
+ return this.store.getValue(item,this.labelAttr); // String
+ }else{
+ return this.store.getLabel(item); // String
+ }
+ },
+
+ // =======================================================================
+ // Write interface
+
+ newItem: function(/* dojo.dnd.Item */ args, /*Item*/ parent, /*int?*/ insertIndex){
+ // 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.
+ // description:
+ // Developers will need to override this method if new items get added
+ // to parents with multiple children attributes, in order to define which
+ // children attribute points to the new item.
+
+ var pInfo = {parent: parent, attribute: this.childrenAttrs[0]}, LnewItem;
+
+ if(this.newItemIdAttr && args[this.newItemIdAttr]){
+ // Maybe there's already a corresponding item in the store; if so, reuse it.
+ this.fetchItemByIdentity({identity: args[this.newItemIdAttr], scope: this, onItem: function(item){
+ if(item){
+ // There's already a matching item in store, use it
+ this.pasteItem(item, null, parent, true, insertIndex);
+ }else{
+ // Create new item in the tree, based on the drag source.
+ LnewItem=this.store.newItem(args, pInfo);
+ if(LnewItem && (insertIndex!=undefined)){
+ // Move new item to desired position
+ this.pasteItem(LnewItem, parent, parent, false, insertIndex);
+ }
+ }
+ }});
+ }else{
+ // [as far as we know] there is no id so we must assume this is a new item
+ LnewItem=this.store.newItem(args, pInfo);
+ if(LnewItem && (insertIndex!=undefined)){
+ // Move new item to desired position
+ this.pasteItem(LnewItem, parent, parent, false, insertIndex);
+ }
+ }
+ },
+
+ 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
+ var store = this.store,
+ parentAttr = this.childrenAttrs[0]; // name of "children" attr in parent item
+
+ // remove child from source item, and record the attribute that child occurred in
+ if(oldParentItem){
+ array.forEach(this.childrenAttrs, function(attr){
+ if(store.containsValue(oldParentItem, attr, childItem)){
+ if(!bCopy){
+ var values = array.filter(store.getValues(oldParentItem, attr), function(x){
+ return x != childItem;
+ });
+ store.setValues(oldParentItem, attr, values);
+ }
+ parentAttr = attr;
+ }
+ });
+ }
+
+ // modify target item's children attribute to include this item
+ if(newParentItem){
+ if(typeof insertIndex == "number"){
+ // call slice() to avoid modifying the original array, confusing the data store
+ var childItems = store.getValues(newParentItem, parentAttr).slice();
+ childItems.splice(insertIndex, 0, childItem);
+ store.setValues(newParentItem, parentAttr, childItems);
+ }else{
+ store.setValues(newParentItem, parentAttr,
+ store.getValues(newParentItem, parentAttr).concat(childItem));
+ }
+ }
+ },
+
+ // =======================================================================
+ // 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: dojo.data.Item[]
+ // tags:
+ // callback
+ },
+
+ onDelete: function(/*dojo.data.Item*/ /*===== item =====*/){
+ // summary:
+ // Callback when an item has been deleted.
+ // description:
+ // Note that there will also be an onChildrenChange() callback for the parent
+ // of this item.
+ // tags:
+ // callback
+ },
+
+ // =======================================================================
+ // Events from data store
+
+ onNewItem: function(/* dojo.data.Item */ item, /* Object */ parentInfo){
+ // summary:
+ // Handler for when new items appear in the store, either from a drop operation
+ // or some other way. Updates the tree view (if necessary).
+ // description:
+ // If the new item is a child of an existing item,
+ // calls onChildrenChange() with the new list of children
+ // for that existing item.
+ //
+ // tags:
+ // extension
+
+ // We only care about the new item if it has a parent that corresponds to a TreeNode
+ // we are currently displaying
+ if(!parentInfo){
+ return;
+ }
+
+ // Call onChildrenChange() on parent (ie, existing) item with new list of children
+ // In the common case, the new list of children is simply parentInfo.newValue or
+ // [ parentInfo.newValue ], although if items in the store has multiple
+ // child attributes (see `childrenAttr`), then it's a superset of parentInfo.newValue,
+ // so call getChildren() to be sure to get right answer.
+ this.getChildren(parentInfo.item, lang.hitch(this, function(children){
+ this.onChildrenChange(parentInfo.item, children);
+ }));
+ },
+
+ onDeleteItem: function(/*Object*/ item){
+ // summary:
+ // Handler for delete notifications from underlying store
+ this.onDelete(item);
+ },
+
+ onSetItem: function(item, attribute /*===== , oldValue, newValue =====*/){
+ // summary:
+ // Updates the tree view according to changes in the data store.
+ // description:
+ // Handles updates to an item's children by calling onChildrenChange(), and
+ // other updates to an item by calling onChange().
+ //
+ // See `onNewItem` for more details on handling updates to an item's children.
+ // item: Item
+ // attribute: attribute-name-string
+ // oldValue: object | array
+ // newValue: object | array
+ // tags:
+ // extension
+
+ if(array.indexOf(this.childrenAttrs, attribute) != -1){
+ // item's children list changed
+ this.getChildren(item, lang.hitch(this, function(children){
+ // See comments in onNewItem() about calling getChildren()
+ this.onChildrenChange(item, children);
+ }));
+ }else{
+ // item's label/icon/etc. changed.
+ this.onChange(item);
+ }
+ }
+ });
+});
diff --git a/lib/dijit/tree/_dndContainer.js b/lib/dijit/tree/_dndContainer.js
index 9ee8e32ba..f361278c1 100644
--- a/lib/dijit/tree/_dndContainer.js
+++ b/lib/dijit/tree/_dndContainer.js
@@ -1,187 +1,2 @@
-/*
- Copyright (c) 2004-2011, The Dojo Foundation All Rights Reserved.
- Available via Academic Free License >= 2.1 OR the modified BSD license.
- see: http://dojotoolkit.org/license for details
-*/
-
-
-if(!dojo._hasResource["dijit.tree._dndContainer"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
-dojo._hasResource["dijit.tree._dndContainer"] = true;
-dojo.provide("dijit.tree._dndContainer");
-dojo.require("dojo.dnd.common");
-dojo.require("dojo.dnd.Container");
-
-
-dojo.getObject("tree", true, dojo);
-
-dijit.tree._compareNodes = function(n1, n2){
- if(n1 === n2){
- return 0;
- }
-
- if('sourceIndex' in document.documentElement){ //IE
- //TODO: does not yet work if n1 and/or n2 is a text node
- return n1.sourceIndex - n2.sourceIndex;
- }else if('compareDocumentPosition' in document.documentElement){ //FF, Opera
- return n1.compareDocumentPosition(n2) & 2 ? 1: -1;
- }else if(document.createRange){ //Webkit
- var r1 = doc.createRange();
- r1.setStartBefore(n1);
-
- var r2 = doc.createRange();
- r2.setStartBefore(n2);
-
- return r1.compareBoundaryPoints(r1.END_TO_END, r2);
- }else{
- throw Error("dijit.tree._compareNodes don't know how to compare two different nodes in this browser");
- }
-};
-
-dojo.declare("dijit.tree._dndContainer",
- null,
- {
-
- // summary:
- // This is a base class for `dijit.tree._dndSelector`, and isn't meant to be used directly.
- // It's modeled after `dojo.dnd.Container`.
- // tags:
- // protected
-
- /*=====
- // current: DomNode
- // The currently hovered TreeNode.rowNode (which is the DOM node
- // associated w/a given node in the tree, excluding it's descendants)
- current: null,
- =====*/
-
- constructor: function(tree, params){
- // summary:
- // A constructor of the Container
- // tree: Node
- // Node or node's id to build the container on
- // params: dijit.tree.__SourceArgs
- // A dict of parameters, which gets mixed into the object
- // tags:
- // private
- this.tree = tree;
- this.node = tree.domNode; // TODO: rename; it's not a TreeNode but the whole Tree
- dojo.mixin(this, params);
-
- // class-specific variables
- this.map = {};
- this.current = null; // current TreeNode's DOM node
-
- // states
- this.containerState = "";
- dojo.addClass(this.node, "dojoDndContainer");
-
- // set up events
- this.events = [
- // container level events
- dojo.connect(this.node, "onmouseenter", this, "onOverEvent"),
- dojo.connect(this.node, "onmouseleave", this, "onOutEvent"),
-
- // switching between TreeNodes
- dojo.connect(this.tree, "_onNodeMouseEnter", this, "onMouseOver"),
- dojo.connect(this.tree, "_onNodeMouseLeave", this, "onMouseOut"),
-
- // cancel text selection and text dragging
- dojo.connect(this.node, "ondragstart", dojo, "stopEvent"),
- dojo.connect(this.node, "onselectstart", dojo, "stopEvent")
- ];
- },
-
- getItem: function(/*String*/ key){
- // summary:
- // Returns the dojo.dnd.Item (representing a dragged node) by it's key (id).
- // Called by dojo.dnd.Source.checkAcceptance().
- // tags:
- // protected
-
- var widget = this.selection[key],
- ret = {
- data: widget,
- type: ["treeNode"]
- };
-
- return ret; // dojo.dnd.Item
- },
-
- destroy: function(){
- // summary:
- // Prepares this object to be garbage-collected
-
- dojo.forEach(this.events, dojo.disconnect);
- // this.clearItems();
- this.node = this.parent = null;
- },
-
- // mouse events
- onMouseOver: function(/*TreeNode*/ widget, /*Event*/ evt){
- // summary:
- // Called when mouse is moved over a TreeNode
- // tags:
- // protected
- this.current = widget;
- },
-
- onMouseOut: function(/*TreeNode*/ widget, /*Event*/ evt){
- // summary:
- // Called when mouse is moved away from a TreeNode
- // tags:
- // protected
- this.current = null;
- },
-
- _changeState: function(type, newState){
- // summary:
- // Changes a named state to new state value
- // type: String
- // A name of the state to change
- // newState: String
- // new state
- var prefix = "dojoDnd" + type;
- var state = type.toLowerCase() + "State";
- //dojo.replaceClass(this.node, prefix + newState, prefix + this[state]);
- dojo.replaceClass(this.node, prefix + newState, prefix + this[state]);
- this[state] = newState;
- },
-
- _addItemClass: function(node, type){
- // summary:
- // Adds a class with prefix "dojoDndItem"
- // node: Node
- // A node
- // type: String
- // A variable suffix for a class name
- dojo.addClass(node, "dojoDndItem" + type);
- },
-
- _removeItemClass: function(node, type){
- // summary:
- // Removes a class with prefix "dojoDndItem"
- // node: Node
- // A node
- // type: String
- // A variable suffix for a class name
- dojo.removeClass(node, "dojoDndItem" + type);
- },
-
- onOverEvent: function(){
- // summary:
- // This function is called once, when mouse is over our container
- // tags:
- // protected
- this._changeState("Container", "Over");
- },
-
- onOutEvent: function(){
- // summary:
- // This function is called once, when mouse is out of our container
- // tags:
- // protected
- this._changeState("Container", "");
- }
-});
-
-}
+//>>built
+define("dijit/tree/_dndContainer",["dojo/aspect","dojo/_base/declare","dojo/dom-class","dojo/_base/event","dojo/_base/lang","dojo/mouse","dojo/on"],function(_1,_2,_3,_4,_5,_6,on){return _2("dijit.tree._dndContainer",null,{constructor:function(_7,_8){this.tree=_7;this.node=_7.domNode;_5.mixin(this,_8);this.current=null;this.containerState="";_3.add(this.node,"dojoDndContainer");this.events=[on(this.node,_6.enter,_5.hitch(this,"onOverEvent")),on(this.node,_6.leave,_5.hitch(this,"onOutEvent")),_1.after(this.tree,"_onNodeMouseEnter",_5.hitch(this,"onMouseOver"),true),_1.after(this.tree,"_onNodeMouseLeave",_5.hitch(this,"onMouseOut"),true),on(this.node,"dragstart",_5.hitch(_4,"stop")),on(this.node,"selectstart",_5.hitch(_4,"stop"))];},destroy:function(){var h;while(h=this.events.pop()){h.remove();}this.node=this.parent=null;},onMouseOver:function(_9){this.current=_9;},onMouseOut:function(){this.current=null;},_changeState:function(_a,_b){var _c="dojoDnd"+_a;var _d=_a.toLowerCase()+"State";_3.replace(this.node,_c+_b,_c+this[_d]);this[_d]=_b;},_addItemClass:function(_e,_f){_3.add(_e,"dojoDndItem"+_f);},_removeItemClass:function(_10,_11){_3.remove(_10,"dojoDndItem"+_11);},onOverEvent:function(){this._changeState("Container","Over");},onOutEvent:function(){this._changeState("Container","");}});}); \ No newline at end of file
diff --git a/lib/dijit/tree/_dndContainer.js.uncompressed.js b/lib/dijit/tree/_dndContainer.js.uncompressed.js
new file mode 100644
index 000000000..8f457e6d5
--- /dev/null
+++ b/lib/dijit/tree/_dndContainer.js.uncompressed.js
@@ -0,0 +1,150 @@
+define("dijit/tree/_dndContainer", [
+ "dojo/aspect", // aspect.after
+ "dojo/_base/declare", // declare
+ "dojo/dom-class", // domClass.add domClass.remove domClass.replace
+ "dojo/_base/event", // event.stop
+ "dojo/_base/lang", // lang.getObject lang.mixin lang.hitch
+ "dojo/mouse", // mouse.enter, mouse.leave
+ "dojo/on"
+], function(aspect, declare, domClass, event, lang, mouse, on){
+
+ // module:
+ // dijit/tree/_dndContainer
+ // summary:
+ // This is a base class for `dijit.tree._dndSelector`, and isn't meant to be used directly.
+ // It's modeled after `dojo.dnd.Container`.
+
+ return declare("dijit.tree._dndContainer", null, {
+
+ // summary:
+ // This is a base class for `dijit.tree._dndSelector`, and isn't meant to be used directly.
+ // It's modeled after `dojo.dnd.Container`.
+ // tags:
+ // protected
+
+ /*=====
+ // current: DomNode
+ // The currently hovered TreeNode.rowNode (which is the DOM node
+ // associated w/a given node in the tree, excluding it's descendants)
+ current: null,
+ =====*/
+
+ constructor: function(tree, params){
+ // summary:
+ // A constructor of the Container
+ // tree: Node
+ // Node or node's id to build the container on
+ // params: dijit.tree.__SourceArgs
+ // A dict of parameters, which gets mixed into the object
+ // tags:
+ // private
+ this.tree = tree;
+ this.node = tree.domNode; // TODO: rename; it's not a TreeNode but the whole Tree
+ lang.mixin(this, params);
+
+ // class-specific variables
+ this.current = null; // current TreeNode's DOM node
+
+ // states
+ this.containerState = "";
+ domClass.add(this.node, "dojoDndContainer");
+
+ // set up events
+ this.events = [
+ // container level events
+ on(this.node, mouse.enter, lang.hitch(this, "onOverEvent")),
+ on(this.node, mouse.leave, lang.hitch(this, "onOutEvent")),
+
+ // switching between TreeNodes
+ aspect.after(this.tree, "_onNodeMouseEnter", lang.hitch(this, "onMouseOver"), true),
+ aspect.after(this.tree, "_onNodeMouseLeave", lang.hitch(this, "onMouseOut"), true),
+
+ // cancel text selection and text dragging
+ on(this.node, "dragstart", lang.hitch(event, "stop")),
+ on(this.node, "selectstart", lang.hitch(event, "stop"))
+ ];
+ },
+
+ destroy: function(){
+ // summary:
+ // Prepares this object to be garbage-collected
+
+ var h;
+ while(h = this.events.pop()){ h.remove(); }
+
+ // this.clearItems();
+ this.node = this.parent = null;
+ },
+
+ // mouse events
+ onMouseOver: function(widget /*===== , evt =====*/){
+ // summary:
+ // Called when mouse is moved over a TreeNode
+ // widget: TreeNode
+ // evt: Event
+ // tags:
+ // protected
+ this.current = widget;
+ },
+
+ onMouseOut: function(/*===== widget, evt =====*/){
+ // summary:
+ // Called when mouse is moved away from a TreeNode
+ // widget: TreeNode
+ // evt: Event
+ // tags:
+ // protected
+ this.current = null;
+ },
+
+ _changeState: function(type, newState){
+ // summary:
+ // Changes a named state to new state value
+ // type: String
+ // A name of the state to change
+ // newState: String
+ // new state
+ var prefix = "dojoDnd" + type;
+ var state = type.toLowerCase() + "State";
+ //domClass.replace(this.node, prefix + newState, prefix + this[state]);
+ domClass.replace(this.node, prefix + newState, prefix + this[state]);
+ this[state] = newState;
+ },
+
+ _addItemClass: function(node, type){
+ // summary:
+ // Adds a class with prefix "dojoDndItem"
+ // node: Node
+ // A node
+ // type: String
+ // A variable suffix for a class name
+ domClass.add(node, "dojoDndItem" + type);
+ },
+
+ _removeItemClass: function(node, type){
+ // summary:
+ // Removes a class with prefix "dojoDndItem"
+ // node: Node
+ // A node
+ // type: String
+ // A variable suffix for a class name
+ domClass.remove(node, "dojoDndItem" + type);
+ },
+
+ onOverEvent: function(){
+ // summary:
+ // This function is called once, when mouse is over our container
+ // tags:
+ // protected
+ this._changeState("Container", "Over");
+ },
+
+ onOutEvent: function(){
+ // summary:
+ // This function is called once, when mouse is out of our container
+ // tags:
+ // protected
+ this._changeState("Container", "");
+ }
+ });
+});
diff --git a/lib/dijit/tree/_dndSelector.js b/lib/dijit/tree/_dndSelector.js
index 5f9310e71..f0567444f 100644
--- a/lib/dijit/tree/_dndSelector.js
+++ b/lib/dijit/tree/_dndSelector.js
@@ -1,287 +1,2 @@
-/*
- Copyright (c) 2004-2011, The Dojo Foundation All Rights Reserved.
- Available via Academic Free License >= 2.1 OR the modified BSD license.
- see: http://dojotoolkit.org/license for details
-*/
-
-
-if(!dojo._hasResource["dijit.tree._dndSelector"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
-dojo._hasResource["dijit.tree._dndSelector"] = true;
-dojo.provide("dijit.tree._dndSelector");
-dojo.require("dojo.dnd.common");
-dojo.require("dijit.tree._dndContainer");
-
-
-dojo.declare("dijit.tree._dndSelector",
- dijit.tree._dndContainer,
- {
- // summary:
- // This is a base class for `dijit.tree.dndSource` , and isn't meant to be used directly.
- // It's based on `dojo.dnd.Selector`.
- // tags:
- // protected
-
- /*=====
- // selection: Hash<String, DomNode>
- // (id, DomNode) map for every TreeNode that's currently selected.
- // The DOMNode is the TreeNode.rowNode.
- selection: {},
- =====*/
-
- constructor: function(tree, params){
- // summary:
- // Initialization
- // tags:
- // private
-
- this.selection={};
- this.anchor = null;
-
- dijit.setWaiState(this.tree.domNode, "multiselect", !this.singular);
-
- this.events.push(
- dojo.connect(this.tree.domNode, "onmousedown", this,"onMouseDown"),
- dojo.connect(this.tree.domNode, "onmouseup", this,"onMouseUp"),
- dojo.connect(this.tree.domNode, "onmousemove", this,"onMouseMove")
- );
- },
-
- // singular: Boolean
- // Allows selection of only one element, if true.
- // Tree hasn't been tested in singular=true mode, unclear if it works.
- singular: false,
-
- // methods
- getSelectedTreeNodes: function(){
- // summary:
- // Returns a list of selected node(s).
- // Used by dndSource on the start of a drag.
- // tags:
- // protected
- var nodes=[], sel = this.selection;
- for(var i in sel){
- nodes.push(sel[i]);
- }
- return nodes;
- },
-
- selectNone: function(){
- // summary:
- // Unselects all items
- // tags:
- // private
-
- this.setSelection([]);
- return this; // self
- },
-
- destroy: function(){
- // summary:
- // Prepares the object to be garbage-collected
- this.inherited(arguments);
- this.selection = this.anchor = null;
- },
- addTreeNode: function(/*dijit._TreeNode*/node, /*Boolean?*/isAnchor){
- // summary
- // add node to current selection
- // node: Node
- // node to add
- // isAnchor: Boolean
- // Whether the node should become anchor.
-
- this.setSelection(this.getSelectedTreeNodes().concat( [node] ));
- if(isAnchor){ this.anchor = node; }
- return node;
- },
- removeTreeNode: function(/*dijit._TreeNode*/node){
- // summary
- // remove node from current selection
- // node: Node
- // node to remove
- this.setSelection(this._setDifference(this.getSelectedTreeNodes(), [node]))
- return node;
- },
- isTreeNodeSelected: function(/*dijit._TreeNode*/node){
- // summary
- // return true if node is currently selected
- // node: Node
- // the node to check whether it's in the current selection
-
- return node.id && !!this.selection[node.id];
- },
- setSelection: function(/*dijit._treeNode[]*/ newSelection){
- // summary
- // set the list of selected nodes to be exactly newSelection. All changes to the
- // selection should be passed through this function, which ensures that derived
- // attributes are kept up to date. Anchor will be deleted if it has been removed
- // from the selection, but no new anchor will be added by this function.
- // newSelection: Node[]
- // list of tree nodes to make selected
- var oldSelection = this.getSelectedTreeNodes();
- dojo.forEach(this._setDifference(oldSelection, newSelection), dojo.hitch(this, function(node){
- node.setSelected(false);
- if(this.anchor == node){
- delete this.anchor;
- }
- delete this.selection[node.id];
- }));
- dojo.forEach(this._setDifference(newSelection, oldSelection), dojo.hitch(this, function(node){
- node.setSelected(true);
- this.selection[node.id] = node;
- }));
- this._updateSelectionProperties();
- },
- _setDifference: function(xs,ys){
- // summary
- // Returns a copy of xs which lacks any objects
- // occurring in ys. Checks for membership by
- // modifying and then reading the object, so it will
- // not properly handle sets of numbers or strings.
-
- dojo.forEach(ys, function(y){ y.__exclude__ = true; });
- var ret = dojo.filter(xs, function(x){ return !x.__exclude__; });
-
- // clean up after ourselves.
- dojo.forEach(ys, function(y){ delete y['__exclude__'] });
- return ret;
- },
- _updateSelectionProperties: function() {
- // summary
- // Update the following tree properties from the current selection:
- // path[s], selectedItem[s], selectedNode[s]
-
- var selected = this.getSelectedTreeNodes();
- var paths = [], nodes = [];
- dojo.forEach(selected, function(node) {
- nodes.push(node);
- paths.push(node.getTreePath());
- });
- var items = dojo.map(nodes,function(node) { return node.item; });
- this.tree._set("paths", paths);
- this.tree._set("path", paths[0] || []);
- this.tree._set("selectedNodes", nodes);
- this.tree._set("selectedNode", nodes[0] || null);
- this.tree._set("selectedItems", items);
- this.tree._set("selectedItem", items[0] || null);
- },
- // mouse events
- onMouseDown: function(e){
- // summary:
- // Event processor for onmousedown
- // e: Event
- // mouse event
- // tags:
- // protected
-
- // ignore click on expando node
- if(!this.current || this.tree.isExpandoNode( e.target, this.current)){ return; }
-
- if(e.button == dojo.mouseButtons.RIGHT){ return; } // ignore right-click
-
- dojo.stopEvent(e);
-
- var treeNode = this.current,
- copy = dojo.isCopyKey(e), id = treeNode.id;
-
- // if shift key is not pressed, and the node is already in the selection,
- // delay deselection until onmouseup so in the case of DND, deselection
- // will be canceled by onmousemove.
- if(!this.singular && !e.shiftKey && this.selection[id]){
- this._doDeselect = true;
- return;
- }else{
- this._doDeselect = false;
- }
- this.userSelect(treeNode, copy, e.shiftKey);
- },
-
- onMouseUp: function(e){
- // summary:
- // Event processor for onmouseup
- // e: Event
- // mouse event
- // tags:
- // protected
-
- // _doDeselect is the flag to indicate that the user wants to either ctrl+click on
- // a already selected item (to deselect the item), or click on a not-yet selected item
- // (which should remove all current selection, and add the clicked item). This can not
- // be done in onMouseDown, because the user may start a drag after mousedown. By moving
- // the deselection logic here, the user can drags an already selected item.
- if(!this._doDeselect){ return; }
- this._doDeselect = false;
- this.userSelect(this.current, dojo.isCopyKey( e ), e.shiftKey);
- },
- onMouseMove: function(e){
- // summary
- // event processor for onmousemove
- // e: Event
- // mouse event
- this._doDeselect = false;
- },
-
- userSelect: function(node, multi, range){
- // summary:
- // Add or remove the given node from selection, responding
- // to a user action such as a click or keypress.
- // multi: Boolean
- // Indicates whether this is meant to be a multi-select action (e.g. ctrl-click)
- // range: Boolean
- // Indicates whether this is meant to be a ranged action (e.g. shift-click)
- // tags:
- // protected
-
- if(this.singular){
- if(this.anchor == node && multi){
- this.selectNone();
- }else{
- this.setSelection([node]);
- this.anchor = node;
- }
- }else{
- if(range && this.anchor){
- var cr = dijit.tree._compareNodes(this.anchor.rowNode, node.rowNode),
- begin, end, anchor = this.anchor;
-
- if(cr < 0){ //current is after anchor
- begin = anchor;
- end = node;
- }else{ //current is before anchor
- begin = node;
- end = anchor;
- }
- nodes = [];
- //add everything betweeen begin and end inclusively
- while(begin != end) {
- nodes.push(begin)
- begin = this.tree._getNextNode(begin);
- }
- nodes.push(end)
-
- this.setSelection(nodes);
- }else{
- if( this.selection[ node.id ] && multi ) {
- this.removeTreeNode( node );
- } else if(multi) {
- this.addTreeNode(node, true);
- } else {
- this.setSelection([node]);
- this.anchor = node;
- }
- }
- }
- },
-
- forInSelectedItems: function(/*Function*/ f, /*Object?*/ o){
- // summary:
- // Iterates over selected items;
- // see `dojo.dnd.Container.forInItems()` for details
- o = o || dojo.global;
- for(var id in this.selection){
- // console.log("selected item id: " + id);
- f.call(o, this.getItem(id), id, this);
- }
- }
-});
-
-}
+//>>built
+define("dijit/tree/_dndSelector",["dojo/_base/array","dojo/_base/connect","dojo/_base/declare","dojo/_base/lang","dojo/mouse","dojo/on","dojo/touch","dojo/_base/window","./_dndContainer"],function(_1,_2,_3,_4,_5,on,_6,_7,_8){return _3("dijit.tree._dndSelector",_8,{constructor:function(){this.selection={};this.anchor=null;this.tree.domNode.setAttribute("aria-multiselect",!this.singular);this.events.push(on(this.tree.domNode,_6.press,_4.hitch(this,"onMouseDown")),on(this.tree.domNode,_6.release,_4.hitch(this,"onMouseUp")),on(this.tree.domNode,_6.move,_4.hitch(this,"onMouseMove")));},singular:false,getSelectedTreeNodes:function(){var _9=[],_a=this.selection;for(var i in _a){_9.push(_a[i]);}return _9;},selectNone:function(){this.setSelection([]);return this;},destroy:function(){this.inherited(arguments);this.selection=this.anchor=null;},addTreeNode:function(_b,_c){this.setSelection(this.getSelectedTreeNodes().concat([_b]));if(_c){this.anchor=_b;}return _b;},removeTreeNode:function(_d){this.setSelection(this._setDifference(this.getSelectedTreeNodes(),[_d]));return _d;},isTreeNodeSelected:function(_e){return _e.id&&!!this.selection[_e.id];},setSelection:function(_f){var _10=this.getSelectedTreeNodes();_1.forEach(this._setDifference(_10,_f),_4.hitch(this,function(_11){_11.setSelected(false);if(this.anchor==_11){delete this.anchor;}delete this.selection[_11.id];}));_1.forEach(this._setDifference(_f,_10),_4.hitch(this,function(_12){_12.setSelected(true);this.selection[_12.id]=_12;}));this._updateSelectionProperties();},_setDifference:function(xs,ys){_1.forEach(ys,function(y){y.__exclude__=true;});var ret=_1.filter(xs,function(x){return !x.__exclude__;});_1.forEach(ys,function(y){delete y["__exclude__"];});return ret;},_updateSelectionProperties:function(){var _13=this.getSelectedTreeNodes();var _14=[],_15=[];_1.forEach(_13,function(_16){_15.push(_16);_14.push(_16.getTreePath());});var _17=_1.map(_15,function(_18){return _18.item;});this.tree._set("paths",_14);this.tree._set("path",_14[0]||[]);this.tree._set("selectedNodes",_15);this.tree._set("selectedNode",_15[0]||null);this.tree._set("selectedItems",_17);this.tree._set("selectedItem",_17[0]||null);},onMouseDown:function(e){if(!this.current||this.tree.isExpandoNode(e.target,this.current)){return;}if(!_5.isLeft(e)){return;}e.preventDefault();var _19=this.current,_1a=_2.isCopyKey(e),id=_19.id;if(!this.singular&&!e.shiftKey&&this.selection[id]){this._doDeselect=true;return;}else{this._doDeselect=false;}this.userSelect(_19,_1a,e.shiftKey);},onMouseUp:function(e){if(!this._doDeselect){return;}this._doDeselect=false;this.userSelect(this.current,_2.isCopyKey(e),e.shiftKey);},onMouseMove:function(){this._doDeselect=false;},_compareNodes:function(n1,n2){if(n1===n2){return 0;}if("sourceIndex" in document.documentElement){return n1.sourceIndex-n2.sourceIndex;}else{if("compareDocumentPosition" in document.documentElement){return n1.compareDocumentPosition(n2)&2?1:-1;}else{if(document.createRange){var r1=doc.createRange();r1.setStartBefore(n1);var r2=doc.createRange();r2.setStartBefore(n2);return r1.compareBoundaryPoints(r1.END_TO_END,r2);}else{throw Error("dijit.tree._compareNodes don't know how to compare two different nodes in this browser");}}}},userSelect:function(_1b,_1c,_1d){if(this.singular){if(this.anchor==_1b&&_1c){this.selectNone();}else{this.setSelection([_1b]);this.anchor=_1b;}}else{if(_1d&&this.anchor){var cr=this._compareNodes(this.anchor.rowNode,_1b.rowNode),_1e,end,_1f=this.anchor;if(cr<0){_1e=_1f;end=_1b;}else{_1e=_1b;end=_1f;}var _20=[];while(_1e!=end){_20.push(_1e);_1e=this.tree._getNextNode(_1e);}_20.push(end);this.setSelection(_20);}else{if(this.selection[_1b.id]&&_1c){this.removeTreeNode(_1b);}else{if(_1c){this.addTreeNode(_1b,true);}else{this.setSelection([_1b]);this.anchor=_1b;}}}}},getItem:function(key){var _21=this.selection[key];return {data:_21,type:["treeNode"]};},forInSelectedItems:function(f,o){o=o||_7.global;for(var id in this.selection){f.call(o,this.getItem(id),id,this);}}});}); \ No newline at end of file
diff --git a/lib/dijit/tree/_dndSelector.js.uncompressed.js b/lib/dijit/tree/_dndSelector.js.uncompressed.js
new file mode 100644
index 000000000..133ef1924
--- /dev/null
+++ b/lib/dijit/tree/_dndSelector.js.uncompressed.js
@@ -0,0 +1,326 @@
+define("dijit/tree/_dndSelector", [
+ "dojo/_base/array", // array.filter array.forEach array.map
+ "dojo/_base/connect", // connect.isCopyKey
+ "dojo/_base/declare", // declare
+ "dojo/_base/lang", // lang.hitch
+ "dojo/mouse", // mouse.isLeft
+ "dojo/on",
+ "dojo/touch",
+ "dojo/_base/window", // win.global
+ "./_dndContainer"
+], function(array, connect, declare, lang, mouse, on, touch, win, _dndContainer){
+
+ // module:
+ // dijit/tree/_dndSelector
+ // summary:
+ // This is a base class for `dijit.tree.dndSource` , and isn't meant to be used directly.
+ // It's based on `dojo.dnd.Selector`.
+
+
+ return declare("dijit.tree._dndSelector", _dndContainer, {
+ // summary:
+ // This is a base class for `dijit.tree.dndSource` , and isn't meant to be used directly.
+ // It's based on `dojo.dnd.Selector`.
+ // tags:
+ // protected
+
+ /*=====
+ // selection: Hash<String, DomNode>
+ // (id, DomNode) map for every TreeNode that's currently selected.
+ // The DOMNode is the TreeNode.rowNode.
+ selection: {},
+ =====*/
+
+ constructor: function(){
+ // summary:
+ // Initialization
+ // tags:
+ // private
+
+ this.selection={};
+ this.anchor = null;
+
+ this.tree.domNode.setAttribute("aria-multiselect", !this.singular);
+
+ this.events.push(
+ on(this.tree.domNode, touch.press, lang.hitch(this,"onMouseDown")),
+ on(this.tree.domNode, touch.release, lang.hitch(this,"onMouseUp")),
+ on(this.tree.domNode, touch.move, lang.hitch(this,"onMouseMove"))
+ );
+ },
+
+ // singular: Boolean
+ // Allows selection of only one element, if true.
+ // Tree hasn't been tested in singular=true mode, unclear if it works.
+ singular: false,
+
+ // methods
+ getSelectedTreeNodes: function(){
+ // summary:
+ // Returns a list of selected node(s).
+ // Used by dndSource on the start of a drag.
+ // tags:
+ // protected
+ var nodes=[], sel = this.selection;
+ for(var i in sel){
+ nodes.push(sel[i]);
+ }
+ return nodes;
+ },
+
+ selectNone: function(){
+ // summary:
+ // Unselects all items
+ // tags:
+ // private
+
+ this.setSelection([]);
+ return this; // self
+ },
+
+ destroy: function(){
+ // summary:
+ // Prepares the object to be garbage-collected
+ this.inherited(arguments);
+ this.selection = this.anchor = null;
+ },
+ addTreeNode: function(/*dijit._TreeNode*/node, /*Boolean?*/isAnchor){
+ // summary:
+ // add node to current selection
+ // node: Node
+ // node to add
+ // isAnchor: Boolean
+ // Whether the node should become anchor.
+
+ this.setSelection(this.getSelectedTreeNodes().concat( [node] ));
+ if(isAnchor){ this.anchor = node; }
+ return node;
+ },
+ removeTreeNode: function(/*dijit._TreeNode*/node){
+ // summary:
+ // remove node from current selection
+ // node: Node
+ // node to remove
+ this.setSelection(this._setDifference(this.getSelectedTreeNodes(), [node]));
+ return node;
+ },
+ isTreeNodeSelected: function(/*dijit._TreeNode*/node){
+ // summary:
+ // return true if node is currently selected
+ // node: Node
+ // the node to check whether it's in the current selection
+
+ return node.id && !!this.selection[node.id];
+ },
+ setSelection: function(/*dijit._treeNode[]*/ newSelection){
+ // summary:
+ // set the list of selected nodes to be exactly newSelection. All changes to the
+ // selection should be passed through this function, which ensures that derived
+ // attributes are kept up to date. Anchor will be deleted if it has been removed
+ // from the selection, but no new anchor will be added by this function.
+ // newSelection: Node[]
+ // list of tree nodes to make selected
+ var oldSelection = this.getSelectedTreeNodes();
+ array.forEach(this._setDifference(oldSelection, newSelection), lang.hitch(this, function(node){
+ node.setSelected(false);
+ if(this.anchor == node){
+ delete this.anchor;
+ }
+ delete this.selection[node.id];
+ }));
+ array.forEach(this._setDifference(newSelection, oldSelection), lang.hitch(this, function(node){
+ node.setSelected(true);
+ this.selection[node.id] = node;
+ }));
+ this._updateSelectionProperties();
+ },
+ _setDifference: function(xs,ys){
+ // summary:
+ // Returns a copy of xs which lacks any objects
+ // occurring in ys. Checks for membership by
+ // modifying and then reading the object, so it will
+ // not properly handle sets of numbers or strings.
+
+ array.forEach(ys, function(y){ y.__exclude__ = true; });
+ var ret = array.filter(xs, function(x){ return !x.__exclude__; });
+
+ // clean up after ourselves.
+ array.forEach(ys, function(y){ delete y['__exclude__'] });
+ return ret;
+ },
+ _updateSelectionProperties: function(){
+ // summary:
+ // Update the following tree properties from the current selection:
+ // path[s], selectedItem[s], selectedNode[s]
+
+ var selected = this.getSelectedTreeNodes();
+ var paths = [], nodes = [];
+ array.forEach(selected, function(node){
+ nodes.push(node);
+ paths.push(node.getTreePath());
+ });
+ var items = array.map(nodes,function(node){ return node.item; });
+ this.tree._set("paths", paths);
+ this.tree._set("path", paths[0] || []);
+ this.tree._set("selectedNodes", nodes);
+ this.tree._set("selectedNode", nodes[0] || null);
+ this.tree._set("selectedItems", items);
+ this.tree._set("selectedItem", items[0] || null);
+ },
+ // mouse events
+ onMouseDown: function(e){
+ // summary:
+ // Event processor for onmousedown/ontouchstart
+ // e: Event
+ // onmousedown/ontouchstart event
+ // tags:
+ // protected
+
+ // ignore click on expando node
+ if(!this.current || this.tree.isExpandoNode(e.target, this.current)){ return; }
+
+ if(!mouse.isLeft(e)){ return; } // ignore right-click
+
+ e.preventDefault();
+
+ var treeNode = this.current,
+ copy = connect.isCopyKey(e), id = treeNode.id;
+
+ // if shift key is not pressed, and the node is already in the selection,
+ // delay deselection until onmouseup so in the case of DND, deselection
+ // will be canceled by onmousemove.
+ if(!this.singular && !e.shiftKey && this.selection[id]){
+ this._doDeselect = true;
+ return;
+ }else{
+ this._doDeselect = false;
+ }
+ this.userSelect(treeNode, copy, e.shiftKey);
+ },
+
+ onMouseUp: function(e){
+ // summary:
+ // Event processor for onmouseup/ontouchend
+ // e: Event
+ // onmouseup/ontouchend event
+ // tags:
+ // protected
+
+ // _doDeselect is the flag to indicate that the user wants to either ctrl+click on
+ // a already selected item (to deselect the item), or click on a not-yet selected item
+ // (which should remove all current selection, and add the clicked item). This can not
+ // be done in onMouseDown, because the user may start a drag after mousedown. By moving
+ // the deselection logic here, the user can drags an already selected item.
+ if(!this._doDeselect){ return; }
+ this._doDeselect = false;
+ this.userSelect(this.current, connect.isCopyKey(e), e.shiftKey);
+ },
+ onMouseMove: function(/*===== e =====*/){
+ // summary:
+ // event processor for onmousemove/ontouchmove
+ // e: Event
+ // onmousemove/ontouchmove event
+ this._doDeselect = false;
+ },
+
+ _compareNodes: function(n1, n2){
+ if(n1 === n2){
+ return 0;
+ }
+
+ if('sourceIndex' in document.documentElement){ //IE
+ //TODO: does not yet work if n1 and/or n2 is a text node
+ return n1.sourceIndex - n2.sourceIndex;
+ }else if('compareDocumentPosition' in document.documentElement){ //FF, Opera
+ return n1.compareDocumentPosition(n2) & 2 ? 1: -1;
+ }else if(document.createRange){ //Webkit
+ var r1 = doc.createRange();
+ r1.setStartBefore(n1);
+
+ var r2 = doc.createRange();
+ r2.setStartBefore(n2);
+
+ return r1.compareBoundaryPoints(r1.END_TO_END, r2);
+ }else{
+ throw Error("dijit.tree._compareNodes don't know how to compare two different nodes in this browser");
+ }
+ },
+
+ userSelect: function(node, multi, range){
+ // summary:
+ // Add or remove the given node from selection, responding
+ // to a user action such as a click or keypress.
+ // multi: Boolean
+ // Indicates whether this is meant to be a multi-select action (e.g. ctrl-click)
+ // range: Boolean
+ // Indicates whether this is meant to be a ranged action (e.g. shift-click)
+ // tags:
+ // protected
+
+ if(this.singular){
+ if(this.anchor == node && multi){
+ this.selectNone();
+ }else{
+ this.setSelection([node]);
+ this.anchor = node;
+ }
+ }else{
+ if(range && this.anchor){
+ var cr = this._compareNodes(this.anchor.rowNode, node.rowNode),
+ begin, end, anchor = this.anchor;
+
+ if(cr < 0){ //current is after anchor
+ begin = anchor;
+ end = node;
+ }else{ //current is before anchor
+ begin = node;
+ end = anchor;
+ }
+ var nodes = [];
+ //add everything betweeen begin and end inclusively
+ while(begin != end){
+ nodes.push(begin);
+ begin = this.tree._getNextNode(begin);
+ }
+ nodes.push(end);
+
+ this.setSelection(nodes);
+ }else{
+ if( this.selection[ node.id ] && multi ){
+ this.removeTreeNode( node );
+ }else if(multi){
+ this.addTreeNode(node, true);
+ }else{
+ this.setSelection([node]);
+ this.anchor = node;
+ }
+ }
+ }
+ },
+
+ getItem: function(/*String*/ key){
+ // summary:
+ // Returns the dojo.dnd.Item (representing a dragged node) by it's key (id).
+ // Called by dojo.dnd.Source.checkAcceptance().
+ // tags:
+ // protected
+
+ var widget = this.selection[key];
+ return {
+ data: widget,
+ type: ["treeNode"]
+ }; // dojo.dnd.Item
+ },
+
+ forInSelectedItems: function(/*Function*/ f, /*Object?*/ o){
+ // summary:
+ // Iterates over selected items;
+ // see `dojo.dnd.Container.forInItems()` for details
+ o = o || win.global;
+ for(var id in this.selection){
+ // console.log("selected item id: " + id);
+ f.call(o, this.getItem(id), id, this);
+ }
+ }
+ });
+});
diff --git a/lib/dijit/tree/dndSource.js b/lib/dijit/tree/dndSource.js
index 4fc4660cc..a68af56c4 100644
--- a/lib/dijit/tree/dndSource.js
+++ b/lib/dijit/tree/dndSource.js
@@ -1,544 +1,2 @@
-/*
- Copyright (c) 2004-2011, The Dojo Foundation All Rights Reserved.
- Available via Academic Free License >= 2.1 OR the modified BSD license.
- see: http://dojotoolkit.org/license for details
-*/
-
-
-if(!dojo._hasResource["dijit.tree.dndSource"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
-dojo._hasResource["dijit.tree.dndSource"] = true;
-dojo.provide("dijit.tree.dndSource");
-dojo.require("dijit.tree._dndSelector");
-dojo.require("dojo.dnd.Manager");
-
-
-/*=====
-dijit.tree.__SourceArgs = function(){
- // summary:
- // A dict of parameters for Tree source configuration.
- // isSource: Boolean?
- // Can be used as a DnD source. Defaults to true.
- // accept: String[]
- // List of accepted types (text strings) for a target; defaults to
- // ["text", "treeNode"]
- // copyOnly: Boolean?
- // Copy items, if true, use a state of Ctrl key otherwise,
- // dragThreshold: Number
- // The move delay in pixels before detecting a drag; 0 by default
- // betweenThreshold: Integer
- // Distance from upper/lower edge of node to allow drop to reorder nodes
- this.isSource = isSource;
- this.accept = accept;
- this.autoSync = autoSync;
- this.copyOnly = copyOnly;
- this.dragThreshold = dragThreshold;
- this.betweenThreshold = betweenThreshold;
-}
-=====*/
-
-dojo.declare("dijit.tree.dndSource", dijit.tree._dndSelector, {
- // summary:
- // Handles drag and drop operations (as a source or a target) for `dijit.Tree`
-
- // isSource: [private] Boolean
- // Can be used as a DnD source.
- isSource: true,
-
- // accept: String[]
- // List of accepted types (text strings) for the Tree; defaults to
- // ["text"]
- accept: ["text", "treeNode"],
-
- // copyOnly: [private] Boolean
- // Copy items, if true, use a state of Ctrl key otherwise
- copyOnly: false,
-
- // dragThreshold: Number
- // The move delay in pixels before detecting a drag; 5 by default
- dragThreshold: 5,
-
- // betweenThreshold: Integer
- // Distance from upper/lower edge of node to allow drop to reorder nodes
- betweenThreshold: 0,
-
- constructor: function(/*dijit.Tree*/ tree, /*dijit.tree.__SourceArgs*/ params){
- // summary:
- // a constructor of the Tree DnD Source
- // tags:
- // private
- if(!params){ params = {}; }
- dojo.mixin(this, params);
- this.isSource = typeof params.isSource == "undefined" ? true : params.isSource;
- var type = params.accept instanceof Array ? params.accept : ["text", "treeNode"];
- this.accept = null;
- if(type.length){
- this.accept = {};
- for(var i = 0; i < type.length; ++i){
- this.accept[type[i]] = 1;
- }
- }
-
- // class-specific variables
- this.isDragging = false;
- this.mouseDown = false;
- this.targetAnchor = null; // DOMNode corresponding to the currently moused over TreeNode
- this.targetBox = null; // coordinates of this.targetAnchor
- this.dropPosition = ""; // whether mouse is over/after/before this.targetAnchor
- this._lastX = 0;
- this._lastY = 0;
-
- // states
- this.sourceState = "";
- if(this.isSource){
- dojo.addClass(this.node, "dojoDndSource");
- }
- this.targetState = "";
- if(this.accept){
- dojo.addClass(this.node, "dojoDndTarget");
- }
-
- // set up events
- this.topics = [
- dojo.subscribe("/dnd/source/over", this, "onDndSourceOver"),
- dojo.subscribe("/dnd/start", this, "onDndStart"),
- dojo.subscribe("/dnd/drop", this, "onDndDrop"),
- dojo.subscribe("/dnd/cancel", this, "onDndCancel")
- ];
- },
-
- // methods
- checkAcceptance: function(source, nodes){
- // summary:
- // Checks if the target can accept nodes from this source
- // source: dijit.tree.dndSource
- // The source which provides items
- // nodes: DOMNode[]
- // Array of DOM nodes corresponding to nodes being dropped, dijitTreeRow nodes if
- // source is a dijit.Tree.
- // tags:
- // extension
- return true; // Boolean
- },
-
- copyState: function(keyPressed){
- // summary:
- // Returns true, if we need to copy items, false to move.
- // It is separated to be overwritten dynamically, if needed.
- // keyPressed: Boolean
- // The "copy" control key was pressed
- // tags:
- // protected
- return this.copyOnly || keyPressed; // Boolean
- },
- destroy: function(){
- // summary:
- // Prepares the object to be garbage-collected.
- this.inherited("destroy",arguments);
- dojo.forEach(this.topics, dojo.unsubscribe);
- this.targetAnchor = null;
- },
-
- _onDragMouse: function(e){
- // summary:
- // Helper method for processing onmousemove/onmouseover events while drag is in progress.
- // Keeps track of current drop target.
-
- var m = dojo.dnd.manager(),
- oldTarget = this.targetAnchor, // the TreeNode corresponding to TreeNode mouse was previously over
- newTarget = this.current, // TreeNode corresponding to TreeNode mouse is currently over
- oldDropPosition = this.dropPosition; // the previous drop position (over/before/after)
-
- // calculate if user is indicating to drop the dragged node before, after, or over
- // (i.e., to become a child of) the target node
- var newDropPosition = "Over";
- if(newTarget && this.betweenThreshold > 0){
- // If mouse is over a new TreeNode, then get new TreeNode's position and size
- if(!this.targetBox || oldTarget != newTarget){
- this.targetBox = dojo.position(newTarget.rowNode, true);
- }
- if((e.pageY - this.targetBox.y) <= this.betweenThreshold){
- newDropPosition = "Before";
- }else if((e.pageY - this.targetBox.y) >= (this.targetBox.h - this.betweenThreshold)){
- newDropPosition = "After";
- }
- }
-
- if(newTarget != oldTarget || newDropPosition != oldDropPosition){
- if(oldTarget){
- this._removeItemClass(oldTarget.rowNode, oldDropPosition);
- }
- if(newTarget){
- this._addItemClass(newTarget.rowNode, newDropPosition);
- }
-
- // Check if it's ok to drop the dragged node on/before/after the target node.
- if(!newTarget){
- m.canDrop(false);
- }else if(newTarget == this.tree.rootNode && newDropPosition != "Over"){
- // Can't drop before or after tree's root node; the dropped node would just disappear (at least visually)
- m.canDrop(false);
- }else if(m.source == this && (newTarget.id in this.selection)){
- // Guard against dropping onto yourself (TODO: guard against dropping onto your descendant, #7140)
- m.canDrop(false);
- }else if(this.checkItemAcceptance(newTarget.rowNode, m.source, newDropPosition.toLowerCase())
- && !this._isParentChildDrop(m.source, newTarget.rowNode)){
- m.canDrop(true);
- }else{
- m.canDrop(false);
- }
-
- this.targetAnchor = newTarget;
- this.dropPosition = newDropPosition;
- }
- },
-
- onMouseMove: function(e){
- // summary:
- // Called for any onmousemove events over the Tree
- // e: Event
- // onmousemouse event
- // tags:
- // private
- if(this.isDragging && this.targetState == "Disabled"){ return; }
- this.inherited(arguments);
- var m = dojo.dnd.manager();
- if(this.isDragging){
- this._onDragMouse(e);
- }else{
- if(this.mouseDown && this.isSource &&
- (Math.abs(e.pageX-this._lastX)>=this.dragThreshold || Math.abs(e.pageY-this._lastY)>=this.dragThreshold)){
- var nodes = this.getSelectedTreeNodes();
- if(nodes.length){
- if(nodes.length > 1){
- //filter out all selected items which has one of their ancestor selected as well
- var seen = this.selection, i = 0, r = [], n, p;
- nextitem: while((n = nodes[i++])){
- for(p = n.getParent(); p && p !== this.tree; p = p.getParent()){
- if(seen[p.id]){ //parent is already selected, skip this node
- continue nextitem;
- }
- }
- //this node does not have any ancestors selected, add it
- r.push(n);
- }
- nodes = r;
- }
- nodes = dojo.map(nodes, function(n){return n.domNode});
- m.startDrag(this, nodes, this.copyState(dojo.isCopyKey(e)));
- }
- }
- }
- },
-
- onMouseDown: function(e){
- // summary:
- // Event processor for onmousedown
- // e: Event
- // onmousedown event
- // tags:
- // private
- this.mouseDown = true;
- this.mouseButton = e.button;
- this._lastX = e.pageX;
- this._lastY = e.pageY;
- this.inherited(arguments);
- },
-
- onMouseUp: function(e){
- // summary:
- // Event processor for onmouseup
- // e: Event
- // onmouseup event
- // tags:
- // private
- if(this.mouseDown){
- this.mouseDown = false;
- this.inherited(arguments);
- }
- },
-
- onMouseOut: function(){
- // summary:
- // Event processor for when mouse is moved away from a TreeNode
- // tags:
- // private
- this.inherited(arguments);
- this._unmarkTargetAnchor();
- },
-
- checkItemAcceptance: function(target, source, position){
- // summary:
- // Stub function to be overridden if one wants to check for the ability to drop at the node/item level
- // description:
- // In the base case, this is called to check if target can become a child of source.
- // When betweenThreshold is set, position="before" or "after" means that we
- // are asking if the source node can be dropped before/after the target node.
- // target: DOMNode
- // The dijitTreeRoot DOM node inside of the TreeNode that we are dropping on to
- // Use dijit.getEnclosingWidget(target) to get the TreeNode.
- // source: dijit.tree.dndSource
- // The (set of) nodes we are dropping
- // position: String
- // "over", "before", or "after"
- // tags:
- // extension
- return true;
- },
-
- // topic event processors
- onDndSourceOver: function(source){
- // summary:
- // Topic event processor for /dnd/source/over, called when detected a current source.
- // source: Object
- // The dijit.tree.dndSource / dojo.dnd.Source which has the mouse over it
- // tags:
- // private
- if(this != source){
- this.mouseDown = false;
- this._unmarkTargetAnchor();
- }else if(this.isDragging){
- var m = dojo.dnd.manager();
- m.canDrop(false);
- }
- },
- onDndStart: function(source, nodes, copy){
- // summary:
- // Topic event processor for /dnd/start, called to initiate the DnD operation
- // source: Object
- // The dijit.tree.dndSource / dojo.dnd.Source which is providing the items
- // nodes: DomNode[]
- // The list of transferred items, dndTreeNode nodes if dragging from a Tree
- // copy: Boolean
- // Copy items, if true, move items otherwise
- // tags:
- // private
-
- if(this.isSource){
- this._changeState("Source", this == source ? (copy ? "Copied" : "Moved") : "");
- }
- var accepted = this.checkAcceptance(source, nodes);
-
- this._changeState("Target", accepted ? "" : "Disabled");
-
- if(this == source){
- dojo.dnd.manager().overSource(this);
- }
-
- this.isDragging = true;
- },
-
- itemCreator: function(/*DomNode[]*/ nodes, target, /*dojo.dnd.Source*/ source){
- // summary:
- // Returns objects passed to `Tree.model.newItem()` based on DnD nodes
- // dropped onto the tree. Developer must override this method to enable
- // dropping from external sources onto this Tree, unless the Tree.model's items
- // happen to look like {id: 123, name: "Apple" } with no other attributes.
- // description:
- // For each node in nodes[], which came from source, create a hash of name/value
- // pairs to be passed to Tree.model.newItem(). Returns array of those hashes.
- // returns: Object[]
- // Array of name/value hashes for each new item to be added to the Tree, like:
- // | [
- // | { id: 123, label: "apple", foo: "bar" },
- // | { id: 456, label: "pear", zaz: "bam" }
- // | ]
- // tags:
- // extension
-
- // TODO: for 2.0 refactor so itemCreator() is called once per drag node, and
- // make signature itemCreator(sourceItem, node, target) (or similar).
-
- return dojo.map(nodes, function(node){
- return {
- "id": node.id,
- "name": node.textContent || node.innerText || ""
- };
- }); // Object[]
- },
-
- onDndDrop: function(source, nodes, copy){
- // summary:
- // Topic event processor for /dnd/drop, called to finish the DnD operation.
- // description:
- // Updates data store items according to where node was dragged from and dropped
- // to. The tree will then respond to those data store updates and redraw itself.
- // source: Object
- // The dijit.tree.dndSource / dojo.dnd.Source which is providing the items
- // nodes: DomNode[]
- // The list of transferred items, dndTreeNode nodes if dragging from a Tree
- // copy: Boolean
- // Copy items, if true, move items otherwise
- // tags:
- // protected
- if(this.containerState == "Over"){
- var tree = this.tree,
- model = tree.model,
- target = this.targetAnchor,
- requeryRoot = false; // set to true iff top level items change
-
- this.isDragging = false;
-
- // Compute the new parent item
- var targetWidget = target;
- var newParentItem;
- var insertIndex;
- newParentItem = (targetWidget && targetWidget.item) || tree.item;
- if(this.dropPosition == "Before" || this.dropPosition == "After"){
- // TODO: if there is no parent item then disallow the drop.
- // Actually this should be checked during onMouseMove too, to make the drag icon red.
- newParentItem = (targetWidget.getParent() && targetWidget.getParent().item) || tree.item;
- // Compute the insert index for reordering
- insertIndex = targetWidget.getIndexInParent();
- if(this.dropPosition == "After"){
- insertIndex = targetWidget.getIndexInParent() + 1;
- }
- }else{
- newParentItem = (targetWidget && targetWidget.item) || tree.item;
- }
-
- // If necessary, use this variable to hold array of hashes to pass to model.newItem()
- // (one entry in the array for each dragged node).
- var newItemsParams;
-
- dojo.forEach(nodes, function(node, idx){
- // dojo.dnd.Item representing the thing being dropped.
- // Don't confuse the use of item here (meaning a DnD item) with the
- // uses below where item means dojo.data item.
- var sourceItem = source.getItem(node.id);
-
- // Information that's available if the source is another Tree
- // (possibly but not necessarily this tree, possibly but not
- // necessarily the same model as this Tree)
- if(dojo.indexOf(sourceItem.type, "treeNode") != -1){
- var childTreeNode = sourceItem.data,
- childItem = childTreeNode.item,
- oldParentItem = childTreeNode.getParent().item;
- }
-
- if(source == this){
- // This is a node from my own tree, and we are moving it, not copying.
- // Remove item from old parent's children attribute.
- // TODO: dijit.tree.dndSelector should implement deleteSelectedNodes()
- // and this code should go there.
-
- if(typeof insertIndex == "number"){
- if(newParentItem == oldParentItem && childTreeNode.getIndexInParent() < insertIndex){
- insertIndex -= 1;
- }
- }
- model.pasteItem(childItem, oldParentItem, newParentItem, copy, insertIndex);
- }else if(model.isItem(childItem)){
- // Item from same model
- // (maybe we should only do this branch if the source is a tree?)
- model.pasteItem(childItem, oldParentItem, newParentItem, copy, insertIndex);
- }else{
- // Get the hash to pass to model.newItem(). A single call to
- // itemCreator() returns an array of hashes, one for each drag source node.
- if(!newItemsParams){
- newItemsParams = this.itemCreator(nodes, target.rowNode, source);
- }
-
- // Create new item in the tree, based on the drag source.
- model.newItem(newItemsParams[idx], newParentItem, insertIndex);
- }
- }, this);
-
- // Expand the target node (if it's currently collapsed) so the user can see
- // where their node was dropped. In particular since that node is still selected.
- this.tree._expandNode(targetWidget);
- }
- this.onDndCancel();
- },
-
- onDndCancel: function(){
- // summary:
- // Topic event processor for /dnd/cancel, called to cancel the DnD operation
- // tags:
- // private
- this._unmarkTargetAnchor();
- this.isDragging = false;
- this.mouseDown = false;
- delete this.mouseButton;
- this._changeState("Source", "");
- this._changeState("Target", "");
- },
-
- // When focus moves in/out of the entire Tree
- onOverEvent: function(){
- // summary:
- // This method is called when mouse is moved over our container (like onmouseenter)
- // tags:
- // private
- this.inherited(arguments);
- dojo.dnd.manager().overSource(this);
- },
- onOutEvent: function(){
- // summary:
- // This method is called when mouse is moved out of our container (like onmouseleave)
- // tags:
- // private
- this._unmarkTargetAnchor();
- var m = dojo.dnd.manager();
- if(this.isDragging){
- m.canDrop(false);
- }
- m.outSource(this);
-
- this.inherited(arguments);
- },
-
- _isParentChildDrop: function(source, targetRow){
- // summary:
- // Checks whether the dragged items are parent rows in the tree which are being
- // dragged into their own children.
- //
- // source:
- // The DragSource object.
- //
- // targetRow:
- // The tree row onto which the dragged nodes are being dropped.
- //
- // tags:
- // private
-
- // If the dragged object is not coming from the tree this widget belongs to,
- // it cannot be invalid.
- if(!source.tree || source.tree != this.tree){
- return false;
- }
-
-
- var root = source.tree.domNode;
- var ids = source.selection;
-
- var node = targetRow.parentNode;
-
- // Iterate up the DOM hierarchy from the target drop row,
- // checking of any of the dragged nodes have the same ID.
- while(node != root && !ids[node.id]){
- node = node.parentNode;
- }
-
- return node.id && ids[node.id];
- },
-
- _unmarkTargetAnchor: function(){
- // summary:
- // Removes hover class of the current target anchor
- // tags:
- // private
- if(!this.targetAnchor){ return; }
- this._removeItemClass(this.targetAnchor.rowNode, this.dropPosition);
- this.targetAnchor = null;
- this.targetBox = null;
- this.dropPosition = null;
- },
-
- _markDndStatus: function(copy){
- // summary:
- // Changes source's state based on "copy" status
- this._changeState("Source", copy ? "Copied" : "Moved");
- }
-});
-
-}
+//>>built
+define("dijit/tree/dndSource",["dojo/_base/array","dojo/_base/connect","dojo/_base/declare","dojo/dom-class","dojo/dom-geometry","dojo/_base/lang","dojo/on","dojo/touch","dojo/topic","dojo/dnd/Manager","./_dndSelector"],function(_1,_2,_3,_4,_5,_6,on,_7,_8,_9,_a){return _3("dijit.tree.dndSource",_a,{isSource:true,accept:["text","treeNode"],copyOnly:false,dragThreshold:5,betweenThreshold:0,constructor:function(_b,_c){if(!_c){_c={};}_6.mixin(this,_c);this.isSource=typeof _c.isSource=="undefined"?true:_c.isSource;var _d=_c.accept instanceof Array?_c.accept:["text","treeNode"];this.accept=null;if(_d.length){this.accept={};for(var i=0;i<_d.length;++i){this.accept[_d[i]]=1;}}this.isDragging=false;this.mouseDown=false;this.targetAnchor=null;this.targetBox=null;this.dropPosition="";this._lastX=0;this._lastY=0;this.sourceState="";if(this.isSource){_4.add(this.node,"dojoDndSource");}this.targetState="";if(this.accept){_4.add(this.node,"dojoDndTarget");}this.topics=[_8.subscribe("/dnd/source/over",_6.hitch(this,"onDndSourceOver")),_8.subscribe("/dnd/start",_6.hitch(this,"onDndStart")),_8.subscribe("/dnd/drop",_6.hitch(this,"onDndDrop")),_8.subscribe("/dnd/cancel",_6.hitch(this,"onDndCancel"))];},checkAcceptance:function(){return true;},copyState:function(_e){return this.copyOnly||_e;},destroy:function(){this.inherited(arguments);var h;while(h=this.topics.pop()){h.remove();}this.targetAnchor=null;},_onDragMouse:function(e){var m=_9.manager(),_f=this.targetAnchor,_10=this.current,_11=this.dropPosition;var _12="Over";if(_10&&this.betweenThreshold>0){if(!this.targetBox||_f!=_10){this.targetBox=_5.position(_10.rowNode,true);}if((e.pageY-this.targetBox.y)<=this.betweenThreshold){_12="Before";}else{if((e.pageY-this.targetBox.y)>=(this.targetBox.h-this.betweenThreshold)){_12="After";}}}if(_10!=_f||_12!=_11){if(_f){this._removeItemClass(_f.rowNode,_11);}if(_10){this._addItemClass(_10.rowNode,_12);}if(!_10){m.canDrop(false);}else{if(_10==this.tree.rootNode&&_12!="Over"){m.canDrop(false);}else{var _13=this.tree.model,_14=false;if(m.source==this){for(var _15 in this.selection){var _16=this.selection[_15];if(_16.item===_10.item){_14=true;break;}}}if(_14){m.canDrop(false);}else{if(this.checkItemAcceptance(_10.rowNode,m.source,_12.toLowerCase())&&!this._isParentChildDrop(m.source,_10.rowNode)){m.canDrop(true);}else{m.canDrop(false);}}}}this.targetAnchor=_10;this.dropPosition=_12;}},onMouseMove:function(e){if(this.isDragging&&this.targetState=="Disabled"){return;}this.inherited(arguments);var m=_9.manager();if(this.isDragging){this._onDragMouse(e);}else{if(this.mouseDown&&this.isSource&&(Math.abs(e.pageX-this._lastX)>=this.dragThreshold||Math.abs(e.pageY-this._lastY)>=this.dragThreshold)){var _17=this.getSelectedTreeNodes();if(_17.length){if(_17.length>1){var _18=this.selection,i=0,r=[],n,p;nextitem:while((n=_17[i++])){for(p=n.getParent();p&&p!==this.tree;p=p.getParent()){if(_18[p.id]){continue nextitem;}}r.push(n);}_17=r;}_17=_1.map(_17,function(n){return n.domNode;});m.startDrag(this,_17,this.copyState(_2.isCopyKey(e)));}}}},onMouseDown:function(e){this.mouseDown=true;this.mouseButton=e.button;this._lastX=e.pageX;this._lastY=e.pageY;this.inherited(arguments);},onMouseUp:function(e){if(this.mouseDown){this.mouseDown=false;this.inherited(arguments);}},onMouseOut:function(){this.inherited(arguments);this._unmarkTargetAnchor();},checkItemAcceptance:function(){return true;},onDndSourceOver:function(_19){if(this!=_19){this.mouseDown=false;this._unmarkTargetAnchor();}else{if(this.isDragging){var m=_9.manager();m.canDrop(false);}}},onDndStart:function(_1a,_1b,_1c){if(this.isSource){this._changeState("Source",this==_1a?(_1c?"Copied":"Moved"):"");}var _1d=this.checkAcceptance(_1a,_1b);this._changeState("Target",_1d?"":"Disabled");if(this==_1a){_9.manager().overSource(this);}this.isDragging=true;},itemCreator:function(_1e){return _1.map(_1e,function(_1f){return {"id":_1f.id,"name":_1f.textContent||_1f.innerText||""};});},onDndDrop:function(_20,_21,_22){if(this.containerState=="Over"){var _23=this.tree,_24=_23.model,_25=this.targetAnchor;this.isDragging=false;var _26;var _27;_26=(_25&&_25.item)||_23.item;if(this.dropPosition=="Before"||this.dropPosition=="After"){_26=(_25.getParent()&&_25.getParent().item)||_23.item;_27=_25.getIndexInParent();if(this.dropPosition=="After"){_27=_25.getIndexInParent()+1;}}else{_26=(_25&&_25.item)||_23.item;}var _28;_1.forEach(_21,function(_29,idx){var _2a=_20.getItem(_29.id);if(_1.indexOf(_2a.type,"treeNode")!=-1){var _2b=_2a.data,_2c=_2b.item,_2d=_2b.getParent().item;}if(_20==this){if(typeof _27=="number"){if(_26==_2d&&_2b.getIndexInParent()<_27){_27-=1;}}_24.pasteItem(_2c,_2d,_26,_22,_27);}else{if(_24.isItem(_2c)){_24.pasteItem(_2c,_2d,_26,_22,_27);}else{if(!_28){_28=this.itemCreator(_21,_25.rowNode,_20);}_24.newItem(_28[idx],_26,_27);}}},this);this.tree._expandNode(_25);}this.onDndCancel();},onDndCancel:function(){this._unmarkTargetAnchor();this.isDragging=false;this.mouseDown=false;delete this.mouseButton;this._changeState("Source","");this._changeState("Target","");},onOverEvent:function(){this.inherited(arguments);_9.manager().overSource(this);},onOutEvent:function(){this._unmarkTargetAnchor();var m=_9.manager();if(this.isDragging){m.canDrop(false);}m.outSource(this);this.inherited(arguments);},_isParentChildDrop:function(_2e,_2f){if(!_2e.tree||_2e.tree!=this.tree){return false;}var _30=_2e.tree.domNode;var ids=_2e.selection;var _31=_2f.parentNode;while(_31!=_30&&!ids[_31.id]){_31=_31.parentNode;}return _31.id&&ids[_31.id];},_unmarkTargetAnchor:function(){if(!this.targetAnchor){return;}this._removeItemClass(this.targetAnchor.rowNode,this.dropPosition);this.targetAnchor=null;this.targetBox=null;this.dropPosition=null;},_markDndStatus:function(_32){this._changeState("Source",_32?"Copied":"Moved");}});}); \ No newline at end of file
diff --git a/lib/dijit/tree/dndSource.js.uncompressed.js b/lib/dijit/tree/dndSource.js.uncompressed.js
new file mode 100644
index 000000000..d161e369f
--- /dev/null
+++ b/lib/dijit/tree/dndSource.js.uncompressed.js
@@ -0,0 +1,564 @@
+define("dijit/tree/dndSource", [
+ "dojo/_base/array", // array.forEach array.indexOf array.map
+ "dojo/_base/connect", // isCopyKey
+ "dojo/_base/declare", // declare
+ "dojo/dom-class", // domClass.add
+ "dojo/dom-geometry", // domGeometry.position
+ "dojo/_base/lang", // lang.mixin lang.hitch
+ "dojo/on", // subscribe
+ "dojo/touch",
+ "dojo/topic",
+ "dojo/dnd/Manager", // DNDManager.manager
+ "./_dndSelector"
+], function(array, connect, declare, domClass, domGeometry, lang, on, touch, topic, DNDManager, _dndSelector){
+
+// module:
+// dijit/tree/dndSource
+// summary:
+// Handles drag and drop operations (as a source or a target) for `dijit.Tree`
+
+/*=====
+dijit.tree.__SourceArgs = function(){
+ // summary:
+ // A dict of parameters for Tree source configuration.
+ // isSource: Boolean?
+ // Can be used as a DnD source. Defaults to true.
+ // accept: String[]
+ // List of accepted types (text strings) for a target; defaults to
+ // ["text", "treeNode"]
+ // copyOnly: Boolean?
+ // Copy items, if true, use a state of Ctrl key otherwise,
+ // dragThreshold: Number
+ // The move delay in pixels before detecting a drag; 0 by default
+ // betweenThreshold: Integer
+ // Distance from upper/lower edge of node to allow drop to reorder nodes
+ this.isSource = isSource;
+ this.accept = accept;
+ this.autoSync = autoSync;
+ this.copyOnly = copyOnly;
+ this.dragThreshold = dragThreshold;
+ this.betweenThreshold = betweenThreshold;
+}
+=====*/
+
+return declare("dijit.tree.dndSource", _dndSelector, {
+ // summary:
+ // Handles drag and drop operations (as a source or a target) for `dijit.Tree`
+
+ // isSource: [private] Boolean
+ // Can be used as a DnD source.
+ isSource: true,
+
+ // accept: String[]
+ // List of accepted types (text strings) for the Tree; defaults to
+ // ["text"]
+ accept: ["text", "treeNode"],
+
+ // copyOnly: [private] Boolean
+ // Copy items, if true, use a state of Ctrl key otherwise
+ copyOnly: false,
+
+ // dragThreshold: Number
+ // The move delay in pixels before detecting a drag; 5 by default
+ dragThreshold: 5,
+
+ // betweenThreshold: Integer
+ // Distance from upper/lower edge of node to allow drop to reorder nodes
+ betweenThreshold: 0,
+
+ constructor: function(/*dijit.Tree*/ tree, /*dijit.tree.__SourceArgs*/ params){
+ // summary:
+ // a constructor of the Tree DnD Source
+ // tags:
+ // private
+ if(!params){ params = {}; }
+ lang.mixin(this, params);
+ this.isSource = typeof params.isSource == "undefined" ? true : params.isSource;
+ var type = params.accept instanceof Array ? params.accept : ["text", "treeNode"];
+ this.accept = null;
+ if(type.length){
+ this.accept = {};
+ for(var i = 0; i < type.length; ++i){
+ this.accept[type[i]] = 1;
+ }
+ }
+
+ // class-specific variables
+ this.isDragging = false;
+ this.mouseDown = false;
+ this.targetAnchor = null; // DOMNode corresponding to the currently moused over TreeNode
+ this.targetBox = null; // coordinates of this.targetAnchor
+ this.dropPosition = ""; // whether mouse is over/after/before this.targetAnchor
+ this._lastX = 0;
+ this._lastY = 0;
+
+ // states
+ this.sourceState = "";
+ if(this.isSource){
+ domClass.add(this.node, "dojoDndSource");
+ }
+ this.targetState = "";
+ if(this.accept){
+ domClass.add(this.node, "dojoDndTarget");
+ }
+
+ // set up events
+ this.topics = [
+ topic.subscribe("/dnd/source/over", lang.hitch(this, "onDndSourceOver")),
+ topic.subscribe("/dnd/start", lang.hitch(this, "onDndStart")),
+ topic.subscribe("/dnd/drop", lang.hitch(this, "onDndDrop")),
+ topic.subscribe("/dnd/cancel", lang.hitch(this, "onDndCancel"))
+ ];
+ },
+
+ // methods
+ checkAcceptance: function(/*===== source, nodes =====*/){
+ // summary:
+ // Checks if the target can accept nodes from this source
+ // source: dijit.tree.dndSource
+ // The source which provides items
+ // nodes: DOMNode[]
+ // Array of DOM nodes corresponding to nodes being dropped, dijitTreeRow nodes if
+ // source is a dijit.Tree.
+ // tags:
+ // extension
+ return true; // Boolean
+ },
+
+ copyState: function(keyPressed){
+ // summary:
+ // Returns true, if we need to copy items, false to move.
+ // It is separated to be overwritten dynamically, if needed.
+ // keyPressed: Boolean
+ // The "copy" control key was pressed
+ // tags:
+ // protected
+ return this.copyOnly || keyPressed; // Boolean
+ },
+ destroy: function(){
+ // summary:
+ // Prepares the object to be garbage-collected.
+ this.inherited(arguments);
+ var h;
+ while(h = this.topics.pop()){ h.remove(); }
+ this.targetAnchor = null;
+ },
+
+ _onDragMouse: function(e){
+ // summary:
+ // Helper method for processing onmousemove/onmouseover events while drag is in progress.
+ // Keeps track of current drop target.
+
+ var m = DNDManager.manager(),
+ oldTarget = this.targetAnchor, // the TreeNode corresponding to TreeNode mouse was previously over
+ newTarget = this.current, // TreeNode corresponding to TreeNode mouse is currently over
+ oldDropPosition = this.dropPosition; // the previous drop position (over/before/after)
+
+ // calculate if user is indicating to drop the dragged node before, after, or over
+ // (i.e., to become a child of) the target node
+ var newDropPosition = "Over";
+ if(newTarget && this.betweenThreshold > 0){
+ // If mouse is over a new TreeNode, then get new TreeNode's position and size
+ if(!this.targetBox || oldTarget != newTarget){
+ this.targetBox = domGeometry.position(newTarget.rowNode, true);
+ }
+ if((e.pageY - this.targetBox.y) <= this.betweenThreshold){
+ newDropPosition = "Before";
+ }else if((e.pageY - this.targetBox.y) >= (this.targetBox.h - this.betweenThreshold)){
+ newDropPosition = "After";
+ }
+ }
+
+ if(newTarget != oldTarget || newDropPosition != oldDropPosition){
+ if(oldTarget){
+ this._removeItemClass(oldTarget.rowNode, oldDropPosition);
+ }
+ if(newTarget){
+ this._addItemClass(newTarget.rowNode, newDropPosition);
+ }
+
+ // Check if it's ok to drop the dragged node on/before/after the target node.
+ if(!newTarget){
+ m.canDrop(false);
+ }else if(newTarget == this.tree.rootNode && newDropPosition != "Over"){
+ // Can't drop before or after tree's root node; the dropped node would just disappear (at least visually)
+ m.canDrop(false);
+ }else{
+ // Guard against dropping onto yourself (TODO: guard against dropping onto your descendant, #7140)
+ var model = this.tree.model,
+ sameId = false;
+ if(m.source == this){
+ for(var dragId in this.selection){
+ var dragNode = this.selection[dragId];
+ if(dragNode.item === newTarget.item){
+ sameId = true;
+ break;
+ }
+ }
+ }
+ if(sameId){
+ m.canDrop(false);
+ }else if(this.checkItemAcceptance(newTarget.rowNode, m.source, newDropPosition.toLowerCase())
+ && !this._isParentChildDrop(m.source, newTarget.rowNode)){
+ m.canDrop(true);
+ }else{
+ m.canDrop(false);
+ }
+ }
+
+ this.targetAnchor = newTarget;
+ this.dropPosition = newDropPosition;
+ }
+ },
+
+ onMouseMove: function(e){
+ // summary:
+ // Called for any onmousemove/ontouchmove events over the Tree
+ // e: Event
+ // onmousemouse/ontouchmove event
+ // tags:
+ // private
+ if(this.isDragging && this.targetState == "Disabled"){ return; }
+ this.inherited(arguments);
+ var m = DNDManager.manager();
+ if(this.isDragging){
+ this._onDragMouse(e);
+ }else{
+ if(this.mouseDown && this.isSource &&
+ (Math.abs(e.pageX-this._lastX)>=this.dragThreshold || Math.abs(e.pageY-this._lastY)>=this.dragThreshold)){
+ var nodes = this.getSelectedTreeNodes();
+ if(nodes.length){
+ if(nodes.length > 1){
+ //filter out all selected items which has one of their ancestor selected as well
+ var seen = this.selection, i = 0, r = [], n, p;
+ nextitem: while((n = nodes[i++])){
+ for(p = n.getParent(); p && p !== this.tree; p = p.getParent()){
+ if(seen[p.id]){ //parent is already selected, skip this node
+ continue nextitem;
+ }
+ }
+ //this node does not have any ancestors selected, add it
+ r.push(n);
+ }
+ nodes = r;
+ }
+ nodes = array.map(nodes, function(n){return n.domNode});
+ m.startDrag(this, nodes, this.copyState(connect.isCopyKey(e)));
+ }
+ }
+ }
+ },
+
+ onMouseDown: function(e){
+ // summary:
+ // Event processor for onmousedown/ontouchstart
+ // e: Event
+ // onmousedown/ontouchend event
+ // tags:
+ // private
+ this.mouseDown = true;
+ this.mouseButton = e.button;
+ this._lastX = e.pageX;
+ this._lastY = e.pageY;
+ this.inherited(arguments);
+ },
+
+ onMouseUp: function(e){
+ // summary:
+ // Event processor for onmouseup/ontouchend
+ // e: Event
+ // onmouseup/ontouchend event
+ // tags:
+ // private
+ if(this.mouseDown){
+ this.mouseDown = false;
+ this.inherited(arguments);
+ }
+ },
+
+ onMouseOut: function(){
+ // summary:
+ // Event processor for when mouse is moved away from a TreeNode
+ // tags:
+ // private
+ this.inherited(arguments);
+ this._unmarkTargetAnchor();
+ },
+
+ checkItemAcceptance: function(/*===== target, source, position =====*/){
+ // summary:
+ // Stub function to be overridden if one wants to check for the ability to drop at the node/item level
+ // description:
+ // In the base case, this is called to check if target can become a child of source.
+ // When betweenThreshold is set, position="before" or "after" means that we
+ // are asking if the source node can be dropped before/after the target node.
+ // target: DOMNode
+ // The dijitTreeRoot DOM node inside of the TreeNode that we are dropping on to
+ // Use dijit.getEnclosingWidget(target) to get the TreeNode.
+ // source: dijit.tree.dndSource
+ // The (set of) nodes we are dropping
+ // position: String
+ // "over", "before", or "after"
+ // tags:
+ // extension
+ return true;
+ },
+
+ // topic event processors
+ onDndSourceOver: function(source){
+ // summary:
+ // Topic event processor for /dnd/source/over, called when detected a current source.
+ // source: Object
+ // The dijit.tree.dndSource / dojo.dnd.Source which has the mouse over it
+ // tags:
+ // private
+ if(this != source){
+ this.mouseDown = false;
+ this._unmarkTargetAnchor();
+ }else if(this.isDragging){
+ var m = DNDManager.manager();
+ m.canDrop(false);
+ }
+ },
+ onDndStart: function(source, nodes, copy){
+ // summary:
+ // Topic event processor for /dnd/start, called to initiate the DnD operation
+ // source: Object
+ // The dijit.tree.dndSource / dojo.dnd.Source which is providing the items
+ // nodes: DomNode[]
+ // The list of transferred items, dndTreeNode nodes if dragging from a Tree
+ // copy: Boolean
+ // Copy items, if true, move items otherwise
+ // tags:
+ // private
+
+ if(this.isSource){
+ this._changeState("Source", this == source ? (copy ? "Copied" : "Moved") : "");
+ }
+ var accepted = this.checkAcceptance(source, nodes);
+
+ this._changeState("Target", accepted ? "" : "Disabled");
+
+ if(this == source){
+ DNDManager.manager().overSource(this);
+ }
+
+ this.isDragging = true;
+ },
+
+ itemCreator: function(nodes /*===== , target, source =====*/){
+ // summary:
+ // Returns objects passed to `Tree.model.newItem()` based on DnD nodes
+ // dropped onto the tree. Developer must override this method to enable
+ // dropping from external sources onto this Tree, unless the Tree.model's items
+ // happen to look like {id: 123, name: "Apple" } with no other attributes.
+ // description:
+ // For each node in nodes[], which came from source, create a hash of name/value
+ // pairs to be passed to Tree.model.newItem(). Returns array of those hashes.
+ // nodes: DomNode[]
+ // target: DomNode
+ // source: dojo.dnd.Source
+ // returns: Object[]
+ // Array of name/value hashes for each new item to be added to the Tree, like:
+ // | [
+ // | { id: 123, label: "apple", foo: "bar" },
+ // | { id: 456, label: "pear", zaz: "bam" }
+ // | ]
+ // tags:
+ // extension
+
+ // TODO: for 2.0 refactor so itemCreator() is called once per drag node, and
+ // make signature itemCreator(sourceItem, node, target) (or similar).
+
+ return array.map(nodes, function(node){
+ return {
+ "id": node.id,
+ "name": node.textContent || node.innerText || ""
+ };
+ }); // Object[]
+ },
+
+ onDndDrop: function(source, nodes, copy){
+ // summary:
+ // Topic event processor for /dnd/drop, called to finish the DnD operation.
+ // description:
+ // Updates data store items according to where node was dragged from and dropped
+ // to. The tree will then respond to those data store updates and redraw itself.
+ // source: Object
+ // The dijit.tree.dndSource / dojo.dnd.Source which is providing the items
+ // nodes: DomNode[]
+ // The list of transferred items, dndTreeNode nodes if dragging from a Tree
+ // copy: Boolean
+ // Copy items, if true, move items otherwise
+ // tags:
+ // protected
+ if(this.containerState == "Over"){
+ var tree = this.tree,
+ model = tree.model,
+ target = this.targetAnchor;
+
+ this.isDragging = false;
+
+ // Compute the new parent item
+ var newParentItem;
+ var insertIndex;
+ newParentItem = (target && target.item) || tree.item;
+ if(this.dropPosition == "Before" || this.dropPosition == "After"){
+ // TODO: if there is no parent item then disallow the drop.
+ // Actually this should be checked during onMouseMove too, to make the drag icon red.
+ newParentItem = (target.getParent() && target.getParent().item) || tree.item;
+ // Compute the insert index for reordering
+ insertIndex = target.getIndexInParent();
+ if(this.dropPosition == "After"){
+ insertIndex = target.getIndexInParent() + 1;
+ }
+ }else{
+ newParentItem = (target && target.item) || tree.item;
+ }
+
+ // If necessary, use this variable to hold array of hashes to pass to model.newItem()
+ // (one entry in the array for each dragged node).
+ var newItemsParams;
+
+ array.forEach(nodes, function(node, idx){
+ // dojo.dnd.Item representing the thing being dropped.
+ // Don't confuse the use of item here (meaning a DnD item) with the
+ // uses below where item means dojo.data item.
+ var sourceItem = source.getItem(node.id);
+
+ // Information that's available if the source is another Tree
+ // (possibly but not necessarily this tree, possibly but not
+ // necessarily the same model as this Tree)
+ if(array.indexOf(sourceItem.type, "treeNode") != -1){
+ var childTreeNode = sourceItem.data,
+ childItem = childTreeNode.item,
+ oldParentItem = childTreeNode.getParent().item;
+ }
+
+ if(source == this){
+ // This is a node from my own tree, and we are moving it, not copying.
+ // Remove item from old parent's children attribute.
+ // TODO: dijit.tree.dndSelector should implement deleteSelectedNodes()
+ // and this code should go there.
+
+ if(typeof insertIndex == "number"){
+ if(newParentItem == oldParentItem && childTreeNode.getIndexInParent() < insertIndex){
+ insertIndex -= 1;
+ }
+ }
+ model.pasteItem(childItem, oldParentItem, newParentItem, copy, insertIndex);
+ }else if(model.isItem(childItem)){
+ // Item from same model
+ // (maybe we should only do this branch if the source is a tree?)
+ model.pasteItem(childItem, oldParentItem, newParentItem, copy, insertIndex);
+ }else{
+ // Get the hash to pass to model.newItem(). A single call to
+ // itemCreator() returns an array of hashes, one for each drag source node.
+ if(!newItemsParams){
+ newItemsParams = this.itemCreator(nodes, target.rowNode, source);
+ }
+
+ // Create new item in the tree, based on the drag source.
+ model.newItem(newItemsParams[idx], newParentItem, insertIndex);
+ }
+ }, this);
+
+ // Expand the target node (if it's currently collapsed) so the user can see
+ // where their node was dropped. In particular since that node is still selected.
+ this.tree._expandNode(target);
+ }
+ this.onDndCancel();
+ },
+
+ onDndCancel: function(){
+ // summary:
+ // Topic event processor for /dnd/cancel, called to cancel the DnD operation
+ // tags:
+ // private
+ this._unmarkTargetAnchor();
+ this.isDragging = false;
+ this.mouseDown = false;
+ delete this.mouseButton;
+ this._changeState("Source", "");
+ this._changeState("Target", "");
+ },
+
+ // When focus moves in/out of the entire Tree
+ onOverEvent: function(){
+ // summary:
+ // This method is called when mouse is moved over our container (like onmouseenter)
+ // tags:
+ // private
+ this.inherited(arguments);
+ DNDManager.manager().overSource(this);
+ },
+ onOutEvent: function(){
+ // summary:
+ // This method is called when mouse is moved out of our container (like onmouseleave)
+ // tags:
+ // private
+ this._unmarkTargetAnchor();
+ var m = DNDManager.manager();
+ if(this.isDragging){
+ m.canDrop(false);
+ }
+ m.outSource(this);
+
+ this.inherited(arguments);
+ },
+
+ _isParentChildDrop: function(source, targetRow){
+ // summary:
+ // Checks whether the dragged items are parent rows in the tree which are being
+ // dragged into their own children.
+ //
+ // source:
+ // The DragSource object.
+ //
+ // targetRow:
+ // The tree row onto which the dragged nodes are being dropped.
+ //
+ // tags:
+ // private
+
+ // If the dragged object is not coming from the tree this widget belongs to,
+ // it cannot be invalid.
+ if(!source.tree || source.tree != this.tree){
+ return false;
+ }
+
+
+ var root = source.tree.domNode;
+ var ids = source.selection;
+
+ var node = targetRow.parentNode;
+
+ // Iterate up the DOM hierarchy from the target drop row,
+ // checking of any of the dragged nodes have the same ID.
+ while(node != root && !ids[node.id]){
+ node = node.parentNode;
+ }
+
+ return node.id && ids[node.id];
+ },
+
+ _unmarkTargetAnchor: function(){
+ // summary:
+ // Removes hover class of the current target anchor
+ // tags:
+ // private
+ if(!this.targetAnchor){ return; }
+ this._removeItemClass(this.targetAnchor.rowNode, this.dropPosition);
+ this.targetAnchor = null;
+ this.targetBox = null;
+ this.dropPosition = null;
+ },
+
+ _markDndStatus: function(copy){
+ // summary:
+ // Changes source's state based on "copy" status
+ this._changeState("Source", copy ? "Copied" : "Moved");
+ }
+});
+
+});
diff --git a/lib/dijit/tree/model.js b/lib/dijit/tree/model.js
index 46b27c676..5add44298 100644
--- a/lib/dijit/tree/model.js
+++ b/lib/dijit/tree/model.js
@@ -1,135 +1 @@
-/*
- Copyright (c) 2004-2011, The Dojo Foundation All Rights Reserved.
- Available via Academic Free License >= 2.1 OR the modified BSD license.
- see: http://dojotoolkit.org/license for details
-*/
-
-
-
-dojo.declare(
- "dijit.tree.model",
- null,
-{
- // summary:
- // Contract for any data provider object for the tree.
- // description:
- // Tree passes in values to the constructor to specify the callbacks.
- // "item" is typically a dojo.data.Item but it's just a black box so
- // it could be anything.
- //
- // This (like `dojo.data.api.Read`) is just documentation, and not meant to be used.
-
- destroy: function(){
- // summary:
- // Destroys this object, releasing connections to the store
- // tags:
- // extension
- },
-
- // =======================================================================
- // Methods for traversing hierarchy
-
- getRoot: function(onItem){
- // summary:
- // Calls onItem with the root item for the tree, possibly a fabricated item.
- // Throws exception on error.
- // tags:
- // extension
- },
-
- 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
- },
-
- getChildren: function(/*dojo.data.Item*/ parentItem, /*function(items)*/ onComplete){
- // summary:
- // Calls onComplete() with array of child items of given parent item, all loaded.
- // Throws exception on error.
- // tags:
- // extension
- },
-
- // =======================================================================
- // Inspecting items
-
- isItem: function(/* anything */ something){
- // summary:
- // Returns true if *something* is an item and came from this model instance.
- // Returns false if *something* is a literal, an item from another model instance,
- // or is any object other than an item.
- // tags:
- // extension
- },
-
- fetchItemByIdentity: function(/* object */ keywordArgs){
- // summary:
- // Given the identity of an item, this method returns the item that has
- // that identity through the onItem callback. Conforming implementations
- // should return null if there is no item with the given identity.
- // Implementations of fetchItemByIdentity() may sometimes return an item
- // from a local cache and may sometimes fetch an item from a remote server.
- // tags:
- // extension
- },
-
- getIdentity: function(/* item */ item){
- // summary:
- // Returns identity for an item
- // tags:
- // extension
- },
-
- getLabel: function(/*dojo.data.Item*/ item){
- // summary:
- // Get the label for an item
- // tags:
- // extension
- },
-
- // =======================================================================
- // Write interface
-
- newItem: function(/* dojo.dnd.Item */ args, /*Item*/ parent, /*int?*/ insertIndex){
- // summary:
- // Creates a new item. See `dojo.data.api.Write` for details on args.
- // tags:
- // extension
- },
-
- pasteItem: function(/*Item*/ childItem, /*Item*/ oldParentItem, /*Item*/ newParentItem, /*Boolean*/ bCopy){
- // summary:
- // Move or copy an item from one parent item to another.
- // Used in drag & drop.
- // If oldParentItem is specified and bCopy is false, childItem is removed from oldParentItem.
- // If newParentItem is specified, childItem is attached to newParentItem.
- // tags:
- // extension
- },
-
- // =======================================================================
- // 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(/*dojo.data.Item*/ parent, /*dojo.data.Item[]*/ newChildrenList){
- // summary:
- // Callback to do notifications about new, updated, or deleted items.
- // tags:
- // callback
- }
-});
-
+//>>built
diff --git a/lib/dijit/tree/model.js.uncompressed.js b/lib/dijit/tree/model.js.uncompressed.js
new file mode 100644
index 000000000..9345825e2
--- /dev/null
+++ b/lib/dijit/tree/model.js.uncompressed.js
@@ -0,0 +1,142 @@
+
+/*=====
+declare(
+ "dijit.tree.model",
+ null,
+{
+ // summary:
+ // Contract for any data provider object for the tree.
+ // description:
+ // Tree passes in values to the constructor to specify the callbacks.
+ // "item" is typically a dojo.data.Item but it's just a black box so
+ // it could be anything.
+ //
+ // This (like `dojo.data.api.Read`) is just documentation, and not meant to be used.
+
+ destroy: function(){
+ // summary:
+ // Destroys this object, releasing connections to the store
+ // tags:
+ // extension
+ },
+
+ // =======================================================================
+ // Methods for traversing hierarchy
+
+ getRoot: function(onItem){
+ // summary:
+ // Calls onItem with the root item for the tree, possibly a fabricated item.
+ // Throws exception on error.
+ // tags:
+ // extension
+ },
+
+ 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)
+ // item: dojo.data.Item
+ // tags:
+ // extension
+ },
+
+ getChildren: function(parentItem, onComplete){
+ // summary:
+ // Calls onComplete() with array of child items of given parent item, all loaded.
+ // Throws exception on error.
+ // parentItem: dojo.data.Item
+ // onComplete: function(items)
+ // tags:
+ // extension
+ },
+
+ // =======================================================================
+ // Inspecting items
+
+ isItem: function(something){
+ // summary:
+ // Returns true if *something* is an item and came from this model instance.
+ // Returns false if *something* is a literal, an item from another model instance,
+ // or is any object other than an item.
+ // tags:
+ // extension
+ },
+
+ fetchItemByIdentity: function(keywordArgs){
+ // summary:
+ // Given the identity of an item, this method returns the item that has
+ // that identity through the onItem callback. Conforming implementations
+ // should return null if there is no item with the given identity.
+ // Implementations of fetchItemByIdentity() may sometimes return an item
+ // from a local cache and may sometimes fetch an item from a remote server.
+ // tags:
+ // extension
+ },
+
+ getIdentity: function(item){
+ // summary:
+ // Returns identity for an item
+ // tags:
+ // extension
+ },
+
+ getLabel: function(item){
+ // summary:
+ // Get the label for an item
+ // tags:
+ // extension
+ },
+
+ // =======================================================================
+ // Write interface
+
+ newItem: function(args, parent, insertIndex){
+ // summary:
+ // Creates a new item. See `dojo.data.api.Write` for details on args.
+ // args: dojo.dnd.Item
+ // parent: Item
+ // insertIndex: int?
+ // tags:
+ // extension
+ },
+
+ pasteItem: function(childItem, oldParentItem, newParentItem, bCopy){
+ // summary:
+ // Move or copy an item from one parent item to another.
+ // Used in drag & drop.
+ // If oldParentItem is specified and bCopy is false, childItem is removed from oldParentItem.
+ // If newParentItem is specified, childItem is attached to newParentItem.
+ // childItem: Item
+ // oldParentItem: Item
+ // newParentItem: Item
+ // bCopy: Boolean
+ // tags:
+ // extension
+ },
+
+ // =======================================================================
+ // Callbacks
+
+ onChange: function(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.
+ // item: dojo.data.Item
+ // tags:
+ // callback
+ },
+
+ onChildrenChange: function(parent, newChildrenList){
+ // summary:
+ // Callback to do notifications about new, updated, or deleted items.
+ // parent: dojo.data.Item
+ // newChildrenList: dojo.data.Item[]
+ // tags:
+ // callback
+ }
+});
+=====*/ \ No newline at end of file