index.mustache revision 767003094c9794f0804c663a8abc131b86554999
767003094c9794f0804c663a8abc131b86554999Satyen Desai<div class="intro">
767003094c9794f0804c663a8abc131b86554999Satyen Desai <p>
767003094c9794f0804c663a8abc131b86554999Satyen Desai Plugins allow you to unobtrusively add functionality to objects (referred to as the "host" object) such as nodes and widgets.
767003094c9794f0804c663a8abc131b86554999Satyen Desai Plugins can inherit from the `Plugin.Base` class, but this is not a hard requirement as we'll see later.
767003094c9794f0804c663a8abc131b86554999Satyen Desai </p>
767003094c9794f0804c663a8abc131b86554999Satyen Desai
767003094c9794f0804c663a8abc131b86554999Satyen Desai <p>
767003094c9794f0804c663a8abc131b86554999Satyen Desai Plugins are used to add atomic pieces of functionality or features to component instances (hosts), without having to bake support or even
767003094c9794f0804c663a8abc131b86554999Satyen Desai knowledge of the feature into the component class. This allows features to be mixed and matched per component instance, without having to build all
767003094c9794f0804c663a8abc131b86554999Satyen Desai features into a monolithic component class or having to ship multiple versions of the component class with varying combinations of features.
767003094c9794f0804c663a8abc131b86554999Satyen Desai </p>
767003094c9794f0804c663a8abc131b86554999Satyen Desai</div>
767003094c9794f0804c663a8abc131b86554999Satyen Desai
767003094c9794f0804c663a8abc131b86554999Satyen Desai{{>getting-started}}
767003094c9794f0804c663a8abc131b86554999Satyen Desai
767003094c9794f0804c663a8abc131b86554999Satyen Desai<h2 id="using">Creating Plugins</h2>
767003094c9794f0804c663a8abc131b86554999Satyen Desai
767003094c9794f0804c663a8abc131b86554999Satyen Desai<h3 id="simple">Simple Plugins</h3>
767003094c9794f0804c663a8abc131b86554999Satyen Desai
767003094c9794f0804c663a8abc131b86554999Satyen Desai<p>
767003094c9794f0804c663a8abc131b86554999Satyen DesaiFor the most basic plugins, which don't have any events or attributes of their own, and which don't modify the behavior
767003094c9794f0804c663a8abc131b86554999Satyen Desaiof the host by listening for any host events, or overriding any of the host's methods, plugins can simply be basic JavaScript classes.
767003094c9794f0804c663a8abc131b86554999Satyen Desai</p>
767003094c9794f0804c663a8abc131b86554999Satyen Desai
767003094c9794f0804c663a8abc131b86554999Satyen Desai<p>
767003094c9794f0804c663a8abc131b86554999Satyen DesaiThe only requirement for the class is that it has a static namespace property `NS` with a value assigned to it.
767003094c9794f0804c663a8abc131b86554999Satyen DesaiThe value of the `NS` property is used to define the property on the host instance which will refer to
767003094c9794f0804c663a8abc131b86554999Satyen Desaithe plugin when it's plugged into the host.
767003094c9794f0804c663a8abc131b86554999Satyen Desai</p>
767003094c9794f0804c663a8abc131b86554999Satyen Desai
767003094c9794f0804c663a8abc131b86554999Satyen Desai<p>
767003094c9794f0804c663a8abc131b86554999Satyen DesaiWhen plugins are plugged into a host instance a new instance of the plugin is created,
767003094c9794f0804c663a8abc131b86554999Satyen Desaiand a reference to the host is added to the configuration object passed to the plugin's constructor,
767003094c9794f0804c663a8abc131b86554999Satyen Desaiso that the plugin has a way to reference the host object. (similarly, when plugins are unplugged from a host
767003094c9794f0804c663a8abc131b86554999Satyen Desaiobject they are destroyed).
767003094c9794f0804c663a8abc131b86554999Satyen Desai</p>
767003094c9794f0804c663a8abc131b86554999Satyen Desai
767003094c9794f0804c663a8abc131b86554999Satyen Desai<p>So, putting this all together, a simple plugin class may look something like the following:</p>
767003094c9794f0804c663a8abc131b86554999Satyen Desai
767003094c9794f0804c663a8abc131b86554999Satyen Desai```
767003094c9794f0804c663a8abc131b86554999Satyen Desai// This AnchorPlugin is designed to be added to Node instances (the host will be a Node instance)
767003094c9794f0804c663a8abc131b86554999Satyen Desai
767003094c9794f0804c663a8abc131b86554999Satyen Desaifunction AnchorPlugin(config) {
767003094c9794f0804c663a8abc131b86554999Satyen Desai
767003094c9794f0804c663a8abc131b86554999Satyen Desai // Hold onto the host instance (a Node in this case),
767003094c9794f0804c663a8abc131b86554999Satyen Desai // for other plugin methods to use.
767003094c9794f0804c663a8abc131b86554999Satyen Desai
767003094c9794f0804c663a8abc131b86554999Satyen Desai this._node = config.host;
767003094c9794f0804c663a8abc131b86554999Satyen Desai}
767003094c9794f0804c663a8abc131b86554999Satyen Desai
767003094c9794f0804c663a8abc131b86554999Satyen Desai// When plugged into a node instance, the plugin will be
767003094c9794f0804c663a8abc131b86554999Satyen Desai// available on the "anchors" property.
767003094c9794f0804c663a8abc131b86554999Satyen DesaiAnchorPlugin.NS = "anchors"
767003094c9794f0804c663a8abc131b86554999Satyen Desai
767003094c9794f0804c663a8abc131b86554999Satyen DesaiAnchorPlugin.prototype = {
767003094c9794f0804c663a8abc131b86554999Satyen Desai disable: function() {
767003094c9794f0804c663a8abc131b86554999Satyen Desai var node = this._node;
767003094c9794f0804c663a8abc131b86554999Satyen Desai var anchors = node.queryAll("a");
767003094c9794f0804c663a8abc131b86554999Satyen Desai anchors.addClass("disabled");
767003094c9794f0804c663a8abc131b86554999Satyen Desai anchors.setAttribute("disabled", true);
767003094c9794f0804c663a8abc131b86554999Satyen Desai }
767003094c9794f0804c663a8abc131b86554999Satyen Desai};
767003094c9794f0804c663a8abc131b86554999Satyen Desai
767003094c9794f0804c663a8abc131b86554999Satyen Desai```
767003094c9794f0804c663a8abc131b86554999Satyen Desai
767003094c9794f0804c663a8abc131b86554999Satyen Desai<p>To use the `AnchorPlugin`, the user would plug it into a Node reference they were holding on to:</p>
767003094c9794f0804c663a8abc131b86554999Satyen Desai
767003094c9794f0804c663a8abc131b86554999Satyen Desai```
767003094c9794f0804c663a8abc131b86554999Satyen Desaivar container = Y.one("div.actions");
767003094c9794f0804c663a8abc131b86554999Satyen Desaicontainer.plug(AnchorPlugin);
767003094c9794f0804c663a8abc131b86554999Satyen Desai
767003094c9794f0804c663a8abc131b86554999Satyen Desai```
767003094c9794f0804c663a8abc131b86554999Satyen Desai
767003094c9794f0804c663a8abc131b86554999Satyen Desai<p>And invoke methods on the plugin, through the namespace it is bound to:</p>
767003094c9794f0804c663a8abc131b86554999Satyen Desai
767003094c9794f0804c663a8abc131b86554999Satyen Desai```
767003094c9794f0804c663a8abc131b86554999Satyen Desaicontainer.anchors.disable();
767003094c9794f0804c663a8abc131b86554999Satyen Desai
767003094c9794f0804c663a8abc131b86554999Satyen Desai```
767003094c9794f0804c663a8abc131b86554999Satyen Desai
767003094c9794f0804c663a8abc131b86554999Satyen Desai<h3 id="advanced">Advanced Plugins</h3>
767003094c9794f0804c663a8abc131b86554999Satyen Desai
767003094c9794f0804c663a8abc131b86554999Satyen Desai<p>For basic features, simple plugin classes as described above may suffice. However, when you have more complex features which you'd like to encapsulate, the ability to use
767003094c9794f0804c663a8abc131b86554999Satyen Desaiattributes and events for your plugin implementation becomes useful. More importantly, for many plugins, you'll be looking to modify the default
767003094c9794f0804c663a8abc131b86554999Satyen Desaibehavior of the host instance in some way (for example an Animation Plugin may want to change the default show/hide behavior of a Widget, to be animated).</p>
767003094c9794f0804c663a8abc131b86554999Satyen Desai
767003094c9794f0804c663a8abc131b86554999Satyen Desai<p>For these richer plugins, you should extend the base plugin class <a href="{{apiDocs}}/Plugin.Base.html">`Plugin.Base`</a>. </p>
767003094c9794f0804c663a8abc131b86554999Satyen Desai
767003094c9794f0804c663a8abc131b86554999Satyen Desai<p>`Plugin` is a subclass of `Base`, thereby providing managed attributes, lifecycle methods, and custom event support. Additionally it allows the plugin code to
767003094c9794f0804c663a8abc131b86554999Satyen Desaieither listen for and react to events fired by the host or inject custom logic before or after methods invoked on the host object (through the YUI 3 <a href="{{apiDocs}}/Do.html">AOP</a> infrastructure).
767003094c9794f0804c663a8abc131b86554999Satyen Desai`Plugin.Base` also sets up `host` as an attribute, so you can access it through `this.get("host")` in your plugin implementation code.
767003094c9794f0804c663a8abc131b86554999Satyen Desai</p>
767003094c9794f0804c663a8abc131b86554999Satyen Desai
767003094c9794f0804c663a8abc131b86554999Satyen Desai<h4 id="extendingplugin">Extending Plugin.Base</h4>
767003094c9794f0804c663a8abc131b86554999Satyen Desai
767003094c9794f0804c663a8abc131b86554999Satyen Desai<p>You can extend the `Plugin.Base` class, just as you would extend the <a href="../base/index.html">`Base`</a> class. One thing to note when comparing this to simple plugins
767003094c9794f0804c663a8abc131b86554999Satyen Desaiis that the host reference is automatically set up as an attribute by the `Plugin.Base` class, so a reference to it does not need to be set up explicitly.</p>
767003094c9794f0804c663a8abc131b86554999Satyen Desai
767003094c9794f0804c663a8abc131b86554999Satyen Desai<p>The class structure for an advanced plugin follows the pattern for all classes derived from Base, with the addition of the `NS` property to define
767003094c9794f0804c663a8abc131b86554999Satyen Desaithe namespace for the plugin (see the <a href="../base/index.html">Base</a> documentation for details about NAME and ATTRS).</p>
767003094c9794f0804c663a8abc131b86554999Satyen Desai
767003094c9794f0804c663a8abc131b86554999Satyen Desai
767003094c9794f0804c663a8abc131b86554999Satyen Desai```
767003094c9794f0804c663a8abc131b86554999Satyen Desai// A plugin class designed to animate Widget's show and hide methods.
767003094c9794f0804c663a8abc131b86554999Satyen Desaifunction WidgetAnimPlugin(config) {
767003094c9794f0804c663a8abc131b86554999Satyen Desai WidgetAnimPlugin.superclass.constructor.apply(this, arguments);
767003094c9794f0804c663a8abc131b86554999Satyen Desai}
767003094c9794f0804c663a8abc131b86554999Satyen Desai
767003094c9794f0804c663a8abc131b86554999Satyen Desai// Define Static properties NAME (to identify the class) and NS (to identify the namespace)
767003094c9794f0804c663a8abc131b86554999Satyen DesaiWidgetAnimPlugin.NAME = 'widgetAnimPlugin';
767003094c9794f0804c663a8abc131b86554999Satyen DesaiWidgetAnimPlugin.NS = 'fx';
767003094c9794f0804c663a8abc131b86554999Satyen Desai
767003094c9794f0804c663a8abc131b86554999Satyen Desai// Attribute definitions for the plugin
767003094c9794f0804c663a8abc131b86554999Satyen DesaiWidgetAnimPlugin.ATTRS = {
767003094c9794f0804c663a8abc131b86554999Satyen Desai
767003094c9794f0804c663a8abc131b86554999Satyen Desai animHidden : {
767003094c9794f0804c663a8abc131b86554999Satyen Desai ...
767003094c9794f0804c663a8abc131b86554999Satyen Desai },
767003094c9794f0804c663a8abc131b86554999Satyen Desai
767003094c9794f0804c663a8abc131b86554999Satyen Desai animVisible: {
767003094c9794f0804c663a8abc131b86554999Satyen Desai ...
767003094c9794f0804c663a8abc131b86554999Satyen Desai }
767003094c9794f0804c663a8abc131b86554999Satyen Desai};
767003094c9794f0804c663a8abc131b86554999Satyen Desai
767003094c9794f0804c663a8abc131b86554999Satyen Desai// Extend Plugin.Base
767003094c9794f0804c663a8abc131b86554999Satyen DesaiY.extend(WidgetAnimPlugin, Y.Plugin.Base, {
767003094c9794f0804c663a8abc131b86554999Satyen Desai
767003094c9794f0804c663a8abc131b86554999Satyen Desai // Add any required prototype methods
767003094c9794f0804c663a8abc131b86554999Satyen Desai
767003094c9794f0804c663a8abc131b86554999Satyen Desai});
767003094c9794f0804c663a8abc131b86554999Satyen Desai
767003094c9794f0804c663a8abc131b86554999Satyen Desai```
767003094c9794f0804c663a8abc131b86554999Satyen Desai
767003094c9794f0804c663a8abc131b86554999Satyen Desai<p>The plugin class structure described above is captured in this <a href="{{componentAssets}}/myplugin.js.txt">"MyPlugin" Template File</a>, which you can use as a starting point to create your own plugins derived from `Plugin.Base`.</p>
767003094c9794f0804c663a8abc131b86554999Satyen Desai
767003094c9794f0804c663a8abc131b86554999Satyen Desai<h4 id="pluginlisteners">Plugin Listeners</h4>
767003094c9794f0804c663a8abc131b86554999Satyen Desai
767003094c9794f0804c663a8abc131b86554999Satyen Desai<p>The main value obtained by extending `Plugin.Base` is the ability to react to events fired by the host
767003094c9794f0804c663a8abc131b86554999Satyen Desaiusing `Plugin.Base`'s <a href="{{apiDocs}}/Plugin.Base.html#method_onHostEvent">`onHostEvent`</a> and <a href="{{apiDocs}}/Plugin.Base.html#method_afterHostEvent">`afterHostEvent`</a> methods, or
767003094c9794f0804c663a8abc131b86554999Satyen Desaimodify methods on the host, using <a href="{{apiDocs}}/Plugin.Base.html#method_beforeHostMethod">`beforeHostMethod`</a> and <a href="{{apiDocs}}/Plugin.Base.html#method_afterHostMethod">`afterHostMethod`</a>.</p>
767003094c9794f0804c663a8abc131b86554999Satyen Desai
767003094c9794f0804c663a8abc131b86554999Satyen Desai<p>The value of doing this through the above `Plugin.Base` methods as opposed to working with the host directly, is that any listeners added by the plugin using the above methods are removed when the plugin is unplugged.
767003094c9794f0804c663a8abc131b86554999Satyen DesaiThis is important. Plugins should clean up after themselves when unplugged from the host.</p>
767003094c9794f0804c663a8abc131b86554999Satyen Desai
767003094c9794f0804c663a8abc131b86554999Satyen Desai<h5>Events</h5>
767003094c9794f0804c663a8abc131b86554999Satyen Desai
767003094c9794f0804c663a8abc131b86554999Satyen Desai<p>As mentioned, plugins which derive from `Plugin.Base` have the ability to listen for events on the host object and react to them.</p>
767003094c9794f0804c663a8abc131b86554999Satyen Desai
767003094c9794f0804c663a8abc131b86554999Satyen Desai<p>For example, all widgets fire a `render` event when they are rendered. Your widget-specific plugin may need to know when this occurs,
767003094c9794f0804c663a8abc131b86554999Satyen Desaiso that it can inject custom elements into the markup the host renders. It can do this through the `afterHostEvent` method:</p>
767003094c9794f0804c663a8abc131b86554999Satyen Desai
767003094c9794f0804c663a8abc131b86554999Satyen Desai```
767003094c9794f0804c663a8abc131b86554999Satyen Desai// A plugin which introduces rounded corners to a widget.
767003094c9794f0804c663a8abc131b86554999Satyen Desaifunction RoundedCornersPlugin(config) {
767003094c9794f0804c663a8abc131b86554999Satyen Desai //...
767003094c9794f0804c663a8abc131b86554999Satyen Desai}
767003094c9794f0804c663a8abc131b86554999Satyen Desai
767003094c9794f0804c663a8abc131b86554999Satyen DesaiRoundedCornersPlugin.NAME = 'roundedCornersPlugin';
767003094c9794f0804c663a8abc131b86554999Satyen DesaiRoundedCornersPlugin.NS = 'corners';
767003094c9794f0804c663a8abc131b86554999Satyen Desai
767003094c9794f0804c663a8abc131b86554999Satyen DesaiY.extend(RoundedCornersPlugin, Y.Plugin.Base, {
767003094c9794f0804c663a8abc131b86554999Satyen Desai
767003094c9794f0804c663a8abc131b86554999Satyen Desai // Automatically called by Base, during construction
767003094c9794f0804c663a8abc131b86554999Satyen Desai initializer: function(config) {
767003094c9794f0804c663a8abc131b86554999Satyen Desai // "render" is a widget event
767003094c9794f0804c663a8abc131b86554999Satyen Desai this.afterHostEvent('render', this.insertCornerElements);
767003094c9794f0804c663a8abc131b86554999Satyen Desai },
767003094c9794f0804c663a8abc131b86554999Satyen Desai
767003094c9794f0804c663a8abc131b86554999Satyen Desai insertCornerElements: function() {
767003094c9794f0804c663a8abc131b86554999Satyen Desai var widget = this.get("host");
767003094c9794f0804c663a8abc131b86554999Satyen Desai var boundingBox = widget.get("boundingBox");
767003094c9794f0804c663a8abc131b86554999Satyen Desai
767003094c9794f0804c663a8abc131b86554999Satyen Desai var tl = Y.Node.create(TL_TEMPLATE);
767003094c9794f0804c663a8abc131b86554999Satyen Desai //...
767003094c9794f0804c663a8abc131b86554999Satyen Desai
767003094c9794f0804c663a8abc131b86554999Satyen Desai boundingBox.appendChild(tlNode);
767003094c9794f0804c663a8abc131b86554999Satyen Desai boundingBox.appendChild(trNode);
767003094c9794f0804c663a8abc131b86554999Satyen Desai boundingBox.appendChild(blNode);
767003094c9794f0804c663a8abc131b86554999Satyen Desai boundingBox.appendChild(brNode);
767003094c9794f0804c663a8abc131b86554999Satyen Desai }
767003094c9794f0804c663a8abc131b86554999Satyen Desai});
767003094c9794f0804c663a8abc131b86554999Satyen Desai
767003094c9794f0804c663a8abc131b86554999Satyen Desai```
767003094c9794f0804c663a8abc131b86554999Satyen Desai
767003094c9794f0804c663a8abc131b86554999Satyen Desai<h5>Methods</h5>
767003094c9794f0804c663a8abc131b86554999Satyen Desai
767003094c9794f0804c663a8abc131b86554999Satyen Desai<p>In some cases, your plugin may need to override the logic in the host class' methods. The `beforeHostMethod` and `afterHostMethod` methods provided by `Plugin.Base`
767003094c9794f0804c663a8abc131b86554999Satyen Desaiallow you to insert custom plugin logic before or after a method is executed on the host object.</p>
767003094c9794f0804c663a8abc131b86554999Satyen Desai
767003094c9794f0804c663a8abc131b86554999Satyen Desai<p>For example, to animate the way a widget is shown or hidden, we may need to override the method
767003094c9794f0804c663a8abc131b86554999Satyen Desaiwhich actually flips the visibility style attribute on the widget's bounding box and replace it with an animated opacity implementation,
767003094c9794f0804c663a8abc131b86554999Satyen Desaias shown below:</p>
767003094c9794f0804c663a8abc131b86554999Satyen Desai
767003094c9794f0804c663a8abc131b86554999Satyen Desai```
767003094c9794f0804c663a8abc131b86554999Satyen Desai// A plugin class designed to animate Widget's show and hide methods.
767003094c9794f0804c663a8abc131b86554999Satyen Desaifunction WidgetAnimPlugin(config) {
767003094c9794f0804c663a8abc131b86554999Satyen Desai //...
767003094c9794f0804c663a8abc131b86554999Satyen Desai}
767003094c9794f0804c663a8abc131b86554999Satyen Desai
767003094c9794f0804c663a8abc131b86554999Satyen DesaiWidgetAnimPlugin.NAME = 'widgetAnimPlugin';
767003094c9794f0804c663a8abc131b86554999Satyen DesaiWidgetAnimPlugin.NS = 'fx';
767003094c9794f0804c663a8abc131b86554999Satyen Desai
767003094c9794f0804c663a8abc131b86554999Satyen DesaiWidgetAnimPlugin.ATTRS = {
767003094c9794f0804c663a8abc131b86554999Satyen Desai
767003094c9794f0804c663a8abc131b86554999Satyen Desai animHidden : {
767003094c9794f0804c663a8abc131b86554999Satyen Desai //...
767003094c9794f0804c663a8abc131b86554999Satyen Desai },
767003094c9794f0804c663a8abc131b86554999Satyen Desai
767003094c9794f0804c663a8abc131b86554999Satyen Desai animVisible: {
767003094c9794f0804c663a8abc131b86554999Satyen Desai //...
767003094c9794f0804c663a8abc131b86554999Satyen Desai }
767003094c9794f0804c663a8abc131b86554999Satyen Desai};
767003094c9794f0804c663a8abc131b86554999Satyen Desai
767003094c9794f0804c663a8abc131b86554999Satyen Desai// Extend Plugin.Base, and override the default
767003094c9794f0804c663a8abc131b86554999Satyen Desai// method _uiSetVisible, used by Widget to flip the visibility
767003094c9794f0804c663a8abc131b86554999Satyen DesaiY.extend(WidgetAnimPlugin, Y.Plugin.Base, {
767003094c9794f0804c663a8abc131b86554999Satyen Desai
767003094c9794f0804c663a8abc131b86554999Satyen Desai initializer : function(config) {
767003094c9794f0804c663a8abc131b86554999Satyen Desai
767003094c9794f0804c663a8abc131b86554999Satyen Desai // Override Widget's _uiSetVisible method, with the custom animated method
767003094c9794f0804c663a8abc131b86554999Satyen Desai this.beforeHostMethod("_uiSetVisible", this._uiAnimSetVisible);
767003094c9794f0804c663a8abc131b86554999Satyen Desai },
767003094c9794f0804c663a8abc131b86554999Satyen Desai
767003094c9794f0804c663a8abc131b86554999Satyen Desai _uiAnimSetVisible : function(show) {
767003094c9794f0804c663a8abc131b86554999Satyen Desai // Instead of flipping visibility, use the animation
767003094c9794f0804c663a8abc131b86554999Satyen Desai // instances configured for the plugin to animate
767003094c9794f0804c663a8abc131b86554999Satyen Desai // hide/show.
767003094c9794f0804c663a8abc131b86554999Satyen Desai if (this.get("host").get("rendered")) {
767003094c9794f0804c663a8abc131b86554999Satyen Desai if (show) {
767003094c9794f0804c663a8abc131b86554999Satyen Desai this.get("animHidden").stop();
767003094c9794f0804c663a8abc131b86554999Satyen Desai this.get("animVisible").run();
767003094c9794f0804c663a8abc131b86554999Satyen Desai } else {
767003094c9794f0804c663a8abc131b86554999Satyen Desai this.get("animVisible").stop();
767003094c9794f0804c663a8abc131b86554999Satyen Desai this.get("animHidden").run();
767003094c9794f0804c663a8abc131b86554999Satyen Desai }
767003094c9794f0804c663a8abc131b86554999Satyen Desai
767003094c9794f0804c663a8abc131b86554999Satyen Desai // Prevent the default method from being invoked.
767003094c9794f0804c663a8abc131b86554999Satyen Desai return new Y.Do.Prevent();
767003094c9794f0804c663a8abc131b86554999Satyen Desai }
767003094c9794f0804c663a8abc131b86554999Satyen Desai }
767003094c9794f0804c663a8abc131b86554999Satyen Desai});
767003094c9794f0804c663a8abc131b86554999Satyen Desai
767003094c9794f0804c663a8abc131b86554999Satyen Desai```