📄 tree.js
字号:
//// identity methods -- override these for your custom trees////> @method tree.getName()//// Get the 'name' of a node. This is node[+link{Tree.nameProperty}]. If that value has not// been set on the node, a unique value (within this parent) will be auto-generated and// returned.// // @param node (TreeNode) node in question// @return (string) name of the node //// @visibility external//<_autoName : 0,getName : function (node) { var ns = isc._emptyString; if (!node) return ns; var name = node[this.nameProperty]; if (name == null) name = node[this.idField]; if (name == null) { // unnamed node: give it a unique name. // never assign an autoName to a node not from our tree if (!this.isDescendantOf(node, this.root) && node != this.root) return null; // assign unique autoNames per tree so we don't get cross-tree name collisions on D&D if (!this._autoNameBase) this._autoNameBase = isc.Tree.autoID++ + "_"; name = this._autoNameBase+this._autoName++; } // convert to string because we call string methods on this value elsewhere if (!isc.isA.String(name)) name = ns+name; // cache node[this.nameProperty] = name; return name;},//> @method tree.getTitle()//// Return the title of a node -- the name as it should be presented to the user. This method// works as follows:// <ul>// <li> If a +link{attr:Tree.titleProperty} is set on the node, the value of that property is// returned.// <li> Otherwise, if the +link{attr:Tree.nameProperty} is set on the node, that value is// returned, minus any trailing +link{attr:Tree.pathDelim}.// <li> Finally, if none of the above yielded a title, the value of// +link{attr:Tree.defaultNodeTitle} is returned.// </ul>// You can override this method to return the title of your choice for a given node.// <br><br>// To override the title for an autoconstructed tree (for example, in a databound TreeGrid),// override +link{method:TreeGrid.getNodeTitle} instead.//// @param node (TreeNode) node for which the title is being requested// @return (string) title to display//// @see method:TreeGrid.getNodeTitle//// @visibility external//<getTitle : function (node) { if (!node) return null; // if the node has an explicit title, return that if (node[this.titleProperty] != null) return node[this.titleProperty]; // otherwise derive from the name var name = node[this.nameProperty]; if (name == null) name = this.defaultNodeTitle; return (isc.endsWith(name, this.pathDelim) ? name.substring(0,name.length-this.pathDelim.length) : name);},//> @method tree.getPath()//// Returns the path of a node - a path has the following format:// <code>([name][pathDelim]?)*</code>// <br><br>// For example, in this tree:// <pre>// root// foo// bar// </pre>// Assuming that +link{attr:Tree.pathDelim} is the default <code>/</code>, the <code>bar</code>// node would have the path <code>root/foo/bar</code> and the path for the <code>foo</code>// node would be <code>root/foo</code>.// <br><br>// Once you have a path to a node, you can call find(path) to retrieve a reference to the node// later.//// @param node (TreeNode) node in question// @return (string) path to the node//// @see method:Tree.getParentPath// @visibility external//<getPath : function (node) { var parent = this.getParent(node); if (parent == null) return this.getName(node); var parentName = this.getName(parent); return this.getPath(parent) + (parentName == this.pathDelim ? isc.emptyString : this.pathDelim) + this.getName(node); },//> @method tree.getParentPath()//// Given a node, return the path to it's parent. This works just like// +link{method:Tree.getPath} except the node itself is not reported as part of the path.//// @param node (TreeNode) node in question// @return (string) path to the node's parent//// @see method:Tree.getPath// @visibility external//<getParentPath : function (node) { // get the node's path var name = this.getName(node), path = this.getPath(node); // return the path minus the name of the node return path.substring(0, path.length - name.length - this.pathDelim.length);},//> @method tree.getParent()//// Returns the parent of this node.//// @param node (TreeNode) node in question// @return (node) parent of this node//// @visibility external//<getParent : function (node) { if (node == null) return null; return node[this.parentProperty];},//> @method tree.getParents()//// Given a node, return an array of the node's parents with the immediate parent first. The// node itself is not included in the result. For example, for the following tree:// <pre>// root// foo// bar// </pre>// Calling <code>tree.getParents(bar)</code> would return: <code>[foo, root]</code>. Note that// the returned array will contain references to the nodes, not the names.//// @param node (TreeNode) node in question// @return (Array) array of node's parents//// @visibility external//<getParents : function (node) { var list = [], parent = this.getParent(node); // while parents exist while (parent) { // add them to the list list.add(parent); // if the parent is the root, jump out! // this lets us handle subTrees of other trees if (parent == this.root) break; // and get the next parent in the chain parent = this.getParent(parent); } // return the list of parents return list;},//> @method tree.getLevel() (A)//// Return the number of levels deep this node is in the tree. For example, for this tree:// <pre>// root// foo// bar// </pre>// Calling <code>tree.getLevel(bar)</code> will return <code>2</code>. //// @param node (TreeNode) node in question// @return (number) number of parents the node has//// @visibility external//<getLevel : function (node) { return this.getParents(node).length;},//> @method tree.isFolder()//// Determines whether a particular node is a folder. The logic works as follows:<br><br>// <ul>// <li> If the +link{TreeNode} has a value for the +link{attr:Tree.isFolderProperty}// (+link{TreeNode.isFolder} by default) that value is returned.// <li> Next, the existence of the +link{attr:Tree.childrenProperty} (by default// +link{TreeNode.children} is checked on the +link{TreeNode}. If the node has the children// property defined (regardless of whether it actually has any children), then isFolder()// returns true for that node.// </ul>// <P>// You can override this method to provide your own intepretation of what constitutes a folder.//// @param node (TreeNode) node in question// @return (boolean) true if the node is a folder//// @visibility external//<isFolder : function (node) { if (node == null) return false; // explicit isFolder set var isFolder = node[this.isFolderProperty]; if (isFolder != null) return isFolder; // has a children array (may have zero actual children currently, but having a children // array is sufficient for us to regard this as a folder). Note that we scribble the // children array on the nodes even in modelTypes other than "children", so this check // is correct for other modelTypes as well. if (node[this.childrenProperty]) return true; // infer folderness from the name of the node // XXX 10/13/2005 : this is purposefully not documented. We have it here for backcompat // with trees that may have relied on this, but disclosing this will confuse people - // they'll start to think about having to tack on the path delimiter on their nodes to // signify folderness, which in turn translates into confusion about when you should or // should not supply the slash or give back a trailing slash from e.g. getPath() var name = this.getName(node); // if there's no name, we have no way of knowing if (name == null) return false; // if the last character is the pathDelim, it's a folder. return isc.endsWith(name, this.pathDelim);},//> @method tree.isLeaf()//// Returns true if the passed in node is a leaf.//// @param node (TreeNode) node in question// @return (boolean) true if the node is a leaf//// @visibility external//<isLeaf : function (node) { return ! this.isFolder(node);},//> @method tree.isLast() (A)// Note: because this needs to take the sort order into account, it can be EXTREMELY expensive!// @group ancestry // Return if this item is the last one in it's parents list.//// @param node (TreeNode) node in question// @return (boolean) true == node is the last child of its parent//<isLast : function (node) { var parent = this.getParent(node); if (! parent) return true; var kids = this.getChildren(parent, this.opendisplayNodeType, this._openNormalizer, this.sortDirection, null, this._sortContext); return kids[kids.length-1] == node;},//// finding a node////> @method tree.findById() (A)//// Find the node with the specified ID. Specifically, it returns the node whose idField// matches the id passed to this method. If the tree is using the "parent" modelType, this// lookup will be constant-time. For all other modelTypes, the tree will be searched// recursively.//// @group location// @param id (string) ID of the node to return.// @return (object) node with appropriate ID, or null if not found.//// @see attr:Tree.idField// @see method:Tree.find//// @visibility external//<findById : function (id) { return this.find(this.idField, id);},//> @method tree.find()//// Find a node within this tree using a string path or by attribute value. This method can be// called with 1 or 2 arguments. If a single// argument is supplied, the value of the argument is treated as the path to the node.// <br>// If 2 arguments are supplied, this method will treat the first argument as a fieldName, and// return the first node encountered where <code>node[fieldName]</code>matches the second // argument. So for example, given this tree:// <pre>// foo// zoo// bar// moo// bar// </pre>// Assuming your +link{attr:Tree.pathDelim} is the default <code>/</code> and <code>foo</code>// is the name of the root node, then// <code>tree.find("foo/moo/bar")</code> would return the <code>bar</code> node under the// <code>moo</code> node.// <br><br>// <code>tree.find("name", "bar")</code> would return the first <code>bar</code> node because// it is the first one in the list whose <code>name</code> (default value of// +link{attr:Tree.nameProperty}) property matches the value// <code>bar</code>. The two argument usage is generally more interesting when your tree nodes// have some custom unique property that you wish to search on. For example if your tree nodes// had a unique field called "UID", their serialized form would look something like this:// <pre>// { name: "foo", children: [...], UID:"someUniqueId"}// </pre> // You could then call <code>tree.find("UID", "someUniqueId")</code> to find that node. Note// that the value doesn't have to be a string - it can be any valid JS value, but since this// data generally comes from the server, the typical types are string, number, and boolean.// <br><br>// When searching by path, trailing path delimiters are ignored. So for example// <code>tree.find("foo/zoo/bar")</code> is equivalent to// <code>tree.find("foo/zoo/bar/")</code>// // @group location // @param fieldName|path (string) Either the path to the node to be found, or the // @param [value] (any) If specified, this is the desired value for the // appropriate field// @return (object) the node matching the supplied criteria or null if not found//// @see attr:Tree.root// @see attr:Tree.pathDelim// @see attr:Tree.nameProperty//// @visibility external//<// NOTE: This should be a good generic implemention, try overriding findChildNum instead.find : function (fieldName, value) { var undef; if (value === undef) return this._findByPath(fieldName); // constant time lookup when we have nodeIndex if (fieldName == this.idField) return this.nodeIndex[value]; // special-case root, which may not appear in getDescendants() depending on this.showRoot
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -