<!DOCTYPE html>
|
<html>
|
<head>
|
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
|
<title>The source code</title>
|
<link href="../resources/prettify/prettify.css" type="text/css" rel="stylesheet" />
|
<script type="text/javascript" src="../resources/prettify/prettify.js"></script>
|
<style type="text/css">
|
.highlight { display: block; background-color: #ddd; }
|
</style>
|
<script type="text/javascript">
|
function highlight() {
|
document.getElementById(location.hash.replace(/#/, "")).className = "highlight";
|
}
|
</script>
|
</head>
|
<body onload="prettyPrint(); highlight();">
|
<pre class="prettyprint lang-js"><span id='Ext-data-NodeStore'>/**
|
</span> * Node Store
|
* @private
|
*/
|
Ext.define('Ext.data.NodeStore', {
|
extend: 'Ext.data.Store',
|
alias: 'store.node',
|
requires: ['Ext.data.NodeInterface'],
|
|
<span id='Ext-data-NodeStore-property-isNodeStore'> /**
|
</span> * @property {Boolean} isNodeStore
|
* `true` in this class to identify an object as an instantiated NodeStore, or subclass thereof.
|
*/
|
isNodeStore: true,
|
|
<span id='Ext-data-NodeStore-cfg-node'> /**
|
</span> * @cfg {Ext.data.Model} node
|
* The Record you want to bind this Store to. Note that
|
* this record will be decorated with the Ext.data.NodeInterface if this is not the
|
* case yet.
|
*/
|
node: null,
|
|
<span id='Ext-data-NodeStore-cfg-recursive'> /**
|
</span> * @cfg {Boolean} recursive
|
* Set this to true if you want this NodeStore to represent
|
* all the descendents of the node in its flat data collection. This is useful for
|
* rendering a tree structure to a DataView and is being used internally by
|
* the TreeView. Any records that are moved, removed, inserted or appended to the
|
* node at any depth below the node this store is bound to will be automatically
|
* updated in this Store's internal flat data structure.
|
*/
|
recursive: false,
|
|
<span id='Ext-data-NodeStore-cfg-rootVisible'> /**
|
</span> * @cfg {Boolean} rootVisible
|
* False to not include the root node in this Stores collection.
|
*/
|
rootVisible: false,
|
|
<span id='Ext-data-NodeStore-cfg-treeStore'> /**
|
</span> * @cfg {Ext.data.TreeStore} treeStore
|
* The TreeStore that is used by this NodeStore's Ext.tree.View.
|
*/
|
|
<span id='Ext-data-NodeStore-property-isExpandingOrCollapsing'> /**
|
</span> * @protected
|
* Recursion level counter. Incremented when expansion or collaping of a node is initiated,
|
* including when nested nodes below the expanding/collapsing root begin expanding or collapsing.
|
*
|
* This ensures that collapsestart, collapsecomplete, expandstart and expandcomplete only
|
* fire on the top level node being collapsed/expanded.
|
*
|
* Also, allows listeners to the `add` and `remove` events to know whether a collapse of expand is in progress.
|
*/
|
isExpandingOrCollapsing: 0,
|
|
<span id='Ext-data-NodeStore-method-constructor'> constructor: function(config) {
|
</span> var me = this,
|
node;
|
|
config = config || {};
|
Ext.apply(me, config);
|
|
//<debug>
|
if (Ext.isDefined(me.proxy)) {
|
Ext.Error.raise("A NodeStore cannot be bound to a proxy. Instead bind it to a record " +
|
"decorated with the NodeInterface by setting the node config.");
|
}
|
me.useModelWarning = false;
|
//</debug>
|
|
config.proxy = {type: 'proxy'};
|
me.callParent([config]);
|
|
node = me.node;
|
if (node) {
|
me.node = null;
|
me.setNode(node);
|
}
|
},
|
|
<span id='Ext-data-NodeStore-method-getTotalCount'> // NodeStores are never buffered or paged. They are loaded from the TreeStore to reflect all visible
|
</span> // nodes.
|
// BufferedRenderer always asks for the *total* count, so this must return the count.
|
getTotalCount: function() {
|
return this.getCount();
|
},
|
|
<span id='Ext-data-NodeStore-method-setNode'> setNode: function(node) {
|
</span> var me = this;
|
if (me.node && me.node != node) {
|
// We want to unbind our listeners on the old node
|
me.mun(me.node, {
|
expand: me.onNodeExpand,
|
collapse: me.onNodeCollapse,
|
append: me.onNodeAppend,
|
insert: me.onNodeInsert,
|
bulkremove: me.onBulkRemove,
|
remove: me.onNodeRemove,
|
sort: me.onNodeSort,
|
scope: me
|
});
|
me.node = null;
|
}
|
|
if (node) {
|
Ext.data.NodeInterface.decorate(node.self);
|
me.removeAll();
|
if (me.rootVisible) {
|
me.add(node);
|
} else if (!node.isExpanded() && me.treeStore.autoLoad !== false) {
|
node.expand();
|
}
|
|
me.mon(node, {
|
expand: me.onNodeExpand,
|
collapse: me.onNodeCollapse,
|
append: me.onNodeAppend,
|
insert: me.onNodeInsert,
|
bulkremove: me.onBulkRemove,
|
remove: me.onNodeRemove,
|
sort: me.onNodeSort,
|
scope: me
|
});
|
me.node = node;
|
if (node.isExpanded() && node.isLoaded()) {
|
me.onNodeExpand(node, node.childNodes, true);
|
}
|
}
|
},
|
|
<span id='Ext-data-NodeStore-method-onNodeSort'> onNodeSort: function(node, childNodes) {
|
</span> var me = this;
|
|
if ((me.indexOf(node) !== -1 || (node === me.node && !me.rootVisible) && node.isExpanded())) {
|
Ext.suspendLayouts();
|
me.onNodeCollapse(node, childNodes, true);
|
me.onNodeExpand(node, childNodes, true);
|
Ext.resumeLayouts(true);
|
}
|
},
|
|
<span id='Ext-data-NodeStore-method-onNodeExpand'> // Triggered by a NodeInterface's bubbled "expand" event.
|
</span> onNodeExpand: function(parent, records, suppressEvent) {
|
var me = this,
|
insertIndex = me.indexOf(parent) + 1,
|
toAdd = [];
|
|
// Used by the TreeView to bracket recursive expand & collapse ops
|
// and refresh the size. This is most effective when folder nodes are loaded,
|
// and this method is able to recurse.
|
if (!suppressEvent) {
|
me.fireEvent('beforeexpand', parent, records, insertIndex);
|
}
|
|
me.handleNodeExpand(parent, records, toAdd);
|
|
// The add event from this insertion is handled by TreeView.onAdd.
|
// That implementation calls parent and then ensures the previous sibling's joining lines are correct.
|
// The datachanged event is relayed by the TreeStore. Internally, that's not used.
|
me.insert(insertIndex, toAdd);
|
|
// Triggers the TreeView's onExpand method which calls refreshSize,
|
// and fires its afteritemexpand event
|
if (!suppressEvent) {
|
me.fireEvent('expand', parent, records);
|
}
|
},
|
|
<span id='Ext-data-NodeStore-method-handleNodeExpand'> // Collects child nodes to remove into the passed toRemove array.
|
</span> // When available, all descendant nodes are pushed into that array using recursion.
|
handleNodeExpand: function(parent, records, toAdd) {
|
var me = this,
|
ln = records ? records.length : 0,
|
i, record;
|
|
// recursive is hardcoded to true in TreeView.
|
if (!me.recursive && parent !== me.node) {
|
return;
|
}
|
|
if (parent !== this.node && !me.isVisible(parent)) {
|
return;
|
}
|
|
if (ln) {
|
// The view items corresponding to these are rendered.
|
// Loop through and expand any of the non-leaf nodes which are expanded
|
for (i = 0; i < ln; i++) {
|
record = records[i];
|
|
// Add to array being collected by recursion when child nodes are loaded.
|
// Must be done here in loop so that child nodes are inserted into the stream in place
|
// in recursive calls.
|
toAdd.push(record);
|
|
if (record.isExpanded()) {
|
if (record.isLoaded()) {
|
// Take a shortcut - appends to toAdd array
|
me.handleNodeExpand(record, record.childNodes, toAdd);
|
}
|
else {
|
// Might be asynchronous if child nodes are not immediately available
|
record.set('expanded', false);
|
record.expand();
|
}
|
}
|
}
|
}
|
},
|
|
<span id='Ext-data-NodeStore-method-onBulkRemove'> // Triggered by NodeInterface's bubbled bulkremove event
|
</span> onBulkRemove: function(parent, childNodes, isMove) {
|
this.onNodeCollapse(parent, childNodes, true);
|
},
|
|
<span id='Ext-data-NodeStore-method-onNodeCollapse'> // Triggered by a NodeInterface's bubbled "collapse" event.
|
</span> onNodeCollapse: function(parent, records, suppressEvent, callback, scope) {
|
var me = this,
|
collapseIndex = me.indexOf(parent) + 1,
|
node, lastNodeIndexPlus, sibling, found;
|
|
if (!me.recursive && parent !== me.node) {
|
return;
|
}
|
|
// Used by the TreeView to bracket recursive expand & collapse ops.
|
// The TreeViewsets up the animWrap object if we are animating.
|
// It also caches the collapse callback to call when it receives the
|
// end collapse event. See below.
|
if (!suppressEvent) {
|
me.fireEvent('beforecollapse', parent, records, collapseIndex, callback, scope);
|
}
|
|
// Only attempt to remove the records if they are there.
|
// Collapsing an ancestor node *immediately removes from the view, ALL its descendant nodes at all levels*.
|
// But if the collapse was recursive, all descendant root nodes will still fire their
|
// events. But we must ignore those events here - we have nothing to do.
|
if (records.length && me.data.contains(records[0])) {
|
|
// Calculate the index *one beyond* the last node we are going to remove
|
// Need to loop up the tree to find the nearest view sibling, since it could
|
// exist at some level above the current node.
|
node = parent;
|
while (node.parentNode) {
|
sibling = node.nextSibling;
|
if (sibling) {
|
found = true;
|
lastNodeIndexPlus = me.indexOf(sibling);
|
break;
|
} else {
|
node = node.parentNode;
|
}
|
}
|
if (!found) {
|
lastNodeIndexPlus = me.getCount();
|
}
|
|
// Remove the whole collapsed node set.
|
me.removeAt(collapseIndex, lastNodeIndexPlus - collapseIndex);
|
}
|
|
// Triggers the TreeView's onCollapse method which calls refreshSize,
|
// and fires its afteritecollapse event
|
if (!suppressEvent) {
|
me.fireEvent('collapse', parent, records, collapseIndex);
|
}
|
},
|
|
<span id='Ext-data-NodeStore-method-onNodeAppend'> onNodeAppend: function(parent, node, index) {
|
</span> var me = this,
|
refNode, sibling;
|
|
// Only react to a node append if it is to a node which is expanded, and is part of a tree
|
if (me.isVisible(node)) {
|
if (index === 0) {
|
refNode = parent;
|
} else {
|
sibling = node.previousSibling;
|
while (sibling.isExpanded() && sibling.lastChild) {
|
sibling = sibling.lastChild;
|
}
|
refNode = sibling;
|
}
|
me.insert(me.indexOf(refNode) + 1, node);
|
if (!node.isLeaf() && node.isExpanded()) {
|
if (node.isLoaded()) {
|
// Take a shortcut
|
me.onNodeExpand(node, node.childNodes, true);
|
} else if (!me.treeStore.fillCount ) {
|
// If the node has been marked as expanded, it means the children
|
// should be provided as part of the raw data. If we're filling the nodes,
|
// the children may not have been loaded yet, so only do this if we're
|
// not in the middle of populating the nodes.
|
node.set('expanded', false);
|
node.expand();
|
}
|
}
|
}
|
},
|
|
<span id='Ext-data-NodeStore-method-onNodeInsert'> onNodeInsert: function(parent, node, refNode) {
|
</span> var me = this,
|
index = this.indexOf(refNode);
|
|
if (index != -1 && me.isVisible(node)) {
|
me.insert(index, node);
|
if (!node.isLeaf() && node.isExpanded()) {
|
if (node.isLoaded()) {
|
// Take a shortcut
|
me.onNodeExpand(node, node.childNodes, true);
|
}
|
else {
|
node.set('expanded', false);
|
node.expand();
|
}
|
}
|
}
|
},
|
|
<span id='Ext-data-NodeStore-method-onNodeRemove'> onNodeRemove: function(parent, node, isMove) {
|
</span> var me = this;
|
if (me.indexOf(node) != -1) {
|
|
// If the removed node is a non-leaf and is expanded, use the onCollapse method to get rid
|
// of all descendants at any level.
|
if (!node.isLeaf() && node.isExpanded()) {
|
|
// onCollapse expects to be able to use the "collapsing" node's parentNode
|
// and nextSibling pointers so temporarily reinstate them.
|
// Reinstating them is safe because we pass the suppressEvents flag, and no user code
|
// is executed.
|
node.parentNode = node.removeContext.parentNode;
|
node.nextSibling = node.removeContext.nextSibling;
|
me.onNodeCollapse(node, node.childNodes, true);
|
node.parentNode = node.nextSibling = null;
|
}
|
me.remove(node);
|
}
|
},
|
|
<span id='Ext-data-NodeStore-method-isVisible'> isVisible: function(node) {
|
</span> var parent = node.parentNode;
|
while (parent) {
|
// Hit root and it is expanded, the node is visible
|
if (parent === this.node && parent.data.expanded) {
|
return true;
|
}
|
|
// Hit a collapsed ancestor, the node is not visible
|
if (!parent.data.expanded) {
|
return false;
|
}
|
|
parent = parent.parentNode;
|
}
|
// Walked off the top - the node is not part of the tree structure
|
return false;
|
}
|
});</pre>
|
</body>
|
</html>
|