2 * @license In-Field Label jQuery Plugin
3 * http://fuelyourcoding.com/scripts/infield.html
4 * http://github.com/streetpc/jquery-infieldlabels
6 * Copyright (c) 2009 Doug Neiner, Adrien Lavoillotte
7 * Dual licensed under the MIT and GPL licenses, see:
8 * http://docs.jquery.com/License
16 var BLUR = 0, // field is empty & unfocused
17 FOCUS = 1, // field is empty & focused
18 NOT_EMPTY = 2, // field is not empty
19 // - accepted input type
20 INPUT_TYPE = /^(?:text|password|search|number|tel|url|email|date(?:time(?:-local)?)?|time|month|week)?$/,
21 // - state transitions
22 T = function(from, to) { return (from << 3) | to; },
26 TRANSITIONS[T( FOCUS, BLUR )] = function(base) { base.fadeTo(1.0); };
27 TRANSITIONS[T( NOT_EMPTY, BLUR )] = function(base) { base.$label.css({opacity: 1.0}).show(); base.emptied(true); };
28 TRANSITIONS[T( BLUR, FOCUS )] = function(base) { base.fadeTo(base.options.fadeOpacity); };
29 TRANSITIONS[T( NOT_EMPTY, FOCUS )] = function(base) { base.$label.css({opacity: base.options.fadeOpacity}).show(); base.emptied(true); };
30 TRANSITIONS[T( BLUR, NOT_EMPTY )] = function(base) { base.$label.hide(); base.emptied(false); };
31 TRANSITIONS[T( FOCUS, NOT_EMPTY )] = TRANSITIONS[T( BLUR, NOT_EMPTY )];
33 $.InFieldLabels = function (label, field, options) {
34 // To avoid scope issues, use 'base' instead of 'this'
35 // to reference this class from internal events and functions.
38 // Access to jQuery and DOM versions of each element
39 base.$label = $(label);
42 base.$field = $(field);
45 base.$label.data('InFieldLabels', base);
48 base.init = function () {
49 // Merge supplied options with default options
50 base.options = $.extend({}, $.InFieldLabels.defaultOptions, options);
52 if (base.options.labelClass) {
53 base.$label.addClass(base.options.labelClass);
55 if (base.options.disableAutocomplete) {
56 base.$field.attr('autocomplete', 'off');
60 .bind('blur focus change keyup.infield cut', base.updateState)
61 // paste cannot be empty
62 .bind('paste', function(e){ base.setState(NOT_EMPTY); });
67 base.emptied = function(empty) {
68 if (!base.options.emptyWatch) {
70 // namespace ensures we unbind only our handler
71 base.$field.bind('keyup.infield', base.updateState);
73 // save CPU but won't detect empty until blur
74 base.$field.unbind('keyup.infield', base.updateState);
79 base.fadeTo = function (opacity) {
80 if (!base.options.fadeDuration) {
81 base.$label.css({ opacity: opacity });
83 base.$label.stop().animate({ opacity: opacity }, base.options.fadeDuration);
87 base.updateState = function (e, nl) {
88 var state = NOT_EMPTY;
89 if (base.field.value === '') {
90 var focus = e && e.type;
91 if (focus === 'focus' || focus === 'keyup') {
93 } else if (focus === 'blur' || focus === 'change') {
95 } else { // last resort because slowest
96 focus = base.$field.is(':focus');
98 state = focus ? FOCUS : BLUR;
100 base.setState(state, nl);
103 base.setState = function (state, nl) {
104 if (state === base.state) {
108 var transition = TRANSITIONS[T(base.state, state)];
109 if (typeof transition === 'function') {
112 } else { // unkown transition - shouldn't happen
114 nl || base.updateState(null, true);
118 // Run the initialization method
122 $.InFieldLabels.defaultOptions = {
123 emptyWatch: true, // Keep watching the field as the user types (slower but brings back the label immediately when the field is emptied)
124 disableAutocomplete: true, // Disable autocomplete on the matched fields
125 fadeOpacity: 0.5, // Once a field has focus, how transparent should the label be
126 fadeDuration: 300, // How long should it take to animate from 1.0 opacity to the fadeOpacity
127 labelClass: 'in-field' // CSS class to apply to the label when it gets in-field
131 $.fn.inFieldLabels = function (options) {
132 return this.each(function () {
133 if (this.tagName !== 'LABEL') {
136 // Find input or textarea based on for= attribute
137 // The for attribute on the label must contain the ID
138 // of the input or textarea element
139 var for_attr = this.getAttribute('for') || this.htmlFor,
142 return; // Nothing to attach, since the for field wasn't used
145 // Find the referenced input or textarea element
146 field = document.getElementById(for_attr);
151 if (field.tagName === 'INPUT') {
152 valid = INPUT_TYPE.test(field.type.toLowerCase());
153 } else if (field.tagName !== 'TEXTAREA') {
157 valid = valid && !field.getAttribute('placeholder');
160 return; // Again, nothing to attach
163 // Only create object for input[text], input[password], or textarea
164 (new $.InFieldLabels(this, field, options));