All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.smartclient.debug.public.sc.client.application.ResultTree.js Maven / Gradle / Ivy

The newest version!
/*
 * Isomorphic SmartClient
 * Version SC_SNAPSHOT-2011-08-08 (2011-08-08)
 * Copyright(c) 1998 and beyond Isomorphic Software, Inc. All rights reserved.
 * "SmartClient" is a trademark of Isomorphic Software, Inc.
 *
 * [email protected]
 *
 * http://smartclient.com/license
 */



//> @groupDef treeDataBinding
// 
// The SmartClient +link{TreeGrid} component is a visual representation of a tree and requires
// a +link{Tree} or +link{ResultTree} datatype passed via the +link{TreeGrid.data} attribute to
// initialize the tree view.  The +link{Tree} datatype is used when you want to provide all of
// the tree nodes in one shot at initialization time.  The +link{ResultTree} datatype is used
// when you want portions of the tree to be loaded on demand from the server.
// 

// Providing all data to the Tree at creation //

// The simplest mechanism by which to initialize a Tree is to simply provide all the data // up-front when the Tree itself is created. Depending on the format of your tree data, this // can be done by setting +link{Tree.root} or +link{Tree.data}. This functionality is provided // by the +link{Tree} class. //

// For examples of this type of databinding, see the following SDK examples: //

    //
  • +externalLink{/examples/components/treeGrid_init.html, TreeGrid Initialization Example} //
  • +externalLink{/examples/server_integration/#jstlTree, TreeGrid Initialization with JSTL} //
//

// Loading Tree nodes on demand //

// In this mode, tree nodes are loaded on-demand the first time a user expands a folder. This // approach is necessary for large trees. This functionality is provided by the // +link{ResultTree} class, which uses a +link{DataSource} to load data from the server. Each // DataSource Record becomes a +link{TreeNode}. //

// ResultTrees require that every node in the tree have an +link{Tree.idField,id} that is // unique tree-wide. When the user expands a folder whose contents have not yet been loaded // from the server (or you programmatically call openFolder() on such a node), the client // automatically sends a +link{DSRequest} to the server to ask for all immediate children of // that node. The +link{DSRequest} criteria will specify the id of the node for which children // are being requested via the parentId property (see +link{Tree.parentIdField}). // This client is asking the server: "give me all nodes whose parentId is the id of this // node". //

// If there are no pre-existing node ids in the dataset you are loading, you must generate node // ids (because the client needs some way to identify nodes when talking to the server). // Generally a node id should contain whatever information is required to fetch the node and // it's children on the server. One typical approach is to use the path to the node as a node // id. For XML datasets in particular, the path may be a valid XPath, so that server-side // lookup of child nodes is just a matter of applying the node id as an XPath to a server-side // XMLDocument. //

// +link{ResultTree}s are created for you by the +link{TreeGrid} when you set // +link{TreeGrid.dataSource}, but you can pass an initial dataset to a databound TreeGrid by // setting +link{TreeGrid.initialData}. The +link{Tree.idField} is derived from the dataSource // you provide to the TreeGrid - the first field marked as // +link{DataSourceField.primaryKey}:true becomes the idField of the ResultTree. // The +link{Tree.parentIdField} is found by looking for a field that has a // +link{DataSourceField.foreignKey} property pointing to the idField. //

// If you do not provide +link{TreeGrid.initialData}, the first DSRequest you receive will be a // request for the nodes under root. The id of the root node of the tree is the value of the // rootValue attribute on the +link{Tree.parentIdField} of the Tree DataSource. //

// For examples of this type of databinding, see the following SDK examples: //

    //
  • +externalLink{/examples/databinding/tree_databinding.jsp, TreeGrid DataBinding Example} //
  • +externalLink{/examples/server_integration/#xml2JSLOD, TreeGrid XML DataBinding} //
//

// Multi-Level load on demand //

// The ResultTree's DSRequests ask for the immediate children of a node only (by specifying // parentId in the criteria). Any nodes returned whose parentId field // value is unset or matches this criterion will be added to the tree as immediate children of the // node. However you are also free to return multiple levels of children. This can be done by // simply returning a flat list of descendents with valid id's and parentId's, exactly as though // you were initializing a multi-level tree via +link{Tree.data}. //

// Note that when receiving multiple levels of children, the ResultTree's assumption is that // if any children are loaded for a parent, then that parent is considered fully loaded. //

// When loading children for a given parent node, the ResultTree calls // +link{DataSource.fetchData} on its DataSource. For custom code that may need to reference // the parentNode or tree in some way, the parent node whose children are being loaded is // available on the dsRequest instance in the DataSource flow as dsRequest.parentNode, where it // can be inspected during +link{DataSource.transformRequest()}. // // @title Tree DataBinding // @treeLocation Client Reference/Data Binding // @visibility external //< //> @class ResultTree // ResultTrees are an implementation of the +link{class:Tree} API, used to handle hierarchical // data, whose nodes are DataSource records which are retrieved from a server. // // @visibility external // @treeLocation Client Reference/Data Binding //< isc.ClassFactory.defineClass("ResultTree", isc.Tree); isc.ResultTree.addProperties({ nameProperty:"__nodePath", nodeTypeProperty:"nodeType", childTypeProperty:"childType", modelType: "parent", // DataModel // --------------------------------------------------------------------------------------- //> @attr resultTree.dataSource (DataSource or ID : null : IR) // What +link{class:DataSource} is this resultTree associated with? // // @include dataModel.dataSource // @visibility external //< //> @attr resultTree.context (OperationContext : null : IRA) // OperationContext to be sent with all operations performed by this ResultTree. //< //> @attr resultTree.loadDataOnDemand (boolean : true : IR) // Does this resultTree load data incrementally as folders within the tree are opened, or // is it all loaded in a single request? // @see treeGrid.loadDataOnDemand // @visibility external //< loadDataOnDemand:true, //> @attr resultTree.defaultIsFolder (boolean : null : IR) // Controls whether nodes are assumed to be folders or leaves by default. //

// Nodes that have children or have the +link{tree.isFolderProperty,isFolderProperty} set // to true will always be considered folders. Other nodes will be considered folders or // leaves by default according to this setting. //

// If defaultIsFolder is unset, the ResultTree will automatically set it to // match the value of +link{loadDataOnDemand}. This means that, when using // folder-by-folder load on demand (loadDataOnDemand:true), by default a newly // loaded node will be considered to be a folder that has not loaded its children yet. //

// When not using folder-by-folder load on demand, by default a newly loaded node is // considered a leaf. If you set defaultIsFolder:true explicitly, by default // a newly loaded node is considered to be a folder with no children. //

// See +link{Tree.isFolder()} for details on how to explicitly mark nodes as folders or leaves. // // @see treeGrid.loadDataOnDemand // @visibility external //< //> @attr resultTree.rootNode (any : null :IR) // This attribute may be used to specify a root value for the parentIdField of this resultTree. // This overrides the default +link{DataSourceField.rootValue} for this tree, allowing // a component to navigate a tree starting at a specific node. //

// May be overridden via +link{TreeGrid.treeRootValue} for ResultTrees generated by a TreeGrid // component. // @visibility external //< //> @attr resultTree.discardParentlessNodes (boolean : null : IRA) // When data is loaded from the server, should nodes with an explicit value for // the +link{tree.parentIdField} which doesn't map to a valid parent node be dropped? // If set to false, for +link{TreeGrid.loadDataOnDemand}:false trees, parentless nodes will be // added as children of the root node - for +link{TreeGrid.loadDataOnDemand}:true, they will be // added as children of the folder currently requesting children. //

// This effectively allows nodes to be loaded into the current (or root) folder without // needing an explicit +link{tree.parentIdField,parentIdField value} that matches the folder's // ID or rootValue for the resultTree. //

// Note: For loadDataOnDemand:false trees, if this property is unset at init time, // it will default to true if an explicit +link{resultTree.rootNode} has been // specified. This ensures that if the data tree retrieved from the server includes ancestors // of the desired root-node we don't display them. Otherwise this property always defaults to // false. // @visibility external //< //>@attr ResultTree.defaultNewNodesToRoot (boolean : false : IRWA) // This attribute governs how to handle cache-synch when a new node is added to this dataSource // with no explicit parentId. //

// If set to true, when a new node is added to this dataSource via // +link{DataSource.addData()}, with no explicit parentId, the node will be added as a // child of the root node of this result tree. Otherwise it will be ignored. //

// Similar logic applies to +link{DataSource.updateData(),updated nodes} - if this property is // true and the parentId of an updated node is cleared, it will be moved to become a child of // root, otherwise it will be dropped from the tree. // @visibility external //< defaultNewNodesToRoot:false, //> @attr resultTree.updateCacheFromRequest (boolean : true : IRA) // When a successful Add, Update or Remove type operation fires on this ResultTree's // dataSource, if +link{dsResponse.data} is unset, should we integrate the submitted // data values (from the request) into our data-set? // // @group cacheSync // @visibility external //< updateCacheFromRequest:true //> @attr resultTree.disableCacheSync (boolean : false : IRA) // By default when the data of this ResultTree's dataSource is modified, the ResultTree will // be updated to display these changes. // Set this flag to true to disable this behavior. // @group cacheSync // @visibility external //< }); isc.ResultTree.addMethods({ //> @method resultTree.init() (A) // Initialize this ResultTree. Pass in objects with properties to add or override // defaults. // // @param [all arguments] (object) objects with properties to override from default //< init : function (a,b,c,d,e,f) { // create a pointer to us in the global context isc.ClassFactory.addGlobalID(this); if (!this.criteria) this.criteria = {}; if (!this.operation) this.operation = {operationType : "fetch"}; // dataSource can be specified either on the operation or the ResultTree. if (!this.dataSource) this.dataSource = this.operation.dataSource; if (!this.operation.dataSource) this.operation.dataSource = this.dataSource; if (isc.isAn.Array(this.dataSource)) { this.dataSource = this.dataSource[0]; this.operation.dataSource = this.dataSource; } // If any of rootValue, idField, parentIdField are not explicitly specified on this // ResultTree, autodetect them from the DataSource relationship. if (!this.isMultiDSTree()) { // root node has to exist for getTreeRelationship to work, so create it now if it // doesn't exist if (!this.root) this.root = this.makeRoot(); var relationship = this.getTreeRelationship(this.root); var undef; // compare to undef because rootValue can be set to null if (this.rootValue === undef) this.rootValue = relationship.rootValue; // If we're not loading on demand, and the rootValue is not null/undef, // 'discardParentlessNodes' to true. // This ensures that if we load an entire tree, and have a rootValue set to pick up // a sub-tree of that, we don't add the full tree's top level element to root and thus // show the entire tree if (!this.loadDataOnDemand && (this.rootValue != null || (this.root != null && this.root[this.idField] != null)) && this.discardParentlessNodes == null) { this.discardParentlessNodes = true; } if (this.idField == null) this.idField = relationship.idField; if (this.parentIdField == null) this.parentIdField = relationship.parentIdField; if (relationship.childrenProperty) this.childrenProperty = relationship.childrenProperty; this.root[this.idField] = this.rootValue; } // establish default values for isFolderProperty et al that were not derived from the tree // relationship this.setupProperties(); if (this.initialData) { if ("parent" == this.modelType) this.data = this.initialData; else if ("children" == this.modelType) this.root = this.initialData; } // observe dataChanged on our dataSource var dataSource = isc.DataSource.getDataSource(this.dataSource); this.observe(dataSource, "dataChanged", "observer.dataSourceDataChanged(dsRequest,dsResponse);"); // whether to invalidate our cache when an update occurs on one of our datasources. // Default is update the current cache in place. this.dropCacheOnUpdate = this.operation.dropCacheOnUpdate; // set up defaultIsFolder before invoking Tree.init // This is required in linkNodes to ensure LOD ResultTrees' child nodes show up as // openable folders if (this.defaultIsFolder == null) this.defaultIsFolder = this.loadDataOnDemand; this.invokeSuper(isc.ResultTree, "init", a,b,c,d,e,f); // if we're not using folder-by-folder load on demand, all nodes should be initially marked loaded this.defaultLoadState = this.loadDataOnDemand ? isc.Tree.UNLOADED : isc.Tree.LOADED; }, destroy : function () { this.Super("destroy", arguments); var dataSource = isc.DataSource.getDataSource(this.dataSource); if (dataSource) this.ignore(dataSource, "dataChanged"); }, // A Tree navigates a 1 to many (parent to children) relationship, which can exist within or // across DataSources. // figuring out the type of child records at each level of the tree // - use cases // - all one type // - supported: set just this.dataSource // - fixed levels // - example: salesOrder, lineItem // - supported: set this.dataSource for root DataSource, this.treeRelations for transitions // - mixed child types (each parent in a level has different child types) // - example: outlook left-hand tree navigation: top level is a random conglomeration of Inbox, // Favorites, etc, each with different child node types (message folders, filesystem folders, // etc) // - 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 node getNodeDataSource : 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 root getRootDataSource : function () { if (this.operation && this.operation.dataSource) return isc.DS.get(this.operation.dataSource); else return isc.DS.get(this.dataSource); }, // get the criteria to apply (aside from parentId) when selecting children from childDS getCriteria : 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 parentNode getOperationId : 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; }, //> @method resultTree.loadChildren() // @include tree.loadChildren() //< //> @method resultTree.unloadChildren() // @include tree.unloadChildren() //< // 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) var parentIdFieldValue = parentNode[relationship.idField]; // Note: If we're loading the children of the root node, default to the // rootValue as specified at the dataSource level if no rootValue was specified directly // on the tree var undefined; if (isRoot && parentIdFieldValue === undefined) { parentIdFieldValue = relationship.rootValue; } criteria[relationship.parentIdField] = parentIdFieldValue; //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); // If this is the initial fetch, hang a flag on the clientContext so we know to fire the initial // fetch callback. if (!this._performedInitialFetch) { clientContext._isInitialFetch = true; this._performedInitialFetch = true; } 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: " + this.echoFull(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 we're returned the STATUS_OFFLINE condition, handle it as an empty dataset if (dsResponse.status == isc.RPCResponse.STATUS_OFFLINE) { newNodes = []; if (parentNode != null && !this.isRoot(parentNode)) { isc.say(window[request.componentId].offlineNodeMessage); } } if (newNodes == null || newNodes.length == 0) { // no new nodes, mark parentNode as loaded if (dsResponse.status == isc.RPCResponse.STATUS_OFFLINE) { this.setLoadState(parentNode, isc.Tree.UNLOADED); this.delayCall("closeFolder", [parentNode], 0); } else { 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. if (dsResponse.status == isc.RPCResponse.STATUS_OFFLINE) { this.setLoadState(parentNode, isc.Tree.UNLOADED); this.delayCall("closeFolder", [parentNode], 0); } else { this.linkNodes(newNodes, relationship.idField, relationship.parentIdField, relationship.rootValue, relationship.isFolderProperty, parentNode); } } // Fire any callback passed to 'loadChildren' in the scope of this tree. if (context.childrenReplyCallback) { this.fireCallback(context.childrenReplyCallback, "node", [parentNode], this); } // NOTE: when paging within child sets is implemented, we'll add "startChild,endChild" to // this signature if (this.dataArrived != null) { isc.Func.replaceWithMethod(this, "dataArrived", "parentNode"); this.dataArrived(parentNode); } }, // Cache sync // ------------------------------------ // On initial load of data for some folder, we always retrieve the entire set of children for the // parents of the node. // When dataChanged fires on our dataSource, we need to update these stored children arrays to // incorporate the modified nodes into our tree of local data. // helper method to get this.dataSource as a datasource object (even if specified as an ID only) getDataSource : function () { return isc.DataSource.getDataSource(this.dataSource); }, //> @method resultTree.invalidateCache() [A] // Manually invalidate this ResultTree's cache. //

// Generally a ResultTree will observe and incorporate updates to the DataSource that provides it's // records, but when this is not possible, invalidateCache() allows manual cache // invalidation. //

// Components bound to this ResultTree will typically re-request the currently visible portion // of the dataset, causing the ResultTree to re-fetch data from the server. // @visibility external //< invalidateCache : function () { if (!this.isLoaded(this.root)) return; // reset root to refetch all our data. var root = this.makeRoot(); this.setRoot(root); if (!this.loadDataOnDemand) this.reloadChildren(root); }, dataSourceDataChanged : function (dsRequest, dsResponse) { // respsect the flag to suppress cache sync altogether if (this.disableCacheSync) return; var updateData = isc.DataSource.getUpdatedData(dsRequest, dsResponse, this.updateCacheFromRequest); this.handleUpdate(dsRequest.operationType, updateData, dsResponse.invalidateCache); }, handleUpdate : function (operationType, updateData, forceCacheInvalidation) { if (isc._traceMarkers) arguments.__this = this; if (this.dropCacheOnUpdate || forceCacheInvalidation) { this.invalidateCache(); if (!this.getDataSource().canQueueRequests) this.dataChanged(); return; } // update our cached tree directly Note our cache is filtered, so we may just discard the // update if the new row doesn't pass the filter this.updateCache(operationType, updateData); this.dataChanged(); }, // updateCache() - catch-all method fired when the dataSource dataChanged method fires. // Integrates (or removes) the modified nodes into our local tree of data. updateCache : function (operationType, updateData) { if (updateData == null) return; operationType = isc.DS._getStandardOperationType(operationType); if (!isc.isAn.Array(updateData)) updateData = [updateData]; //>DEBUG if (this.logIsInfoEnabled()) { this.logInfo("Updating cache: operationType '" + operationType + "', " + updateData.length + " rows update data" + (this.logIsDebugEnabled() ? ":\n" + this.echoAll(updateData) : "")); } //DEBUG var removedRows = 0, addedRows = 0; //DEBUG if (this.logIsDebugEnabled() && !matchesFilter) { this.logDebug("updated node :\n" + this.echo(updateRow) + "\ndidn't match filter: " + this.echo(this.criteria)); } //DEBUG if (this.logIsDebugEnabled()) { this.logDebug("updated cache, " + (updateData.length - removedRows) + " out of " + updateData.length + " rows remain in cache, " + addedRows + " row(s) added."); } // @method resultTree.dataArrived // This callback fires whenever the resultTree receives new nodes from the server, after // the new nodes have been integrated into the tree. // // @param parentNode (TreeNode) The parentNode for which children were just loaded // // @visibility external //< dataArrived: "parentNode" });





© 2015 - 2024 Weber Informatics LLC | Privacy Policy