// // TODO: Add GridPanel.getView() to the lib // TODO: Rename Ext.ux.PreviewPlugin -> Ext.grid.RowPreviewPlugin // TODO: Move CSS styles from paging.html into grid.css // TODO: Move JsonStore fix into the lib // /*======================================================================== * * This section contains stuff that should be in Ext4, or stuff that * is up for discussion. It should be removed prior to Ext 4 final. * *========================================================================*/ // This should be working as the alternateClassName but doesn't for some reason Ext.toolbar.Toolbar.SplitButton = Ext.button.Split; // DomHelper does not currently go through the ClassManager so there is no alternateClassName Ext.DomHelper = Ext.core.DomHelper; Ext.apply(Ext.panel.Panel.prototype, { getToolbars : function(){ return this.getDockedItems('toolbar'); } }); // Not sure if these are intended to be deprecated or they just haven't been moved over Ext.apply(Ext.menu.Menu.prototype, { addSeparator : function() { return this.add(Ext.create('Ext.menu.Separator')); }, addElement : function(el) { return this.add(Ext.create('Ext.menu.Item', { el: el })); }, addItem : function(item) { return this.add(item); }, addMenuItem : function(config) { return this.add(this.lookupComponent(config)); }, addText : function(text){ return this.add(Ext.create('Ext.menu.Item', { plain: true, text: text })); } }); /*======================================================================== * * This section contains true compatibility overrides and should ship * with Ext 4 as an optional compatibility layer for Ext 3 code. * Ext.Compat is defined in ext3-core-compat.js. * *========================================================================*/ (function(){ var compat = Ext.Compat, deprecate = Ext.bind(compat.deprecate, compat), notify = Ext.bind(compat.notify, compat), breaking = Ext.bind(compat.breaking, compat); /*------------------------------------------------------------- * Date (from the Ext.util folder in 3.x) *-------------------------------------------------------------*/ (function(){ var nativeDate = window.Date, utilDate = Ext.Date, staticMappings = ['useStrict', 'formatCodeToRegex', 'parseFunctions', 'parseRegexes', 'formatFunctions', 'y2kYear', 'MILLI', 'SECOND', 'MINUTE', 'HOUR', 'DAY', 'MONTH', 'YEAR', 'defaults', 'dayNames', 'monthNames', 'monthNumbers', 'formatCodes', 'getFormatCode', 'createFormat', 'createParser', 'parseCodes'], staticOverrides = ['getShortMonthName', 'getShortDayName', 'getMonthNumber', 'isValid', 'parseDate'], proto = ['dateFormat', 'format', 'getTimezone', 'getGMTOffset', 'getDayOfYear', 'getWeekOfYear', 'isLeapYear', 'getFirstDayOfMonth', 'getLastDayOfMonth', 'getFirstDateOfMonth', 'getLastDateOfMonth', 'getDaysInMonth', 'getSuffix', 'clone', 'isDST', 'clearTime', 'add', 'between']; // Static direct mappings. These are either private methods or any members // that cannot be aliased as methods to include a warning. These are documented // in the migration guide as breaking changes to be fixed. Ext.Array.forEach(staticMappings, function(member) { nativeDate[member] = utilDate[member]; }); // Static overrides. These are public static methods that can be overridden // as methods to include console warnings. Ext.Array.forEach(staticOverrides, function(member) { nativeDate[member] = function(){ deprecate({pkg:'Date', member:member, alt:'Ext.Date.'+member}); return utilDate[member].apply(utilDate, arguments); }; }); // Prototype (instance) overrides Ext.Array.forEach(proto, function(member) { nativeDate.prototype[member] = function() { if(member !== 'dateFormat'){ // dateFormat is actually private, and it is aliased publicly as "format". It needs // to be included, but we can skip the warning as it would be a duplicate of the format // warning and would actually be misleading since it won't have been called directly. // All other methods in this array are public and should give a warning. deprecate({pkg:'Date', member:'.'+member, alt:'Ext.Date.'+member, msg:'Note that this is now a static method, so the date instance will be the first argument to the new version.'}); } return utilDate[member].apply(utilDate, [this].concat(Array.prototype.slice.call(arguments))); }; }); })(); /*------------------------------------------------------------- * XTypes *-------------------------------------------------------------*/ if (Ext.ClassManager) { Ext.apply(Ext.ClassManager, { instantiateByAlias: Ext.Function.createInterceptor(Ext.ClassManager.instantiateByAlias, function() { var args = Ext.Array.toArray(arguments), alias = args.shift(); // // These are xtypes that are not currently aliased in the framework code. // Not sure if these should really be deprecated or not... // if(alias == 'widget.tbsplit'){ deprecate({pkg:'Core', member:'tbsplit', alt:'splitbutton', type:'xtype'}); Ext.ClassManager.setAlias('Ext.button.Split', 'widget.tbsplit'); } if(alias == 'widget.progress'){ deprecate({pkg:'Core', member:'progress', alt:'progressbar', type:'xtype'}); Ext.ClassManager.setAlias('Ext.ProgressBar', 'widget.progress'); } }) }); } /*------------------------------------------------------------- * MicedCollection *-------------------------------------------------------------*/ if (Ext.util.AbstractMixedCollection) { Ext.apply(Ext.util.AbstractMixedCollection.prototype, { removeKey : function() { deprecate({pkg:'Ext.util.MixedCollection', member:'removeKey', alt:'removeAtKey'}); return this.removeAtKey.apply(this, arguments); }, item : function() { deprecate({pkg:'Ext.util.MixedCollection', member:'item', alt:'get'}); return this.get.apply(this, arguments); }, itemAt : function() { deprecate({pkg:'Ext.util.MixedCollection', member:'itemAt', alt:'getAt'}); return this.getAt.apply(this, arguments); }, key : function() { deprecate({pkg:'Ext.util.MixedCollection', member:'key', alt:'getByKey'}); return this.getByKey.apply(this, arguments); } }); } if (Ext.util.MixedCollection) { Ext.apply(Ext.util.MixedCollection.prototype, { constructor: Ext.Function.createInterceptor(Ext.util.MixedCollection.prototype.constructor, function() { this._origSort = this.sort; this.sort = function(dir, fn) { if (Ext.isFunction(fn)) { deprecate({pkg:'Ext.util.MixedCollection', member:'sort (with a comparator fn)', alt:'sortBy', msg:'Calling MixedCollection.sort and passing a comparator function as the second parameter '+ 'is no longer supported. See the docs for MixedCollection.sort to see the current '+ 'valid parameter list. When passing a comparator function, use sortBy instead.'}); return this.sortBy(fn); } return this._origSort(arguments); } }), keySort : function() { deprecate({pkg:'Ext.util.MixedCollection', member:'keySort', alt:'sortByKey'}); return this.sortByKey.apply(this, arguments); } }); } /*------------------------------------------------------------- * AbstractComponent *-------------------------------------------------------------*/ if (Ext.AbstractComponent) { Ext.apply(Ext.AbstractComponent.prototype, { addClass : function() { deprecate({pkg:'Ext.Component', member:'addClass', alt:'addCls'}); return this.addCls.apply(this, arguments); }, removeClass : function() { deprecate({pkg:'Ext.Component', member:'removeClass', alt:'removeCls'}); return this.removeCls.apply(this, arguments); } }); } /*------------------------------------------------------------- * Component *-------------------------------------------------------------*/ if (Ext.Component) { Ext.apply(Ext.Component.prototype, { initComponent: Ext.Function.createInterceptor(Ext.Component.prototype.initComponent, function() { if(Ext.isDefined(this.applyTo)){ deprecate({pkg:'Ext.Component', member:'applyTo', type:'config', alt:'renderTo', msg:'Applying components to existing markup via "applyTo" is no longer supported.'}); var replaced = false; try{ var target = Ext.get(this.applyTo); if (target) { var parent = target.parent(); if (parent) { this.renderTo = parent; target.remove(); replaced = true; notify({pkg:'Ext.Component', member:'applyTo', msg:'This component will attempt to render to '+ 'the applyTo target\'s parent node ("' + parent.id + '"). If this did not work as expected then '+ 'you will have to replace the applyTo config manually before this component will render properly.'}) } } } catch(ex) {} if (!replaced) { breaking({pkg:'Ext.Component', member:'applyTo', msg:'Attempted to render the component to the applyTo target\'s '+ 'parent node, but this failed. You must resolve this manually before the component can render.'}) } } }) }); Ext.define('Ext.BoxComponent', { extend: 'Ext.Component', constructor: function() { deprecate({member:'Ext.BoxComponent', alt:'Ext.Component', msg:'All functionality from BoxComponent is now directly in Component. '+ 'Replace "BoxComponent" with "Component" and/or xtype "box" with "component".'}); this.callParent(arguments); } }); } /*------------------------------------------------------------- * ComponentManager *-------------------------------------------------------------*/ if (Ext.ComponentManager) { var regMsg = 'Calling a separate function to register custom types is no longer necessary. '+ 'Switch your class definition to use Ext.define with "{0}" as the alias config.'; var checkClassRef = function(pkg, cls, member) { if (!Ext.isString(cls)) { breaking({pkg:pkg, member:member, msg:'You must either convert the passed class reference to a string -- e.g. ' + pkg + '.' + member + '("myclass", "Ext.ux.MyClass") -- or change your class definition to use Ext.define. '+ 'See the section in the Migration Guide on registering xtypes for more info.'}); } }; Ext.ComponentManager.registerType = function(xtype, cls){ deprecate({pkg:'ComponentManager', member:'registerType', msg:Ext.String.format(regMsg, 'widget.'+xtype)}); checkClassRef('ComponentManager', cls, 'registerType'); Ext.ClassManager.setAlias(cls, 'widget.'+xtype); }; Ext.reg = function(xtype, cls){ deprecate({pkg:'Ext', member:'reg', msg:Ext.String.format(regMsg, 'widget.'+xtype)}); checkClassRef('Ext', cls, 'reg'); Ext.ClassManager.setAlias(cls, 'widget.'+xtype); }; Ext.ComponentManager.registerPlugin = function(ptype, cls){ deprecate({pkg:'ComponentManager', member:'registerPlugin', msg:Ext.String.format(regMsg, 'plugin.'+ptype)}); checkClassRef('ComponentManager', cls, 'registerPlugin'); Ext.ClassManager.setAlias(cls, 'plugin.'+ptype); }; Ext.preg = function(ptype, cls){ deprecate({pkg:'Ext', member:'preg', msg:Ext.String.format(regMsg, 'plugin.'+ptype)}); checkClassRef('Ext', cls, 'preg'); Ext.ClassManager.setAlias(cls, 'plugin.'+ptype); }; } /*------------------------------------------------------------- * Container *-------------------------------------------------------------*/ if (Ext.container.AbstractContainer) { Ext.apply(Ext.container.AbstractContainer.prototype, { get: function(comp) { deprecate({pkg:'Ext.Container', member:'get', alt:'getComponent'}); return this.getComponent(comp); }, findById: function(id) { deprecate({pkg:'Ext.Container', member:'findById', alt:'query', msg:'Use the query method with the # id syntax, e.g. comp.query("#"+id).'}); return this.query('#'+id); } }); } if (Ext.container.Container) { Ext.apply(Ext.container.Container.prototype, { initComponent: Ext.Function.createInterceptor(Ext.container.Container.prototype.initComponent, function() { if (this.layout === 'form') { deprecate({pkg:'FormPanel', member:'form', type:'layout', msg:'Form layout no longer exists, use a different container layout and allow each field\'s '+ 'Field layout to apply labels. Falling back to anchor layout.'}); this.layout = 'anchor'; } }) }); } /*------------------------------------------------------------- * Toolbar *-------------------------------------------------------------*/ if (Ext.toolbar.Toolbar) { Ext.apply(Ext.toolbar.Toolbar.prototype, { addField : function(field){ deprecate({pkg:'Toolbar', member:'addField', alt:'add'}); return this.add(field); } }); } /*------------------------------------------------------------- * PagingToolbar *-------------------------------------------------------------*/ if (Ext.toolbar.Paging) { Ext.apply(Ext.toolbar.Paging.prototype, { constructor: Ext.Function.createInterceptor(Ext.toolbar.Paging.prototype.constructor, function(config) { if (config.paramNames) { var msg = 'Instead of params specific to this toolbar you should set any needed options on the associated store/proxy. '+ 'See the header docs for Ext.data.Store for details. The defaults for PagingToolbar {start: \'start\', limit: \'limit\'} '+ 'would map to the store\'s proxy as {startParam: \'start\', limitParam: \'limit\'}.'; if (config.store && config.store.proxy) { config.store.proxy.startParam = config.paramNames[start]; config.store.proxy.limitParam = config.paramNames[limit]; deprecate({pkg:'PagingToolbar', member:'paramNames', msg:msg}); } else { breaking({pkg:'PagingToolbar', member:'paramNames', msg:msg + ' No proxy is available in the current PagingToolbar '+ 'configuration so this cannot be aliased automatically.'}); } delete config.paramNames; } if (config.pageSize) { config.store.pageSize = config.pageSize; deprecate({pkg:'PagingToolbar', member:'pageSize', alt:'store.pageSize'}); } }), changePage : function(page){ deprecate({pkg:'PagingToolbar', member:'changePage', alt:'store.loadPage'}); this.store.loadPage(page); } }); } /*------------------------------------------------------------- * Views *-------------------------------------------------------------*/ if (Ext.view.AbstractView) { Ext.apply(Ext.view.AbstractView.prototype, { initComponent : function(){ var isDef = Ext.isDefined; if (!isDef(this.tpl) || !isDef(this.store) || !isDef(this.itemSelector)) { throw "DataView requires tpl, store and itemSelector configurations to be defined."; } Ext.view.AbstractView.superclass.initComponent.call(this); if(Ext.isString(this.tpl) || Ext.isArray(this.tpl)){ this.tpl = new Ext.XTemplate(this.tpl); } if (isDef(this.overClass)){ deprecate({pkg:'DataView', member:'overClass', alt:'overItemCls', type:'config'}); this.overItemCls = this.overClass; delete this.overClass; } if (isDef(this.overCls)){ deprecate({pkg:'DataView', member:'overCls', alt:'overItemCls', type:'config'}); this.overItemCls = this.overCls; delete this.overCls; } if (isDef(this.selectedClass)){ deprecate({pkg:'DataView', member:'selectedClass', alt:'selectedItemCls', type:'config'}); this.selectedItemCls = this.selectedClass; delete this.selectedClass; } if (isDef(this.selectedCls)){ deprecate({pkg:'DataView', member:'selectedCls', alt:'selectedItemCls', type:'config'}); this.selectedItemCls = this.selectedCls; delete this.selectedCls; } this.addEvents( 'beforerefresh', 'refresh' ); this.addCmpEvents(); this.store = Ext.data.StoreManager.lookup(this.store); this.all = new Ext.CompositeElementLite(); this.getSelectionModel().bindComponent(this); } }); } /*------------------------------------------------------------- * Panel *-------------------------------------------------------------*/ if (Ext.panel.Panel) { Ext.apply(Ext.panel.AbstractPanel.prototype, { initComponent: Ext.Function.createInterceptor(Ext.panel.AbstractPanel.prototype.initComponent, function() { if (this.bodyCssClass) { var me = this, msg = '', bodyCssClass = me.bodyCssClass; if (Ext.isFunction(bodyCssClass)) { me.bodyCls = bodyCssClass(); msg = 'Note that passing a function reference as the config value is no longer supported.' } else { me.bodyCls = bodyCssClass; } delete me.bodyCssClass; deprecate({pkg:'Ext.panel.Panel', member:'bodyCssClass', type:'config', alt:'bodyCls', msg:msg}); } }) }); Ext.apply(Ext.panel.Panel.prototype, { getTopToolbar: function(){ notify('Panel now supports an arbitrary number of toolbars, so getTopToolbar() will return the top toolbar at index 0 if multiple are found'); var items = this.getToolbars(); return items.length > 0 ? items[0] : null; }, getBottomToolbar: function(){ notify('Panel now supports an arbitrary number of toolbars, so getBottomToolbar() will return the bottom toolbar at index 0 if multiple are found'); var items = this.getToolbars(); return items.length > 0 ? items[0] : null; } }); } /*------------------------------------------------------------- * Layouts *-------------------------------------------------------------*/ if (Ext.layout.container.Accordion) { Ext.apply(Ext.layout.container.Accordion.prototype, { constructor: Ext.Function.createSequence(Ext.layout.container.Accordion.prototype.constructor, function() { notify('AccordionLayout now defaults to animating expand/collapse. To revert to the 3.x default behavior set animate:false on the layout.') }) }); } /*------------------------------------------------------------- * TablePanel *-------------------------------------------------------------*/ if (Ext.panel.Table) { Ext.apply(Ext.panel.Table.prototype, { initComponent: Ext.Function.createInterceptor(Ext.panel.Table.prototype.initComponent, function() { if (Ext.isDefined(this.preventHeaders)) { deprecate({pkg:'Ext.grid.Panel', member:'preventHeaders', type:'config', alt:'hideHeaders'}); this.hideHeaders = this.preventHeaders; delete this.preventHeaders; } }) }); } /*------------------------------------------------------------- * Grid components *-------------------------------------------------------------*/ if (Ext.grid.Panel) { Ext.apply(Ext.grid.Panel.prototype, { constructor: Ext.Function.createInterceptor(Ext.grid.Panel.prototype.constructor, function(config) { if (config.trackMouseOver !== undefined) { deprecate({pkg:'Ext.GridPanel', member:'trackMouseOver', alt:'trackOver', type:'config', msg:'Specify this as an attribute of the "viewConfig" config (e.g. viewConfig: {trackOver: false}).'}); config.viewConfig = config.viewConfig || {}; config.viewConfig.trackOver = config.viewConfig.trackOver || config.trackMouseOver; delete config.trackMouseOver; } if (config.stripeRows !== undefined) { deprecate({pkg:'Ext.GridPanel', member:'stripeRows', type:'config', msg:'The stripeRows option should now be passed as an attribute of the "viewConfig" config (e.g. viewConfig: {stripeRows: true}).'}); config.viewConfig = config.viewConfig || {}; config.viewConfig.stripeRows = config.viewConfig.stripeRows || config.stripeRows; delete config.stripeRows; } if (config.cm || config.colModel) { deprecate({pkg:'Ext.GridPanel', member:'colModel/cm', type:'config', msg:'Grids no longer use a ColumnModel class. Just specify the columns array config instead.'}); // the ColumnModel mock constructor below just returns the columns array config.columns = config.cm || config.colModel; delete config.cm; delete config.colModel; } var cols = config.columns || this.columns; if (cols && Ext.isArray(cols)) { Ext.each(cols, function(col) { if (col.id && !col.dataIndex) { notify('Grid column "' + col.id + '" is defined with an id, but no dataIndex. In Ext 4 the id is used to reference the '+ 'columns as components, and dataIndex is used to map back to the data id. Please add dataIndex to all columns.'); col.dataIndex = col.id; } }); } if (config.store && config.store instanceof Ext.data.GroupingStore) { notify({pkg:'Ext.GridPanel', msg:'Attempting to convert a GroupingStore store config into a Grouping feature. See the '+ 'GroupingStore constructor warning for additional details.'}); config.features = config.features || []; config.features.push(Ext.create('Ext.grid.feature.Grouping')); } }), initComponent: Ext.Function.createInterceptor(Ext.grid.Panel.prototype.initComponent, function() { if (this.autoExpandColumn !== undefined) { deprecate({pkg:'Ext.grid.Panel', member:'autoExpandColumn', alt:'flex (header config)', type:'config', msg:'You can set "flex: 1" in a specific header config for behavior equivalent to autoExpandColumn.'}); var id; Ext.Array.each(this.headers, function(header){ id = header.id || header.dataIndex; if(id === this.autoExpandColumn){ header.flex = 1; return false; } }, this); } }) }); Ext.apply(Ext.grid.GridPanel.prototype, { getColumnModel: function(){ if (!this.colModel && !this.cm) { this.cm = this.colModel = new Ext.grid.ColumnModel({ columns: this.columns }); } return this.cm; } }); Ext.grid.EditorGridPanel = function(config) { deprecate({pkg:'Ext.grid.EditorGridPanel', msg:'EditorGridPanel no longer exists as a separate class. Instead just '+ 'create a standard GridPanel and include the CellEditing plugin, e.g. "plugins: Ext.create("Ext.grid.plugin.CellEditing", {...})'}); return Ext.createWidget('grid', Ext.apply(config || {}, { plugins: Ext.create('Ext.grid.plugin.CellEditing', { clicksToEdit: 1 }) })); } } if (Ext.grid.View) { Ext.apply(Ext.grid.View.prototype, { constructor: Ext.Function.createInterceptor(Ext.grid.View.prototype.constructor, function(config) { if(Ext.isFunction(config.getRowClass)){ var getRowClass = config.getRowClass; this.__getRowClass = Ext.bind(getRowClass, this); delete config.getRowClass; this.getRowClass = function(rec, rowIndex, rowParams, store){ var result = this.__getRowClass(rec, rowIndex, rowParams, store); if (rowParams.body) { delete rowParams.body; breaking({pkg:'Ext.grid.View', member:'getRowClass.rowParams.body', single:true, msg:'To implement a custom row body you must add the RowBody feature (ftype:"rowbody") '+ 'to the grid\'s viewConfig and override the "getAdditionalData" template method '+ '(or use the Ext.grid.RowBodyPlugin helper class). Unfortunately this cannot be '+ 'inferred at design time so it must be fixed manually.'}); } if (rowParams.bodyStyle) { delete rowParams.bodyStyle; deprecate({pkg:'Ext.grid.View', member:'getRowClass.rowParams.bodyStyle', single:true, msg:'To implement a custom row styles you must add the RowBody feature (ftype:"rowbody") '+ 'to the grid\'s viewConfig and override the "getAdditionalData" template method '+ '(or use the Ext.grid.RowBodyPlugin helper class). Note that in 3.x this property '+ 'was a CSS style spec, whereas now you specify "rowBodyCls" as a CSS classname instead. Ignoring for now.'}); } if (rowParams.tstyle) { delete rowParams.tstyle; deprecate({pkg:'Ext.grid.View', member:'getRowClass.rowParams.tstyle', single:true, msg:'Grid row bodies no longer use a wrapping TABLE element, so the "tstyle" property '+ 'no longer directly applies. If you have CSS styles that still need to be applied, you '+ 'should add the RowBody feature (ftype:"rowbody") to the grid\'s viewConfig and override '+ 'the "getAdditionalData" template method (or use the Ext.grid.RowBodyPlugin helper class). '+ 'Note that in 3.x this property was a CSS style spec, whereas now you would use the "rowBodyCls" '+ 'CSS classname instead (and adjust for the fact that there is no TABLE if needed). Ignoring for now.'}); } return result; }; } }) }); Ext.grid.GroupingView = function(config) { breaking({pkg:'Ext.grid.GroupingView', msg:'GroupingView no longer exists as a separate class, and grid views should '+ 'not need to be instantiated directly. Instead just create a standard GridPanel and include the Grouping feature, '+ 'e.g. "features: Ext.create("Ext.grid.feature.Grouping", {...}). Unfortunately there is no way to alias a call to this '+ 'constructor properly, so you\'ll need to adjust your GridPanel constructor as noted to resolve this.'}); } } if (Ext.grid.header.Container) { Ext.apply(Ext.grid.header.Container.prototype, { constructor: Ext.Function.createSequence(Ext.grid.header.Container.prototype.constructor, function() { this.__prepareData = this.prepareData; this.prepareData = function() { var obj = this.__prepareData.apply(this, arguments); if (obj.cssWarning) { delete obj.cssWarning; deprecate({pkg:'Ext.grid.Panel', single:true, msg:'Your grid column renderer is including the legacy "css" attribute '+ 'in the returned metaData object. This has been renamed to "tdCls" so you should change the attribute name in your renderer.'}); } return obj; } }) }); } if (Ext.grid.Header) { Ext.apply(Ext.grid.Header.prototype, { initComponent: Ext.Function.createInterceptor(Ext.grid.Header.prototype.initComponent, function() { if (Ext.isDefined(this.header)) { deprecate({pkg:'Ext.grid.Panel', member:'header', alt:'text', type:'config', single: true, msg:'In 3.x the grid had a "columns" array containing "header" configs for the title of each column. '+ 'In 4.0 the grid has a "headers" array and you should specify the "text" config for each header.'}); this.text = this.header; delete this.header; } }) }); } Ext.grid.ColumnModel = function(config) { return Ext.applyIf(config.columns ? config.columns : config, { on: Ext.emptyFn, addListener: Ext.emptyFn, getColumnId: Ext.emptyFn, getColumnAt: Ext.emptyFn, setConfig: Ext.emptyFn, getColumnById: Ext.emptyFn, getIndexById: Ext.emptyFn, moveColumn: Ext.emptyFn, getColumnCount: Ext.emptyFn, getColumnsBy: Ext.emptyFn, isSortable: Ext.emptyFn, isMenuDisabled: Ext.emptyFn, getRenderer: Ext.emptyFn, getRendererScope: Ext.emptyFn, setRenderer: Ext.emptyFn, getColumnWidth: Ext.emptyFn, setColumnWidth: Ext.emptyFn, getTotalWidth: Ext.emptyFn, getColumnHeader: Ext.emptyFn, setColumnHeader: Ext.emptyFn, getColumnTooltip: Ext.emptyFn, setColumnTooltip: Ext.emptyFn, getDataIndex: Ext.emptyFn, setDataIndex: Ext.emptyFn, findColumnIndex: Ext.emptyFn, isCellEditable: Ext.emptyFn, getCellEditor: Ext.emptyFn, setEditable: Ext.emptyFn, isHidden: Ext.emptyFn, isFixed: Ext.emptyFn, isResizable: Ext.emptyFn, setHidden: Ext.emptyFn, setEditor: Ext.emptyFn, destroy: Ext.emptyFn, setState: Ext.emptyFn }); }; if (Ext.grid.Column) { Ext.Compat.bindProperty({owner:Ext.grid.Column, name:'types', defaultValue:{}, getterMsg: function(){ deprecate({pkg:'Ext.grid.Column', member:'types', type:'property', alt:'alias (config)', msg:'The new approach to creating a custom column type is to specify the alias config '+ 'within your column\'s class definition (e.g., alias: ["widget.mycolumn"]). You could also '+ 'call the setAlias method after the class is defined.'}); } }); } // temp aliases -- these will be added into Ext 4 Ext.apply(Ext.grid.Panel.prototype, { getStore: function() { return this.store; } }); if (Ext.selection.Model) { Ext.apply(Ext.selection.Model.prototype, { selectRow: function(index){ deprecate({pkg:'Ext.grid.RowSelectionModel', member:'selectRow', alt:'Ext.selection.RowModel.selectRange', msg:'Note that selectRange requires both start and end rows as its first two arguments (defaulting both to '+index+').'}); return this.selectRange(index, index); }, getSelections: function(){ deprecate({pkg:'Ext.grid.RowSelectionModel', member:'getSelections', alt:'Ext.selection.RowModel.getSelection'}); return this.getSelection(); } }); } /*------------------------------------------------------------- * Tree (removed classes) *-------------------------------------------------------------*/ Ext.tree.TreeNode = function(config){ deprecate({pkg:'Ext.tree.TreeNode', msg:'This class is no longer needed. The Tree now uses standard Records that get decorated '+ 'by the NodeInterface class in Ext 4.'}); Ext.apply(this, config); }; Ext.tree.AsyncTreeNode = function(config){ deprecate({pkg:'Ext.tree.AsyncTreeNode', msg:'This class is no longer needed. Specify a TreeStore with an AjaxProxy instead.'}); Ext.apply(this, config); }; Ext.tree.AsyncTreeNode.prototype = { expand: function(){ if (this.store) { this.store.load({ url: this.url || this.dataUrl }); } } }; Ext.tree.TreeSorter = function(tree, config){ deprecate({pkg:'Ext.tree.TreeSorter', msg:'This class is no longer needed. Specify a TreeStore with standard "sorter" config options instead.'}); Ext.apply(this, config); }; Ext.tree.TreeLoader = function(config){ deprecate({pkg:'Ext.tree.TreeLoader', msg:'This class is no longer needed. Specify a TreeStore with standard store options to load the tree.'}); Ext.apply(this, config); }; /*------------------------------------------------------------- * TreePanel *-------------------------------------------------------------*/ if (Ext.tree.Panel) { Ext.apply(Ext.tree.Panel.prototype, { constructor: Ext.Function.createInterceptor(Ext.tree.Panel.prototype.constructor, function(config) { if (config.hlDrop) { delete config.hlDrop; deprecate({pkg:'Ext.tree.TreePanel', member:'hlDrop', type:'config', msg:'Highlighting tree nodes on drop is no longer supported. You can simply remove this config.'}); } if (config.hlColor) { delete config.hlDrop; deprecate({pkg:'Ext.tree.TreePanel', member:'hlColor', type:'config', msg:'Highlighting tree nodes on drop is no longer supported. You can simply remove this config.'}); } var ddConfig = config.ddConfig || {}; if (Ext.isDefined(config.enableDrag)) { deprecate({pkg:'Ext.tree.TreePanel', member:'enableDrag', type:'config', alt:'ddConfig.enableDrag'}); ddConfig.enableDrag = config.enableDrag; delete config.enableDrag; } if (Ext.isDefined(config.enableDrop)) { deprecate({pkg:'Ext.tree.TreePanel', member:'enableDrop', type:'config', alt:'ddConfig.enableDrop'}); ddConfig.enableDrop = config.enableDrop; delete config.enableDrop; } if (Ext.isDefined(config.enableDD)) { var msg = config.enableDD ? 'Note that ddConfig defaults to enabling both drag and drop by default in Ext 4. Since you are '+ 'currently passing "enableDD: true", in this case the config can simply be ommitted entirely.' : ''; ddConfig = { enableDrag: config.enableDD, enableDrop: config.enableDD }; delete config.enableDD; deprecate({pkg:'Ext.tree.TreePanel', member:'enableDD', type:'config', alt:'ddConfig', msg:msg}); } config.ddConfig = ddConfig; var url = config.dataUrl || this.dataUrl; if (url) { deprecate({pkg:'Ext.tree.TreePanel', member:'dataUrl', type:'config', alt:'TreeStore', msg:'The TreePanel no longer supports loading data directly. Creating an implicit TreeStore using the url: '+url}); this.loader = { dataUrl: url }; delete config.dataUrl; delete this.dataUrl; } else if (config.loader) { this.loader = config.loader; delete config.loader; deprecate({pkg:'Ext.tree.TreePanel', member:'loader', type:'config', alt:'TreeStore', msg:'The TreeLoader class and TreePanel.loader config have been removed. Trees now use the TreeStore '+ 'which provides all standard Ext.data.Store loading capabilities.'}); } if (config.root && (config.root instanceof Ext.tree.AsyncTreeNode || config.root.nodeType == 'async')) { config.loader = this.loader; } this.applyCompatOptions(); }), initComponent: Ext.Function.createSequence(Ext.tree.Panel.prototype.initComponent, function() { this.on('itemclick', function(view, model, el, idx, e){ if (this.events['click']) { model.attributes = model.attributes || model.data; this.fireEvent('click', model, e); deprecate({pkg:'Ext.tree.TreePanel', member:'click', type:'event', alt:'itemclick', msg:'Note that the argument order has changed, and that the data argument was a node in 3.x and is now '+ 'the selected model. Instead of node.attributes you can access the data via model.data.'}) } }); }), applyCompatOptions: function(){ var loader = this.loader; if (loader && (loader.url || loader.dataUrl || loader.proxy)) { var urlProp = loader.url ? 'url' : 'dataUrl', proxy = loader.proxy || { type: 'ajax', url: loader[urlProp] }, storeConfig = { proxy: proxy } if (this.root) { storeConfig.root = this.root; delete this.root; } this.store = new Ext.data.TreeStore(storeConfig); this.loader.store = this.store; notify({pkg:'Ext.tree.Panel', msg:'Using the TreeLoader.' + urlProp + ' config to generate a default TreeStore + Proxy with the url: '+loader[urlProp]}); } }, // Aliased in TreePanel // setRootNode: function(root){ // deprecate({pkg:'Ext.tree.Panel', member:'setRootNode', alt:'TreeStore.setRootNode', // msg:'Alternately you could add a "root" option to your TreeStore config.'}); // // if (this.store) { // this.store.setRootNode(root); // } // else { // this.root = root; // this.applyCompatOptions(); // } // }, // Aliased in TreePanel // getRootNode : function(){ // deprecate({pkg:'Ext.tree.Panel', member:'getRootNode', alt:'TreeStore.getRootNode'}); // return this.store.getRootNode.apply(this.store, arguments); // }, getNodeById : function(){ deprecate({pkg:'Ext.tree.Panel', member:'getNodeById', alt:'TreeStore.getNodeById', msg:'If you have a TreePanel reference you can call treePanel.getStore().getNodeById("id").'}); return this.store.getNodeById.apply(this.store, arguments); }, getChecked : function(){ deprecate({pkg:'Ext.tree.Panel', member:'getChecked', alt:'Ext.tree.View.getChecked', msg:'Note that in 3.x this method returned objects of type TreeNode. In 4.0 it returns standard Records, '+ 'so the code that processes the checked items will have to be adjusted accordingly. For compatibility '+ 'the record\'s data objects are being returned, as each record\'s data is now decorated with the node '+ 'interface so they should match the 3.x API. However your 4.0 code should expect full Record objects '+ 'instead and will access the node attributes via Record.get(\'attrName\') or Record.data.attrName.'}); var recs = this.getView().getChecked(), nodes = []; Ext.each(recs, function(rec){ nodes.push(rec.data); }); return nodes; } }); } if (Ext.data.TreeStore) { Ext.override(Ext.data.TreeStore, { fillNode: function(node, records) { var me = this, ln = records ? records.length : 0, i = 0, sortCollection; // if (ln && me.sortOnLoad && !me.remoteSort && me.sorters && me.sorters.items) { // sortCollection = Ext.create('Ext.util.MixedCollection'); // sortCollection.addAll(records); // sortCollection.sort(me.sorters.items); // records = sortCollection.items; // } node.set('loaded', true); for (; i < ln; i++) { node.appendChild(records[i], undefined, true); } return records; } }); } /*------------------------------------------------------------- * SelectionModel *-------------------------------------------------------------*/ if (Ext.selection.RowModel) { Ext.apply(Ext.selection.RowModel.prototype, { constructor: Ext.Function.createSequence(Ext.selection.RowModel.prototype.constructor, function() { this.on('select', function(sm, rec, idx){ if (this.events['rowselect']) { this.fireEvent('rowselect', sm, idx, rec); deprecate({pkg:'Ext.grid.RowSelectionModel', member:'rowselect', type:'event', alt:'select', msg:'Note that the argument order has changed (the index and record/model args have been switched).'}) } }); this.on('deselect', function(sm, rec, idx){ if (this.events['rowdeselect']) { this.fireEvent('rowdeselect', sm, idx, rec); deprecate({pkg:'Ext.grid.RowSelectionModel', member:'rowdeselect', type:'event', alt:'deselect', msg:'Note that the argument order has changed (the index and record/model args have been switched).'}) } }); }) }); } /*------------------------------------------------------------- * Window *-------------------------------------------------------------*/ if (Ext.window.Window) { Ext.apply(Ext.window.Window.prototype, { constructor: Ext.Function.createInterceptor(Ext.window.Window.prototype.constructor, function(config) { if (config.closeAction === 'close') { deprecate({pkg:'Ext.Window', member:'closeAction', type:'config', msg:'The default value of "close" is no longer valid. Use "destroy" instead.'}); delete config.closeAction; this.closeAction = 'destroy'; } }) }); } /*------------------------------------------------------------- * Forms *-------------------------------------------------------------*/ if (Ext.form.Basic) { Ext.apply(Ext.form.Basic.prototype, { add: function() { deprecate({pkg:'Ext.form.Basic', member:'add'}); return this; }, remove: function(field) { deprecate({pkg:'Ext.form.Basic', member:'remove'}); return this; }, cleanDestroyed: function() { deprecate({pkg:'Ext.form.Basic', member:'cleanDestroyed'}); }, render: function() { deprecate({pkg:'Ext.form.Basic', member:'render'}); return this; }, getFieldValues: function(dirtyOnly) { deprecate({pkg:'Ext.form.Basic', member:'getFieldValues', alt:'getValues'}); return this.getValues(false, dirtyOnly); }, callFieldMethod: function(fnName, args) { deprecate({pkg:'Ext.form.Basic', member:'callFieldMethod'}); args = args || []; this.getFields().each(function(f) { if (Ext.isFunction(f[fnName])) { f[fnName].apply(f, args); } }); return this; } }); } if (Ext.form.Panel) { Ext.apply(Ext.form.Panel.prototype, { monitorValid: false, monitorPoll: 200, initComponent: Ext.Function.createInterceptor(Ext.form.Panel.prototype.initComponent, function() { var me = this, fieldDefaultsProps = { hideLabels: 'hideLabel', labelAlign: 'labelAlign', labelPad: 'labelPad', labelSeparator: 'labelSeparator', labelWidth: 'labelWidth' }, fieldDefaults = me.fieldDefaults || (me.fieldDefaults = {}); Ext.iterate(fieldDefaultsProps, function(from, to) { if (from in me) { deprecate({pkg:'Ext.form.Panel', member:from, type:'config', msg:'Use the fieldDefaults config object with a "' + to + '" property instead.'}); fieldDefaults[to] = me[from]; } }); if (me.hasOwnProperty('monitorValid')) { deprecate({pkg:'Ext.form.Panel', member:'monitorValid', alt:'pollForChanges'}); } if (me.hasOwnProperty('monitorPoll')) { deprecate({pkg:'Ext.form.Panel', member:'monitorPoll', alt:'pollInterval'}); } }), startMonitoring: function() { deprecate({pkg:'Ext.form.Panel', member:'startMonitoring', alt:'startPolling'}); this.startPolling(this.monitorPoll); }, stopMonitoring: function() { deprecate({pkg:'Ext.form.Panel', member:'stopMonitoring', alt:'stopPolling'}); this.stopPolling(); } }); } if (Ext.form.field.Base) { Ext.apply(Ext.form.field.Base.prototype, { initComponent: Ext.Function.createInterceptor(Ext.form.field.Base.prototype.initComponent, function() { // Many legacy examples modify the default msgTarget on the Ext.form.Field class's prototype; this doesn't // work anymore since Field is a mixin. Copy to Ext.form.field.Base and inform about change and the new // recommended FormPanel.fieldDefaults. Only do this once rather than for every field. var msgTarget = Ext.form.Field.prototype.msgTarget; if (msgTarget && msgTarget !== 'qtip') { deprecate({pkg:'Ext.form.Field', member:'msgTarget', type:'config', single: true, msg:'Found an overridden value for Ext.form.Field.prototype.msgTarget -- Ext.form.Field is ' + 'now Ext.form.field.Base; either override msgTarget on Ext.form.field.Base\'s prototype ' + 'or use the new recommended Ext.form.Panel#fieldDefaults object instead.'}); Ext.form.field.Base.prototype.msgTarget = Ext.form.Field.prototype.msgTarget; } }) }); } if (Ext.form.field.Checkbox) { Ext.apply(Ext.form.field.Checkbox.prototype, { initComponent: Ext.Function.createInterceptor(Ext.form.field.Checkbox.prototype.initComponent, function() { this.addEvents( /** * @event check * Fires when the checkbox is checked or unchecked. * @deprecated Use the 'change' event instead. * @param {Ext.form.field.Checkbox} this This checkbox * @param {Boolean} checked The new checked value */ 'check' ); // TODO is there a clean way to throw a deprecation warning when the user listens for the check event? }), onChange: Ext.Function.createInterceptor(Ext.form.field.Checkbox.prototype.onChange, function(newVal, oldVal) { this.fireEvent('check', this, this.checked); }) }); } if (Ext.form.CheckboxGroup) { var cbgSetValue = Ext.form.CheckboxGroup.prototype.setValue; Ext.apply(Ext.form.CheckboxGroup.prototype, { initComponent: Ext.Function.createInterceptor(Ext.form.CheckboxGroup.prototype.initComponent, function() { var me = this, items = me.items; // Handle the old structure where the 'items' could be a set of column configs if (items && items[0] && 'columnWidth' in items[0] && me.layout !== 'column') { deprecate({pkg:'Ext.form.CheckboxGroup', type:'config', msg:'CheckboxGroup and RadioGroup no longer accept implicit column containers in the "items" ' + 'config. If you wish to use a custom column arrangement, set layout:"column" and create ' + 'a standard items structure with container xtypes.'}); me.layout = 'column'; Ext.Array.forEach(items, function(column) { column.xtype = 'container'; column.defaultType = me.defaultType; }); } }), setValue: function(id, value) { var me = this, f; if (arguments.length === 1) { value = id; if (Ext.isObject(value)) { cbgSetValue.call(me, value); } if (Ext.isString(value)) { deprecate({pkg:'Ext.form.CheckboxGroup', member:'setValue', msg:'The setValue method no longer accepts a String argument. Use the new Object form instead.'}); me.setValueForItem(value); } else if (Ext.isArray(value)) { deprecate({pkg:'Ext.form.CheckboxGroup', member:'setValue', msg:'The setValue method no longer accepts an Array argument. Use the new Object form instead.'}); me.batchChanges(function() { Ext.each(value, function(val, idx){ if (Ext.isObject(val) && val.setValue) { // array of checkbox components to be checked val.setValue(true); } else if (Ext.isString(val)) { f = me.getBox(val); if (f) { f.setValue(true); } } else { // an array of boolean values var item = me.getBoxes()[idx]; if (item) { item.setValue(val); } } }); }); } } else { deprecate({pkg:'Ext.form.CheckboxGroup', member:'setValue', msg:'The setValue method no longer accepts a two-argument form. Use the new single Object form instead.'}); f = me.getBox(id); if (f) { f.setValue(value); } } return me; }, // private setValueForItem : function(val){ deprecate({pkg:'Ext.form.CheckboxGroup', member:'setValueForItem'}); var me = this; val = String(val).split(','); me.batchChanges(function() { me.eachBox(function(item) { if (val.indexOf(item.inputValue) > -1) { item.setValue(true); } }); }); }, // private getBox : function(id){ deprecate({pkg:'Ext.form.CheckboxGroup', member:'getBox'}); var box = null; this.eachBox(function(f) { if (id == f || f.dataIndex == id || f.id == id || f.getName() == id) { box = f; return false; } }); return box; } }); } /*------------------------------------------------------------- * CompositeField *-------------------------------------------------------------*/ if (Ext.form.FieldContainer) { Ext.define('Ext.form.CompositeField', { extend: 'Ext.form.FieldContainer', alias: 'widget.compositefield', uses: ['Ext.layout.container.HBox'], isComposite: true, combineErrors: true, layout: { type: 'hbox', defaultMargins: {top: 0, right: 5, bottom: 0, left: 0} }, baseDefaults: { hideLabel: true }, initComponent: function() { deprecate({member:'Ext.form.CompositeField', alt:'Ext.form.FieldContainer', msg:'What used to be CompositeField has been replaced by the more flexible FieldContainer. '+ 'We will reintroduce a true Composite field in a future release.'}); this.defaults = Ext.apply({}, this.defaults, this.baseDefaults); this.callParent(arguments); } }); } /*------------------------------------------------------------- * ComboBox *-------------------------------------------------------------*/ if (Ext.form.field.ComboBox) { Ext.apply(Ext.form.field.ComboBox.prototype, { initComponent: Ext.Function.createInterceptor(Ext.form.field.ComboBox.prototype.initComponent, function() { var me = this, isDef = Ext.isDefined; // shortcut for configs that just changed names: var remap = function(cfg, alt){ if(isDef(me[cfg])){ deprecate({pkg:'Ext.form.field.ComboBox', member:cfg, type:'config', alt:alt}); me[alt] = me[cfg]; delete me[cfg]; } }; remap('listAlign', 'pickerAlign'); remap('mode', 'queryMode'); remap('triggerClass', 'triggerCls'); // shortcut for configs that were moved into the listConfig object: var listConfig = me.listConfig || (me.listConfig = {}), remapToListConfig = function(cfg, alt) { if(isDef(me[cfg])){ // the defaultListConfig has been applied at this point, so check that this // option was not simply the default value applied by the superclass if(!isDef(me.defaultListConfig[cfg]) || me.defaultListConfig[cfg] !== me[cfg]) { deprecate({pkg:'Ext.form.field.ComboBox', member:cfg, type:'config', alt:'listConfig.' + alt}); listConfig[alt] = me[cfg]; delete me[cfg]; } } }; remapToListConfig('itemSelector', 'itemSelector'); remapToListConfig('listClass', 'cls'); remapToListConfig('listWidth', 'width'); remapToListConfig('loadingText', 'loadingText'); remapToListConfig('minHeight', 'minHeight'); remapToListConfig('minListWidth', 'minWidth'); remapToListConfig('maxHeight', 'maxHeight'); remapToListConfig('resizable', 'resizable'); remapToListConfig('selectedClass', 'selectedItemCls'); remapToListConfig('shadow', 'shadow'); // shortcut for configs that were completely removed with no replacement: var remove = function(cfg){ if(isDef(me[cfg])){ notify({pkg:'Ext.form.field.ComboBox', member:cfg, msg:'This config is no longer needed and has no replacement -- just remove it from your code.'}); delete me[cfg]; } }; remove('autoCreate'); remove('clearFilterOnReset'); remove('handleHeight'); remove('hiddenId'); remove('hiddenName'); remove('lazyInit'); remove('lazyRender'); remove('title'); // non-standard mappings: if(isDef(me.tpl)){ deprecate({pkg:'Ext.form.field.ComboBox', member:'tpl', type:'config', alt:'getInnerTpl (method)', msg:'There is no config for providing the combo\'s item template now. Instead, you should override '+ 'the "getInnerTpl" method to provide whatever logic is required and return the template string.'}); // make sure we are returning a template string and not an XTemplate instance: var tpl = me.tpl.html ? me.tpl.html : me.tpl; me.getInnerTpl = function(){ return tpl; }; delete me.tpl; } }) }); } /*------------------------------------------------------------- * Slider *-------------------------------------------------------------*/ if (Ext.slider.Multi) { Ext.apply(Ext.slider.Multi.prototype, { initComponent: Ext.Function.createInterceptor(Ext.slider.Multi.prototype.initComponent, function() { if (this.plugins) { Ext.each(this.plugins, function(p){ if (p.getText) { deprecate({pkg:'Ext.Slider', msg:'In 3.x the Ext.slider.Tip plugin was required to provide custom slider tip text. '+ 'In 4.0 you should instead supply the tipText config directly.'}); this.tipText = p.getText; Ext.Array.remove(this.plugins, p); return; } }, this); } }) }); } /*------------------------------------------------------------- * Store *-------------------------------------------------------------*/ if (Ext.data.Store) { Ext.apply(Ext.data.AbstractStore.prototype, { constructor: Ext.Function.createInterceptor(Ext.data.AbstractStore.prototype.constructor, function(config) { if (this.$className == 'Ext.data.NodeStore') { return; } if (config.url) { deprecate({pkg:'Ext.data.Store', member:'url', type:'config', alt:'proxy.url', msg:'The store\'s "url" config should now be passed as a config to a valid remote-style proxy.'}); if (!config.proxy) { deprecate({pkg:'Ext.data.Store', msg:'A store url was specified with no proxy config. Implcitily creating an AjaxProxy with that url. '+ 'Please see the header docs for Ext.data.Store for details on properly setting up your data components.'}); config.proxy = { type: 'ajax', url: config.url }; delete config.url; if (config.reader) { config.proxy.reader = config.reader; delete config.reader; deprecate({pkg:'Ext.data.Store', member:'reader', type:'config', msg:'As part of creating an implicit AjaxProxy for compatibility, '+ 'the store\'s existing reader config has also been moved to the proxy. Note that the reader config should no longer be passed '+ 'directly as a store config, but should be specified on the proxy instead.'}); } } } else if (!this.model && !config.model){ // there is no model set, so we need to try the various possible configurations supported by 3.x // and hopefully find something we can convert into an implicit model var fields; if (config.fields) { // shorthand store classes like ArrayStore and XmlStore support fields directly on the store config fields = config.fields; delete config.fields; // this is required to be done, but skip the warning. In some cases TreeStore internally adds this. The bigger picture // issue of configuring the store correctly will already be covered by other warnings. // deprecate({pkg:'Ext.data.Store', msg:'Passing a "fields" config directly on the store\'s config is no longer supported. '+ // 'Instead you should configure a model and pass it as the store\'s "model" config. ' + // 'Please see the header docs for Ext.data.Store for details on properly setting up your data components.'}); } else if (config.reader) { if (config.reader.model) { // the compat warning for this case is displayed below in the Ext.data.Reader override where // reader.model is set. This code is just here to make it work properly. config.model = config.reader.model; delete this.fields; this.implicitModel = true; return true; } else if (config.reader.fields) { // standard stores typically get fields from the reader config fields = config.reader.fields; delete config.reader.fields; deprecate({pkg:'Ext.data.Store', msg:'Passing a "fields" config via the store\'s reader config is no longer supported. '+ 'Instead you should configure a model and pass it as the store\'s "model" config. ' + 'Please see the header docs for Ext.data.Store for details on properly setting up your data components.'}); } else { breaking({pkg:'Ext.data.Store', msg:'No valid model or field configuration could be found '+ 'so this store could not be constructed. Please see the header docs for Ext.data.Store for '+ 'details on properly setting up your data components.'}); return false; } if (config.proxy) { config.proxy.reader = config.reader; delete config.reader; deprecate({pkg:'Ext.data.Store', member:'reader', type:'config', msg:'The reader config should now be specified on the '+ 'configured proxy rather than directly on the store.'}); } } else { // we should never get here, but just in case breaking({pkg:'Ext.data.Store', msg: 'A store was specified with no model, url, or fields configured. '+ 'Please see the header docs for Ext.data.Store for details on properly setting up your data components.'}); return false; } var pn = config.paramNames; if (config.proxy && pn) { Ext.apply(config.proxy, { startParam: pn.start || 'start', limitParam: pn.limit || 'limit', sortParam : pn.sort || 'sort', directionParam : pn.dir || 'dir' }); deprecate({pkg:'Ext.data.Store', member:'paramNames', msg:'This is now split out into individual configs at the proxy '+ 'level (e.g., paramNames.start == proxy.startParam). Set each config directly on the proxy as needed.'}) } var id = 'Ext.data.Store.ImplicitModel-' + (config.storeId || config.id || Ext.id()); notify({pkg:'Ext.data.Store', msg:'Registering implicit model ' + id + '. Please update your code to create a model explicitly.'}); config.model = Ext.define(id, { extend: 'Ext.data.Model', fields: fields, proxy: config.proxy }); this.implicitModel = true; } }) }); Ext.apply(Ext.data.Store.prototype, { constructor: Ext.Function.createInterceptor(Ext.data.Store.prototype.constructor, function(config) { if (config.data && Ext.isObject(config.data)) { // Seems to be still supported officially for now // deprecate({pkg:'Ext.data.Store', member:'data', type:'config', alt:'data', // msg:'Passing inline data to store\'s constructor as an object is no longer supported. Pass a '+ // 'plain array of record data or use one of the standard proxy configurations for loading data.'}); if(config.root){ this.inlineData = config.data[config.root]; delete config.data; } // else { // breaking({pkg:'Ext.data.Store', // msg:'Passing inline data as an object to the Store constructor without specifying a root property is not supported.'}); // } } if (config.sortInfo) { deprecate({pkg:'Ext.data.Store', member:'sortInfo', type:'config', alt:'sorters'}); config.sorters = [{ property: config.sortInfo.field, direction: config.sortInfo.direction }]; } if (config.autoSave) { deprecate({pkg:'Ext.data.Store', member:'autoSave', type:'config', alt:'autoSync'}); this.autoSync = config.autoSave; delete config.autoSave; } }), setDefaultSort : function(field, dir) { deprecate({pkg:'Ext.data.Store', member:'setDefaultSort', alt:'sorters (config)', msg:'Either add the default sort via the "sorters" config or by adding it to the "sorters" property after the store is created. '+ 'See the Ext.data.Store header docs for details on configuring sorters.'}); this.sorters = new Ext.util.MixedCollection(); this.sorters.add(new Ext.util.Sorter({ property: field, direction: dir ? dir.toUpperCase() : 'ASC' })); }, save: function() { deprecate({pkg:'Ext.data.Store', member:'save', alt:'sync'}); return this.sync.apply(this, arguments); } }); Ext.Compat.bindProperty({owner:Ext.data.Store, name:'recordType', getter: function(){ return this.model; }, getterMsg: function(){ deprecate({pkg:'Ext.data.Store', member:'recordType', type:'property', alt:'model'}); } }); } if (Ext.data.JsonStore) { // TODO: Move this override into the lib? Ext.apply(Ext.data.JsonStore.prototype, { constructor: function(config) { config = config || {}; config.proxy = config.proxy || {}; Ext.applyIf(config.proxy, { url : config.url, type : 'ajax', writer: 'json', reader: new Ext.data.JsonReader(config) }); Ext.data.JsonStore.superclass.constructor.call(this, config); } }); } Ext.data.GroupingStore = function(config) { deprecate({pkg:'Ext.data.GroupingStore', msg:'GroupingStore no longer exists as a separate class. Instead just '+ 'create a standard GridPanel and include the Grouping feature, e.g. "features: Ext.create("Ext.grid.feature.Grouping", {...})'}); return Ext.create('Ext.data.Store', config); } /*------------------------------------------------------------- * Record *-------------------------------------------------------------*/ if (Ext.data.Record) { Ext.data.Record.create = function(o){ deprecate({pkg:'Ext.data.Record', member:'create', msg:'There is no longer any need to statically define records. '+ 'You can simply define a new Model configured with the necessary fields via Ext.define, extending Ext.data.Model.'}); var f = Ext.extend(Ext.data.Record, {}); var p = f.prototype; p.fields = new Ext.util.MixedCollection(false, function(field){ return field.name; }); for(var i = 0, len = o.length; i < len; i++){ p.fields.add(new Ext.data.Field(o[i])); } f.getField = function(name){ return p.fields.get(name); }; return f; }; } /*------------------------------------------------------------- * Readers *-------------------------------------------------------------*/ if (Ext.data.JsonReader) { Ext.data.JsonReader.override({ //TODO: seems to be a bug in the class system that this is required for the Reader override constructor: function(){ this.callParent(arguments); } }); } if (Ext.data.Reader) { Ext.apply(Ext.data.Reader.prototype, { constructor: function(config, recordType) { Ext.apply(this, config || {}); if (config.fields) { // this will get converted to an implicit model in the store constructor deprecate({pkg:'Ext.data.Reader', member:'fields', type:'config', msg:'The fields config is no longer supported. Please refer to the '+ 'Ext.data.Store header docs for the proper way to set up your data components.'}); } if (recordType) { // this will get converted to an implicit model in the store constructor config.fields = recordType; deprecate({pkg:'Ext.data.Reader', member:'recordType', type:'arg', msg:'The recordType argument to the Reader constructor is no longer supported. Please refer to the '+ 'Ext.data.Store header docs for the proper way to set up your data components.'}); } if (config.model) { this.model = Ext.ModelManager.getModel(config.model); } else if (config.fields) { this.model = Ext.define('Ext.data.Store.ImplicitModel-' + Ext.id(), { extend: 'Ext.data.Model', fields: config.fields }); } // This is not always true, e.g. with inline array data: // else { // breaking({pkg:'Ext.data.Reader', // msg:'No valid model or field configuration could be found so this reader could not be constructed.'}); // } if (this.model) { this.buildExtractors(); } } }); } if (Ext.data.XmlReader) { Ext.apply(Ext.data.XmlReader.prototype, { // FYI, this entire constructor is now deprecated because all behavior is now in the superclass constructor constructor: function(config, recordType) { config = config || {}; if (config.idPath) { config.idProperty = config.idPath; deprecate({pkg:'Ext.data.XmlReader', member:'idPath', type:'config', alt:'idProperty'}); } if (config.id) { config.idProperty = config.id; deprecate({pkg:'Ext.data.XmlReader', member:'id', type:'config', alt:'idProperty'}); } if (config.success) { config.successProperty = config.success; deprecate({pkg:'Ext.data.XmlReader', member:'success', type:'config', alt:'successProperty'}); } // make sure we pass arguments in case the deprecated recordType arg is included Ext.data.XmlReader.superclass.constructor.apply(this, arguments); } }); } /*------------------------------------------------------------- * Proxies *-------------------------------------------------------------*/ if (Ext.data.ServerProxy) { Ext.apply(Ext.data.ServerProxy.prototype, { getParams: Ext.Function.createInterceptor(Ext.data.ServerProxy.prototype.getParams, function(params, operation) { if (this.sortParam && operation.sorters && operation.sorters.length > 0) { if (!this.simpleSortMode) { this.simpleSortMode = true; Ext.Compat.warn('ServerProxy now supports multiple sort, so if any sort options are specified '+ 'the sort params get JSON-encoded by default. Unless you have specifically coded for this on '+ 'the server it will not work and you should set "simpleSortMode = true" on the proxy. Since '+ 'this was not supported in Ext 3 and you are passing a sort param, simple sorting is assumed '+ 'and has been set automatically, but you should reexamine this code as you migrate to Ext 4. '+ 'For now just set "simpleSortMode: true" on your proxy to dismiss this warning.'); } } }) }); } if (Ext.data.MemoryProxy) { Ext.apply(Ext.data.MemoryProxy.prototype, { read: Ext.Function.createInterceptor(Ext.data.MemoryProxy.prototype.read, function(op, cb, scope) { if (this.doRequest) { deprecate({pkg:'Ext.data.MemoryProxy', member:'doRequest', alt: 'read', msg:'ClientProxy subclasses no longer implement doRequest.'}); var params = { start: op.start, limit: op.limit }; if (op.sorters && op.sorters.length > 0) { var idx = op.sorters.length-1; // take the last sort if multiple params[this.sortParam || 'sort'] = op.sorters[idx].property; params[this.directionParam || 'dir'] = op.sorters[idx].direction; } if (op.filters && op.filters.length > 0) { // not sure if we can compat this //params[this.filterParam || 'filter'] = ??; } this.doRequest(op.action, op.getRecords(), params, this.getReader(), function(result, options){ Ext.apply(op, { resultSet: result }); op.setCompleted(); op.setSuccessful(); Ext.callback(cb, scope || this, [op]); }, scope); return false; // skip original read logic } }) }); } /*------------------------------------------------------------- * Model *-------------------------------------------------------------*/ if (Ext.data.Model) { Ext.apply(Ext.data.Model.prototype, { constructor: Ext.Function.createInterceptor(Ext.data.Model.prototype.constructor, function(data, id) { var newData = {}; if (Ext.isArray(data)){ // Support for loading an array, needed for calling loadData on an ArrayStore var fields = this.fields.items, length = fields.length, field, name, i = 0, newData = {}; for (; i < length; i++) { field = fields[i]; name = field.name; newData[name] = data[i]; } data = newData; } }), initComponent: Ext.Function.createInterceptor(Ext.data.Model.prototype.initComponent, function() { // Needed to bootstrap 3.x stores that use id. Once converted to a model this will // not be needed, so there's no need for a separate warning, just a temp shim. this.id = this.internalId; }) }); } /*------------------------------------------------------------- * Other Ext.data.* stuff *-------------------------------------------------------------*/ if (Ext.data.Operation) { Ext.apply(Ext.data.Operation.prototype, { markStarted: function() { deprecate({pkg:'Ext.data.Operation', member:'markStarted', alt:'setStarted'}); return this.setStarted(); }, markCompleted: function() { deprecate({pkg:'Ext.data.Operation', member:'markCompleted', alt:'setCompleted'}); return this.setCompleted(); }, markSuccessful: function() { deprecate({pkg:'Ext.data.Operation', member:'markSuccessful', alt:'setSuccessful'}); return this.setSuccessful(); }, markException: function() { deprecate({pkg:'Ext.data.Operation', member:'markException', alt:'setException'}); return this.setException(); } }); } /*------------------------------------------------------------- * Tooltip *-------------------------------------------------------------*/ if (Ext.tip.ToolTip) { Ext.apply(Ext.tip.ToolTip.prototype, { initTarget: function(target) { deprecate({pkg:'Ext.ToolTip', member:'initTarget', alt:'setTarget'}); return this.setTarget(target); } }); } if (Ext.TaskManager) { Ext.TaskMgr = function() { deprecate({pkg:'Ext.TaskMgr', alt:'Ext.TaskManager'}); return Ext.TaskManager; } Ext.TaskMgr.start = Ext.TaskManager.start; Ext.TaskMgr.stop = Ext.TaskManager.stop; Ext.TaskMgr.stopAll = Ext.TaskManager.stopAll; } })(); // // TODO: Remove this once the plugin is integrated into the lib // Ext.define('Ext.ux.PreviewPlugin', { extend: 'Ext.AbstractPlugin', alias: 'plugin.preview', requires: ['Ext.grid.feature.RowBody', 'Ext.grid.feature.RowWrap'], // private, css class to use to hide the body hideBodyCls: 'x-grid-row-body-hidden', /** * @cfg {String} bodyField * Field to display in the preview. Must me a field within the Model definition * that the store is using. */ bodyField: '', /** * @cfg {Boolean} previewExpanded */ previewExpanded: true, constructor: function(config) { this.callParent(arguments); var bodyField = this.bodyField, hideBodyCls = this.hideBodyCls, section = this.getCmp(); section.previewExpanded = this.previewExpanded; section.features = [{ ftype: 'rowbody', getAdditionalData: function(data, idx, record, orig, view) { var o = Ext.grid.feature.RowBody.prototype.getAdditionalData.apply(this, arguments); Ext.apply(o, { rowBody: data[bodyField], rowBodyCls: section.previewExpanded ? '' : hideBodyCls }); return o; } },{ ftype: 'rowwrap' }]; }, /** * Toggle between the preview being expanded/hidden * @param {Boolean} expanded Pass true to expand the record and false to not show the preview. */ toggleExpanded: function(expanded) { var view = this.getCmp(); this.previewExpanded = view.previewExpanded = expanded; view.refresh(); } });