Im trying to get better at writing jQuery plugins. Was hoping to get some feedback on my notes, but also just about the general architechture and implenmentation of this pattern (dont even know this one is called :P)
jsFiddle: http://jsfiddle.net/gajwp/4/ Click the input fields! (No need to comment on positioning or stylnig, it looks better on my site)
Project use jQuery 1.4.2 (so no .on() event handling :( )
Notes:
- Should be DRY, short, fast, beautiful and all that :)
- Havent fully wrapped my head around the constructor/prototype thing. For instance, why am I creating the $bubble in the constructor and not in the prototype init() method? I hoping its because then its the same $bubble that is used throughout.
- I feel like there is a better way to build the bubble content. It must be possible to pass the plugin an object with the information. Tips welcome.
- In the template I used there was stuff like 'this._name = pluginName' in the constructor. What does the underscore mean, and what are the use for it?
- How is the event bindings? Was a bit confused about it because of the functionality. Popup should pop on fucus, and hide on blur. But not hide if focusing on a new field. Also if you click the popup or the "More..." link, it should also stay open - and close again if you click outside it.
Plugin code (same as in fiddle):
;(function ($, window, document, undefined) {
"use strict";
var pluginName = 'formHelper', $input, o, $bubble, stopBlurEvent, key,
defaults = {
position: "left",
dataObject: {
Default: {
info: '<p class="info">Default info</p><a href="#" class="help-more">More...</a>',
extended: '<p class="help-extended">Default extended...</p>'
},
Email: {
info: '<p class="info">Email info</p><a href="#" class="help-more">More...</a>',
extended: '<p class="help-extended">Email extended...</p>'
},
Name: {
info: '<p class="info">Name info</p><a href="#" class="help-more">More...</a>',
extended: '<p class="help-extended">Name extended...</p>'
}
}
};
function FormHelper(element, options) {
var that = this;
$input = $(element);
o = $.extend({}, defaults, options);
$bubble = $('<div class="help-bubble" />').bind({
'mouseenter': function() {
stopBlurEvent = true;
},
'mouseleave': function() {
stopBlurEvent = false;
},
'mousedown': function(e) {
e.stopImmediatePropagation();
$('html').not(this).bind('click', function() {
that.hideBubble();
});
}
}).delegate('.help-more', 'click', function(e) {
e.preventDefault();
e.stopPropagation();
that.toggleExtendedInfo();
});
this.init();
}
FormHelper.prototype = {
showBubble: function(input) {
var $currentInput = $(input);
key = (o.dataObject.hasOwnProperty($currentInput.attr('id'))) ? $currentInput.attr('id') : 'Default';
var bubbleContent = '<h4>' + $currentInput.attr('title') + '</h4>' + o.dataObject[key].info;
$bubble.html(bubbleContent).insertBefore($currentInput).fadeIn();
stopBlurEvent = false;
},
hideBubble: function() {
if (!stopBlurEvent) {
$bubble.fadeOut('fast', function() {
$(this).detach(); $('html').unbind('click');
});
}
},
toggleExtendedInfo: function() {
var $moreLink = $('.help-more', $bubble);
if ($moreLink.hasClass('open')) {
$moreLink.removeClass('open');
$('.help-extended', $bubble).slideUp('fast', function() {
$(this).remove();
});
} else {
$moreLink.addClass('open');
$(o.dataObject[key].extended).appendTo($bubble).slideDown();
}
},
init: function() {
var that = this;
$input.bind({
'focus': function() {
that.showBubble(this);
},
'blur': function(e) {
if (stopBlurEvent) {
e.preventDefault();
} else {
that.hideBubble();
}
},
'mousedown': function() {
stopBlurEvent = true;
}
});
}
};
$.fn[pluginName] = function(options) {
return this.each(function() {
if (!$.data(this, 'plugin_' + pluginName)) {
$.data(this, 'plugin_' + pluginName,
new FormHelper(this, options));
}
});
};
})(jQuery, window, document);