<!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-view-AbstractView'>/** </span> * @class Ext.view.AbstractView * This is an abstract superclass and should not be used directly. Please see {@link Ext.view.View}. * @private */ Ext.define('Ext.view.AbstractView', { extend: 'Ext.Component', requires: [ 'Ext.LoadMask', 'Ext.data.StoreManager', 'Ext.CompositeElementLite', 'Ext.DomQuery', 'Ext.selection.DataViewModel' ], mixins: { bindable: 'Ext.util.Bindable' }, inheritableStatics: { getRecord: function(node) { return this.getBoundView(node).getRecord(node); }, getBoundView: function(node) { return Ext.getCmp(node.boundView); } }, <span id='Ext-view-AbstractView-cfg-tpl'> /** </span> * @cfg {String/String[]/Ext.XTemplate} tpl (required) * The HTML fragment or an array of fragments that will make up the template used by this DataView. This should * be specified in the same format expected by the constructor of {@link Ext.XTemplate}. */ <span id='Ext-view-AbstractView-cfg-store'> /** </span> * @cfg {Ext.data.Store} store (required) * The {@link Ext.data.Store} to bind this DataView to. */ <span id='Ext-view-AbstractView-cfg-deferInitialRefresh'> /** </span> * @cfg {Boolean} deferInitialRefresh * <p>Defaults to <code>true</code> to defer the initial refresh of the view.</p> * <p>This allows the View to execute its render and initial layout more quickly because the process will not be encumbered * by the expensive update of the view structure.</p> * <p><b>Important: </b>Be aware that this will mean that the View's item elements will not be available immediately upon render, so * <i>selection</i> may not take place at render time. To access a View's item elements as soon as possible, use the {@link #viewready} event. * Or set <code>deferInitialrefresh</code> to false, but this will be at the cost of slower rendering.</p> */ deferInitialRefresh: true, <span id='Ext-view-AbstractView-cfg-itemSelector'> /** </span> * @cfg {String} itemSelector (required) * <b>This is a required setting</b>. A simple CSS selector (e.g. <tt>div.some-class</tt> or * <tt>span:first-child</tt>) that will be used to determine what nodes this DataView will be * working with. The itemSelector is used to map DOM nodes to records. As such, there should * only be one root level element that matches the selector for each record. */ <span id='Ext-view-AbstractView-cfg-itemCls'> /** </span> * @cfg {String} itemCls * Specifies the class to be assigned to each element in the view when used in conjunction with the * {@link #itemTpl} configuration. */ itemCls: Ext.baseCSSPrefix + 'dataview-item', <span id='Ext-view-AbstractView-cfg-itemTpl'> /** </span> * @cfg {String/String[]/Ext.XTemplate} itemTpl * The inner portion of the item template to be rendered. Follows an XTemplate * structure and will be placed inside of a tpl. */ <span id='Ext-view-AbstractView-cfg-overItemCls'> /** </span> * @cfg {String} overItemCls * A CSS class to apply to each item in the view on mouseover. * Setting this will automatically set {@link #trackOver} to `true`. */ //<locale> <span id='Ext-view-AbstractView-cfg-loadingText'> /** </span> * @cfg {String} loadingText * A string to display during data load operations. If specified, this text will be * displayed in a loading div and the view's contents will be cleared while loading, otherwise the view's * contents will continue to display normally until the new data is loaded and the contents are replaced. */ loadingText: 'Loading...', //</locale> <span id='Ext-view-AbstractView-cfg-loadMask'> /** </span> * @cfg {Boolean/Object} loadMask * False to disable a load mask from displaying while the view is loading. This can also be a * {@link Ext.LoadMask} configuration object. */ loadMask: true, <span id='Ext-view-AbstractView-cfg-loadingCls'> /** </span> * @cfg {String} loadingCls * The CSS class to apply to the loading message element. Defaults to Ext.LoadMask.prototype.msgCls "x-mask-loading". */ <span id='Ext-view-AbstractView-cfg-loadingUseMsg'> /** </span> * @cfg {Boolean} loadingUseMsg * Whether or not to use the loading message. * @private */ loadingUseMsg: true, <span id='Ext-view-AbstractView-cfg-loadingHeight'> /** </span> * @cfg {Number} loadingHeight * If specified, gives an explicit height for the data view when it is showing the {@link #loadingText}, * if that is specified. This is useful to prevent the view's height from collapsing to zero when the * loading mask is applied and there are no other contents in the data view. */ <span id='Ext-view-AbstractView-cfg-selectedItemCls'> /** </span> * @cfg {String} selectedItemCls * A CSS class to apply to each selected item in the view. */ selectedItemCls: Ext.baseCSSPrefix + 'item-selected', //<locale> <span id='Ext-view-AbstractView-cfg-emptyText'> /** </span> * @cfg {String} emptyText * The text to display in the view when there is no data to display. * Note that when using local data the emptyText will not be displayed unless you set * the {@link #deferEmptyText} option to false. */ emptyText: "", //</locale> <span id='Ext-view-AbstractView-cfg-deferEmptyText'> /** </span> * @cfg {Boolean} deferEmptyText * True to defer emptyText being applied until the store's first load. */ deferEmptyText: true, <span id='Ext-view-AbstractView-cfg-trackOver'> /** </span> * @cfg {Boolean} trackOver * When `true` the {@link #overItemCls} will be applied to rows when hovered over. * This in return will also cause {@link Ext.view.View#highlightitem highlightitem} and * {@link Ext.view.View#unhighlightitem unhighlightitem} events to be fired. * * Enabled automatically when the {@link #overItemCls} config is set. */ trackOver: false, <span id='Ext-view-AbstractView-cfg-blockRefresh'> /** </span> * @cfg {Boolean} blockRefresh * Set this to true to ignore refresh events on the bound store. This is useful if * you wish to provide custom transition animations via a plugin */ blockRefresh: false, <span id='Ext-view-AbstractView-cfg-disableSelection'> /** </span> * @cfg {Boolean} disableSelection * True to disable selection within the DataView. This configuration will lock the selection model * that the DataView uses. */ <span id='Ext-view-AbstractView-cfg-preserveScrollOnRefresh'> /** </span> * @cfg {Boolean} preserveScrollOnRefresh=false * True to preserve scroll position across refresh operations. */ preserveScrollOnRefresh: false, //private last: false, triggerEvent: 'itemclick', triggerCtEvent: 'containerclick', addCmpEvents: function() { }, // private initComponent : function(){ var me = this, isDef = Ext.isDefined, itemTpl = me.itemTpl, memberFn = {}; if (itemTpl) { if (Ext.isArray(itemTpl)) { // string array itemTpl = itemTpl.join(''); } else if (Ext.isObject(itemTpl)) { // tpl instance memberFn = Ext.apply(memberFn, itemTpl.initialConfig); itemTpl = itemTpl.html; } if (!me.itemSelector) { me.itemSelector = '.' + me.itemCls; } itemTpl = Ext.String.format('<tpl for="."><div class="{0}">{1}</div></tpl>', me.itemCls, itemTpl); me.tpl = new Ext.XTemplate(itemTpl, memberFn); } //<debug> if (!isDef(me.tpl) || !isDef(me.itemSelector)) { Ext.Error.raise({ sourceClass: 'Ext.view.View', tpl: me.tpl, itemSelector: me.itemSelector, msg: "DataView requires both tpl and itemSelector configurations to be defined." }); } //</debug> me.callParent(); if(Ext.isString(me.tpl) || Ext.isArray(me.tpl)){ me.tpl = new Ext.XTemplate(me.tpl); } //<debug> // backwards compat alias for overClass/selectedClass // TODO: Consider support for overCls generation Ext.Component config if (isDef(me.overCls) || isDef(me.overClass)) { if (Ext.isDefined(Ext.global.console)) { Ext.global.console.warn('Ext.view.View: Using the deprecated overCls or overClass configuration. Use overItemCls instead.'); } me.overItemCls = me.overCls || me.overClass; delete me.overCls; delete me.overClass; } if (me.overItemCls) { me.trackOver = true; } if (isDef(me.selectedCls) || isDef(me.selectedClass)) { if (Ext.isDefined(Ext.global.console)) { Ext.global.console.warn('Ext.view.View: Using the deprecated selectedCls or selectedClass configuration. Use selectedItemCls instead.'); } me.selectedItemCls = me.selectedCls || me.selectedClass; delete me.selectedCls; delete me.selectedClass; } //</debug> me.addEvents( <span id='Ext-view-AbstractView-event-beforerefresh'> /** </span> * @event beforerefresh * Fires before the view is refreshed * @param {Ext.view.View} this The DataView object */ 'beforerefresh', <span id='Ext-view-AbstractView-event-refresh'> /** </span> * @event refresh * Fires when the view is refreshed * @param {Ext.view.View} this The DataView object */ 'refresh', <span id='Ext-view-AbstractView-event-viewready'> /** </span> * @event viewready * Fires when the View's item elements representing Store items has been rendered. If the {@link #deferInitialRefresh} flag * was set (and it is <code>true</code> by default), this will be <b>after</b> initial render, and no items will be available * for selection until this event fires. * @param {Ext.view.View} this */ 'viewready', <span id='Ext-view-AbstractView-event-itemupdate'> /** </span> * @event itemupdate * Fires when the node associated with an individual record is updated * @param {Ext.data.Model} record The model instance * @param {Number} index The index of the record/node * @param {HTMLElement} node The node that has just been updated */ 'itemupdate', <span id='Ext-view-AbstractView-event-itemadd'> /** </span> * @event itemadd * Fires when the nodes associated with an recordset have been added to the underlying store * @param {Ext.data.Model[]} records The model instance * @param {Number} index The index at which the set of record/nodes starts * @param {HTMLElement[]} node The node that has just been updated */ 'itemadd', <span id='Ext-view-AbstractView-event-itemremove'> /** </span> * @event itemremove * Fires when the node associated with an individual record is removed * @param {Ext.data.Model} record The model instance * @param {Number} index The index of the record/node */ 'itemremove' ); me.addCmpEvents(); // Look up the configured Store. If none configured, use the fieldless, empty Store defined in Ext.data.Store. me.store = Ext.data.StoreManager.lookup(me.store || 'ext-empty-store'); me.bindStore(me.store, true); me.all = new Ext.CompositeElementLite(); // We track the scroll position me.scrollState = { top: 0, left: 0 }; me.on({ scroll: me.onViewScroll, element: 'el', scope: me }); }, onRender: function() { var me = this, mask = me.loadMask, cfg = { msg: me.loadingText, msgCls: me.loadingCls, useMsg: me.loadingUseMsg, // The store gets bound in initComponent, so while // rendering let's push on the store store: me.getMaskStore() }; me.callParent(arguments); if (mask) { // either a config object if (Ext.isObject(mask)) { cfg = Ext.apply(cfg, mask); } // Attach the LoadMask to a *Component* so that it can be sensitive to resizing during long loads. // If this DataView is floating, then mask this DataView. // Otherwise, mask its owning Container (or this, if there *is* no owning Container). // LoadMask captures the element upon render. me.loadMask = new Ext.LoadMask(me, cfg); me.loadMask.on({ scope: me, beforeshow: me.onMaskBeforeShow, hide: me.onMaskHide }); } }, finishRender: function(){ var me = this; me.callParent(arguments); // Kick off the refresh before layouts are resumed after the render // completes, but after afterrender is fired on the view if (!me.up('[collapsed],[hidden]')) { me.doFirstRefresh(me.store); } }, onBoxReady: function() { var me = this; me.callParent(arguments); // If the refresh was not kicked off on render due to a collapsed or hidden ancestor, // kick it off as soon as we get layed out if (!me.firstRefreshDone) { me.doFirstRefresh(me.store); } }, getMaskStore: function(){ return this.store; }, onMaskBeforeShow: function(){ var me = this, loadingHeight = me.loadingHeight; me.getSelectionModel().deselectAll(); me.all.clear(); if (loadingHeight && loadingHeight > me.getHeight()) { me.hasLoadingHeight = true; me.oldMinHeight = me.minHeight; me.minHeight = loadingHeight; me.updateLayout(); } }, onMaskHide: function(){ var me = this; if (!me.destroying && me.hasLoadingHeight) { me.minHeight = me.oldMinHeight; me.updateLayout(); delete me.hasLoadingHeight; } }, beforeRender: function() { this.callParent(arguments); this.getSelectionModel().beforeViewRender(this); }, afterRender: function() { this.callParent(arguments); // Init the SelectionModel after any on('render') listeners have been added. // Drag plugins create a DragDrop instance in a render listener, and that needs // to see an itemmousedown event first. this.getSelectionModel().bindComponent(this); }, <span id='Ext-view-AbstractView-method-getSelectionModel'> /** </span> * Gets the selection model for this view. * @return {Ext.selection.Model} The selection model */ getSelectionModel: function(){ var me = this, mode = 'SINGLE'; if (!me.selModel) { me.selModel = {}; } if (me.simpleSelect) { mode = 'SIMPLE'; } else if (me.multiSelect) { mode = 'MULTI'; } Ext.applyIf(me.selModel, { allowDeselect: me.allowDeselect, mode: mode }); if (!me.selModel.events) { me.selModel = new Ext.selection.DataViewModel(me.selModel); } if (!me.selModel.hasRelaySetup) { me.relayEvents(me.selModel, [ 'selectionchange', 'beforeselect', 'beforedeselect', 'select', 'deselect', 'focuschange' ]); me.selModel.hasRelaySetup = true; } // lock the selection model if user // has disabled selection if (me.disableSelection) { me.selModel.locked = true; } return me.selModel; }, <span id='Ext-view-AbstractView-method-refresh'> /** </span> * Refreshes the view by reloading the data from the store and re-rendering the template. */ refresh: function() { var me = this, targetEl, targetParent, oldDisplay, nextSibling, dom, records; if (!me.rendered || me.isDestroyed) { return; } if (!me.hasListeners.beforerefresh || me.fireEvent('beforerefresh', me) !== false) { targetEl = me.getTargetEl(); records = me.store.getRange(); dom = targetEl.dom; // Updating is much quicker if done when the targetEl is detached from the document, and not displayed. // But this resets the scroll position, so when preserving scroll position, this cannot be done. if (!me.preserveScrollOnRefresh) { targetParent = dom.parentNode; oldDisplay = dom.style.display; dom.style.display = 'none'; nextSibling = dom.nextSibling; targetParent.removeChild(dom); } if (me.refreshCounter) { me.clearViewEl(); } else { me.fixedNodes = targetEl.dom.childNodes.length; me.refreshCounter = 1; } // Always attempt to create the required markup after the fixedNodes. // Usually, for an empty record set, this would be blank, but when the Template // Creates markup outside of the record loop, this must still be honoured even if there are no // records. me.tpl.append(targetEl, me.collectData(records, 0)); // The emptyText is now appended to the View's element // after any fixedNodes. if (records.length < 1) { if (!me.deferEmptyText || me.hasSkippedEmptyText) { Ext.core.DomHelper.insertHtml('beforeEnd', targetEl.dom, me.emptyText); } me.all.clear(); } else { me.all.fill(Ext.query(me.getItemSelector(), targetEl.dom)); me.updateIndexes(0); } me.selModel.refresh(); me.hasSkippedEmptyText = true; if (!me.preserveScrollOnRefresh) { targetParent.insertBefore(dom, nextSibling); dom.style.display = oldDisplay; } // Ensure layout system knows about new content size this.refreshSize(); me.fireEvent('refresh', me); // Upon first refresh, fire the viewready event. // Reconfiguring the grid "renews" this event. if (!me.viewReady) { // Fire an event when deferred content becomes available. // This supports grid Panel's deferRowRender capability me.viewReady = true; me.fireEvent('viewready', me); } } }, <span id='Ext-view-AbstractView-method-refreshSize'> /** </span> * @private * Called by the framework when the view is refreshed, or when rows are added or deleted. * * These operations may cause the view's dimensions to change, and if the owning container * is shrinkwrapping this view, then the layout must be updated to accommodate these new dimensions. */ refreshSize: function() { var sizeModel = this.getSizeModel(); if (sizeModel.height.shrinkWrap || sizeModel.width.shrinkWrap) { this.updateLayout(); } }, clearViewEl: function(){ // The purpose of this is to allow boilerplate HTML nodes to remain in place inside a View // while the transient, templated data can be discarded and recreated. // The first time through this code, we take a count of the number of existing child nodes. // Subsequent refreshes then do not clear the entire element, but remove all nodes // *after* the fixedNodes count. // In particular, this is used in infinite grid scrolling: A very tall "stretcher" element is // inserted into the View's element to create a scrollbar of the correct proportion. var me = this, el = me.getTargetEl(); if (me.fixedNodes) { while (el.dom.childNodes[me.fixedNodes]) { el.dom.removeChild(el.dom.childNodes[me.fixedNodes]); } } else { el.update(''); } me.refreshCounter++; }, // Private template method to be overridden in subclasses. onViewScroll: Ext.emptyFn, <span id='Ext-view-AbstractView-method-saveScrollState'> /** </span> * Saves the scrollState in a private variable. Must be used in conjunction with restoreScrollState. * @private */ saveScrollState: function() { if (this.rendered) { var dom = this.el.dom, state = this.scrollState; state.left = dom.scrollLeft; state.top = dom.scrollTop; } }, <span id='Ext-view-AbstractView-method-restoreScrollState'> /** </span> * Restores the scrollState. * Must be used in conjunction with saveScrollState * @private */ restoreScrollState: function() { if (this.rendered) { var dom = this.el.dom, state = this.scrollState; dom.scrollLeft = state.left; dom.scrollTop = state.top; } }, <span id='Ext-view-AbstractView-method-prepareData'> /** </span> * Function which can be overridden to provide custom formatting for each Record that is used by this * DataView's {@link #tpl template} to render each node. * @param {Object/Object[]} data The raw data object that was used to create the Record. * @param {Number} recordIndex the index number of the Record being prepared for rendering. * @param {Ext.data.Model} record The Record being prepared for rendering. * @return {Array/Object} The formatted data in a format expected by the internal {@link #tpl template}'s overwrite() method. * (either an array if your params are numeric (i.e. {0}) or an object (i.e. {foo: 'bar'})) */ prepareData: function(data, index, record) { var associatedData, attr; if (record) { associatedData = record.getAssociatedData(); for (attr in associatedData) { if (associatedData.hasOwnProperty(attr)) { data[attr] = associatedData[attr]; } } } return data; }, <span id='Ext-view-AbstractView-method-collectData'> /** </span> * <p>Function which can be overridden which returns the data object passed to this * DataView's {@link #tpl template} to render the whole DataView.</p> * <p>This is usually an Array of data objects, each element of which is processed by an * {@link Ext.XTemplate XTemplate} which uses <tt>'&lt;tpl for="."&gt;'</tt> to iterate over its supplied * data object as an Array. However, <i>named</i> properties may be placed into the data object to * provide non-repeating data such as headings, totals etc.</p> * @param {Ext.data.Model[]} records An Array of {@link Ext.data.Model}s to be rendered into the DataView. * @param {Number} startIndex the index number of the Record being prepared for rendering. * @return {Object[]} An Array of data objects to be processed by a repeating XTemplate. May also * contain <i>named</i> properties. */ collectData : function(records, startIndex){ var data = [], i = 0, len = records.length, record; for (; i < len; i++) { record = records[i]; data[i] = this.prepareData(record.data, startIndex + i, record); } return data; }, // private bufferRender : function(records, index){ var me = this, div = me.renderBuffer || (me.renderBuffer = document.createElement('div')); me.tpl.overwrite(div, me.collectData(records, index)); return Ext.query(me.getItemSelector(), div); }, // private onUpdate : function(ds, record){ var me = this, index, node; if (me.viewReady) { index = me.store.indexOf(record); if (index > -1) { node = me.bufferRender([record], index)[0]; // ensure the node actually exists in the DOM if (me.getNode(record)) { me.all.replaceElement(index, node, true); me.updateIndexes(index, index); // Maintain selection after update // TODO: Move to approriate event handler. me.selModel.refresh(); if (me.hasListeners.itemupdate) { me.fireEvent('itemupdate', record, index, node); } return node; } } } }, // private onAdd : function(ds, records, index) { var me = this, nodes; if (me.rendered) { // If we are adding into an empty view, we must refresh in order that the *full tpl* is applied // which might create boilerplate content *around* the record nodes. if (me.all.getCount() === 0) { me.refresh(); return; } nodes = me.bufferRender(records, index); me.doAdd(nodes, records, index); me.selModel.refresh(); me.updateIndexes(index); // Ensure layout system knows about new content size me.refreshSize(); if (me.hasListeners.itemadd) { me.fireEvent('itemadd', records, index, nodes); } } }, doAdd: function(nodes, records, index) { var all = this.all, count = all.getCount(); if (count === 0) { this.clearViewEl(); this.getTargetEl().appendChild(nodes); } else if (index < count) { if (index === 0) { all.item(index).insertSibling(nodes, 'before', true); } else { all.item(index - 1).insertSibling(nodes, 'after', true); } } else { all.last().insertSibling(nodes, 'after', true); } Ext.Array.insert(all.elements, index, nodes); }, // private onRemove : function(ds, record, index) { var me = this; if (me.all.getCount()) { if (me.store.getCount() === 0) { // Refresh so emptyText can be applied if necessary me.refresh(); } else { // Just remove the element which corresponds to the removed record // The tpl's full HTML will still be in place. me.doRemove(record, index); if (me.selModel.refreshOnRemove) { me.selModel.refresh(); } me.updateIndexes(index); } // Ensure layout system knows about new content height this.refreshSize(); if (me.hasListeners.itemremove) { me.fireEvent('itemremove', record, index); } } }, doRemove: function(record, index) { this.all.removeElement(index, true); }, <span id='Ext-view-AbstractView-method-refreshNode'> /** </span> * Refreshes an individual node's data from the store. * @param {Number} index The item's data index in the store */ refreshNode : function(index){ this.onUpdate(this.store, this.store.getAt(index)); }, // private updateIndexes : function(startIndex, endIndex) { var ns = this.all.elements, records = this.store.getRange(), i; startIndex = startIndex || 0; endIndex = endIndex || ((endIndex === 0) ? 0 : (ns.length - 1)); for (i = startIndex; i <= endIndex; i++) { ns[i].viewIndex = i; ns[i].viewRecordId = records[i].internalId; if (!ns[i].boundView) { ns[i].boundView = this.id; } } }, <span id='Ext-view-AbstractView-method-getStore'> /** </span> * Returns the store associated with this DataView. * @return {Ext.data.Store} The store */ getStore : function() { return this.store; }, <span id='Ext-view-AbstractView-method-bindStore'> /** </span> * Changes the data store bound to this view and refreshes it. * @param {Ext.data.Store} store The store to bind to this view */ bindStore : function(store, initial) { var me = this; me.mixins.bindable.bindStore.apply(me, arguments); // Bind the store to our selection model unless it's the initial bind. // Initial bind takes place afterRender if (!initial) { me.getSelectionModel().bindStore(me.store); } // If we have already achieved our first layout, refresh immediately. // If we have bound to the Store before the first layout, then onBoxReady will // call doFirstRefresh if (me.componentLayoutCounter) { me.doFirstRefresh(store); } }, <span id='Ext-view-AbstractView-method-doFirstRefresh'> /** </span> * @private * Perform the first refresh of the View from a newly bound store. * * This is called when this View has been sized for the first time. */ doFirstRefresh: function(store) { var me = this; // Flag to prevent a second "first" refresh from onBoxReady me.firstRefreshDone = true; // 4.1.0: If we have a store, and the Store is *NOT* already loading (a refresh is on the way), then // on first layout, refresh regardless of record count. // Template may contain boilerplate HTML outside of record iteration loop. // Also, emptyText is appended by the refresh method. // We call refresh on a defer if this is the initial call, and we are configured to defer the initial refresh. if (store && !store.loading) { if (me.deferInitialRefresh) { me.applyFirstRefresh(); } else { me.refresh(); } } }, applyFirstRefresh: function(){ var me = this; if (me.isDestroyed) { return; } // In the case of an animated collapse/expand, the layout will // be marked as though it's complete, yet the element itself may // still be animating, which means we could trigger a layout while // everything is not in the correct place. As such, wait until the // animation has finished before kicking off the refresh. The problem // occurs because both the refresh and the animation are running on // a timer which makes it impossible to control the order of when // the refresh is fired. if (me.up('[isCollapsingOrExpanding]')) { Ext.Function.defer(me.applyFirstRefresh, 100, me); } else { Ext.Function.defer(function () { if (!me.isDestroyed) { me.refresh(); } }, 1); } }, onUnbindStore: function(store) { this.setMaskBind(null); }, onBindStore: function(store) { this.setMaskBind(store); }, setMaskBind: function(store) { var mask = this.loadMask; if (mask && mask.bindStore) { mask.bindStore(store); } }, getStoreListeners: function() { var me = this; return { refresh: me.onDataRefresh, add: me.onAdd, remove: me.onRemove, update: me.onUpdate, clear: me.refresh }; }, <span id='Ext-view-AbstractView-method-onDataRefresh'> /** </span> * @private * Calls this.refresh if this.blockRefresh is not true */ onDataRefresh: function() { var me = this, // If we have an ancestor in a non-boxready state (collapsed or in-transition, or hidden), and we are still waiting // for the first refresh, then block the refresh because that first visible, expanded layout will trigger the refresh blockedByAncestor = !me.firstRefreshDone && (!me.rendered || me.up('[collapsed],[isCollapsingOrExpanding],[hidden]')); // If are blocking *an initial refresh* because of an ancestor in a non-boxready state, // then cancel any defer on the initial refresh that is going to happen on boxReady - that will be a data-driven refresh, NOT // a render-time, delayable refresh. This is particularly important if the boxready occurs because of the "preflight" layout // of an animated expand. If refresh is delayed it occur during the expand animation and cause errors. if (blockedByAncestor) { me.deferInitialRefresh = false; } else if (me.blockRefresh !== true) { me.firstRefreshDone = true; me.refresh.apply(me, arguments); } }, <span id='Ext-view-AbstractView-method-findItemByChild'> /** </span> * Returns the template node the passed child belongs to, or null if it doesn't belong to one. * @param {HTMLElement} node * @return {HTMLElement} The template node */ findItemByChild: function(node){ return Ext.fly(node).findParent(this.getItemSelector(), this.getTargetEl()); }, <span id='Ext-view-AbstractView-method-findTargetByEvent'> /** </span> * Returns the template node by the Ext.EventObject or null if it is not found. * @param {Ext.EventObject} e */ findTargetByEvent: function(e) { return e.getTarget(this.getItemSelector(), this.getTargetEl()); }, <span id='Ext-view-AbstractView-method-getSelectedNodes'> /** </span> * Gets the currently selected nodes. * @return {HTMLElement[]} An array of HTMLElements */ getSelectedNodes: function(){ var nodes = [], records = this.selModel.getSelection(), ln = records.length, i = 0; for (; i < ln; i++) { nodes.push(this.getNode(records[i])); } return nodes; }, <span id='Ext-view-AbstractView-method-getRecords'> /** </span> * Gets an array of the records from an array of nodes * @param {HTMLElement[]} nodes The nodes to evaluate * @return {Ext.data.Model[]} records The {@link Ext.data.Model} objects */ getRecords: function(nodes) { var records = [], i = 0, len = nodes.length, data = this.store.data; for (; i < len; i++) { records[records.length] = data.getByKey(nodes[i].viewRecordId); } return records; }, <span id='Ext-view-AbstractView-method-getRecord'> /** </span> * Gets a record from a node * @param {Ext.Element/HTMLElement} node The node to evaluate * * @return {Ext.data.Model} record The {@link Ext.data.Model} object */ getRecord: function(node){ return this.store.data.getByKey(Ext.getDom(node).viewRecordId); }, <span id='Ext-view-AbstractView-method-isSelected'> /** </span> * Returns true if the passed node is selected, else false. * @param {HTMLElement/Number/Ext.data.Model} node The node, node index or record to check * @return {Boolean} True if selected, else false */ isSelected : function(node) { // TODO: El/Idx/Record var r = this.getRecord(node); return this.selModel.isSelected(r); }, <span id='Ext-view-AbstractView-method-select'> /** </span> * Selects a record instance by record instance or index. * @param {Ext.data.Model[]/Number} records An array of records or an index * @param {Boolean} keepExisting * @param {Boolean} suppressEvent Set to false to not fire a select event * @deprecated 4.0 Use {@link Ext.selection.Model#select} instead. */ select: function(records, keepExisting, suppressEvent) { this.selModel.select(records, keepExisting, suppressEvent); }, <span id='Ext-view-AbstractView-method-deselect'> /** </span> * Deselects a record instance by record instance or index. * @param {Ext.data.Model[]/Number} records An array of records or an index * @param {Boolean} suppressEvent Set to false to not fire a deselect event */ deselect: function(records, suppressEvent) { this.selModel.deselect(records, suppressEvent); }, <span id='Ext-view-AbstractView-method-getNode'> /** </span> * Gets a template node. * @param {HTMLElement/String/Number/Ext.data.Model} nodeInfo An HTMLElement template node, index of a template node, * the id of a template node or the record associated with the node. * @return {HTMLElement} The node or null if it wasn't found */ getNode : function(nodeInfo) { if ((!nodeInfo && nodeInfo !== 0) || !this.rendered) { return null; } if (Ext.isString(nodeInfo)) { return document.getElementById(nodeInfo); } if (Ext.isNumber(nodeInfo)) { return this.all.elements[nodeInfo]; } if (nodeInfo.isModel) { return this.getNodeByRecord(nodeInfo); } return nodeInfo; // already an HTMLElement }, <span id='Ext-view-AbstractView-method-getNodeByRecord'> /** </span> * @private */ getNodeByRecord: function(record) { var ns = this.all.elements, ln = ns.length, i = 0; for (; i < ln; i++) { if (ns[i].viewRecordId === record.internalId) { return ns[i]; } } return null; }, <span id='Ext-view-AbstractView-method-getNodes'> /** </span> * Gets a range nodes. * @param {Number} start (optional) The index of the first node in the range * @param {Number} end (optional) The index of the last node in the range * @return {HTMLElement[]} An array of nodes */ getNodes: function(start, end) { var ns = this.all.elements; if (end === undefined) { end = ns.length; } else { end++; } return this.all.elements.slice(start||0, end); }, <span id='Ext-view-AbstractView-method-indexOf'> /** </span> * Finds the index of the passed node. * @param {HTMLElement/String/Number/Ext.data.Model} nodeInfo An HTMLElement template node, index of a template node, the id of a template node * or a record associated with a node. * @return {Number} The index of the node or -1 */ indexOf: function(node) { node = this.getNode(node); if (!node && node !== 0) { return -1; } if (Ext.isNumber(node.viewIndex)) { return node.viewIndex; } return this.all.indexOf(node); }, onDestroy : function() { var me = this; me.all.clear(); me.callParent(); me.bindStore(null); me.selModel.destroy(); }, // invoked by the selection model to maintain visual UI cues onItemSelect: function(record) { var node = this.getNode(record); if (node) { Ext.fly(node).addCls(this.selectedItemCls); } }, // invoked by the selection model to maintain visual UI cues onItemDeselect: function(record) { var node = this.getNode(record); if (node) { Ext.fly(node).removeCls(this.selectedItemCls); } }, getItemSelector: function() { return this.itemSelector; } }, function() { // all of this information is available directly // from the SelectionModel itself, the only added methods // to DataView regarding selection will perform some transformation/lookup // between HTMLElement/Nodes to records and vice versa. Ext.deprecate('extjs', '4.0', function() { Ext.view.AbstractView.override({ <span id='Ext-view-AbstractView-cfg-multiSelect'> /** </span> * @cfg {Boolean} [multiSelect=false] * True to allow selection of more than one item at a time, false to allow selection of only a single item * at a time or no selection at all, depending on the value of {@link #singleSelect}. * @deprecated 4.1.1 Use {@link Ext.selection.Model#mode} 'MULTI' instead. */ <span id='Ext-view-AbstractView-cfg-singleSelect'> /** </span> * @cfg {Boolean} [singleSelect] * Allows selection of exactly one item at a time. As this is the default selection mode anyway, this config * is completely ignored. * @removed 4.1.1 Use {@link Ext.selection.Model#mode} 'SINGLE' instead. */ <span id='Ext-view-AbstractView-cfg-simpleSelect'> /** </span> * @cfg {Boolean} [simpleSelect=false] * True to enable multiselection by clicking on multiple items without requiring the user to hold Shift or Ctrl, * false to force the user to hold Ctrl or Shift to select more than on item. * @deprecated 4.1.1 Use {@link Ext.selection.Model#mode} 'SIMPLE' instead. */ <span id='Ext-view-AbstractView-method-getSelectionCount'> /** </span> * Gets the number of selected nodes. * @return {Number} The node count * @deprecated 4.0 Use {@link Ext.selection.Model#getCount} instead. */ getSelectionCount : function(){ if (Ext.global.console) { Ext.global.console.warn("DataView: getSelectionCount will be removed, please interact with the Ext.selection.DataViewModel"); } return this.selModel.getSelection().length; }, <span id='Ext-view-AbstractView-method-getSelectedRecords'> /** </span> * Gets an array of the selected records * @return {Ext.data.Model[]} An array of {@link Ext.data.Model} objects * @deprecated 4.0 Use {@link Ext.selection.Model#getSelection} instead. */ getSelectedRecords : function(){ if (Ext.global.console) { Ext.global.console.warn("DataView: getSelectedRecords will be removed, please interact with the Ext.selection.DataViewModel"); } return this.selModel.getSelection(); }, select: function(records, keepExisting, supressEvents) { if (Ext.global.console) { Ext.global.console.warn("DataView: select will be removed, please access select through a DataView's SelectionModel, ie: view.getSelectionModel().select()"); } var sm = this.getSelectionModel(); return sm.select.apply(sm, arguments); }, <span id='Ext-view-AbstractView-method-clearSelections'> /** </span> * Deselects all selected records. * @deprecated 4.0 Use {@link Ext.selection.Model#deselectAll} instead. */ clearSelections: function() { if (Ext.global.console) { Ext.global.console.warn("DataView: clearSelections will be removed, please access deselectAll through DataView's SelectionModel, ie: view.getSelectionModel().deselectAll()"); } var sm = this.getSelectionModel(); return sm.deselectAll(); } }); }); }); </pre> </body> </html>