icloudtweetdeckhipchattelegramhangoutsslackgmailskypefacebook-workplaceoutlookemailmicrosoft-teamsdiscordmessengercustom-servicesmacoslinuxwindowsinboxwhatsapp
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
780 lines
28 KiB
780 lines
28 KiB
/** |
|
* This class is intended as a mixin for classes that want to provide a "bind" config that |
|
* connects to a `ViewModel`. |
|
* @private |
|
* @since 5.0.0 |
|
*/ |
|
Ext.define('Ext.mixin.Bindable', { |
|
mixinId: 'bindable', |
|
|
|
config: { |
|
/** |
|
* @cfg {Object} [bind] |
|
* Setting this config option adds or removes data bindings for other configs. |
|
* For example, to bind the `title` config: |
|
* |
|
* var panel = Ext.create({ |
|
* xtype: 'panel', |
|
* bind: { |
|
* title: 'Hello {user.name}' |
|
* } |
|
* }); |
|
* |
|
* To dynamically add bindings: |
|
* |
|
* panel.setBind({ |
|
* title: 'Greetings {user.name}!' |
|
* }); |
|
* |
|
* To remove bindings: |
|
* |
|
* panel.setBind({ |
|
* title: null |
|
* }); |
|
* |
|
* The bind expressions are presented to `{@link Ext.app.ViewModel#bind}`. The |
|
* `ViewModel` instance is determined by `lookupViewModel`. |
|
*/ |
|
bind: { |
|
$value: null, |
|
lazy: true |
|
}, |
|
|
|
// @cmd-auto-dependency { aliasPrefix: 'controller.' } |
|
/** |
|
* @cfg {String/Object/Ext.app.ViewController} controller |
|
* A string alias, a configuration object or an instance of a `ViewController` for |
|
* this container. Sample usage: |
|
* |
|
* Ext.define('MyApp.UserController', { |
|
* alias: 'controller.user' |
|
* }); |
|
* |
|
* Ext.define('UserContainer', { |
|
* extend: 'Ext.container.container', |
|
* controller: 'user' |
|
* }); |
|
* // Or |
|
* Ext.define('UserContainer', { |
|
* extend: 'Ext.container.container', |
|
* controller: { |
|
* type: 'user', |
|
* someConfig: true |
|
* } |
|
* }); |
|
* |
|
* // Can also instance at runtime |
|
* var ctrl = new MyApp.UserController(); |
|
* var view = new UserContainer({ |
|
* controller: ctrl |
|
* }); |
|
* |
|
*/ |
|
controller: null, |
|
|
|
/** |
|
* @cfg {Boolean} defaultListenerScope |
|
* If `true`, this component will be the default scope (this pointer) for events |
|
* specified with string names so that the scope can be dynamically resolved. The |
|
* component will automatically become the defaultListenerScope if a |
|
* {@link #controller} is specified. |
|
* |
|
* See the introductory docs for {@link Ext.container.Container} for some sample |
|
* usages. |
|
* |
|
* **NOTE**: This value can only be reliably set at construction time. Setting it |
|
* after that time may not correctly rewire all of the potentially effected |
|
* listeners. |
|
*/ |
|
defaultListenerScope: false, |
|
|
|
/** |
|
* @cfg {String/String[]/Object} publishes |
|
* One or more names of config properties that this component should publish |
|
* to its ViewModel. Generally speaking, only properties defined in a class config |
|
* block (including ancestor config blocks and mixins) are eligible for publishing |
|
* to the viewModel. Some components override this and publish their most useful |
|
* configs by default. |
|
* |
|
* **Note:** We'll discuss publishing properties **not** found in the config block below. |
|
* |
|
* Values determined to be invalid by component (often form fields and model validations) |
|
* will not be published to the ViewModel. |
|
* |
|
* This config uses the `{@link #cfg-reference}` to determine the name of the data |
|
* object to place in the `ViewModel`. If `reference` is not set then this config |
|
* is ignored. |
|
* |
|
* By using this config and `{@link #cfg-reference}` you can bind configs between |
|
* components. For example: |
|
* |
|
* ... |
|
* items: [{ |
|
* xtype: 'textfield', |
|
* reference: 'somefield', // component's name in the ViewModel |
|
* publishes: 'value' // value is not published by default |
|
* },{ |
|
* ... |
|
* },{ |
|
* xtype: 'displayfield', |
|
* bind: 'You have entered "{somefield.value}"' |
|
* }] |
|
* ... |
|
* |
|
* Classes must provide this config as an Object: |
|
* |
|
* Ext.define('App.foo.Bar', { |
|
* publishes: { |
|
* foo: true, |
|
* bar: true |
|
* } |
|
* }); |
|
* |
|
* This is required for the config system to properly merge values from derived |
|
* classes. |
|
* |
|
* For instances this value can be specified as a value as show above or an array |
|
* or object as follows: |
|
* |
|
* { |
|
* xtype: 'textfield', |
|
* reference: 'somefield', |
|
* publishes: [ |
|
* 'value', |
|
* 'rawValue', |
|
* 'dirty' |
|
* ] |
|
* } |
|
* |
|
* // This achieves the same result as the above array form. |
|
* { |
|
* xtype: 'textfield', |
|
* reference: 'somefield', |
|
* publishes: { |
|
* value: true, |
|
* rawValue: true, |
|
* dirty: true |
|
* } |
|
* } |
|
* |
|
* In some cases, users may want to publish a property to the viewModel that is not found in a class |
|
* config block. In these situations, you may utilize {@link #publishState} if the property has a |
|
* setter method. Let's use {@link Ext.form.Labelable#setFieldLabel setFieldLabel} as an example: |
|
* |
|
* setFieldLabel: function(fieldLabel) { |
|
* this.callParent(arguments); |
|
* this.publishState('fieldLabel', fieldLabel); |
|
* } |
|
* |
|
* With the above chunk of code, fieldLabel may now be published to the viewModel. |
|
* |
|
* @since 5.0.0 |
|
*/ |
|
publishes: { |
|
$value: null, |
|
lazy: true, |
|
merge: function (newValue, oldValue) { |
|
return this.mergeSets(newValue, oldValue); |
|
} |
|
}, |
|
|
|
/** |
|
* @cfg {String} reference |
|
* Specifies a name for this component inside its component hierarchy. This name |
|
* must be unique within its {@link Ext.container.Container#referenceHolder view} |
|
* or its {@link Ext.app.ViewController ViewController}. See the documentation in |
|
* {@link Ext.container.Container} for more information about references. |
|
* |
|
* **Note**: Valid identifiers start with a letter or underscore and are followed |
|
* by zero or more additional letters, underscores or digits. References are case |
|
* sensitive. |
|
*/ |
|
reference: null, |
|
|
|
// @cmd-auto-dependency { directRef: 'Ext.data.Session' } |
|
/** |
|
* @cfg {Boolean/Object/Ext.data.Session} [session=null] |
|
* If provided this creates a new `Session` instance for this component. If this |
|
* is a `Container`, this will then be inherited by all child components. |
|
* |
|
* To create a new session you can specify `true`: |
|
* |
|
* Ext.create({ |
|
* xtype: 'viewport', |
|
* session: true, |
|
* |
|
* items: [{ |
|
* ... |
|
* }] |
|
* }); |
|
* |
|
* Alternatively, a config object can be provided: |
|
* |
|
* Ext.create({ |
|
* xtype: 'viewport', |
|
* session: { |
|
* ... |
|
* }, |
|
* |
|
* items: [{ |
|
* ... |
|
* }] |
|
* }); |
|
* |
|
*/ |
|
session: { |
|
$value: null, |
|
lazy: true |
|
}, |
|
|
|
/** |
|
* @cfg {String/String[]/Object} twoWayBindable |
|
* This object holds a map of `config` properties that will update their binding |
|
* as they are modified. For example, `value` is a key added by form fields. The |
|
* form of this config is the same as `{@link #publishes}`. |
|
* |
|
* This config is defined so that updaters are not created and added for all |
|
* bound properties since most cannot be modified by the end-user and hence are |
|
* not appropriate for two-way binding. |
|
*/ |
|
twoWayBindable: { |
|
$value: null, |
|
lazy: true, |
|
merge: function (newValue, oldValue) { |
|
return this.mergeSets(newValue, oldValue); |
|
} |
|
}, |
|
|
|
// @cmd-auto-dependency { aliasPrefix: 'viewmodel.' } |
|
/** |
|
* @cfg {String/Object/Ext.app.ViewModel} viewModel |
|
* The `ViewModel` is a data provider for this component and its children. The |
|
* data contained in the `ViewModel` is typically used by adding `bind` configs |
|
* to the components that want present or edit this data. |
|
* |
|
* When set, the `ViewModel` is created and links to any inherited `viewModel` |
|
* instance from an ancestor container as the "parent". The `ViewModel` hierarchy, |
|
* once established, only supports creation or destruction of children. The |
|
* parent of a `ViewModel` cannot be changed on the fly. |
|
* |
|
* If this is a root-level `ViewModel`, the data model connection is made to this |
|
* component's associated `{@link Ext.data.Session Data Session}`. This is |
|
* determined by calling `getInheritedSession`. |
|
* |
|
*/ |
|
viewModel: { |
|
$value: null, |
|
lazy: true |
|
} |
|
}, |
|
|
|
/** |
|
* @property {String} [defaultBindProperty] |
|
* This property is used to determine the property of a `bind` config that is just |
|
* the value. For example, if `defaultBindProperty="value"`, then this shorthand |
|
* `bind` config: |
|
* |
|
* bind: '{name}' |
|
* |
|
* Is equivalent to this object form: |
|
* |
|
* bind: { |
|
* value: '{name}' |
|
* } |
|
* |
|
* The `defaultBindProperty` is set to "value" for form fields and to "store" for |
|
* grids and trees. |
|
* @protected |
|
*/ |
|
defaultBindProperty: null, |
|
|
|
/** |
|
* @property {RegExp} |
|
* Regular expression used for validating `reference` values. |
|
* @private |
|
*/ |
|
validRefRe: /^[a-z_][a-z0-9_]*$/i, |
|
|
|
/** |
|
* Called by `getInherited` to initialize the inheritedState the first time it is |
|
* requested. |
|
* @protected |
|
*/ |
|
initInheritedState: function (inheritedState) { |
|
var me = this, |
|
reference = me.getReference(), |
|
controller = me.getController(), |
|
// Don't instantiate the view model here, we only need to know that |
|
// it exists |
|
viewModel = me.getConfig('viewModel', true), |
|
session = me.getConfig('session', true), |
|
defaultListenerScope = me.getDefaultListenerScope(); |
|
|
|
if (controller) { |
|
inheritedState.controller = controller; |
|
} |
|
|
|
if (defaultListenerScope) { |
|
inheritedState.defaultListenerScope = me; |
|
} else if (controller) { |
|
inheritedState.defaultListenerScope = controller; |
|
} |
|
|
|
if (viewModel) { |
|
// If we're not configured with an instance, just stamp the current component as |
|
// the thing that holds the view model. When we ask to get the inherited view model, |
|
// we will know that it's not an instance yet so we need to spin it up on this component. |
|
// We need to initialize them from top-down, but we don't want to do it up front. |
|
if (!viewModel.isViewModel) { |
|
viewModel = me; |
|
} |
|
inheritedState.viewModel = viewModel; |
|
} |
|
|
|
// Same checks as the view model |
|
if (session) { |
|
if (!session.isSession) { |
|
session = me; |
|
} |
|
inheritedState.session = session; |
|
} |
|
|
|
if (reference) { |
|
me.referenceKey = (inheritedState.referencePath || '') + reference; |
|
me.viewModelKey = (inheritedState.viewModelPath || '') + reference; |
|
} |
|
}, |
|
|
|
/** |
|
* Gets the controller that controls this view. May be a controller that belongs |
|
* to a view higher in the hierarchy. |
|
* |
|
* @param {Boolean} [skipThis=false] `true` to not consider the controller directly attached |
|
* to this view (if it exists). |
|
* @return {Ext.app.ViewController} The controller. `null` if no controller is found. |
|
* |
|
* @since 5.0.1 |
|
*/ |
|
lookupController: function(skipThis) { |
|
return this.getInheritedConfig('controller', skipThis) || null; |
|
}, |
|
|
|
/** |
|
* Returns the `Ext.data.Session` for this instance. This property may come |
|
* from this instance's `{@link #session}` or be inherited from this object's parent. |
|
* @param {Boolean} [skipThis=false] Pass `true` to ignore a `session` configured on |
|
* this instance and only consider an inherited session. |
|
* @return {Ext.data.Session} |
|
* @since 5.0.0 |
|
*/ |
|
lookupSession: function (skipThis) { |
|
// See lookupViewModel |
|
var ret = skipThis ? null : this.getSession(); // may be the initGetter! |
|
if (!ret) { |
|
ret = this.getInheritedConfig('session', skipThis); |
|
if (ret && !ret.isSession) { |
|
ret = ret.getInherited().session = ret.getSession(); |
|
} |
|
} |
|
|
|
return ret || null; |
|
}, |
|
|
|
/** |
|
* Returns the `Ext.app.ViewModel` for this instance. This property may come from this |
|
* this instance's `{@link #viewModel}` or be inherited from this object's parent. |
|
* @param {Boolean} [skipThis=false] Pass `true` to ignore a `viewModel` configured on |
|
* this instance and only consider an inherited view model. |
|
* @return {Ext.app.ViewModel} |
|
* @since 5.0.0 |
|
*/ |
|
lookupViewModel: function (skipThis) { |
|
var ret = skipThis ? null : this.getViewModel(); // may be the initGetter! |
|
|
|
if (!ret) { |
|
ret = this.getInheritedConfig('viewModel', skipThis); |
|
// If what we get back is a component, it means the component was configured |
|
// with a view model, however the construction of it has been delayed until |
|
// we need it. As such, go and construct it and store it on the inherited state. |
|
if (ret && !ret.isViewModel) { |
|
ret = ret.getInherited().viewModel = ret.getViewModel(); |
|
} |
|
} |
|
|
|
return ret || null; |
|
}, |
|
|
|
/** |
|
* Publish this components state to the `ViewModel`. If no arguments are given (or if |
|
* this is the first call), the entire state is published. This state is determined by |
|
* the `publishes` property. |
|
* |
|
* This method is called only by component authors. |
|
* |
|
* @param {String} [property] The name of the property to update. |
|
* @param {Object} [value] The value of `property`. Only needed if `property` is given. |
|
* @protected |
|
* @since 5.0.0 |
|
*/ |
|
publishState: function (property, value) { |
|
var me = this, |
|
path = me.viewModelKey, |
|
state = me.publishedState, |
|
binds = me.getBind(), |
|
binding = binds && property && binds[property], |
|
count = 0, |
|
name, publishes, vm; |
|
|
|
if (binding && !binding.syncing && !binding.isReadOnly()) { |
|
// If the binding has never fired & our value is either: |
|
// a) undefined |
|
// b) null |
|
// c) The value we were initially configured with |
|
// Then we don't want to publish it back to the view model. If we do, we'll be |
|
// overwriting whatever is in the viewmodel and it will never have a chance to fire. |
|
if (!(binding.calls === 0 && (value == null || value === me.getInitialConfig()[property]))) { |
|
binding.setValue(value); |
|
} |
|
} |
|
|
|
if (!path || !(publishes = me.getPublishes())) { |
|
return; |
|
} |
|
|
|
if (!(vm = me.lookupViewModel())) { |
|
return; |
|
} |
|
|
|
if (property && state) { |
|
if (!publishes[property]) { |
|
return; |
|
} |
|
|
|
// If we are setting an individual property and that is not a {} or a [] then |
|
// check to see if it is unchanged. |
|
if (!(value && value.constructor === Object) && !(value instanceof Array)) { |
|
if (state[property] === value) { |
|
return; |
|
} |
|
} |
|
path += '.'; |
|
path += property; |
|
} else { |
|
state = state || (me.publishedState = {}); |
|
|
|
for (name in publishes) { |
|
++count; |
|
// If there are no properties to publish this loop will not run and the |
|
// value = null above will remain. |
|
if (name === property) { |
|
state[name] = value; |
|
} else { |
|
state[name] = me[name]; |
|
} |
|
} |
|
|
|
if (!count) { // if (no properties were put in "state") |
|
return; |
|
} |
|
value = state; |
|
} |
|
|
|
vm.set(path, value); |
|
}, |
|
|
|
//========================================================================= |
|
|
|
privates: { |
|
/** |
|
* Ensures that the given property (if it is a Config System config) has a proper |
|
* "updater" method on this instance to sync changes to the config. |
|
* @param {String} property The name of the config property. |
|
* @private |
|
* @since 5.0.0 |
|
*/ |
|
addBindableUpdater: function (property) { |
|
var me = this, |
|
configs = me.self.$config.configs, |
|
cfg = configs[property], |
|
updateName; |
|
|
|
// While we store the updater on this instance, the function is cached and |
|
// re-used across all instances. |
|
if (cfg && !me.hasOwnProperty(updateName = cfg.names.update)) { |
|
me[updateName] = cfg.bindableUpdater || |
|
(cfg.root.bindableUpdater = me.makeBindableUpdater(cfg)); |
|
} |
|
}, |
|
|
|
/** |
|
* @param {String/Object} binds |
|
* @param {Object} currentBindings |
|
* @return {Object} |
|
* @private |
|
* @since 5.0.0 |
|
*/ |
|
applyBind: function (binds, currentBindings) { |
|
var me = this, |
|
viewModel = me.lookupViewModel(), |
|
twoWayable = me.getTwoWayBindable(), |
|
getBindTemplateScope = me._getBindTemplateScope, |
|
b, property, descriptor; |
|
|
|
if (!currentBindings || typeof currentBindings === 'string') { |
|
currentBindings = {}; |
|
} |
|
|
|
//<debug> |
|
if (!viewModel) { |
|
Ext.Error.raise('Cannot use bind config without a viewModel'); |
|
} |
|
//</debug> |
|
|
|
if (Ext.isString(binds)) { |
|
//<debug> |
|
if (!me.defaultBindProperty) { |
|
Ext.Error.raise(me.$className + ' has no defaultBindProperty - '+ |
|
'Please specify a bind object'); |
|
} |
|
//</debug> |
|
|
|
b = binds; |
|
binds = {}; |
|
binds[me.defaultBindProperty] = b; |
|
} |
|
|
|
for (property in binds) { |
|
descriptor = binds[property]; |
|
b = currentBindings[property]; |
|
|
|
if (b && typeof b !== 'string') { |
|
b.destroy(); |
|
b = null; |
|
} |
|
|
|
if (descriptor) { |
|
b = viewModel.bind(descriptor, me.onBindNotify, me); |
|
b._config = Ext.Config.get(property); |
|
b.getTemplateScope = getBindTemplateScope; |
|
|
|
//<debug> |
|
if (!me[b._config.names.set]) { |
|
Ext.Error.raise('Cannot bind ' + property + ' on ' + me.$className + |
|
' - missing a ' + b._config.names.set + ' method.'); |
|
} |
|
//</debug> |
|
} |
|
|
|
currentBindings[property] = b; |
|
if (twoWayable && twoWayable[property] && !b.isReadOnly()) { |
|
me.addBindableUpdater(property); |
|
} |
|
} |
|
|
|
return currentBindings; |
|
}, |
|
|
|
applyController: function (controller) { |
|
if (controller) { |
|
controller = Ext.Factory.controller(controller); |
|
controller.setView(this); |
|
} |
|
return controller; |
|
}, |
|
|
|
applyPublishes: function (all) { |
|
if (this.lookupViewModel()) { |
|
for (var property in all) { |
|
this.addBindableUpdater(property); |
|
} |
|
} |
|
|
|
return all; |
|
}, |
|
|
|
//<debug> |
|
applyReference: function (reference) { |
|
var validIdRe = this.validRefRe || Ext.validIdRe; |
|
if (reference && !validIdRe.test(reference)) { |
|
Ext.Error.raise('Invalid reference "' + reference + '" for ' + this.getId() + |
|
' - not a valid identifier'); |
|
} |
|
return reference; |
|
}, |
|
//</debug> |
|
|
|
/** |
|
* Transforms a Session config to a proper instance. |
|
* @param {Object} session |
|
* @return {Ext.data.Session} |
|
* @private |
|
* @since 5.0.0 |
|
*/ |
|
applySession: function (session) { |
|
if (!session) { |
|
return null; |
|
} |
|
|
|
if (!session.isSession) { |
|
var parentSession = this.lookupSession(true), // skip this component |
|
config = (session === true) ? {} : session; |
|
|
|
if (parentSession) { |
|
session = parentSession.spawn(config); |
|
} else { |
|
// Mask this use of Session from Cmd - the dependency is not ours but |
|
// the caller |
|
session = new Ext.data['Session'](config); |
|
} |
|
} |
|
|
|
return session; |
|
}, |
|
|
|
/** |
|
* Transforms a ViewModel config to a proper instance. |
|
* @param {String/Object/Ext.app.ViewModel} viewModel |
|
* @return {Ext.app.ViewModel} |
|
* @private |
|
* @since 5.0.0 |
|
*/ |
|
applyViewModel: function (viewModel) { |
|
var me = this, |
|
config, session; |
|
|
|
if (!(viewModel && viewModel.isViewModel)) { |
|
config = { |
|
parent: me.lookupViewModel(true) // skip this component |
|
}; |
|
|
|
config.session = me.getSession(); |
|
if (!session && !config.parent) { |
|
config.session = me.lookupSession(); |
|
} |
|
|
|
if (viewModel) { |
|
if (viewModel.constructor === Object) { |
|
Ext.apply(config, viewModel); |
|
} else if (typeof viewModel === 'string') { |
|
config.type = viewModel; |
|
} |
|
} |
|
|
|
viewModel = Ext.Factory.viewModel(config); |
|
} |
|
return viewModel; |
|
}, |
|
|
|
_getBindTemplateScope: function () { |
|
// This method is called as a method on a Binding instance, so the "this" pointer |
|
// is that of the Binding. The "scope" of the Binding is the component owning it. |
|
return this.scope.resolveListenerScope(); |
|
}, |
|
|
|
/** |
|
* This method triggers the lazy configs and must be called when it is time to |
|
* fully boot up. The configs that must be initialized are: `bind`, `publishes`, |
|
* `session`, `twoWayBindable` and `viewModel`. |
|
* @private |
|
* @since 5.0.0 |
|
*/ |
|
initBindable: function () { |
|
this.initBindable = Ext.emptyFn; |
|
this.getBind(); |
|
this.getPublishes(); |
|
|
|
// If we have binds, the applyBind method will call getTwoWayBindable to ensure |
|
// we have the necessary updaters. If we have no binds then applyBind will not |
|
// be called and we will ignore our twoWayBindable config (which is fine). |
|
// |
|
// If we have publishes or binds then the viewModel will be requested. If not |
|
// this viewModel will be lazily requested by a descendant via inheritedState |
|
// or not at all. If there is no descendant using bind or publishes, then the |
|
// viewModel will sit and wait. |
|
// |
|
// As goes the fate of the viewModel so goes the fate of the session. If we |
|
// have requested the viewModel then the session will also be spun up. If not, |
|
// we wait for a descendant or the user to request them. |
|
}, |
|
|
|
/** |
|
* Returns an `update` method for the given Config that will call `{@link #publishState}` |
|
* to ensure two-way bindings (via `bind`) as well as any `publishes` are updated. |
|
* This method is cached on the `cfg` instance for re-use. |
|
* @param {Ext.Config} cfg |
|
* @return {Function} The updater function. |
|
* @private |
|
* @since 5.0.0 |
|
*/ |
|
makeBindableUpdater: function (cfg) { |
|
var updateName = cfg.names.update; |
|
|
|
return function (newValue, oldValue) { |
|
var me = this, |
|
updater = me.self.prototype[updateName]; |
|
|
|
if (updater) { |
|
updater.call(me, newValue, oldValue); |
|
} |
|
me.publishState(cfg.name, newValue); |
|
}; |
|
}, |
|
|
|
onBindNotify: function (value, oldValue, binding) { |
|
binding.syncing = (binding.syncing + 1) || 1; |
|
this[binding._config.names.set](value); |
|
--binding.syncing; |
|
}, |
|
|
|
removeBindings: function() { |
|
var bindings = this.bind, |
|
key, binding; |
|
|
|
if (bindings && typeof bindings !== 'string') { |
|
for (key in bindings) { |
|
binding = bindings[key]; |
|
binding.destroy(); |
|
binding._config = binding.getTemplateScope = null; |
|
} |
|
} |
|
this.bind = null; |
|
}, |
|
|
|
/** |
|
* Updates the session config. |
|
* @param {Ext.data.Session} session |
|
* @private |
|
* @since 5.0.0 |
|
*/ |
|
updateSession: function (session) { |
|
var state = this.getInherited(); |
|
|
|
if (session) { |
|
state.session = session; |
|
} else { |
|
delete state.session; |
|
} |
|
}, |
|
|
|
/** |
|
* Updates the viewModel config. |
|
* @param {Ext.app.ViewModel} viewModel |
|
* @private |
|
* @since 5.0.0 |
|
*/ |
|
updateViewModel: function (viewModel) { |
|
var state = this.getInherited(), |
|
controller = this.getController(); |
|
|
|
if (viewModel) { |
|
state.viewModel = viewModel; |
|
viewModel.setView(this); |
|
if (controller) { |
|
controller.initViewModel(viewModel); |
|
} |
|
} else { |
|
delete state.viewModel; |
|
} |
|
} |
|
} // private |
|
});
|
|
|