⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 tree.js

📁 javascript 很酷的类库
💻 JS
📖 第 1 页 / 共 5 页
字号:
},//>	@method	tree.setupParentLinks()	(A)//			Make sure the parent links are set up in all children of the root.//			This lets you create a simple structure without back-links, while//			 having the back-links set up automatically//		@group	ancestry		////		@param	[node]	(TreeNode)	parent node to set up child links to//									 (default is this.root)//<setupParentLinks : function (node) {	// if the node wasn't passed in, use the root	if (!node) node = this.root;    this.nodeIndex[node[this.idField]] = node;	// get the children array of the node	var	children = node[this.childrenProperty];        if (children) {        // current assumption whenever loading subtrees is that if any children are returned        // for a node, it's the complete set, and the node is marked "loaded"        this.setLoadState(node, isc.Tree.LOADED);        // handle the children property containing a single child object.        if (!isc.isAn.Array(children)) {            children = node[this.childrenProperty] = [children];        }    }	// if no children defined, bail	if (!children || children.length == 0) return;	// for each child	for (var i = 0, length = children.length, child; i < length; i++) {		child = children[i];		// if the child is null, skip it		if (!child) continue;        // set the parentId on the child if it isn't set already        if (child[this.parentIdField] == null && node[this.idField] != null)             child[this.parentIdField] = node[this.idField];		// set the child's parent to the parent		child[this.parentProperty] = node;		// if the child is a folder, call setupParentLinks recursively on the child		if (this.isFolder(child)) this.setupParentLinks(child);        else this.nodeIndex[child[this.idField]] = child; // link into the nodeIndex	}},// Build or add nodes to a Tree by linking records together by unique ids.//// This method handles receiving a mixture of leaf nodes and parent nodes, even out of order and// with any tree depth.  However, every node must have an id which is unique across all nodes,// not just within its siblings.//// Given a list of nodes which "point to" each other via a "parentId" property that matches a// parent's "idProperty", // - adds all nodes to an index by ID (this.nodeIndex)// - adds all nodes to auto-created "children" arrays on their parents, or on this.root for root//   nodes// - marks any parent that receives children as "loaded", for load on demand (it's assumed for now//   that all children of a given parent are loaded at once)// - can automatically mark parents as folders, as they acquire children, if they aren't already so//   marked// - XXX legacy: creates the "nameProperty" that the Tree currently relies on for several things// NOTE: this is NOT similar to tree.setupParentLinks which assumes that there are already// node.children arrays.// XXX handle multi-column (multi-property) primary keys////> @method tree.linkNodes()//// This method is provided as a mechanism to link new nodes into the tree of modelType// "parent".  This method takes a list of nodes that must contain at a minimum a unique ID// (keyed by +link{attr:Tree.idField}) and a parent ID (keyed by// +link{attr:Tree.parentIdField}).  Based on this information, the list of nodes is integrated// into the tree structure.//// @param nodes (Array of TreeNode) list of nodes to link into the tree.//// @see attr:Tree.data// @see attr:Tree.modelType// @visibility external//<connectByParentID : function (records, idProperty, parentIdProperty, rootValue, isFolderProperty) {    this.linkNodes(records, idProperty, parentIdProperty, rootValue, isFolderProperty);    },connectByParentId : function (records, idProperty, parentIdProperty, rootValue, isFolderProperty) {    this.linkNodes(records, idProperty, parentIdProperty, rootValue, isFolderProperty);},linkNodes : function (records, idProperty, parentIdProperty, rootValue, isFolderProperty, contextNode) {    if (this.modelType == "fields") {        this.connectByFields(records);        return;    }    // XXX impedance mismatch:     // - Tree instances expect each node to have a children array, and think of each node as having    // a "nameProperty" that uniquely identifies it for the level.  A node's nameProperty should end    // in the delimeter ("foo/") if it's a folder.      // - Our nodes do not have children arrays, and have _globally_ unique Ids (the primary key), by    // which they can be linked into a tree.  When dealing with mixed folder/node trees, we have a    // separate property "isFolderProperty" which marks something as a folder.        // So we derive "children" arrays on the fly, and derive the tree's notion of "name" by    // using the primary key and adding a "/" for things marked as folders.    records = records || this.data;    idProperty = idProperty || this.idField;    parentIdProperty = parentIdProperty || this.parentIdField;    rootValue = rootValue || this.rootValue;            var unplacedChildren = records;        var logDebugEnabled = this.logIsDebugEnabled("treeLinking");    while (unplacedChildren.length > 0) {            // try to place the currently unplaced children        var nodes = unplacedChildren,            newParentFound = false;            unplacedChildren = [];        for (var i = 0; i < nodes.length; i++) {            var node = nodes[i],                parentId = node[parentIdProperty],                parent = this.nodeIndex[parentId];            if (parent != null) {                if (logDebugEnabled) {                    this.logDebug("found parent " + parent[idProperty] +                                  " for child " + node[idProperty], "treeLinking");                }                // found this node's parent                this._add(node, parent);                                // we've found a parent                newParentFound = true;            } else if (parentId == null && contextNode) {                // if a contextNode was supplied, use that as the default parent node for all                // nodes that are missing a parentId - this is for loading immediate children                // only, without specifying a parentId                this._add(node, contextNode);                newParentFound = true;            } else if (parentId != rootValue && parentId != null &&                        parentId != -1 && parentId != isc.emptyString)             {                if (logDebugEnabled) {                    this.logDebug("couldn't place child: " + node[idProperty], "treeLinking");                }                    // this node is marked as having a parent, but we haven't found it yet                unplacedChildren.add(node);            } else {                if (logDebugEnabled) {                    this.logDebug("root node: " + node[idProperty], "treeLinking");                }                // this is a root node                this._add(node, this.root);                // we found a parent for this node (its parent is root)                newParentFound = true;            }        }        if (logDebugEnabled) {            this.logDebug("end of linking pass: " + unplacedChildren.length + " unplaced children"                           + ", found new parents: " + newParentFound, "treeLinking");        }        if (!newParentFound && unplacedChildren.length > 0) {            // we didn't manage to place any of the unplaced children - we must not have their            // parents!            //>DEBUG            this.logWarn("Couldn't find parents: " +                         unplacedChildren.getProperty(parentIdProperty) +                         ", unplaced children: " + unplacedChildren.getProperty(idProperty)                         , "treeLinking");            //<DEBUG            break;        }    }        this._markAsDirty();    this.dataChanged();},connectByFields : function (data) {    if (!data) data = this.data;    // for each record    for (var i = 0; i < data.length; i++) {        this.addNodeByFields(data[i]);    }},addNodeByFields : function (node) {    // go through each field in this.fields in turn, descending through the hierarchy, creating    // hierarchy as necessary        var parent = this.root;    for (var i = 0; i < this.fieldOrder.length; i++) {        var fieldName = this.fieldOrder[i],            fieldValue = node[fieldName];        var folderName = fieldValue,            childNum = this.findChildNum(parent, folderName),            child;        if (childNum != -1) {            //this.logWarn("found child for '" + fieldName + "':'" + fieldValue + "'");            child = this.getChildren(parent).get(childNum);        } else {            // if there's no child with this field value, create one            //this.logWarn("creating child for '" + fieldName + "':'" + fieldValue + "'");            child = {};            child[this.nameProperty] = folderName;            this.add(child, parent);            this.convertToFolder(child);        }        parent = child;    }    // add the new node to the Tree    //this.logWarn("adding node at: " + this.getPath(parent));    this.add(node, parent);},//>	@method	tree.getRoot()//// Returns the root node of the tree.//// @return  (TreeNode)    the root node//// @visibility external//<getRoot : function () {	return this.root;},//>	@method	tree.setRoot()//// Set the root of the tree. //// @param   newRoot (TreeNode)    new root node// @param   autoOpen (boolean)  set to true to automatically open the new root node.//// @visibility external//<setRoot : function (newRoot, autoOpen) {	// assign the new root	this.root = newRoot;    // avoid issues if setRoot() is used to re-root a Tree on one of it's own nodes    if (newRoot && this.parentProperty.endsWith(this.ID)) newRoot[this.parentProperty] = null;    if (this.rootValue == null) this.rootValue = this.root[this.idField];    // if the root node has no name, assign the path property to it.  This is for backcompat    // and also a reasonable default.    var rootName = this.root[this.nameProperty];        if (rootName == null || rootName == isc.emptyString) this.root[this.nameProperty] = this.pathDelim;    // the root node is always a folder    if (!this.isFolder(this.root)) this.convertToFolder(this.root);    // NOTE: this index is permanent, staying with this Tree instance so that additional sets of    // nodes can be incrementally linked into the existing structure.     this.nodeIndex = {};    // (re)create the structure of the Tree according to the model type    if ("parent" == this.modelType) {        // nodes provided as flat list (this.data); each record is expected to have a property        // which is a globally unique ID (this.idField) and a property which has the globally        // unique ID of its parent (this.parentIdField).        // assemble the tree from this.data        if (this.data) this.linkNodes();    } else if ("fields" == this.modelType) {                // nodes provided as flat list; a list of fields, in order, defines the Tree        if (this.data) this.connectByFields();    } else if ("children" == this.modelType) {        // each parent has an array of children        if (this.autoSetupParentLinks) 	this.setupParentLinks();        if (this.data) {            var data = this.data;            this.data = null;            this.addList(data, this.root);        }    } else {        this.logWarn("Unsupported modelType: " + this.modelType);    }	// open the new root if autoOpen: true passed in or this.autoOpenRoot is true.  Suppress    // autoOpen if autoOpen:false passed in    if (autoOpen !== false && (this.autoOpenRoot || autoOpen)) {        this.openFolder(newRoot);    }    	// mark the tree as dirty and note that the data has changed	this._markAsDirty();	this.dataChanged();},// get a copy of these nodes without all the properties the Tree scribbles on them.// Note the intent here is that children should in fact be serialized unless the caller has// explicitly trimmed them.getCleanNodeData : function (nodeList, includeChildren) {    if (nodeList == null) return null;    var nodes = [], wasSingular = false;    if (!isc.isAn.Array(nodeList)) {        nodeList = [nodeList];        wasSingular = true;    }    // known imperfections:    // - by default, isFolderProperty is "isFolder", we write this into nodes and sent it when    //   saving    // - we create empty children arrays for childless nodes, and save them    for (var i = 0; i < nodeList.length; i++) {        var treeNode = nodeList[i],            node = {};        // copy the properties of the tree node, dropping some Tree/TreeGrid artifacts		for (var propName in treeNode) {            			if (propName == this.parentProperty ||                // currently hardcoded                propName == "_loadState" ||                propName == "_isc_tree" ||                // the openProperty and isFolderProperty are documented and settable, and if                // they've been set should be saved, so only remove these properties if they                // use the prefix that indicates they've been auto-generated (NOTE: this prefix                // is obfuscated)                propName.startsWith("_isOpen_") ||                 propName.startsWith("_isFolder_") ||                                 // default nameProperty from ResultTree, which by default does not have                // meaningful node names                propName.startsWith("__nodePath") ||                 // class of child nodes, set up by ResultTree                propName == "_derivedChildNodeType" ||                                // from selection model                propName.startsWith("_selection_") ||                                // Explicit false passed as 'includeChildren' param.                (includeChildren == false && propName == this.childrenProperty)) continue;            node[propName] = treeNode[propName];               // Clean up the children as well (if there are any)            if (propName == this.childrenProperty && isc.isAn.Array(node[propName])) {                node[propName] = this.getCleanNodeData(node[propName]);            }        }        nodes.add(node);    }    if (wasSingular) return nodes[0];    return nodes;},

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -