From e44a7e37b6c7b5961adaffc62b9042b8d442938e Mon Sep 17 00:00:00 2001
From: mensonge
Date: Thu, 13 Nov 2008 09:49:11 +0000
Subject: New feature: basic Ajax suggestion for tags and implementation of
Dojo toolkit
git-svn-id: https://semanticscuttle.svn.sourceforge.net/svnroot/semanticscuttle/trunk@151 b3834d28-1941-0410-a4f8-b48e95affb8f
---
includes/js/dijit/Tree.js | 1336 +++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 1336 insertions(+)
create mode 100644 includes/js/dijit/Tree.js
(limited to 'includes/js/dijit/Tree.js')
diff --git a/includes/js/dijit/Tree.js b/includes/js/dijit/Tree.js
new file mode 100644
index 0000000..fc9be8b
--- /dev/null
+++ b/includes/js/dijit/Tree.js
@@ -0,0 +1,1336 @@
+if(!dojo._hasResource["dijit.Tree"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
+dojo._hasResource["dijit.Tree"] = true;
+dojo.provide("dijit.Tree");
+
+dojo.require("dojo.fx");
+
+dojo.require("dijit._Widget");
+dojo.require("dijit._Templated");
+dojo.require("dijit._Container");
+dojo.require("dojo.cookie");
+
+dojo.declare(
+ "dijit._TreeNode",
+ [dijit._Widget, dijit._Templated, dijit._Container, dijit._Contained],
+{
+ // summary
+ // Single node within a tree
+
+ // item: dojo.data.Item
+ // the dojo.data entry this tree represents
+ item: null,
+
+ isTreeNode: true,
+
+ // label: String
+ // Text of this tree node
+ label: "",
+
+ isExpandable: null, // show expando node
+
+ isExpanded: false,
+
+ // state: String
+ // dynamic loading-related stuff.
+ // When an empty folder node appears, it is "UNCHECKED" first,
+ // then after dojo.data query it becomes "LOADING" and, finally "LOADED"
+ state: "UNCHECKED",
+
+ templateString:"
\n",
+
+ postCreate: function(){
+ // set label, escaping special characters
+ this.setLabelNode(this.label);
+
+ // set expand icon for leaf
+ this._setExpando();
+
+ // set icon and label class based on item
+ this._updateItemClasses(this.item);
+
+ if(this.isExpandable){
+ dijit.setWaiState(this.labelNode, "expanded", this.isExpanded);
+ }
+ },
+
+ markProcessing: function(){
+ // summary: visually denote that tree is loading data, etc.
+ this.state = "LOADING";
+ this._setExpando(true);
+ },
+
+ unmarkProcessing: function(){
+ // summary: clear markup from markProcessing() call
+ this._setExpando(false);
+ },
+
+ _updateItemClasses: function(item){
+ // summary: set appropriate CSS classes for icon and label dom node (used to allow for item updates to change respective CSS)
+ var tree = this.tree, model = tree.model;
+ if(tree._v10Compat && item === model.root){
+ // For back-compat with 1.0, need to use null to specify root item (TODO: remove in 2.0)
+ item = null;
+ }
+ this.iconNode.className = "dijitInline dijitTreeIcon " + tree.getIconClass(item, this.isExpanded);
+ this.labelNode.className = "dijitTreeLabel " + tree.getLabelClass(item, this.isExpanded);
+ },
+
+ _updateLayout: function(){
+ // summary: set appropriate CSS classes for this.domNode
+ var parent = this.getParent();
+ if(!parent || parent.rowNode.style.display == "none"){
+ /* if we are hiding the root node then make every first level child look like a root node */
+ dojo.addClass(this.domNode, "dijitTreeIsRoot");
+ }else{
+ dojo.toggleClass(this.domNode, "dijitTreeIsLast", !this.getNextSibling());
+ }
+ },
+
+ _setExpando: function(/*Boolean*/ processing){
+ // summary: set the right image for the expando node
+
+ // apply the appropriate class to the expando node
+ var styles = ["dijitTreeExpandoLoading", "dijitTreeExpandoOpened",
+ "dijitTreeExpandoClosed", "dijitTreeExpandoLeaf"];
+ var idx = processing ? 0 : (this.isExpandable ? (this.isExpanded ? 1 : 2) : 3);
+ dojo.forEach(styles,
+ function(s){
+ dojo.removeClass(this.expandoNode, s);
+ }, this
+ );
+ dojo.addClass(this.expandoNode, styles[idx]);
+
+ // provide a non-image based indicator for images-off mode
+ this.expandoNodeText.innerHTML =
+ processing ? "*" :
+ (this.isExpandable ?
+ (this.isExpanded ? "-" : "+") : "*");
+ },
+
+ expand: function(){
+ // summary: show my children
+ if(this.isExpanded){ return; }
+ // cancel in progress collapse operation
+ if(this._wipeOut.status() == "playing"){
+ this._wipeOut.stop();
+ }
+
+ this.isExpanded = true;
+ dijit.setWaiState(this.labelNode, "expanded", "true");
+ dijit.setWaiRole(this.containerNode, "group");
+ this.contentNode.className = "dijitTreeContent dijitTreeContentExpanded";
+ this._setExpando();
+ this._updateItemClasses(this.item);
+
+ this._wipeIn.play();
+ },
+
+ collapse: function(){
+ if(!this.isExpanded){ return; }
+
+ // cancel in progress expand operation
+ if(this._wipeIn.status() == "playing"){
+ this._wipeIn.stop();
+ }
+
+ this.isExpanded = false;
+ dijit.setWaiState(this.labelNode, "expanded", "false");
+ this.contentNode.className = "dijitTreeContent";
+ this._setExpando();
+ this._updateItemClasses(this.item);
+
+ this._wipeOut.play();
+ },
+
+ setLabelNode: function(label){
+ this.labelNode.innerHTML="";
+ this.labelNode.appendChild(dojo.doc.createTextNode(label));
+ },
+
+ setChildItems: function(/* Object[] */ items){
+ // summary:
+ // Sets the child items of this node, removing/adding nodes
+ // from current children to match specified items[] array.
+
+ var tree = this.tree,
+ model = tree.model;
+
+ // Orphan all my existing children.
+ // If items contains some of the same items as before then we will reattach them.
+ // Don't call this.removeChild() because that will collapse the tree etc.
+ this.getChildren().forEach(function(child){
+ dijit._Container.prototype.removeChild.call(this, child);
+ }, this);
+
+ this.state = "LOADED";
+
+ if(items && items.length > 0){
+ this.isExpandable = true;
+ if(!this.containerNode){ // maybe this node was unfolderized and still has container
+ this.containerNode = this.tree.containerNodeTemplate.cloneNode(true);
+ this.domNode.appendChild(this.containerNode);
+ }
+
+ // Create _TreeNode widget for each specified tree node, unless one already
+ // exists and isn't being used (presumably it's from a DnD move and was recently
+ // released
+ dojo.forEach(items, function(item){
+ var id = model.getIdentity(item),
+ existingNode = tree._itemNodeMap[id],
+ node =
+ ( existingNode && !existingNode.getParent() ) ?
+ existingNode :
+ new dijit._TreeNode({
+ item: item,
+ tree: tree,
+ isExpandable: model.mayHaveChildren(item),
+ label: tree.getLabel(item)
+ });
+ this.addChild(node);
+ // note: this won't work if there are two nodes for one item (multi-parented items); will be fixed later
+ tree._itemNodeMap[id] = node;
+ if(this.tree.persist){
+ if(tree._openedItemIds[id]){
+ tree._expandNode(node);
+ }
+ }
+ }, this);
+
+ // note that updateLayout() needs to be called on each child after
+ // _all_ the children exist
+ dojo.forEach(this.getChildren(), function(child, idx){
+ child._updateLayout();
+ });
+ }else{
+ this.isExpandable=false;
+ }
+
+ if(this._setExpando){
+ // change expando to/from dot or + icon, as appropriate
+ this._setExpando(false);
+ }
+
+ // On initial tree show, put focus on either the root node of the tree,
+ // or the first child, if the root node is hidden
+ if(!this.parent){
+ var fc = this.tree.showRoot ? this : this.getChildren()[0],
+ tabnode = fc ? fc.labelNode : this.domNode;
+ tabnode.setAttribute("tabIndex", "0");
+ }
+
+ // create animations for showing/hiding the children (if children exist)
+ if(this.containerNode && !this._wipeIn){
+ this._wipeIn = dojo.fx.wipeIn({node: this.containerNode, duration: 150});
+ this._wipeOut = dojo.fx.wipeOut({node: this.containerNode, duration: 150});
+ }
+ },
+
+ removeChild: function(/* treeNode */ node){
+ this.inherited(arguments);
+
+ var children = this.getChildren();
+ if(children.length == 0){
+ this.isExpandable = false;
+ this.collapse();
+ }
+
+ dojo.forEach(children, function(child){
+ child._updateLayout();
+ });
+ },
+
+ makeExpandable: function(){
+ //summary
+ // if this node wasn't already showing the expando node,
+ // turn it into one and call _setExpando()
+ this.isExpandable = true;
+ this._setExpando(false);
+ },
+
+ _onNodeFocus: function(evt){
+ var node = dijit.getEnclosingWidget(evt.target);
+ this.tree._onTreeFocus(node);
+ }
+});
+
+dojo.declare(
+ "dijit.Tree",
+ [dijit._Widget, dijit._Templated],
+{
+ // summary
+ // This widget displays hierarchical data from a store. A query is specified
+ // to get the "top level children" from a data store, and then those items are
+ // queried for their children and so on (but lazily, as the user clicks the expand node).
+ //
+ // Thus in the default mode of operation this widget is technically a forest, not a tree,
+ // in that there can be multiple "top level children". However, if you specify label,
+ // then a special top level node (not corresponding to any item in the datastore) is
+ // created, to father all the top level children.
+
+ // store: String||dojo.data.Store
+ // The store to get data to display in the tree.
+ // May remove for 2.0 in favor of "model".
+ store: null,
+
+ // model: dijit.Tree.model
+ // Alternate interface from store to access data (and changes to data) in the tree
+ model: null,
+
+ // query: anything
+ // Specifies datastore query to return the root item for the tree.
+ //
+ // Deprecated functionality: if the query returns multiple items, the tree is given
+ // a fake root node (not corresponding to any item in the data store),
+ // whose children are the items that match this query.
+ //
+ // The root node is shown or hidden based on whether a label is specified.
+ //
+ // Having a query return multiple items is deprecated.
+ // If your store doesn't have a root item, wrap the store with
+ // dijit.tree.ForestStoreModel, and specify model=myModel
+ //
+ // example:
+ // {type:'continent'}
+ query: null,
+
+ // label: String
+ // Deprecated. Use dijit.tree.ForestStoreModel directly instead.
+ // Used in conjunction with query parameter.
+ // If a query is specified (rather than a root node id), and a label is also specified,
+ // then a fake root node is created and displayed, with this label.
+ label: "",
+
+ // showRoot: Boolean
+ // Should the root node be displayed, or hidden?
+ showRoot: true,
+
+ // childrenAttr: String[]
+ // one ore more attributes that holds children of a tree node
+ childrenAttr: ["children"],
+
+ // openOnClick: Boolean
+ // If true, clicking a folder node's label will open it, rather than calling onClick()
+ openOnClick: false,
+
+ templateString:"\n
\n",
+
+ isExpandable: true,
+
+ isTree: true,
+
+ // persist: Boolean
+ // enables/disables use of cookies for state saving.
+ persist: true,
+
+ // dndController: String
+ // class name to use as as the dnd controller
+ dndController: null,
+
+ //parameters to pull off of the tree and pass on to the dndController as its params
+ dndParams: ["onDndDrop","itemCreator","onDndCancel","checkAcceptance", "checkItemAcceptance"],
+
+ //declare the above items so they can be pulled from the tree's markup
+ onDndDrop:null,
+ itemCreator:null,
+ onDndCancel:null,
+ checkAcceptance:null,
+ checkItemAcceptance:null,
+
+ _publish: function(/*String*/ topicName, /*Object*/ message){
+ // summary:
+ // Publish a message for this widget/topic
+ dojo.publish(this.id, [dojo.mixin({tree: this, event: topicName}, message||{})]);
+ },
+
+ postMixInProperties: function(){
+ this.tree = this;
+
+ this._itemNodeMap={};
+
+ if(!this.cookieName){
+ this.cookieName = this.id + "SaveStateCookie";
+ }
+ },
+
+ postCreate: function(){
+ // load in which nodes should be opened automatically
+ if(this.persist){
+ var cookie = dojo.cookie(this.cookieName);
+ this._openedItemIds = {};
+ if(cookie){
+ dojo.forEach(cookie.split(','), function(item){
+ this._openedItemIds[item] = true;
+ }, this);
+ }
+ }
+
+ // make template for container node (we will clone this and insert it into
+ // any nodes that have children)
+ var div = dojo.doc.createElement('div');
+ div.style.display = 'none';
+ div.className = "dijitTreeContainer";
+ dijit.setWaiRole(div, "presentation");
+ this.containerNodeTemplate = div;
+
+ // Create glue between store and Tree, if not specified directly by user
+ if(!this.model){
+ this._store2model();
+ }
+
+ // monitor changes to items
+ this.connect(this.model, "onChange", "_onItemChange");
+ this.connect(this.model, "onChildrenChange", "_onItemChildrenChange");
+ // TODO: monitor item deletes so we don't end up w/orphaned nodes?
+
+ this._load();
+
+ this.inherited("postCreate", arguments);
+
+ if(this.dndController){
+ if(dojo.isString(this.dndController)){
+ this.dndController= dojo.getObject(this.dndController);
+ }
+ var params={};
+ for (var i=0; i