A Plugin Development Pattern

This article is meant to share the pattern that I’ve found especially useful for plugin authoring. It assumes you already have an understanding of plugin development for jQuery; if you’re a novice plugin author, please review the jQuery Authoring Guidelines first.

There are a few requirements that I feel this pattern handles nicely:

  1. Claim only a single name in the jQuery namespace
  2. Accept an options argument to control plugin behavior
  3. Provide public access to default plugin settings
  4. Provide public access to secondary functions (as applicable)
  5. Keep private functions private
  6. Support the Metadata Plugin

I’ll cover these requirements one by one, and as we work through them we’ll build a simple plugin which highlights text.

1. Claim only a single name in the jQuery namespace

This implies a single-plugin script. If your script contains multiple plugins, or complementary plugins (like $.fn.doSomething() and $.fn.undoSomething()) then you’ll claim multiple names are required. But in general when authoring a plugin, strive to use only a single name to hold all of its implementation details.

In our example plugin we will claim the name “hilight”.

And our plugin can be invoked like this:

But what if we need to break up our implementation into more than one function? There are many reasons to do so: the design may require it; it may result in a simpler or more readable implementation; and it may yield better OO semantics.

It’s really quite trivial to break up the implementation into multiple functions without adding noise to the namespace. We do this by recognizing, and taking advantage of, the fact that functions are first-class objects in JavaScript. Like any other object, functions can be assigned properties. Since we have already claimed the “hilight” name in the jQuery prototype object, any other properties or functions that we need to expose can be declared as properties on our “hilight” function. More on this later.

2. Accept an options argument to control plugin behavior

Let’s add support to our hilight plugin for specifying the foreground and background colors to use. We should allow options like these to be passed as an options object to the plugin function. For example:

Now our plugin can be invoked like this:

3. Provide public access to default plugin settings

An improvement we can, and should, make to the code above is to expose the default plugin settings. This is important because it makes it very easy for plugin users to override/customize the plugin with minimal code. And this is where we begin to take advantage of the function object.

Now users can include a line like this in their scripts:

And now we can call the plugin method like this and it will use a blue foreground color:

As you can see, we’ve allowed the user to write a single line of code to alter the default foreground color of the plugin. And users can still selectively override this new default value when they want:

4. Provide public access to secondary functions as applicable

This item goes hand-in-hand with the previous item and is an interesting way to extend your plugin (and to let others extend your plugin). For example, the implementation of our plugin may define a function called “format” which formats the hilight text. Our plugin may now look like this, with the default implementation of the format method defined below the hilight function.

We could have just as easily supported another property on the options object that allowed a callback function to be provided to override the default formatting. That’s another excellent way to support customization of your plugin. The technique shown here takes this a step further by actually exposing the format function so that it can be redefined. With this technique it would be possible for others to ship their own custom overrides of your plugin ?in other words, it means others can write plugins for your plugin.

Considering the trivial example plugin we’re building in this article, you may be wondering when this would ever be useful. One real-world example is the Cycle Plugin. The Cycle Plugin is a slideshow plugin which supports a number of built-in transition effects ?scroll, slide, fade, etc. But realistically, there is no way to define every single type of effect that one might wish to apply to a slide transition. And that’s where this type of extensibility is useful. The Cycle Plugin exposes a “transitions” object to which users can add their own custom transition definitions. It’s defined in the plugin like this:

This technique makes it possible for others to define and ship transition definitions that plug-in to the Cycle Plugin.

5. Keep private functions private

The technique of exposing part of your plugin to be overridden can be very powerful. But you need to think carefully about what parts of your implementation to expose. Once it’s exposed, you need to keep in mind that any changes to the calling arguments or semantics may break backward compatibility. As a general rule, if you’re not sure whether to expose a particular function, then you probably shouldn’t.

So how then do we define more functions without cluttering the namespace and without exposing the implementation? This is a job for closures. To demonstrate, we’ll add another function to our plugin called “debug”. The debug function will log the number of selected elements to the Firebug console. To create a closure, we wrap the entire plugin definition in a function (as detailed in the jQuery Authoring Guidelines).

Our “debug” method cannot be accessed from outside of the closure and thus is private to our implementation.

6. Support the Metadata Plugin

Depending on the type of plugin you’re writing, adding support for the Metadata Plugin can make it even more powerful. Personally, I love the Metadata Plugin because it lets you use unobtrusive markup to override plugin options (which is particularly useful when creating demos and examples). And supporting it is very simple!

Update: This bit was optimized per suggestion in the comments.

This changed line does a couple of things:

  • it tests to see if the Metadata Plugin is installed
  • if it is installed, it extends our options object with the extracted metadata.

This line is added as the last argument to jQuery.extend so it will override any other option settings. Now we can drive behavior from the markup if we choose:

And now we can hilight each of these divs uniquely using a single line of script:

7. Putting it All Together

Below is the completed code for our example:

8. Note

is a shortcut for

That is roughly equivalent to . The purpose is to run your jQuery code after the entire page has loaded, included jQuery itself, and the dom is ready for manipulation.

$.extend({}, opts, $this.metadata())” returns a new object extending opts with $this.metadata() without modifying opts

as the first argument of $.extends is like passed by reference, using {} will return a brand new object.

using “$.extend(opts, $this.metadata())” will modify the general options witch is not wanted…

Altogether a pulgin template:

Prototype variables should variables should be avoided. If a context specific variable is required you should use the each() construct and set the variable to this.namespaceVariable. In this way you are using the native DOM construct for variable settings.

Finally, it is generally considered good etiquette to put a usage information in a comment aat the head of your script file along with author attribute, copyright, version and source repository information. That way developers can easily find where to submit bug reports and change ideas.

Although this isn’t standard practice, you can greatly clarify your code by using a private object as opposed to using free-floating private functions and variable. The the private section would therefore look like this:

Resource: Learningjquery

Leave a Reply

Your email address will not be published. Required fields are marked *