/ext-4.0.7/docs/source/Lockable.html
https://bitbucket.org/srogerf/javascript · HTML · 733 lines · 634 code · 99 blank · 0 comment · 0 complexity · 3c7601a636189997dfc2fd0da6b274fb MD5 · raw file
- <!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-grid-Lockable'>/**
- </span> * @class Ext.grid.Lockable
- * @private
- *
- * Lockable is a private mixin which injects lockable behavior into any
- * TablePanel subclass such as GridPanel or TreePanel. TablePanel will
- * automatically inject the Ext.grid.Lockable mixin in when one of the
- * these conditions are met:
- *
- * - The TablePanel has the lockable configuration set to true
- * - One of the columns in the TablePanel has locked set to true/false
- *
- * Each TablePanel subclass must register an alias. It should have an array
- * of configurations to copy to the 2 separate tablepanel's that will be generated
- * to note what configurations should be copied. These are named normalCfgCopy and
- * lockedCfgCopy respectively.
- *
- * Columns which are locked must specify a fixed width. They do NOT support a
- * flex width.
- *
- * Configurations which are specified in this class will be available on any grid or
- * tree which is using the lockable functionality.
- */
- Ext.define('Ext.grid.Lockable', {
- requires: ['Ext.grid.LockingView'],
- <span id='Ext-grid-Lockable-cfg-syncRowHeight'> /**
- </span> * @cfg {Boolean} syncRowHeight Synchronize rowHeight between the normal and
- * locked grid view. This is turned on by default. If your grid is guaranteed
- * to have rows of all the same height, you should set this to false to
- * optimize performance.
- */
- syncRowHeight: true,
- <span id='Ext-grid-Lockable-cfg-subGridXType'> /**
- </span> * @cfg {String} subGridXType The xtype of the subgrid to specify. If this is
- * not specified lockable will determine the subgrid xtype to create by the
- * following rule. Use the superclasses xtype if the superclass is NOT
- * tablepanel, otherwise use the xtype itself.
- */
- <span id='Ext-grid-Lockable-cfg-lockedViewConfig'> /**
- </span> * @cfg {Object} lockedViewConfig A view configuration to be applied to the
- * locked side of the grid. Any conflicting configurations between lockedViewConfig
- * and viewConfig will be overwritten by the lockedViewConfig.
- */
- <span id='Ext-grid-Lockable-cfg-normalViewConfig'> /**
- </span> * @cfg {Object} normalViewConfig A view configuration to be applied to the
- * normal/unlocked side of the grid. Any conflicting configurations between normalViewConfig
- * and viewConfig will be overwritten by the normalViewConfig.
- */
- // private variable to track whether or not the spacer is hidden/visible
- spacerHidden: true,
- headerCounter: 0,
- // i8n text
- unlockText: 'Unlock',
- lockText: 'Lock',
- determineXTypeToCreate: function() {
- var me = this,
- typeToCreate;
- if (me.subGridXType) {
- typeToCreate = me.subGridXType;
- } else {
- var xtypes = this.getXTypes().split('/'),
- xtypesLn = xtypes.length,
- xtype = xtypes[xtypesLn - 1],
- superxtype = xtypes[xtypesLn - 2];
- if (superxtype !== 'tablepanel') {
- typeToCreate = superxtype;
- } else {
- typeToCreate = xtype;
- }
- }
- return typeToCreate;
- },
- // injectLockable will be invoked before initComponent's parent class implementation
- // is called, so throughout this method this. are configurations
- injectLockable: function() {
- // ensure lockable is set to true in the TablePanel
- this.lockable = true;
- // Instruct the TablePanel it already has a view and not to create one.
- // We are going to aggregate 2 copies of whatever TablePanel we are using
- this.hasView = true;
- var me = this,
- // xtype of this class, 'treepanel' or 'gridpanel'
- // (Note: this makes it a requirement that any subclass that wants to use lockable functionality needs to register an
- // alias.)
- xtype = me.determineXTypeToCreate(),
- // share the selection model
- selModel = me.getSelectionModel(),
- lockedGrid = {
- xtype: xtype,
- // Lockable does NOT support animations for Tree
- enableAnimations: false,
- scroll: false,
- scrollerOwner: false,
- selModel: selModel,
- border: false,
- cls: Ext.baseCSSPrefix + 'grid-inner-locked'
- },
- normalGrid = {
- xtype: xtype,
- enableAnimations: false,
- scrollerOwner: false,
- selModel: selModel,
- border: false
- },
- i = 0,
- columns,
- lockedHeaderCt,
- normalHeaderCt;
- me.addCls(Ext.baseCSSPrefix + 'grid-locked');
- // copy appropriate configurations to the respective
- // aggregated tablepanel instances and then delete them
- // from the master tablepanel.
- Ext.copyTo(normalGrid, me, me.normalCfgCopy);
- Ext.copyTo(lockedGrid, me, me.lockedCfgCopy);
- for (; i < me.normalCfgCopy.length; i++) {
- delete me[me.normalCfgCopy[i]];
- }
- for (i = 0; i < me.lockedCfgCopy.length; i++) {
- delete me[me.lockedCfgCopy[i]];
- }
- me.addEvents(
- <span id='Ext-grid-Lockable-event-lockcolumn'> /**
- </span> * @event lockcolumn
- * Fires when a column is locked.
- * @param {Ext.grid.Panel} this The gridpanel.
- * @param {Ext.grid.column.Column} column The column being locked.
- */
- 'lockcolumn',
- <span id='Ext-grid-Lockable-event-unlockcolumn'> /**
- </span> * @event unlockcolumn
- * Fires when a column is unlocked.
- * @param {Ext.grid.Panel} this The gridpanel.
- * @param {Ext.grid.column.Column} column The column being unlocked.
- */
- 'unlockcolumn'
- );
- me.addStateEvents(['lockcolumn', 'unlockcolumn']);
- me.lockedHeights = [];
- me.normalHeights = [];
- columns = me.processColumns(me.columns);
- lockedGrid.width = columns.lockedWidth + Ext.num(selModel.headerWidth, 0);
- lockedGrid.columns = columns.locked;
- normalGrid.columns = columns.normal;
- me.store = Ext.StoreManager.lookup(me.store);
- lockedGrid.store = me.store;
- normalGrid.store = me.store;
- // normal grid should flex the rest of the width
- normalGrid.flex = 1;
- lockedGrid.viewConfig = me.lockedViewConfig || {};
- lockedGrid.viewConfig.loadingUseMsg = false;
- normalGrid.viewConfig = me.normalViewConfig || {};
- Ext.applyIf(lockedGrid.viewConfig, me.viewConfig);
- Ext.applyIf(normalGrid.viewConfig, me.viewConfig);
- me.normalGrid = Ext.ComponentManager.create(normalGrid);
- me.lockedGrid = Ext.ComponentManager.create(lockedGrid);
- me.view = Ext.create('Ext.grid.LockingView', {
- locked: me.lockedGrid,
- normal: me.normalGrid,
- panel: me
- });
- if (me.syncRowHeight) {
- me.lockedGrid.getView().on({
- refresh: me.onLockedGridAfterRefresh,
- itemupdate: me.onLockedGridAfterUpdate,
- scope: me
- });
- me.normalGrid.getView().on({
- refresh: me.onNormalGridAfterRefresh,
- itemupdate: me.onNormalGridAfterUpdate,
- scope: me
- });
- }
- lockedHeaderCt = me.lockedGrid.headerCt;
- normalHeaderCt = me.normalGrid.headerCt;
- lockedHeaderCt.lockedCt = true;
- lockedHeaderCt.lockableInjected = true;
- normalHeaderCt.lockableInjected = true;
- lockedHeaderCt.on({
- columnshow: me.onLockedHeaderShow,
- columnhide: me.onLockedHeaderHide,
- columnmove: me.onLockedHeaderMove,
- sortchange: me.onLockedHeaderSortChange,
- columnresize: me.onLockedHeaderResize,
- scope: me
- });
- normalHeaderCt.on({
- columnmove: me.onNormalHeaderMove,
- sortchange: me.onNormalHeaderSortChange,
- scope: me
- });
- me.normalGrid.on({
- scrollershow: me.onScrollerShow,
- scrollerhide: me.onScrollerHide,
- scope: me
- });
- me.lockedGrid.on('afterlayout', me.onLockedGridAfterLayout, me, {single: true});
- me.modifyHeaderCt();
- me.items = [me.lockedGrid, me.normalGrid];
- me.relayHeaderCtEvents(lockedHeaderCt);
- me.relayHeaderCtEvents(normalHeaderCt);
- me.layout = {
- type: 'hbox',
- align: 'stretch'
- };
- },
- processColumns: function(columns){
- // split apart normal and lockedWidths
- var i = 0,
- len = columns.length,
- lockedWidth = 1,
- lockedHeaders = [],
- normalHeaders = [],
- column;
- for (; i < len; ++i) {
- column = columns[i];
- // mark the column as processed so that the locked attribute does not
- // trigger trying to aggregate the columns again.
- column.processed = true;
- if (column.locked) {
- // <debug>
- if (column.flex) {
- Ext.Error.raise("Columns which are locked do NOT support a flex width. You must set a width on the " + columns[i].text + "column.");
- }
- // </debug>
- if (!column.hidden) {
- lockedWidth += column.width || Ext.grid.header.Container.prototype.defaultWidth;
- }
- lockedHeaders.push(column);
- } else {
- normalHeaders.push(column);
- }
- if (!column.headerId) {
- column.headerId = (column.initialConfig || column).id || ('L' + (++this.headerCounter));
- }
- }
- return {
- lockedWidth: lockedWidth,
- locked: lockedHeaders,
- normal: normalHeaders
- };
- },
- // create a new spacer after the table is refreshed
- onLockedGridAfterLayout: function() {
- var me = this,
- lockedView = me.lockedGrid.getView();
- lockedView.on({
- beforerefresh: me.destroySpacer,
- scope: me
- });
- },
- // trigger a pseudo refresh on the normal side
- onLockedHeaderMove: function() {
- if (this.syncRowHeight) {
- this.onNormalGridAfterRefresh();
- }
- },
- // trigger a pseudo refresh on the locked side
- onNormalHeaderMove: function() {
- if (this.syncRowHeight) {
- this.onLockedGridAfterRefresh();
- }
- },
- // create a spacer in lockedsection and store a reference
- // TODO: Should destroy before refreshing content
- getSpacerEl: function() {
- var me = this,
- w,
- view,
- el;
- if (!me.spacerEl) {
- // This affects scrolling all the way to the bottom of a locked grid
- // additional test, sort a column and make sure it synchronizes
- w = Ext.getScrollBarWidth() + (Ext.isIE ? 2 : 0);
- view = me.lockedGrid.getView();
- el = view.el;
- me.spacerEl = Ext.DomHelper.append(el, {
- cls: me.spacerHidden ? (Ext.baseCSSPrefix + 'hidden') : '',
- style: 'height: ' + w + 'px;'
- }, true);
- }
- return me.spacerEl;
- },
- destroySpacer: function() {
- var me = this;
- if (me.spacerEl) {
- me.spacerEl.destroy();
- delete me.spacerEl;
- }
- },
- // cache the heights of all locked rows and sync rowheights
- onLockedGridAfterRefresh: function() {
- var me = this,
- view = me.lockedGrid.getView(),
- el = view.el,
- rowEls = el.query(view.getItemSelector()),
- ln = rowEls.length,
- i = 0;
- // reset heights each time.
- me.lockedHeights = [];
- for (; i < ln; i++) {
- me.lockedHeights[i] = rowEls[i].clientHeight;
- }
- me.syncRowHeights();
- },
- // cache the heights of all normal rows and sync rowheights
- onNormalGridAfterRefresh: function() {
- var me = this,
- view = me.normalGrid.getView(),
- el = view.el,
- rowEls = el.query(view.getItemSelector()),
- ln = rowEls.length,
- i = 0;
- // reset heights each time.
- me.normalHeights = [];
- for (; i < ln; i++) {
- me.normalHeights[i] = rowEls[i].clientHeight;
- }
- me.syncRowHeights();
- },
- // rows can get bigger/smaller
- onLockedGridAfterUpdate: function(record, index, node) {
- this.lockedHeights[index] = node.clientHeight;
- this.syncRowHeights();
- },
- // rows can get bigger/smaller
- onNormalGridAfterUpdate: function(record, index, node) {
- this.normalHeights[index] = node.clientHeight;
- this.syncRowHeights();
- },
- // match the rowheights to the biggest rowheight on either
- // side
- syncRowHeights: function() {
- var me = this,
- lockedHeights = me.lockedHeights,
- normalHeights = me.normalHeights,
- calcHeights = [],
- ln = lockedHeights.length,
- i = 0,
- lockedView, normalView,
- lockedRowEls, normalRowEls,
- vertScroller = me.getVerticalScroller(),
- scrollTop;
- // ensure there are an equal num of locked and normal
- // rows before synchronization
- if (lockedHeights.length && normalHeights.length) {
- lockedView = me.lockedGrid.getView();
- normalView = me.normalGrid.getView();
- lockedRowEls = lockedView.el.query(lockedView.getItemSelector());
- normalRowEls = normalView.el.query(normalView.getItemSelector());
- // loop thru all of the heights and sync to the other side
- for (; i < ln; i++) {
- // ensure both are numbers
- if (!isNaN(lockedHeights[i]) && !isNaN(normalHeights[i])) {
- if (lockedHeights[i] > normalHeights[i]) {
- Ext.fly(normalRowEls[i]).setHeight(lockedHeights[i]);
- } else if (lockedHeights[i] < normalHeights[i]) {
- Ext.fly(lockedRowEls[i]).setHeight(normalHeights[i]);
- }
- }
- }
- // invalidate the scroller and sync the scrollers
- me.normalGrid.invalidateScroller();
- // synchronize the view with the scroller, if we have a virtualScrollTop
- // then the user is using a PagingScroller
- if (vertScroller && vertScroller.setViewScrollTop) {
- vertScroller.setViewScrollTop(me.virtualScrollTop);
- } else {
- // We don't use setScrollTop here because if the scrollTop is
- // set to the exact same value some browsers won't fire the scroll
- // event. Instead, we directly set the scrollTop.
- scrollTop = normalView.el.dom.scrollTop;
- normalView.el.dom.scrollTop = scrollTop;
- lockedView.el.dom.scrollTop = scrollTop;
- }
- // reset the heights
- me.lockedHeights = [];
- me.normalHeights = [];
- }
- },
- // track when scroller is shown
- onScrollerShow: function(scroller, direction) {
- if (direction === 'horizontal') {
- this.spacerHidden = false;
- this.getSpacerEl().removeCls(Ext.baseCSSPrefix + 'hidden');
- }
- },
- // track when scroller is hidden
- onScrollerHide: function(scroller, direction) {
- if (direction === 'horizontal') {
- this.spacerHidden = true;
- if (this.spacerEl) {
- this.spacerEl.addCls(Ext.baseCSSPrefix + 'hidden');
- }
- }
- },
- // inject Lock and Unlock text
- modifyHeaderCt: function() {
- var me = this;
- me.lockedGrid.headerCt.getMenuItems = me.getMenuItems(true);
- me.normalGrid.headerCt.getMenuItems = me.getMenuItems(false);
- },
- onUnlockMenuClick: function() {
- this.unlock();
- },
- onLockMenuClick: function() {
- this.lock();
- },
- getMenuItems: function(locked) {
- var me = this,
- unlockText = me.unlockText,
- lockText = me.lockText,
- unlockCls = Ext.baseCSSPrefix + 'hmenu-unlock',
- lockCls = Ext.baseCSSPrefix + 'hmenu-lock',
- unlockHandler = Ext.Function.bind(me.onUnlockMenuClick, me),
- lockHandler = Ext.Function.bind(me.onLockMenuClick, me);
- // runs in the scope of headerCt
- return function() {
- var o = Ext.grid.header.Container.prototype.getMenuItems.call(this);
- o.push('-',{
- cls: unlockCls,
- text: unlockText,
- handler: unlockHandler,
- disabled: !locked
- });
- o.push({
- cls: lockCls,
- text: lockText,
- handler: lockHandler,
- disabled: locked
- });
- return o;
- };
- },
- // going from unlocked section to locked
- <span id='Ext-grid-Lockable-method-lock'> /**
- </span> * Locks the activeHeader as determined by which menu is open OR a header
- * as specified.
- * @param {Ext.grid.column.Column} header (Optional) Header to unlock from the locked section. Defaults to the header which has the menu open currently.
- * @param {Number} toIdx (Optional) The index to move the unlocked header to. Defaults to appending as the last item.
- * @private
- */
- lock: function(activeHd, toIdx) {
- var me = this,
- normalGrid = me.normalGrid,
- lockedGrid = me.lockedGrid,
- normalHCt = normalGrid.headerCt,
- lockedHCt = lockedGrid.headerCt;
- activeHd = activeHd || normalHCt.getMenu().activeHeader;
- // if column was previously flexed, get/set current width
- // and remove the flex
- if (activeHd.flex) {
- activeHd.width = activeHd.getWidth();
- delete activeHd.flex;
- }
- normalHCt.remove(activeHd, false);
- lockedHCt.suspendLayout = true;
- activeHd.locked = true;
- if (Ext.isDefined(toIdx)) {
- lockedHCt.insert(toIdx, activeHd);
- } else {
- lockedHCt.add(activeHd);
- }
- lockedHCt.suspendLayout = false;
- me.syncLockedSection();
- me.fireEvent('lockcolumn', me, activeHd);
- },
- syncLockedSection: function() {
- var me = this;
- me.syncLockedWidth();
- me.lockedGrid.getView().refresh();
- me.normalGrid.getView().refresh();
- },
- // adjust the locked section to the width of its respective
- // headerCt
- syncLockedWidth: function() {
- var me = this,
- width = me.lockedGrid.headerCt.getFullWidth(true);
- me.lockedGrid.setWidth(width+1); // +1 for border pixel
- me.doComponentLayout();
- },
- onLockedHeaderResize: function() {
- this.syncLockedWidth();
- },
- onLockedHeaderHide: function() {
- this.syncLockedWidth();
- },
- onLockedHeaderShow: function() {
- this.syncLockedWidth();
- },
- onLockedHeaderSortChange: function(headerCt, header, sortState) {
- if (sortState) {
- // no real header, and silence the event so we dont get into an
- // infinite loop
- this.normalGrid.headerCt.clearOtherSortStates(null, true);
- }
- },
- onNormalHeaderSortChange: function(headerCt, header, sortState) {
- if (sortState) {
- // no real header, and silence the event so we dont get into an
- // infinite loop
- this.lockedGrid.headerCt.clearOtherSortStates(null, true);
- }
- },
- // going from locked section to unlocked
- <span id='Ext-grid-Lockable-method-unlock'> /**
- </span> * Unlocks the activeHeader as determined by which menu is open OR a header
- * as specified.
- * @param {Ext.grid.column.Column} header (Optional) Header to unlock from the locked section. Defaults to the header which has the menu open currently.
- * @param {Number} toIdx (Optional) The index to move the unlocked header to. Defaults to 0.
- * @private
- */
- unlock: function(activeHd, toIdx) {
- var me = this,
- normalGrid = me.normalGrid,
- lockedGrid = me.lockedGrid,
- normalHCt = normalGrid.headerCt,
- lockedHCt = lockedGrid.headerCt;
- if (!Ext.isDefined(toIdx)) {
- toIdx = 0;
- }
- activeHd = activeHd || lockedHCt.getMenu().activeHeader;
- lockedHCt.remove(activeHd, false);
- me.syncLockedWidth();
- me.lockedGrid.getView().refresh();
- activeHd.locked = false;
- normalHCt.insert(toIdx, activeHd);
- me.normalGrid.getView().refresh();
- me.fireEvent('unlockcolumn', me, activeHd);
- },
- applyColumnsState: function (columns) {
- var me = this,
- lockedGrid = me.lockedGrid,
- lockedHeaderCt = lockedGrid.headerCt,
- normalHeaderCt = me.normalGrid.headerCt,
- lockedCols = lockedHeaderCt.items,
- normalCols = normalHeaderCt.items,
- existing,
- locked = [],
- normal = [],
- lockedDefault,
- lockedWidth = 1;
- Ext.each(columns, function (col) {
- function matches (item) {
- return item.headerId == col.id;
- }
- lockedDefault = true;
- if (!(existing = lockedCols.findBy(matches))) {
- existing = normalCols.findBy(matches);
- lockedDefault = false;
- }
- if (existing) {
- if (existing.applyColumnState) {
- existing.applyColumnState(col);
- }
- if (!Ext.isDefined(existing.locked)) {
- existing.locked = lockedDefault;
- }
- if (existing.locked) {
- locked.push(existing);
- if (!existing.hidden && Ext.isNumber(existing.width)) {
- lockedWidth += existing.width;
- }
- } else {
- normal.push(existing);
- }
- }
- });
- // state and config must have the same columns (compare counts for now):
- if (locked.length + normal.length == lockedCols.getCount() + normalCols.getCount()) {
- lockedHeaderCt.removeAll(false);
- normalHeaderCt.removeAll(false);
- lockedHeaderCt.add(locked);
- normalHeaderCt.add(normal);
- lockedGrid.setWidth(lockedWidth);
- }
- },
- getColumnsState: function () {
- var me = this,
- locked = me.lockedGrid.headerCt.getColumnsState(),
- normal = me.normalGrid.headerCt.getColumnsState();
- return locked.concat(normal);
- },
- // we want to totally override the reconfigure behaviour here, since we're creating 2 sub-grids
- reconfigureLockable: function(store, columns) {
- var me = this,
- lockedGrid = me.lockedGrid,
- normalGrid = me.normalGrid;
- if (columns) {
- lockedGrid.headerCt.suspendLayout = true;
- normalGrid.headerCt.suspendLayout = true;
- lockedGrid.headerCt.removeAll();
- normalGrid.headerCt.removeAll();
- columns = me.processColumns(columns);
- lockedGrid.setWidth(columns.lockedWidth);
- lockedGrid.headerCt.add(columns.locked);
- normalGrid.headerCt.add(columns.normal);
- }
- if (store) {
- store = Ext.data.StoreManager.lookup(store);
- me.store = store;
- lockedGrid.bindStore(store);
- normalGrid.bindStore(store);
- } else {
- lockedGrid.getView().refresh();
- normalGrid.getView().refresh();
- }
- if (columns) {
- lockedGrid.headerCt.suspendLayout = false;
- normalGrid.headerCt.suspendLayout = false;
- lockedGrid.headerCt.forceComponentLayout();
- normalGrid.headerCt.forceComponentLayout();
- }
- }
- });
- </pre>
- </body>
- </html>