/**
* This is the base class from which all plugins should extend.
*
* This class defines the essential API of plugins as used by Components by defining the
* following methods:
*
* - `init` : The plugin initialization method which the host Component calls during
* Component initialization. The Component passes itself as the sole parameter.
* Subclasses should set up bidirectional links between the plugin and its host
* Component here.
*
* - `destroy` : The plugin cleanup method which the host Component calls at Component
* destruction time. Use this method to break links between the plugin and the
* Component and to free any allocated resources.
*/
Ext.define('Ext.plugin.Abstract', {
alternateClassName: 'Ext.AbstractPlugin',
mixins: [
'Ext.mixin.Identifiable'
],
/**
* @property {Boolean} isPlugin
* The value `true` to identify objects of this class or a subclass thereof.
* @readonly
*/
isPlugin: true,
/**
* @cfg {String} id
* An identifier for the plugin that can be set at creation time to later retrieve the
* plugin using the {@link #getPlugin getPlugin} method. For example:
*
* var panel = Ext.create({
* xtype: 'panel',
*
* plugins: {
* foobar: {
* id: 'foo',
* ...
* }
* }
* });
*
* // later on:
* var plugin = panel.getPlugin('foo');
* @since 6.2.0
*/
/**
* @cfg {String} pluginId
* @deprecated 6.2.0 Use `id` instead
*/
/**
* Initializes the plugin.
* @param {Object} [config] Configuration object.
*/
constructor: function(config) {
if (config) {
this.cmp = config.cmp;
this.pluginConfig = config;
this.initConfig(config);
}
},
/**
* @method init
* The init method is invoked to formally associate the host component and the plugin.
*
* Subclasses should perform initialization and set up any requires links between the
* plugin and its host Component in their own implementation of this method.
* @param {Ext.Component} host The host Component which owns this plugin.
*/
init: Ext.emptyFn,
/**
* The destroy method is invoked by the owning Component at the time the Component is
* being destroyed.
*/
destroy: function() {
var me = this;
me.destroy = Ext.emptyFn;
me.destroying = true;
me.cmp = me.pluginConfig = null;
me.doDestroy();
me.callParent();
// This just makes it hard to ask "was destroy() called?":
// me.destroying = false; // removed in 7.0
},
doDestroy: Ext.emptyFn,
/**
* Creates clone of the plugin.
* @param {Object} [overrideCfg] Additional config for the derived plugin.
*/
clonePlugin: function(overrideCfg) {
return new this.self(Ext.apply({}, overrideCfg, this.pluginConfig));
},
/**
* @method detachCmp
* Plugins that can be disconnected from their host component should implement
* this method.
* @since 6.2.0
*/
/**
* Returns the component to which this plugin is attached.
* @return {Ext.Component} The owning host component.
*/
getCmp: function() {
return this.cmp;
},
/**
* Sets the host component to which this plugin is attached. For a plugin to be
* removable without being destroyed, this method should be provided and be prepared
* to receive `null` for the component.
* @param {Ext.Component} host The owning host component.
*/
setCmp: function(host) {
this.cmp = host;
},
getStatefulOwner: function() {
return [this.cmp, 'plugins'];
},
onClassExtended: function(cls, data, hooks) {
var alias = data.alias,
prototype = cls.prototype;
// Inject a ptype property so that findPlugin() works.
if (alias && !data.ptype) {
if (Ext.isArray(alias)) {
alias = alias[0];
}
prototype.ptype = alias.split('plugin.')[1];
}
},
resolveListenerScope: function(defaultScope) {
var me = this,
cmp = me.getCmp(),
scope;
if (cmp) {
scope = cmp.resolveSatelliteListenerScope(me, defaultScope);
}
// If this method was called, it means the plugin subclass must
// have mixed in Observable, so we can rely on there being
// a "this.mixins.observable" even though Ext.plugin.Abstract
// does not mix it in directly
return scope || me.mixins.observable.resolveListenerScope.call(me, defaultScope);
},
statics: {
decode: function(plugins, typeProp, include) {
if (plugins) {
// eslint-disable-next-line vars-on-top
var type = Ext.typeOf(plugins), // 'object', 'array', 'string'
entry, key, obj, value;
if (type === 'string') {
obj = {};
// allows for findPlugin to find a plugin
// defined as a string
obj[typeProp] = plugins;
plugins = [ obj ];
}
else if (plugins.isInstance) {
plugins = [ plugins ];
}
else if (type === 'object') {
if (plugins[typeProp]) {
plugins = [plugins];
}
else {
obj = include ? Ext.merge(Ext.clone(include), plugins) : plugins;
plugins = [];
for (key in obj) {
if (!(value = obj[key])) {
continue;
}
entry = {
id: key
};
entry[typeProp] = key;
Ext.apply(entry, value);
plugins.push(entry);
}
Ext.sortByWeight(plugins);
}
}
//<debug>
else if (type !== 'array') {
Ext.raise('Invalid value for "plugins" config ("' + type + '"');
}
//</debug>
else {
plugins = plugins.slice(); // so that all cases return mutable array
}
}
return plugins;
}
}
});