Created
January 1, 2012 16:28
-
-
Save Satyam/1547708 to your computer and use it in GitHub Desktop.
App plugin
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* | |
App plugins can be loaded over an instance of App by setting a route with a wildcard path | |
such as: | |
{ | |
path:'/:app/*', | |
callback: 'dispatchApp' | |
} | |
where the app param is the module name of the plugin, | |
which should have its entry in the YUI config file (unless loaded by some other means) | |
*/ | |
dispatchApp: function (req) { | |
var appName = req.params.app, | |
self = this; | |
if (!Y[appName] || !this[appName]) { | |
Y.use(appName, function() { | |
if (Y[appName]) { | |
self.plug(Y[appName]); | |
self.dispatch(); | |
} else { | |
Y.error('Plugin not found'); | |
} | |
}); | |
} else { | |
req.next(); | |
} | |
} | |
} | |
/* | |
Once loaded and plugged in, dispatch is called to process the new routes just added. | |
Thus, it doesn't really matter what extra arguments the path contained besides the | |
plugin name, they will be caught by the routes added by the plugin. | |
Any further calls to this route will find the app plugin already loaded and plugged | |
so it will call the next route to deal with its routes. In fact, this happens as soon as | |
it got loaded sin the call to dispatch() would have made router enter dispatchApp again | |
and jump directly to the req.next() call. | |
The App Plugin should inherit from the following class: | |
*/ | |
Y.Plugin.App = Y.Base.create('appPlugin', Y.Plugin.Base, [], { | |
_boundCallbacks:null, | |
initializer: function () { | |
var self = this, | |
host = self.get('host'), | |
constr = self.constructor, | |
binds = [], | |
b; | |
Y.each(constr.routes, function(item) { | |
b = Y.bind(self[item.callback],self); | |
binds.push({p:item.path, b:b}) | |
host.route(item.path, b ); | |
}); | |
this._boundCallbacks = binds; | |
Y.mix(host.views,constr.views); | |
}, | |
destructor: function () { | |
var self = this, | |
host = self.get('host'), | |
constr = self.constructor, | |
binds = this._boundCallbacks, | |
routes = host.get('routes'), | |
i,r,b = binds.pop(); | |
Y.each(constr.views, function (value, key) { | |
if (host.views[key].type === value.type) { | |
delete host.views[key]; | |
} | |
}); | |
for (i = routes.length -1;i>=0 && b ;i--) { | |
r = routes[i]; | |
if (b.p === r.path && b.b === r.callback) { | |
routes.splice(i,1); | |
b = binds.pop(); | |
} | |
} | |
host.set('routes',routes); | |
} | |
}); | |
/* | |
The App plugin can have its own set of views and routes | |
defined not as instance properties and attributes but as static members | |
which then get merged into the base views and routes. | |
The code is more complex than it should since it is somewhat hard to | |
identify the routes properly, specially since in this case they are bound to the | |
instance of the plugin so they can have access to its own properties and attributes | |
and not those of the host. | |
It would be great if routes could have a 'context' or 'scope' property. | |
The App plugin can be defined like this: | |
*/ | |
Y.MyAppPlugin = Y.Base.create('my-app-plugin', Y.Plugin.App, [], { | |
/* ... */ | |
}, { | |
ATTRS: { /* ... */ }, | |
NS:'MyAppPlugin', | |
routes: [ /* ... */ ], | |
views: { /* ... */ } | |
}); | |
/* | |
Unlike proper App instances, views and routes are defined as static properties, | |
their contents are the same as they would otherwise be. | |
The dispatchApp method at the top relies on the module name to be the same | |
as the name of the class for the plugin and the same as the namespace (NS) of the app Plugin. | |
In doing so, I'm bending a little bit the rules for naming modules, classes and plugin | |
namespaces since they should not all use the same capitalization. | |
Changing the code for the plugin dispatcher, this might not be so. | |
Other changes are possible: | |
The classes for the plugins might well reside all under a namespace under Y | |
instead of directly under Y, i.e.: Y.Apps.MyAppPlugin instead of Y.MyAppPlugin. | |
Furthermore, all plugins might use the same namespace (NS) so that only one of them | |
would be plugged in at any one time. The app plugin should make sure it destroys | |
any views and models it might have generated and the destructors for all these | |
views and models should free any resources they might have taken, | |
which should be done anyway, and is even more important in this case. | |
*/ |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment