linuxwindowsinboxwhatsappicloudtweetdeckhipchattelegramhangoutsslackgmailskypefacebook-workplaceoutlookemailmicrosoft-teamsdiscordmessengercustom-servicesmacos
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.
302 lines
9.1 KiB
302 lines
9.1 KiB
/** |
|
* @class Ext.Config |
|
* This class manages a config property. Instances of this type are created and cached as |
|
* classes declare their config properties. One instance of this class is created per |
|
* config property name. |
|
* |
|
* Ext.define('MyClass', { |
|
* config: { |
|
* foo: 42 |
|
* } |
|
* }); |
|
* |
|
* This uses the cached `Ext.Config` instance for the "foo" property. |
|
* |
|
* When config properties apply options to config properties a prototype chained object is |
|
* created from the cached instance. For example: |
|
* |
|
* Ext.define('MyClass', { |
|
* config: { |
|
* foo: { |
|
* $value: 42, |
|
* lazy: true |
|
* } |
|
* } |
|
* }); |
|
* |
|
* This creates a prototype chain to the cached "foo" instance of `Ext.Config` and applies |
|
* the `lazy` option to that new instance. This chained instance is then kept by the |
|
* `Ext.Configurator` for that class. |
|
* @private |
|
*/ |
|
Ext.Config = function (name) { |
|
// @define Ext.class.Config |
|
// @define Ext.Config |
|
|
|
var me = this, |
|
capitalizedName = name.charAt(0).toUpperCase() + name.substr(1); |
|
|
|
/** |
|
* @property {String} name |
|
* The name of this config property. |
|
* @readonly |
|
* @private |
|
* @since 5.0.0 |
|
*/ |
|
me.name = name; |
|
|
|
/** |
|
* @property {Object} names |
|
* This object holds the cached names used to lookup properties or methods for this |
|
* config property. The properties of this object are explained in the context of an |
|
* example property named "foo". |
|
* |
|
* @property {String} names.internal The default backing property ("_foo"). |
|
* |
|
* @property {String} names.initializing The property that is `true` when the config |
|
* is being initialized ("isFooInitializing"). |
|
* |
|
* @property {String} names.apply The name of the applier method ("applyFoo"). |
|
* |
|
* @property {String} names.update The name of the updater method ("updateFoo"). |
|
* |
|
* @property {String} names.get The name of the getter method ("getFoo"). |
|
* |
|
* @property {String} names.set The name of the setter method ("setFoo"). |
|
* |
|
* @property {String} names.initGet The name of the initializing getter ("initGetFoo"). |
|
* |
|
* @property {String} names.doSet The name of the evented setter ("doSetFoo"). |
|
* |
|
* @property {String} names.changeEvent The name of the change event ("foochange"). |
|
* |
|
* @readonly |
|
* @private |
|
* @since 5.0.0 |
|
*/ |
|
me.names = { |
|
internal: '_' + name, |
|
initializing: 'is' + capitalizedName + 'Initializing', |
|
apply: 'apply' + capitalizedName, |
|
update: 'update' + capitalizedName, |
|
get: 'get' + capitalizedName, |
|
set: 'set' + capitalizedName, |
|
initGet: 'initGet' + capitalizedName, |
|
doSet : 'doSet' + capitalizedName, |
|
changeEvent: name.toLowerCase() + 'change' |
|
}; |
|
|
|
// This allows folks to prototype chain on top of these objects and yet still cache |
|
// generated methods at the bottom of the chain. |
|
me.root = me; |
|
}; |
|
|
|
Ext.Config.map = {}; |
|
|
|
Ext.Config.get = function (name) { |
|
var map = Ext.Config.map, |
|
ret = map[name] || (map[name] = new Ext.Config(name)); |
|
|
|
return ret; |
|
}; |
|
|
|
Ext.Config.prototype = { |
|
self: Ext.Config, |
|
|
|
isConfig: true, |
|
|
|
/** |
|
* @cfg {Boolean} [cached=false] |
|
* When set as `true` the config property will be stored on the class prototype once |
|
* the first instance has had a chance to process the default value. |
|
* @private |
|
* @since 5.0.0 |
|
*/ |
|
|
|
/** |
|
* @cfg {Boolean} [lazy=false] |
|
* When set as `true` the config property will not be immediately initialized during |
|
* the `initConfig` call. |
|
* @private |
|
* @since 5.0.0 |
|
*/ |
|
|
|
/** |
|
* @cfg {Function} [merge] |
|
* This function if supplied will be called as classes or instances provide values |
|
* that need to be combined with inherited values. The function should return the |
|
* value that will be the config value. Further calls may receive such returned |
|
* values as `oldValue`. |
|
* |
|
* @cfg {Mixed} merge.newValue The new value to merge with the old. |
|
* |
|
* @cfg {Mixed} merge.oldValue The current value prior to `newValue` being merged. |
|
* |
|
* @cfg {Mixed} merge.target The class or instance to which the merged config value |
|
* will be applied. |
|
* |
|
* @cfg {Ext.Class} merge.mixinClass The mixin providing the `newValue` or `null` if |
|
* the `newValue` is not being provided by a mixin. |
|
*/ |
|
|
|
getGetter: function () { |
|
return this.getter || (this.root.getter = this.makeGetter()); |
|
}, |
|
|
|
getInitGetter: function () { |
|
return this.initGetter || (this.root.initGetter = this.makeInitGetter()); |
|
}, |
|
|
|
getSetter: function () { |
|
return this.setter || (this.root.setter = this.makeSetter()); |
|
}, |
|
|
|
/** |
|
* Returns the name of the property that stores this config on the given instance or |
|
* class prototype. |
|
* @param {Object} target |
|
* @return {String} |
|
*/ |
|
getInternalName: function (target) { |
|
return target.$configPrefixed ? this.names.internal : this.name; |
|
}, |
|
|
|
mergeNew: function (newValue, oldValue, target, mixinClass) { |
|
var ret, key; |
|
|
|
if (!oldValue) { |
|
ret = newValue; |
|
} else if (!newValue) { |
|
ret = oldValue; |
|
} else { |
|
ret = Ext.Object.chain(oldValue); |
|
|
|
for (key in newValue) { |
|
if (!mixinClass || !(key in ret)) { |
|
ret[key] = newValue[key]; |
|
} |
|
} |
|
} |
|
return ret; |
|
}, |
|
|
|
/** |
|
* Merges the `newValue` and the `oldValue` assuming that these are basically objects |
|
* the represent sets. For example something like: |
|
* |
|
* { |
|
* foo: true, |
|
* bar: true |
|
* } |
|
* |
|
* The merge process converts arrays like the following into the above: |
|
* |
|
* [ 'foo', 'bar' ] |
|
* |
|
* @param {String/String[]/Object} newValue |
|
* @param {Object} oldValue |
|
* @param {Boolean} [preserveExisting=false] |
|
* @return {Object} |
|
* @private |
|
* @since 5.0.0 |
|
*/ |
|
mergeSets: function (newValue, oldValue, preserveExisting) { |
|
var ret = oldValue ? Ext.Object.chain(oldValue) : {}, |
|
i, val; |
|
|
|
if (newValue instanceof Array) { |
|
for (i = newValue.length; i--; ) { |
|
val = newValue[i]; |
|
if (!preserveExisting || !(val in ret)) { |
|
ret[val] = true; |
|
} |
|
} |
|
} else if (newValue) { |
|
if (newValue.constructor === Object) { |
|
for (i in newValue) { |
|
val = newValue[i]; |
|
if (!preserveExisting || !(i in ret)) { |
|
ret[i] = val; |
|
} |
|
} |
|
} else if (!preserveExisting || !(newValue in ret)) { |
|
ret[newValue] = true; |
|
} |
|
} |
|
|
|
return ret; |
|
}, |
|
|
|
//-------------------------------------------------- |
|
// Factories |
|
|
|
makeGetter: function () { |
|
var name = this.name, |
|
prefixedName = this.names.internal; |
|
|
|
return function () { |
|
var internalName = this.$configPrefixed ? prefixedName : name; |
|
return this[internalName]; |
|
}; |
|
}, |
|
|
|
makeInitGetter: function () { |
|
var name = this.name, |
|
names = this.names, |
|
setName = names.set, |
|
getName = names.get, |
|
initializingName = names.initializing; |
|
|
|
return function () { |
|
var me = this; |
|
|
|
me[initializingName] = true; |
|
// Remove the initGetter from the instance now that the value has been set. |
|
delete me[getName]; |
|
|
|
me[setName](me.config[name]); |
|
delete me[initializingName]; |
|
|
|
return me[getName].apply(me, arguments); |
|
}; |
|
}, |
|
|
|
makeSetter: function () { |
|
var name = this.name, |
|
names = this.names, |
|
prefixedName = names.internal, |
|
getName = names.get, |
|
applyName = names.apply, |
|
updateName = names.update, |
|
setter; |
|
|
|
// http://jsperf.com/method-call-apply-or-direct |
|
// http://jsperf.com/method-detect-invoke |
|
setter = function (value) { |
|
var me = this, |
|
internalName = me.$configPrefixed ? prefixedName : name, |
|
oldValue = me[internalName]; |
|
|
|
// Remove the initGetter from the instance now that the value has been set. |
|
delete me[getName]; |
|
|
|
if (!me[applyName] || (value = me[applyName](value, oldValue)) !== undefined) { |
|
// The old value might have been changed at this point |
|
// (after the apply call chain) so it should be read again |
|
if (value !== (oldValue = me[internalName])) { |
|
me[internalName] = value; |
|
|
|
if (me[updateName]) { |
|
me[updateName](value, oldValue); |
|
} |
|
} |
|
} |
|
|
|
return me; |
|
}; |
|
|
|
setter.$isDefault = true; |
|
|
|
return setter; |
|
} |
|
};
|
|
|