jquery.placeholder.js 6.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217
  1. /*
  2. jQuery placeholder plugin
  3. by Andrey Kuzmin, @unsoundscapes
  4. Based on existing plugin http://mths.be/placeholder by @mathias
  5. and this demo http://robertnyman.com/2011/05/02/ by @robertnyman
  6. Adopted to toggle placeholder on user input instead of focus
  7. Released under the MIT license
  8. */
  9. (function (factory) {
  10. 'use strict';
  11. if (typeof define === 'function' && define.amd) {
  12. // AMD. Register as anonymous module.
  13. define(['jquery'], factory)
  14. } else {
  15. // Browser globals.
  16. factory(jQuery)
  17. }
  18. }(function ($) {
  19. 'use strict';
  20. var isInputSupported = 'placeholder' in document.createElement('input')
  21. , isTextareaSupported = 'placeholder' in document.createElement('textarea')
  22. , $placeholders = $()
  23. function getAttributes (element) {
  24. // Return an object of element attributes
  25. var newAttrs = {}
  26. , rinlinejQuery = /^jQuery\d+$/
  27. $.each(element.attributes, function () {
  28. if (this.specified && !rinlinejQuery.test(this.name)) {
  29. newAttrs[this.name] = this.value
  30. }
  31. })
  32. return newAttrs
  33. }
  34. function setCaretTo (element, index) {
  35. // Set caret to specified @index
  36. if (element.createTextRange) {
  37. var range = element.createTextRange()
  38. range.move('character', index)
  39. range.select()
  40. } else if (element.selectionStart !== null) {
  41. element.focus()
  42. element.setSelectionRange(index, index)
  43. }
  44. }
  45. function Placeholder (element, options) {
  46. this.options = options || {}
  47. this.$replacement = this.$element = $(element)
  48. this.initialize.apply(this, arguments)
  49. // Cache all elements with placeholders
  50. $placeholders = $placeholders.add(element)
  51. }
  52. Placeholder.prototype = {
  53. initialize: function () {
  54. this.isHidden = true
  55. this.placeholderAttr = this.$element.attr('placeholder')
  56. // do not mess with default behavior
  57. this.$element.removeAttr('placeholder')
  58. this.isPassword = this.$element.is('[type=password]')
  59. if (this.isPassword) this.makeReplacement()
  60. this.$replacement.on({
  61. 'keydown.placeholder': $.proxy(this.hide, this)
  62. , 'focus.placeholder drop.placeholder click.placeholder': $.proxy(this.setCaret, this)
  63. })
  64. this.$element.on({
  65. 'blur.placeholder keyup.placeholder': $.proxy(this.show, this)
  66. })
  67. this.show()
  68. }
  69. // Set or get input value
  70. // Setting value toggles placeholder
  71. , val: function (value) {
  72. if (value === undefined) {
  73. return this.isHidden ? this.$element[0].value : '';
  74. }
  75. if (value === '') {
  76. if (this.isHidden) {
  77. this.$element[0].value = value
  78. this.show()
  79. }
  80. } else {
  81. if (!this.isHidden) this.hide()
  82. this.$element[0].value = value
  83. }
  84. return this
  85. }
  86. // Hide placeholder at user input
  87. , hide: function (e) {
  88. var isActiveElement = this.$replacement.is(':focus')
  89. if (this.isHidden) return;
  90. if (!e || !(e.shiftKey && e.keyCode === 16) && e.keyCode !== 9) {
  91. this.isHidden = true
  92. if (this.isPassword) {
  93. this.$replacement.before(this.$element.show()).hide()
  94. if (isActiveElement) this.$element.focus()
  95. } else {
  96. this.$element[0].value = ''
  97. this.$element.removeClass(this.options.className)
  98. }
  99. }
  100. }
  101. // Show placeholder on blur and keyup
  102. , show: function (e) {
  103. var isActiveElement = this.$element.is(':focus')
  104. if (!this.isHidden) return;
  105. if (this.$element[0].value === '') {
  106. this.isHidden = false
  107. if (this.isPassword) {
  108. this.$element.before(this.$replacement.show()).hide()
  109. if (isActiveElement) this.$replacement.focus()
  110. } else {
  111. this.$element[0].value = this.placeholderAttr
  112. this.$element.addClass(this.options.className)
  113. if (isActiveElement) this.setCaret(e)
  114. }
  115. }
  116. }
  117. // Set caret at the beginning of the input
  118. , setCaret: function (e) {
  119. if (e && !this.isHidden) {
  120. setCaretTo(this.$replacement[0], 0)
  121. e.preventDefault()
  122. }
  123. }
  124. // Make and return replacement element
  125. , makeReplacement: function () {
  126. // we can't use $.fn.clone because ie <= 8 doesn't allow type change
  127. var replacementAttributes =
  128. $.extend(
  129. getAttributes(this.$element[0])
  130. , { 'type': 'text'
  131. , 'value': this.placeholderAttr
  132. }
  133. )
  134. // replacement should not have input name
  135. delete replacementAttributes.name
  136. this.$replacement = $('<input>', replacementAttributes)
  137. .data('placeholder', this)
  138. .addClass(this.options.className)
  139. return this.$replacement;
  140. }
  141. }
  142. // Override jQuery val and prop hooks
  143. $.valHooks.input = $.valHooks.textarea = $.propHooks.value = {
  144. get: function (element) {
  145. var placeholder = $(element).data('placeholder')
  146. return placeholder ? placeholder.val() : element.value;
  147. }
  148. , set: function (element, value) {
  149. var placeholder = $(element).data('placeholder')
  150. return placeholder ? placeholder.val(value) : element.value = value;
  151. }
  152. }
  153. // Plugin definition
  154. $.fn.placeholder = function (option) {
  155. return this.each(function () {
  156. var $this = $(this)
  157. , data = $this.data('placeholder')
  158. , options = $.extend({}, $.fn.placeholder.defaults, typeof option === 'object' && option)
  159. if (!data && $this.is('[placeholder]') && (options.force ||
  160. !isInputSupported && $this.is('input') ||
  161. !isTextareaSupported && $this.is('textarea'))) {
  162. $this.data('placeholder', data = new Placeholder(this, options))
  163. }
  164. if (data && typeof option === 'string') data[option]()
  165. })
  166. }
  167. $.fn.placeholder.defaults = {
  168. force: false
  169. , className: 'placeholder'
  170. }
  171. $.fn.placeholder.Constructor = Placeholder
  172. // Events
  173. $(document).on('submit.placeholder', 'form', function () {
  174. // Clear the placeholder values so they don't get submitted
  175. $placeholders.placeholder('hide')
  176. // And then restore them back
  177. setTimeout(function () { $placeholders.placeholder('show') }, 10)
  178. })
  179. $(window).on('beforeunload.placeholder', function () {
  180. // Clear placeholders upon page reload
  181. $placeholders.placeholder('hide')
  182. })
  183. return Placeholder
  184. }));