📄 resulttree.js
字号:
// - supported: next level is specified via node[this.childNodeType], or via overriding// getChildDataSource// - mixed type within a level// - supported: the Tree just needs a DataSource with a primary key for the level. Any join// that can produce this is fine.getTreeRelationship : function (parentNode) { var childDS = this.getChildDataSource(parentNode); // ask the datasource for a tree relationship, which can be declared explicitly or // autodetected from field declarations var relationship = childDS.getTreeRelationship(); return relationship; },//> @method resultTree.getChildDataSource()// Get the DataSource for children under this node.//// If this node has no appropriate child node type, this method will return null - in a multi-DS// tree this indicates that there is no appropriate next DataSource to navigate to, and this node// will be a leaf.//<// NOTE: nodeDS is an optional parameter, used when we need to know the child datasource of a node// before it gets linked into the tree (at that time, the node's DS can't be determined by looking// at it's future parent).getChildDataSource : function (node, nodeDS) { // look for explicitly specified child type var childDSName = node[this.childTypeProperty]; if (childDSName != null) return isc.DS.get(childDSName); // see if there is a mapping from this parent's type to its child type var nodeDS = nodeDS || this.getNodeDataSource(node); // - if this is a single DS tree, use the one and only DataSource // - if we're at root (which is the only node with no DS), use the root DataSource if (nodeDS == null || !this.isMultiDSTree()) return this.getRootDataSource(); // otherwise try to find a relation from this node's DS to some other DS // see if there's an explicitly declared tree relation var treeRelations = this.treeRelations, childDataSources = nodeDS.getChildDataSources(); //this.logWarn("getChildDataSource: nodeDS is : " + nodeDS + // ", treeRelations: " + this.echo(treeRelations) + // ", childDataSources: " + this.echo(childDataSources)); if (treeRelations) { childDSName = treeRelations[nodeDS.ID]; if (childDSName != null) return isc.DS.get(childDSName); } // otherwise take the first relationship to any other DataSource if (childDataSources != null) return childDataSources[0];},// get the DataSource for this nodegetNodeDataSource : function (node) { // check for explicitly specified type (this allows mixed types within a set of children) var dsName = node[this.nodeTypeProperty]; // use the type stored on parent node when this child was fetched if (dsName == null) { var parentNode = this.getParent(node); if (parentNode == null) { // the special, singular "root" object has no DataSource return null; } else if (parentNode == this.root) { // nodes under root are of the first or "root" DataSource (slightly confusing) dsName = this.getRootDataSource().ID; } else { // when we have a mixture of node types, and the parent stores the type of the // child nodes when they are loaded dsName = parentNode._derivedChildNodeType; // otherwise we have just one node type if (dsName == null) dsName = this.getRootDataSource().ID; } } return isc.DS.get(dsName) || this.getRootDataSource();},isMultiDSTree : function () { return this.multiDSTree || this.treeRelations != null;},// get the DataSource for the nodes that appear at rootgetRootDataSource : function () { return isc.DS.get(this.operation.dataSource || this.dataSource);},// get the criteria to apply (aside from parentId) when selecting children from childDSgetCriteria : function (childDS, parentDS, parentNode) { if (this.getRootDataSource() == childDS) return this.criteria; return null;},// get an operationId to use to select children from childDS. operation can optionally depend// on parentDS and parentNodegetOperationId : function (childDS, parentDS, parentNode) { // FIXME we may want a declarative way to specify the operation to use to select on each // DataSource the tree may encounter return this.operation ? this.operation.ID : null;},// Note this is an internal method to fetch the children and fold them into the children array// for the node in question. It doesn't check for the children already being loaded - so if// called repeatedly you'd end up with duplicates in the children array.loadChildren : function (parentNode, callback) { // figure out what parent-child relationship will be used to select children of this node. var isRoot = (parentNode == null || parentNode == this.root), relationship, childDS, parentDS;// this.logWarn("parentNode: " + this.echo(parentNode) + // ", isRoot: " + isRoot); // if we're at root, and this is a multi-DataSource tree, the root-level nodes have no parent // dataSource. We just do a normal select, using only the criteria if (isRoot && this.isMultiDSTree()) { childDS = this.getRootDataSource(); // XXX this isn't really a relationship: the singular "root" has no schema, hence there is // no "parentDS" or "idField", and in the childDS there is no parentIDField that points to // root. But the notion of "childDS", the DataSource of the nodes being loaded, is still // valid. relationship = { childDS:childDS }; } else { // otherwise, we detect some relationship that this node has either within its own // DataSource or across DataSources, and load children using that relationship relationship = this.getTreeRelationship(parentNode); childDS = relationship.childDS; parentDS = relationship.parentDS; } if (!this.isMultiDSTree()) { // force local overrides of idField, parentIdField and rootValue on the relationship - // these are autodetected and initialized in init() if unset on this ResultTree. relationship.idField = this.idField; relationship.parentIdField = this.parentIdField; relationship.rootValue = relationship.rootValue; } if (this.logIsDebugEnabled()) { this.logDebug("parent id: " + (isRoot ? "[root]" : parentNode[relationship.idField]) + " (type: " + (isRoot ? "[root]" : parentDS.ID) + ")" + " has childDS: " + childDS.ID + ", relationship: " + this.echo(relationship)); } // remember the type of children under this parent, because we'll use this to figure out the // type of the children's children. parentNode._derivedChildNodeType = childDS.ID; // put together criteria that should always be used when selecting against this DataSource var criteria = isc.addProperties({}, this.getCriteria(childDS, parentDS, parentNode)); if (isRoot && this.isMultiDSTree()) { // leave criteria alone } else if (this.loadDataOnDemand) { // loadOnDemand: instead of loading the whole tree, only load the children of a single // node. Put together criteria that will find all records from the childDS that belong // under this parent record (eg lineItems in a salesOrder) criteria[relationship.parentIdField] = (isRoot ? relationship.rootValue : parentNode[relationship.idField]); //this.logWarn("criteria is: " + this.echo(criteria)); } else { // we're going to fetch the entire tree in one go, so mark everything as loaded this.defaultLoadState = isc.Tree.LOADED; } // remember the parentNode whose children we are loading, and what relationship we used // also set up the callback to fire on return. var clientContext = isc.addProperties( {parentNode:parentNode, relationship:relationship, childrenReplyCallback:callback}, this.context ? this.context.clientContext : null); var requestProperties = isc.addProperties({parentNode: parentNode, resultTree:this}, this.context, { clientContext : clientContext }); // get an operation to do a select against the child DS var operationId = this.getOperationId(childDS, parentDS, parentNode); if (operationId) requestProperties.operationId = operationId; // set willHandleErrors to true so we can clear up our loading prompt on a server error requestProperties.willHandleError = true; // set the parent as loading if (parentNode != null) this.setLoadState(parentNode, isc.Tree.LOADING); // kick off the operation to fetch children childDS.fetchData(criteria, {caller:this, methodName:'loadChildrenReply'}, requestProperties); },loadChildrenReply : function (dsResponse, data, request) {// this.logWarn("loadChildren reply: " + Comm.serialize(dsResponse.data)); var context = dsResponse.clientContext; var parentNode = context.parentNode; // incorporate the new records into the tree var relationship = context.relationship, newNodes = dsResponse.data; // if we're returned an error handle it as if we were returned no data, then // call the standard RPCManager error handling code if (dsResponse.status < 0) newNodes = null; if (newNodes == null || newNodes.length == 0) { // no new nodes, mark parentNode as loaded this.setLoadState(parentNode, isc.Tree.LOADED); if (newNodes == null) { if (dsResponse.status < 0) { isc.RPCManager._handleError(dsResponse, request); } else { this.logWarn("null children returned; return empty List instead"); } newNodes = []; } } if (this.isMultiDSTree()) { for (var i = 0; i < newNodes.length; i++) { var node = newNodes[i]; // in a multi-DS tree, a node is a folder if there's a childDS to fetch nodes from var nextChildDS = this.getChildDataSource(node, relationship.childDS); if (nextChildDS != null) this.convertToFolder(node); // Node naming: // - in a single-DS tree, all nodes have an id that is unique tree-wide, the "idField" from // the tree relationship // - in a multi-DS tree, nodes are from a mix of DataSources and do not necessarily have a // tree-wide unique id - they only have a unique id within each set of children, since // each set of children can be from a different DataSource (even when on the same level). // // So, for multiDSTrees, in this case all newNodes are immediate children // // link it in this.add(node, parentNode); } } else { // we're dealing with a mixed bag of parents and children, any number of levels deep. In // this case we assume a unique id across all tree nodes, as opposed to just one level, and // run a linking algorithm that can handle the nodes in any order. this.linkNodes(newNodes, relationship.idField, relationship.parentIdField, relationship.rootValue, relationship.isFolderProperty, parentNode); }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -