📄 tree.js
字号:
// you omitted <code>name:"root"</code>, then the path to the <code>bar</code> node would be// <code>/foo/bar</code>.// <br><br>// Note: if you initialize a Tree with no <code>root</code> value, a root node will be// auto-created for you. You can then call +link{method:Tree.add} to construct the tree.//// @see Tree.modelType// @see Tree.setRoot()//// @visibility external// @example childrenArrays//<//> @object TreeNode//// Every node in the tree is represented by TreeNode object which is an object literal with a// set or properties that configure the node.// <p>// When a Tree is supplied as +link{TreeGrid.data} to +link{TreeGrid}, you can also set// properties from +link{ListGridRecord} on the TreeNode (e.g. setting// +link{ListGridRecord.enabled}:<code>false</code> on the node).//// @treeLocation Client Reference/Grids/TreeGrid// @treeLocation Client Reference/System/Tree// @visibility external//<//> @attr treeNode.enabled (boolean : null : IR)// @include ListGridRecord.enabled// @visibility external//<//> @attr treeNode.canDrag (boolean : null : IRA)// Governs whether this node can be dragged. Only has an effect if this node is displayed in// a +link{TreeGrid} where +link{TreeGrid.canDragRecordsOut}, +link{TreeGrid.canReorderRecords}// or +link{TreeGrid.canReparentNodes} is <code>true</code>// @visibility external//<//> @attr treeNode.canAcceptDrop (boolean : null : IRA)//// Governs whether dragged data (typicaly other <code>treeNode</code>s) may be dropped over// this node. Only has an effect if this node is displayed in a +link{TreeGrid} where// +link{TreeGrid.canAcceptDroppedRecords}, +link{TreeGrid.canReorderRecords} or // +link{TreeGrid.canReparentNodes} is true.//// @visibility external//<//> @attr treeNode.isFolder (Boolean or String : null : IR)//// Set to <code>true</code> or a string that is not equal to (ignoring case)// <code>"false"</code> to explicitly mark this node as a folder. See +link{Tree.isFolder} for// a full description of how the +link{Tree} determines whether a node is a folder or not.// <p>// Note: the name of this property can be changed by setting +link{Tree.isFolderProperty}.//// @see Tree.isFolderProperty// @visibility external//<//> @attr treeNode.name (String : null, but see below : IR)//// The <code>name</code> property of a TreeNode is used for assembling a unique path (see// +link{Tree.getPath()}) to the node. A node's path is the concatenation of all parent names// with the +link{attr:Tree.pathDelim}. The path can then be used to find any node in the tree// using +link{method:Tree.find}.// <p>// If the nameProperty is not set on a given node, +link{method:Tree.getName} and// +link{method:Tree.getPath} will auto-generate a unique name for you.// <p>// This property is also used as the default title for the node (see +link{Tree.getTitle()})// if +link{TreeNode.title} is not specified.// <p>// Note: the name of this property can be changed by setting +link{Tree.nameProperty}.//// @see Tree.nameProperty// @see Tree.pathDelim// @see Tree.getPath// @see Tree.getTitle// @visibility external//<//> @attr treeNode.title (HTML : null : IR)//// The title of the node as it should appear next to the node icon in the +link{Tree}. If left// unset, the value of +link{TreeNode.name} is used by default. See the description in// +link{Tree.getTitle()} for full details.// <p>// Note: the name of this property can be changed by setting +link{Tree.titleProperty}.//// @see Tree.titleProperty// @see Tree.getTitle()// @visibility external//<//> @attr treeNode.id (String or Number: null : IR)//// For trees with +link{Tree.modelType} "parent", this property specifies the unique ID of this// node. The unique ID of a node, together with the unique ID of its parent (see// +link{TreeNode.parentId}) is used by +link{Tree.linkNodes} to link a list of nodes into a// tree.// <p>// Note: the name of this property can be changed by setting +link{Tree.idField}.//// @see TreeNode.parentId// @see Tree.linkNodes()// @see Tree.modelType// @see Tree.idField// @visibility external//<//> @attr treeNode.parentId (String or Number : null : IR)//// For trees with modelType "parent", this property specifies unique parent ID of this node.// The unique ID of a node, together with the unique ID of its parent is used by// +link{method:Tree.linkNodes} to link a list of nodes into a tree.// <p>// Note: the name of this property can be changed by setting +link{Tree.parentIdField}.//// @see TreeNode.id// @see Tree.linkNodes()// @see Tree.modelType// @see Tree.parentIdField// @visibility external//<//> @attr treeNode.children (List of TreeNode : null : IRW)//// For trees with the modelType "children", this property specifies the children of this// TreeNode.// <p>// Note: the name of this property can be changed by setting +link{Tree.childrenProperty}//// @see Tree.modelType// @see Tree.childrenProperty// @visibility external//<//> @attr tree.sortProp (string : null : IRW)// @group openList// Name of the property to sort by. // Set to null because we don't sort by default.//<//> @attr tree.sortDirection (SortDirection : Array.ASCENDING : IRW)// Sort ascending by default//<sortDirection: Array.ASCENDING,//> @attr tree.showRoot (boolean : false : IRW)// Controls whether a call to +link{getOpenList()} includes the root node. Since view// components such as a +link{TreeGrid} use <code>getOpenList()</code> to display the currently// visible tree, <code>showRoot</code> controls whether the root node is shown to the user.// <P>// All Trees must have a single, logical root, however, most applications want to show multiple// nodes at top level. <code>showRoot:false</code>, the default setting, prevents the logical// root from being shown, so that the displayed tree begins with the children of root.// <P>// You can set <code>showRoot:true</code> to show the single, logical root node as the only// top-level node. This property is only meaningful for Trees where you supplied a value for// +link{Tree.root}, otherwise, you will see an automatically generated root node that is// meaningless to the user.//// @visibility external//<showRoot: false,//> @attr tree.autoOpenRoot (boolean : true : IRW)//// If true, the root node is automatically opened when the tree is created or// +link{Tree.setRoot()} is called.//// @visibility external//<autoOpenRoot: true,//> @attr tree.separateFolders (boolean : false : IRW)// @group openList// true == folders should be sorted separately from leaves//<separateFolders:false,//> @attr tree.defaultNodeTitle (string : "Untitled" : IRW)//// Title assigned to nodes without a +link{attr:Tree.titleProperty} value or a// +link{attr:Tree.nameProperty} value.//// @visibility external//<defaultNodeTitle:"Untitled",//> @attr tree.defaultLoadState (LoadState : isc.Tree.UNLOADED : IRW)// @group loadState// default load state for nodes where is has not been explicitly set//<defaultLoadState:isc.Tree.UNLOADED });//// add methods to the tree//isc.Tree.addMethods({//> @method tree.init() (A)// Initialize the tree.<br><br>//// Links the initially provided nodes of the tree according to the tree.modelType.// <br><br>//// Gives the tree a global ID and places it in the global scope.//// @group creation //// @param [all arguments] (object) objects with properties to override from default//// @see group:sharingNodes//<init : function () { // create a pointer to us in the global context isc.ClassFactory.addGlobalID(this); // use a unique property for the parent link so that nodes moved between trees can't get // confused. Advanced usages may still override. if (!this.parentProperty) this.parentProperty = "_parent_"+this.ID; // we rely on being able to scribble the isFolderProperty on nodes - if the user set this // to null or the empty string, create a unique identifier. if (!this.isFolderProperty) this.isFolderProperty = "_isFolder_"+this.ID; // initialize here instead of in addProperties() so we can detect if the user provided // explicit values - used by ResultTree. if (this.idField == null) this.idField = "id"; if (this.parentIdField == null) this.parentIdField = "parentId"; // set the openProperty if it wasn't set already if (!this.openProperty) this.openProperty = "_isOpen_" + this.ID; // if a root wasn't specified, create one this.setRoot(this.root || this.makeRoot()); // load breadth-first on init if so configured if (this.loadOnInit && this.loadBatchSize >= 0) this.loadSubtree(null, null, true);},destroy : function () { // remove the window.ID pointer to us. NOTE: don't destroy the global variable if it no longer // points to this instance (this might happen if you create a new instance with the same ID) if (window[this.ID] == this) window[this.ID] = null;},//> @method tree.makeRoot()// @group creation// Make a new, empty root node.//// @return (object) new root node.//<makeRoot : function () { var root = {}; var undef; if (this.idField !== undef) root[this.idField] = this.rootValue; return root;},// convert a node to a folderconvertToFolder : function (node) { // mark the node as a folder node[this.isFolderProperty] = true;},//> @method tree.makeNode()// Make a new, empty node from just a path// NOTE: creates any parents along the chain, as necessary// @group creation// @return (TreeNode) new node//<// autoConvertParents forces the conversion of nodes in the parent chain to leaf or folder status as// necessary to avoid dups. For example, makeNode('foo') followed by makeNode('foo/') would// normally create a leaf foo and a folder foo. If autoConvertParents is set to true, there would// only be the folder foo regardless of the makeNode() call order.//makeNode : function (path, autoConvertParents) { // first try to find the node -- if we can find it, just return it var node = this.find(path); if (node) { if (autoConvertParents) this.convertToFolder(node); return node; } // The path will be in the format: // "root/p1/p2/p3/newLeaf" or // "/p1/p2/p3/newFolder/" // where p1 etc are existing parents // get the parent path for this node var pathComponents = path.split(this.pathDelim); // array:['','p1','p2','p3','newNode'] // The path must start at the root - if it doesn't, assume it was intended to var rootName = this.getRoot()[this.nameProperty]; if (rootName.endsWith(this.pathDelim)) rootName = rootName.substring(0, rootName.length - this.pathDelim.length); if (pathComponents[0] != rootName) pathComponents.addAt(rootName, 0); // If we're making a folder rather than a leaf, the path passed in will finish with the path // delimiter, so we'll have a blank at the end of the array var newNodeName = pathComponents[pathComponents.length - 1], makingLeaf = (newNodeName != isc.emptyString); if (!makingLeaf) { // chop off the empty slot at the end pathComponents.length = pathComponents.length -1; newNodeName = pathComponents[pathComponents.length - 1] }// this.logWarn("makingLeaf: " + makingLeaf + ", pathComponents:" + pathComponents); var parentPath = pathComponents.slice(0, (pathComponents.length -1)).join(this.pathDelim) + this.pathDelim; // get a pointer to the parent var parent = this.find(parentPath); if (parent == null) { parent = this.find(parentPath.substring(0, parentPath.length - this.pathDelim.length)); } // We need to create the parent if it doesn't exist, or is a leaf, and we're not converting // parents. Call ourselves recursively to get the parent. // NOTE: this should bottom out at the root, which should always be defined if (!parent) { parent = this.makeNode(parentPath, autoConvertParents); } else if (!this.isFolder(parent)) { // If necessary convert the leaf parent to a folder this.convertToFolder(parent); } // make the actual node var node = {}; // set the name and path of the node node[this.nameProperty] = newNodeName; // making a folder - convert the node to a folder if (!makingLeaf) this.convertToFolder(node); // and add it to the tree return this.add(node, parent);},//> @method tree.isRoot()//// Return true if the passed node is the root node.//// @param node (TreeNode) node to test// @return (boolean) true if the node is the root node//// @visibility external//<isRoot : function (node) { return this.root == node;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -