1
YUI.add('gallery-base-componentmgr', function(Y) {
4
* Base Component Manager
7
* Copyright (c) 2010-2011 Eric Ferraiuolo - http://eric.ferraiuolo.name
8
* YUI BSD License - http://developer.yahoo.com/yui/license.html
13
REQUIRES = 'requires',
14
INITIALIZER = 'initializer',
15
DESTRUCTOR = 'destructor',
16
INSTANCE = 'instance',
18
E_INIT_COMPONENT = 'initComponent',
19
E_INIT_COMPONENTS = 'initComponents',
20
E_DESTROY_COMPONENT = 'destroyComponent',
23
isArray = YLang.isArray,
24
isString = YLang.isString,
25
isObject = YLang.isObject,
26
isFunction = YLang.isFunction,
29
// *** Constructor *** //
31
ComponentMgr = function () {
33
this._initComponentMgr.apply(this, arguments);
38
ComponentMgr._COMPONENT_CFG = [REQUIRES, INITIALIZER, DESTRUCTOR, INSTANCE];
40
// *** Prototype *** //
42
ComponentMgr.prototype = {
44
// *** Instance Members *** //
48
// *** Lifecycle Methods *** //
50
_initComponentMgr : function () {
53
this._components = new Y.State();
54
this._initComponentHierarchy();
57
* Fired right after init event to allow implementers to add components to be eagerly initialized.
58
* A <code>componentsToInit</code> array is passed to subscribers whom can push on components to be initialized,
59
* components can be referenced by string name or object reference.
61
* @event initComponents
62
* @param event {Event} The event object for initComponents; has property: componentsToInit
64
this.publish(E_INIT_COMPONENTS, {
65
defaultFn : this._defInitComponentsFn,
70
* Fired when a component is going to be initialized.
71
* The <code>componentToInit</code> property is the String name of the component going to be initialized.
72
* Developers can listen to the 'on' moment to prevent the default action of initializing the component.
73
* Listening to the 'after' moment, a <code>component</code> property on the Event Object is the component instance.
75
* @event initComponent
76
* @param event {Event} The event object for initComponent; has properties: componentToInit, component
78
this.publish(E_INIT_COMPONENT, { defaultFn: this._defInitComponentFn });
81
* Fired when a component is going to be destroyed.
82
* The <code>component</code> property is the String name of the component going to be destroyed.
83
* Developers can listen to the 'on' moment to prevent the default action of destroying the component.
85
* @event destroyComponent
86
* @param event {Event} The event object for destoryComponent; has properties: component
88
this.publish(E_DESTROY_COMPONENT, { defaultFn: this._defDestoryComponentFn });
90
// Fire initComponents during Y.Base initialization
91
if (this.get('initialized')) {
92
this.fire(E_INIT_COMPONENTS, { componentsToInit: [] });
94
this.after('initializedChange', function(e){
95
this.fire(E_INIT_COMPONENTS, { componentsToInit: [] });
99
Y.before(this._destroyComponents, this.constructor.prototype, 'destructor', this);
102
// *** Public Methods *** //
105
* Adds a component to the Class.
106
* Components are added by giving an name and configuration.
107
* The Component Manager uses the requires and initializer function to create the component instance on demand.
109
* @method addComponent
110
* @param name {String} name of the component to add
111
* @param config {Object} defining: {Array} requires, {function} initializer
114
addComponent : function (name, config) {
116
if ( ! isString(name)) { return; } // string name
117
if ( ! isObject(config)) { return; } // config object
119
var components = this._components,
120
requires = config.requires,
121
initializer = config.initializer,
122
destructor = config.destructor,
123
instance = config.instance;
125
initializer = isFunction(initializer) ? initializer :
126
isString(initializer) && isFunction(this[initializer]) ? this[initializer] : null;
128
destructor = isFunction(destructor) ? destructor :
129
isString(destructor) && isFunction(this[destructor]) ? this[destructor] : null;
131
components.add(name, REQUIRES, requires);
132
components.add(name, INITIALIZER, initializer);
133
components.add(name, DESTRUCTOR, destructor);
134
components.add(name, INSTANCE, instance);
138
* Retrieves component an instance by string name.
139
* The component must have previously been initialized otherwise null is returned.
141
* @method getComponent
142
* @param component {String} component to get instance of
143
* @return instance {Object|undefined} the component instance if previously initialized, otherwise undefined
145
getComponent : function (component) {
147
return this._components.get(component, INSTANCE);
151
* Destroys a component or set of components by string name.
152
* This will call the component???s configured destructor fn (preferred), or
153
* if the instance has a <code>destroy</code> method that will be used by convention.
155
* @method destroyComponent
156
* @param component {String | String... | Array} components to destroy
159
destroyComponent : function () {
161
var args = Y.Array(arguments, 0, true),
162
components = isArray(args[0]) ? args[0] : args;
164
Y.Array.each(components, function(c){
165
if (this._components.get(c, INSTANCE)) {
166
this._destroyComponent(c);
172
* Supplies the callback with component instance(s) that were requested by string name,
173
* any non-initialized components will be initialized.
174
* Component instance(s) will be passed to the callback as arguments in the order requested.
176
* @method useComponent
177
* @param component* {String} 1-n components to use and/or create instances of
178
* @param *callback {function} callback to pass component instances to
181
useComponent : function () {
184
var args = Y.Array(arguments, 0, true),
185
callback = isFunction(args[args.length-1]) ? args[args.length-1] : noop, // last param or noop
186
components = callback === noop ? args : args.slice(0, -1), // if callback is noop then all params, otherwise all but last params
190
if (components.length < 1) {
195
initialized = Y.Array.partition(components, function(c){
196
var instance = this.getComponent(c);
197
instances.push(instance);
201
if (initialized.rejects.length > 0) {
202
Y.use.apply(Y, this._getRequires(initialized.rejects).concat(Y.bind(function(Y){
204
Y.Array.each(initialized.rejects, this._initComponent, this);
205
Y.Array.each(components, function(c){
206
instances.push(this.getComponent(c));
208
callback.apply(this, instances);
211
callback.apply(this, instances);
215
// *** Private Methods *** //
217
_initComponentHierarchy : function () {
219
var classes = this._getClasses(),
221
componentConfigProps = ComponentMgr._COMPONENT_CFG,
222
i, mergeComponentConfigs;
224
// Loop over the Class Hierarchy, aggregating the Component configs
226
mergeComponentConfigs = function (config, name) {
228
if ( ! components[name]) {
229
components[name] = Y.mix({}, config, true, componentConfigProps);
231
Y.mix(components[name], config, true, componentConfigProps);
235
for (i = classes.length-1; i >= 0; i--) {
236
Y.Object.each(classes[i].COMPONENTS, mergeComponentConfigs);
239
// Add the components defined in the static COMPONENTS object
240
Y.Object.each(components, function(config, name){
241
this.addComponent(name, config);
245
_getRequires : function (components) {
247
components = isArray(components) ? components : [components];
250
Y.Array.each(components, function(c){
251
requires = requires.concat(this._components.get(c, REQUIRES) || []);
254
return Y.Array.unique(requires);
257
_initComponent : function (c) {
259
this.fire(E_INIT_COMPONENT, { componentToInit: c });
262
_destroyComponent : function (c) {
264
this.fire(E_DESTROY_COMPONENT, { component: c });
267
_destroyComponents : function () {
269
var instances = this._components.data[INSTANCE];
271
Y.each(instances, function(instance, component){
273
this._destroyComponent(component);
278
_defInitComponentsFn : function (e) {
280
var components = e.componentsToInit,
281
requires = this._getRequires(components);
283
Y.use.apply(Y, requires.concat(Y.bind(function(Y){
284
Y.Array.each(components, this._initComponent, this);
288
_defInitComponentFn : function (e) {
290
var components = this._components,
291
component = e.componentToInit,
292
initializer = components.get(component, INITIALIZER),
293
instance = components.get(component, INSTANCE);
295
if ( ! instance && isFunction(initializer)) {
296
instance = initializer.call(this);
297
// Add us as an event bubble target for the instance
298
if (instance._yuievt && isFunction(instance.addTarget)) {
299
instance.addTarget(this);
301
components.add(component, INSTANCE, instance);
304
e.component = instance;
307
_defDestoryComponentFn : function (e) {
309
var components = this._components,
310
component = e.component,
311
destructor = components.get(component, DESTRUCTOR),
312
instance = components.get(component, INSTANCE);
314
if ( ! instance ) { return; }
316
// removes us as an event bubble target for the instance
317
if (instance._yuievt && isFunction(instance.removeTarget)) {
318
instance.removeTarget(this);
321
// prefer the configured destructor fn, or use use destroy instance method by convention
322
if (isFunction(destructor)) {
323
destructor.call(this, instance);
324
} else if (isFunction(instance.destroy)) {
328
components.remove(component, INSTANCE);
333
Y.BaseComponentMgr = ComponentMgr;
336
}, 'gallery-2011.01.26-20-33' ,{"requires":["base-base", "collection"]});