Building Robust jQuery Plugins
Why bother?
$.each({ focus: 'focusin', blur: 'focusout' }, function( original, fix ){ $.event.special[fix] = { setup:function() { if ( $.browser.msie ) return false; this.addEventListener( original,  $.event.special[fix].handler, true ); }, teardown:function() { if ( $.browser.msie ) return false; this.removeEventListener( original, $.event.special[fix].handler, true ); }, handler: function(e) { arguments[0] = $.event.fix(e); arguments[0].type = fix; return $.event.handle.apply(this, arguments); } }; });
Don't reinvent the wheel
“  Given enough eyeballs, all bugs are shallow  ” -- Eric S. Raymond
Infrastructure
Design
Consider the audience
 
 
 
jQuery.validator. addMethod ("domain", function(value) { return /^http://mycorporatedomain.com/.test(value); } , "Please specify the correct domain"); jQuery.validator.addMethod("nowhite", function(value) { return /^\S+$/.test(value); }, "No white space please"); jQuery.validator.addMethod("nowhite", function(value) { return /^\d+$/.test(value); }, "Please enter only digits");
 
Test-driven development
 
 
Tests first
Behaviour-driven developement
Why bother?
QUnit
test("my ajax code", function() { expect(1); stop(); $.get("myurl", function(response) { equals(response, "expected response"); start(); }); });
Implementing
(function($) {   $.fn.plugin = function() {   return this.each(function() {   // your code here   });   }; })(jQuery);
(function($) {   $.fn.delegate = function(type, delegate, handler) {   return this.bind(type, function(event) {   var target = $(event.target);   if (target.is(delegate)) {   return handler.apply(target, arguments);   }   });   };  })(jQuery);
(function($) {   $.fn.plugin = function(settings) {   settings = $.extend({}, $.plugin.defaults, settings);   return this.each(function() {   // your code here   });   };   $.plugin = {   defaults: {}   }; })(jQuery);
Document
/** * The number of elements currently matched. * * @example $(&quot;img&quot;).length; * @before <img src=&quot;test1.jpg&quot;/> <img src=&quot;test2.jpg&quot;/> * @result 2 * * @property * @name length * @type Number * @cat Core */ /** * The number of elements currently matched. * * @example $(&quot;img&quot;).size(); * @before <img src=&quot;test1.jpg&quot;/> <img src=&quot;test2.jpg&quot;/> * @result 2 * * @name size * @type Number * @cat Core */ size: function() { return this.length; }, length: 0,
Purpose
Dependencies
Pulic API
Options
Examples
Browsing
 
Release
jquery.plugin-1.2.3.zip - jquery-plugin-1.2.3 jquery.plugin.js jquery.plugin.min.js jquery.plugin.pack.js - demo [-docs] [-test]
<target name=&quot;tooltip&quot;>   <antcall target=&quot;generic&quot;>   <param name=&quot;name&quot; value=&quot;tooltip&quot; />   </antcall> </target> ant tooltip
1.3 --- * Added fade option (duration in ms) for fading in/out tooltips; IE <= 6 is excluded when bgiframe plugin is included * Fixed imagemaps in IE, added back example * Added positionLeft-option - positions the tooltip to the left of the cursor * Remove deprecated $.fn.Tooltip in favor of $.fn.tooltip 1.2 --- * Improved bodyHandler option to accept HTML strings, DOM elements and jQuery objects as the return value * Fixed bug in Safari 3 where to tooltip is initially visible, by first appending to DOM then hiding it * Improvement for viewport-border-positioning: Add the classes &quot;viewport-right&quot; and &quot;viewport-bottom&quot; when the element is moved at the viewport border. * Moved and enhanced documentation to docs.jquery.com * Added examples for bodyHandler: footnote-tooltip and thumbnail * Added id option, defaults to &quot;tooltip&quot;, override to use a different id in your stylesheet * Moved demo tooltip style to screen.css * Moved demo files to demo folder and dependencies to lib folder * Dropped image map example - completely incompatible with IE; image maps aren't supported anymore
 
 
Maintain
Avoid Blog Comments
 
 
 
 
 
Mailing list
 
 
General questions
Tracking
Thank you
Questions?
Bon appétit!

Building Robust jQuery Plugins

  • 1.
  • 2.
  • 3.
    $.each({ focus: 'focusin',blur: 'focusout' }, function( original, fix ){ $.event.special[fix] = { setup:function() { if ( $.browser.msie ) return false; this.addEventListener( original, $.event.special[fix].handler, true ); }, teardown:function() { if ( $.browser.msie ) return false; this.removeEventListener( original, $.event.special[fix].handler, true ); }, handler: function(e) { arguments[0] = $.event.fix(e); arguments[0].type = fix; return $.event.handle.apply(this, arguments); } }; });
  • 4.
  • 5.
    “ Givenenough eyeballs, all bugs are shallow ” -- Eric S. Raymond
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
    jQuery.validator. addMethod (&quot;domain&quot;,function(value) { return /^http://mycorporatedomain.com/.test(value); } , &quot;Please specify the correct domain&quot;); jQuery.validator.addMethod(&quot;nowhite&quot;, function(value) { return /^\S+$/.test(value); }, &quot;No white space please&quot;); jQuery.validator.addMethod(&quot;nowhite&quot;, function(value) { return /^\d+$/.test(value); }, &quot;Please enter only digits&quot;);
  • 13.
  • 14.
  • 15.
  • 16.
  • 17.
  • 18.
  • 19.
  • 20.
  • 21.
    test(&quot;my ajax code&quot;,function() { expect(1); stop(); $.get(&quot;myurl&quot;, function(response) { equals(response, &quot;expected response&quot;); start(); }); });
  • 22.
  • 23.
    (function($) { $.fn.plugin = function() { return this.each(function() { // your code here }); }; })(jQuery);
  • 24.
    (function($) { $.fn.delegate = function(type, delegate, handler) { return this.bind(type, function(event) { var target = $(event.target); if (target.is(delegate)) { return handler.apply(target, arguments); } }); }; })(jQuery);
  • 25.
    (function($) { $.fn.plugin = function(settings) { settings = $.extend({}, $.plugin.defaults, settings); return this.each(function() { // your code here }); }; $.plugin = { defaults: {} }; })(jQuery);
  • 26.
  • 27.
    /** * Thenumber of elements currently matched. * * @example $(&quot;img&quot;).length; * @before <img src=&quot;test1.jpg&quot;/> <img src=&quot;test2.jpg&quot;/> * @result 2 * * @property * @name length * @type Number * @cat Core */ /** * The number of elements currently matched. * * @example $(&quot;img&quot;).size(); * @before <img src=&quot;test1.jpg&quot;/> <img src=&quot;test2.jpg&quot;/> * @result 2 * * @name size * @type Number * @cat Core */ size: function() { return this.length; }, length: 0,
  • 28.
  • 29.
  • 30.
  • 31.
  • 32.
  • 33.
  • 34.
  • 35.
  • 36.
    jquery.plugin-1.2.3.zip - jquery-plugin-1.2.3jquery.plugin.js jquery.plugin.min.js jquery.plugin.pack.js - demo [-docs] [-test]
  • 37.
    <target name=&quot;tooltip&quot;> <antcall target=&quot;generic&quot;> <param name=&quot;name&quot; value=&quot;tooltip&quot; /> </antcall> </target> ant tooltip
  • 38.
    1.3 --- *Added fade option (duration in ms) for fading in/out tooltips; IE <= 6 is excluded when bgiframe plugin is included * Fixed imagemaps in IE, added back example * Added positionLeft-option - positions the tooltip to the left of the cursor * Remove deprecated $.fn.Tooltip in favor of $.fn.tooltip 1.2 --- * Improved bodyHandler option to accept HTML strings, DOM elements and jQuery objects as the return value * Fixed bug in Safari 3 where to tooltip is initially visible, by first appending to DOM then hiding it * Improvement for viewport-border-positioning: Add the classes &quot;viewport-right&quot; and &quot;viewport-bottom&quot; when the element is moved at the viewport border. * Moved and enhanced documentation to docs.jquery.com * Added examples for bodyHandler: footnote-tooltip and thumbnail * Added id option, defaults to &quot;tooltip&quot;, override to use a different id in your stylesheet * Moved demo tooltip style to screen.css * Moved demo files to demo folder and dependencies to lib folder * Dropped image map example - completely incompatible with IE; image maps aren't supported anymore
  • 39.
  • 40.
  • 41.
  • 42.
  • 43.
  • 44.
  • 45.
  • 46.
  • 47.
  • 48.
  • 49.
  • 50.
  • 51.
  • 52.
  • 53.
  • 54.
  • 55.

Editor's Notes

  • #2 Goal is to show to how build a robust jQuery plugin, way beyond just coding. Your take-away should be an understanding of the surrounding infrastructure, both to be able to use and to help improve it. We&apos;ve got about 50 minutes. My talk should take about 30 minutes, giving us 20 minutes for open discussion. Please ask questions whenever you want to, though I may defer some answers to the end. To start, lets look at the most important question.