jquery.infieldlabel.js 5.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168
  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. // private constants
  14. // - states
  15. var BLUR = 0, // field is empty & unfocused
  16. FOCUS = 1, // field is empty & focused
  17. NOT_EMPTY = 2, // field is not empty
  18. // - accepted input type
  19. INPUT_TYPE = /^(?:text|password|search|number|tel|url|email|date(?:time(?:-local)?)?|time|month|week)?$/,
  20. // - state transitions
  21. T = function(from, to) { return (from << 3) | to; },
  22. TRANSITIONS = {};
  23. // init transitions
  24. TRANSITIONS[T( FOCUS, BLUR )] = function(base) { base.fadeTo(1.0); };
  25. TRANSITIONS[T( NOT_EMPTY, BLUR )] = function(base) { base.$label.css({opacity: 1.0}).show(); base.emptied(true); };
  26. TRANSITIONS[T( BLUR, FOCUS )] = function(base) { base.fadeTo(base.options.fadeOpacity); };
  27. TRANSITIONS[T( NOT_EMPTY, FOCUS )] = function(base) { base.$label.css({opacity: base.options.fadeOpacity}).show(); base.emptied(true); };
  28. TRANSITIONS[T( BLUR, NOT_EMPTY )] = function(base) { base.$label.hide(); base.emptied(false); };
  29. TRANSITIONS[T( FOCUS, NOT_EMPTY )] = TRANSITIONS[T( BLUR, NOT_EMPTY )];
  30. $.InFieldLabels = function (label, field, options) {
  31. // To avoid scope issues, use 'base' instead of 'this'
  32. // to reference this class from internal events and functions.
  33. var base = this;
  34. // Access to jQuery and DOM versions of each element
  35. base.$label = $(label);
  36. base.label = label;
  37. base.$field = $(field);
  38. base.field = field;
  39. base.$label.data('InFieldLabels', base);
  40. base.state = BLUR;
  41. base.init = function () {
  42. // Merge supplied options with default options
  43. base.options = $.extend({}, $.InFieldLabels.defaultOptions, options);
  44. if (base.options.labelClass) {
  45. base.$label.addClass(base.options.labelClass);
  46. }
  47. if (base.options.disableAutocomplete) {
  48. base.$field.attr('autocomplete', 'off');
  49. }
  50. base.$field
  51. .bind('blur focus change keyup.infield cut', base.updateState)
  52. // paste cannot be empty
  53. .bind('paste', function(e){ base.setState(NOT_EMPTY); });
  54. base.updateState();
  55. };
  56. base.emptied = function(empty) {
  57. if (!base.options.emptyWatch) {
  58. if (empty) {
  59. // namespace ensures we unbind only our handler
  60. base.$field.bind('keyup.infield', base.updateState);
  61. } else {
  62. // save CPU but won't detect empty until blur
  63. base.$field.unbind('keyup.infield', base.updateState);
  64. }
  65. }
  66. };
  67. base.fadeTo = function (opacity) {
  68. if (!base.options.fadeDuration) {
  69. base.$label.css({ opacity: opacity });
  70. } else {
  71. base.$label.stop().animate({ opacity: opacity }, base.options.fadeDuration);
  72. }
  73. };
  74. base.updateState = function (e, nl) {
  75. var state = NOT_EMPTY;
  76. if (base.field.value === '') {
  77. var focus = e && e.type;
  78. if (focus === 'focus' || focus === 'keyup') {
  79. focus = true;
  80. } else if (focus === 'blur' || focus === 'change') {
  81. focus = false;
  82. } else { // last resort because slowest
  83. focus = base.$field.is(':focus');
  84. }
  85. state = focus ? FOCUS : BLUR;
  86. }
  87. base.setState(state, nl);
  88. };
  89. base.setState = function (state, nl) {
  90. if (state === base.state) {
  91. return;
  92. }
  93. var transition = TRANSITIONS[T(base.state, state)];
  94. if (typeof transition === 'function') {
  95. transition(base);
  96. base.state = state;
  97. } else { // unkown transition - shouldn't happen
  98. // nl avoids looping
  99. nl || base.updateState(null, true);
  100. }
  101. };
  102. // Run the initialization method
  103. base.init();
  104. };
  105. $.InFieldLabels.defaultOptions = {
  106. emptyWatch: true, // Keep watching the field as the user types (slower but brings back the label immediately when the field is emptied)
  107. disableAutocomplete: true, // Disable autocomplete on the matched fields
  108. fadeOpacity: 0.5, // Once a field has focus, how transparent should the label be
  109. fadeDuration: 300, // How long should it take to animate from 1.0 opacity to the fadeOpacity
  110. labelClass: 'in-field' // CSS class to apply to the label when it gets in-field
  111. };
  112. $.fn.inFieldLabels = function (options) {
  113. return this.each(function () {
  114. if (this.tagName !== 'LABEL') {
  115. return;
  116. }
  117. // Find input or textarea based on for= attribute
  118. // The for attribute on the label must contain the ID
  119. // of the input or textarea element
  120. var for_attr = this.getAttribute('for') || this.htmlFor,
  121. field, valid = true;
  122. if (!for_attr) {
  123. return; // Nothing to attach, since the for field wasn't used
  124. }
  125. // Find the referenced input or textarea element
  126. field = document.getElementById(for_attr);
  127. if (!field) {
  128. return;
  129. }
  130. if (field.tagName === 'INPUT') {
  131. valid = INPUT_TYPE.test(field.type.toLowerCase());
  132. } else if (field.tagName !== 'TEXTAREA') {
  133. valid = false;
  134. }
  135. valid = valid && !field.getAttribute('placeholder');
  136. if (!valid) {
  137. return; // Again, nothing to attach
  138. }
  139. // Only create object for input[text], input[password], or textarea
  140. (new $.InFieldLabels(this, field, options));
  141. });
  142. };
  143. }(jQuery));