]> git.mxchange.org Git - quix0rs-gnu-social.git/blob - js/extlib/jquery.infieldlabel.js
Merge request 9 on Gitorious
[quix0rs-gnu-social.git] / js / extlib / jquery.infieldlabel.js
1 /**
2  * @license In-Field Label jQuery Plugin
3  * http://fuelyourcoding.com/scripts/infield.html
4  * http://github.com/streetpc/jquery-infieldlabels
5  *
6  * Copyright (c) 2009 Doug Neiner, Adrien Lavoillotte
7  * Dual licensed under the MIT and GPL licenses, see:
8  * http://docs.jquery.com/License
9  *
10  * @version 0.2.1
11  */
12 (function ($) {
13
14   // private constants
15   //  - states
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; },
23       TRANSITIONS = {};
24   
25   // init transitions
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 )];
32
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.
36     var base = this;
37   
38     // Access to jQuery and DOM versions of each element
39     base.$label = $(label);
40     base.label  = label;
41
42     base.$field = $(field);
43     base.field  = field;
44
45     base.$label.data('InFieldLabels', base);
46     base.state = BLUR;
47
48     base.init = function () {
49       // Merge supplied options with default options
50       base.options = $.extend({}, $.InFieldLabels.defaultOptions, options);
51
52       if (base.options.labelClass) {
53         base.$label.addClass(base.options.labelClass);
54       }
55       if (base.options.disableAutocomplete) {
56         base.$field.attr('autocomplete', 'off');
57       }
58
59       base.$field
60           .bind('blur focus change keyup.infield cut', base.updateState)
61           // paste cannot be empty
62           .bind('paste', function(e){ base.setState(NOT_EMPTY); });
63       
64       base.updateState();
65     };
66
67     base.emptied = function(empty) {
68       if (!base.options.emptyWatch) {
69         if (empty) {
70           // namespace ensures we unbind only our handler
71           base.$field.bind('keyup.infield', base.updateState);
72         } else {
73           // save CPU but won't detect empty until blur
74           base.$field.unbind('keyup.infield', base.updateState);
75         }
76       }
77     };
78
79     base.fadeTo = function (opacity) {
80       if (!base.options.fadeDuration) {
81         base.$label.css({ opacity: opacity });
82       } else {
83         base.$label.stop().animate({ opacity: opacity }, base.options.fadeDuration);
84       }
85     };
86
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') {
92           focus = true;
93         } else if (focus === 'blur' || focus === 'change') {
94           focus = false;
95         } else {  // last resort because slowest
96           focus = base.$field.is(':focus');
97         }
98         state = focus ? FOCUS : BLUR;
99       }
100       base.setState(state, nl);
101     };
102
103     base.setState = function (state, nl) {
104       if (state === base.state) {
105         return;
106       }
107
108       var transition = TRANSITIONS[T(base.state, state)];
109       if (typeof transition === 'function') {
110         transition(base);
111         base.state = state;
112       } else { // unkown transition - shouldn't happen
113         // nl avoids looping
114         nl || base.updateState(null, true);
115       }
116     };
117
118     // Run the initialization method
119     base.init();
120   };
121
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
128   };
129
130
131   $.fn.inFieldLabels = function (options) {
132     return this.each(function () {
133       if (this.tagName !== 'LABEL') {
134         return;
135       }
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,
140           field, valid = true;
141       if (!for_attr) {
142         return; // Nothing to attach, since the for field wasn't used
143       }
144
145       // Find the referenced input or textarea element
146       field = document.getElementById(for_attr);
147       if (!field) {
148         return;
149       }
150
151       if (field.tagName === 'INPUT') {
152         valid = INPUT_TYPE.test(field.type.toLowerCase());
153       } else if (field.tagName !== 'TEXTAREA') {
154         valid = false;
155       }
156       
157       valid = valid && !field.getAttribute('placeholder');
158
159       if (!valid) {
160         return; // Again, nothing to attach
161       } 
162
163       // Only create object for input[text], input[password], or textarea
164       (new $.InFieldLabels(this, field, options));
165     });
166   };
167
168 }(jQuery));