├── js ├── .jshintrc ├── jquery.placeholder-enhanced.min.js └── jquery.placeholder-enhanced.js ├── Makefile ├── css ├── placeholder-enhanced.css └── demo.css ├── package.json ├── LICENSE.txt ├── demo.html └── README.md /js/.jshintrc: -------------------------------------------------------------------------------- 1 | { 2 | "camelcase": true, 3 | "curly": true, 4 | "eqeqeq": true, 5 | "forin": true, 6 | "immed": true, 7 | "latedef": true, 8 | "noarg": true, 9 | "noempty": true, 10 | "quotmark": "single", 11 | "undef": true, 12 | "unused": true, 13 | "strict": true, 14 | "trailing": true, 15 | "browser": true, 16 | "jquery": true 17 | } 18 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | # vim: ts=4 sw=4 noexpandtab 2 | SHELL := /bin/bash 3 | LICENSE_SHORT := "/*! jQuery Placeholder Enhanced 1.6.9 | @tdecs | under the MIT license */" 4 | BIN := ./node_modules/.bin 5 | INPUT := ./js/jquery.placeholder-enhanced.js 6 | OUTPUT := ./js/jquery.placeholder-enhanced.min.js 7 | 8 | build: 9 | @rm ${OUTPUT} 10 | @echo ${LICENSE_SHORT} > ${OUTPUT} 11 | @node ${BIN}/uglifyjs ${INPUT} -c -m --comments >> ${OUTPUT} 12 | 13 | lint: 14 | @node ${BIN}/jshint ${INPUT} 15 | 16 | .PHONY: lint 17 | -------------------------------------------------------------------------------- /css/placeholder-enhanced.css: -------------------------------------------------------------------------------- 1 | /*! 2 | * jQuery Placeholder Enhanced 1.6.9 3 | * Copyright (c) 2013-2015 Denis Ciccale (@tdecs) 4 | * Released under MIT license 5 | * https://raw.github.com/dciccale/placeholder-enhanced/master/LICENSE.txt 6 | */ 7 | 8 | /* 9 | * You may change the name of the class 10 | * (remember changing it in the js file too) 11 | */ 12 | 13 | /* All browsers */ 14 | .placeholder { 15 | color: #aaa; 16 | } 17 | 18 | /* WebKit */ 19 | ::-webkit-input-placeholder { 20 | color: #aaa; 21 | } 22 | 23 | /* Firefox 4 to 18 */ 24 | :-moz-placeholder { 25 | color: #aaa; 26 | } 27 | 28 | /* Firefox 19+ */ 29 | ::-moz-placeholder { 30 | color: #aaa; 31 | } 32 | 33 | /* Internet Explorer 10+ */ 34 | :-ms-input-placeholder { 35 | color: #aaa; 36 | } 37 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "placeholder-enhanced", 3 | "version": "1.6.9", 4 | "description": "This jQuery Placeholder plugin is an enhanced polyfill for the HTML5 placeholder attribute.", 5 | "keywords": ["placeholder", "enhanced", "html5", "polyfill"], 6 | "homepage": "https://github.com/dciccale/placeholder-enhanced", 7 | "author": { 8 | "name": "Denis Ciccale", 9 | "email": "dciccale@gmail.com", 10 | "url": "http://twitter.com/tdecs" 11 | }, 12 | "repository": { 13 | "type": "git", 14 | "url": "git://github.com/dciccale/placeholder-enhanced.git" 15 | }, 16 | "bugs": { 17 | "url": "https://github.com/dciccale/placeholder-enhanced/issues" 18 | }, 19 | "licenses": [ 20 | { 21 | "type": "MIT", 22 | "url": "https://github.com/dciccale/placeholder-enhanced/blob/master/LICENSE.txt" 23 | } 24 | ], 25 | "devDependencies": { 26 | "jshint": "^2.8.0", 27 | "uglify-js": "^2.4.23" 28 | }, 29 | "dependencies": { 30 | "jquery": ">=1.4.4" 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /LICENSE.txt: -------------------------------------------------------------------------------- 1 | Copyright (c) 2013 Denis Ciccale (@tdecs) 2 | 3 | Permission is hereby granted, free of charge, to any 4 | person obtaining a copy of this software and associated 5 | documentation files (the "Software"), to deal in the 6 | Software without restriction, including without limitation 7 | the rights to use, copy, modify, merge, publish, 8 | distribute, sublicense, and/or sell copies of the 9 | Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice 13 | shall be included in all copies or substantial portions of 14 | the Software. 15 | 16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY 17 | KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE 18 | WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR 19 | PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS 20 | OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR 21 | OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR 22 | OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 23 | SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 24 | -------------------------------------------------------------------------------- /css/demo.css: -------------------------------------------------------------------------------- 1 | *{margin:0;padding:0;outline:0;font-size:1em;font-weight:normal;font-style:normal;border:0;text-decoration:none;list-style-type:none} 2 | 3 | body { 4 | padding:30px; 5 | font-family:verdana; 6 | background-color:#ebebeb; 7 | font-size:1em; 8 | } 9 | 10 | h1, h2 { 11 | font-family:'Trebuchet MS'; 12 | font-weight:bold; 13 | } 14 | 15 | h1 { 16 | font-size:22px; 17 | margin-bottom:20px; 18 | } 19 | 20 | h2 { 21 | font-size:18px; 22 | margin-bottom:10px; 23 | } 24 | 25 | a { 26 | color:#00F; 27 | text-decoration:underline; 28 | } 29 | 30 | a:hover { 31 | color:#000; 32 | } 33 | 34 | #content { 35 | background-color:#fff; 36 | border:3px solid #ccc; 37 | padding:20px; 38 | } 39 | 40 | p { 41 | margin:10px 0; 42 | } 43 | 44 | label { 45 | cursor:pointer; 46 | font-size:14px; 47 | } 48 | 49 | strong { 50 | font-weight:bold; 51 | } 52 | 53 | .separator { 54 | overflow:hidden; 55 | height:25px; 56 | margin-bottom:25px; 57 | border-bottom:1px solid #999; 58 | clear:left; 59 | } 60 | 61 | #submit { 62 | margin:0; 63 | } 64 | 65 | .btn { 66 | padding:5px 15px; 67 | border:2px solid gray; 68 | font-size:14px; 69 | cursor:pointer; 70 | background-color:#ccc; 71 | color:#333; 72 | font-weight:bold; 73 | } 74 | 75 | input, textarea { 76 | font-family:verdana; 77 | font-size:.85em; 78 | border:1px solid #ccc; 79 | padding:3px; 80 | } 81 | -------------------------------------------------------------------------------- /js/jquery.placeholder-enhanced.min.js: -------------------------------------------------------------------------------- 1 | /*! jQuery Placeholder Enhanced 1.6.9 | @tdecs | under the MIT license */ 2 | !function(e,a){"use strict";var l="placeholderEnhanced",s=a.createElement("input"),t=a.createElement("textarea"),n="placeholder"in s&&"placeholder"in t,r={FOCUS:"focus.placeholder",BLUR:"blur.placeholder"},o={cssClass:"placeholder",normalize:!0},c=e.fn.val,i=function(a){return e.nodeName(a,"input")||e.nodeName(a,"textarea")},d=function(a){for(var l,s=["placeholder","name","id"],t={},n=0,r=a.attributes.length;r>n;n++)l=a.attributes[n],l.specified&&e.inArray(l.name,s)<0&&(t[l.name]=l.value);return t},u=function(e){e.css({position:"",left:""})},p=function(e){e.css({position:"absolute",left:"-9999em"})};(!n||o.normalize)&&(n?n&&o.normalize&&(e.fn.val=function(){var a=arguments,s=this[0];return s?a.length?this.each(function(s,t){var n=e(t),r=e.data(t,l),o=t._placeholder;r&&o&&i(t)&&(a[0]||t.value===o?a[0]&&n.hasClass(r.cssClass)&&n.removeClass(r.cssClass):n.addClass(r.cssClass).attr("placeholder",o)),c.apply(n,a)}):c.apply(this,a):void 0}):e.fn.val=function(){var a,s=arguments,t=this[0];return t?s.length?this.each(function(a,t){var n=e(t),r=e.data(t,l),o=n.attr("placeholder");r&&o&&i(t)?s[0]||t.value===o?s[0]&&(n.hasClass(r.cssClass)&&n.removeClass(r.cssClass),c.apply(n,s)):t.value=n.addClass(r.cssClass).attr("placeholder"):c.apply(n,s)}):(a=e(t).attr("placeholder"),a&&i(t)?t.value===a?"":t.value:c.apply(this,s)):void 0},e.fn[l]=function(a){var s=e.extend(o,a);if(this.length&&(!n||s.normalize))return"destroy"===a?this.filter(function(a,s){return e.data(s,l)}).removeClass(s.cssClass).each(function(a,s){var t=e(s).unbind(".placeholder"),r="password"===s.type,o=t.attr("placeholder");n?delete s._placeholder:(s.value===o&&(s.value=""),r&&(u(t),t.prev().unbind(".placeholder").remove())),e.fn.val=c,e.removeData(s,l)}):this.each(function(a,t){if(!e.data(t,l)){e.data(t,l,s);var o=e(t),c="password"===t.type,i=o.attr("placeholder"),h=null,v=null,f=null;n?n&&s.normalize&&(t._placeholder=o.attr("placeholder"),v=function(){t.value||o.addClass(s.cssClass).attr("placeholder",i)},f=function(){o.removeAttr("placeholder").removeClass(s.cssClass)}):(v=function(){o.val()?o.val()&&c&&f():c?(u(h),p(o)):o.val(i).addClass(s.cssClass)},c?(f=function(){u(o),p(h)},h=e("",e.extend(d(t),{type:"text",value:i,tabindex:-1})).addClass(s.cssClass).bind(r.FOCUS,function(){o.trigger(r.FOCUS)}).insertBefore(o)):f=function(){o.hasClass(s.cssClass)&&(t.value="",o.removeClass(s.cssClass))}),o.bind(r.BLUR,v).bind(r.FOCUS,f).trigger(r.BLUR)}})},e(function(){e("input[placeholder], textarea[placeholder]")[l]()}))}(jQuery,document); 3 | -------------------------------------------------------------------------------- /demo.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | jQuery Placeholder Enhanced - Demo 5 | 6 | 7 | 8 | 9 | 10 | 11 |

jQuery Placeholder Enhanced

12 | 13 |
14 |
15 |
16 |

17 |

18 |

19 |

20 |

21 |

22 |

Setting size attribute on password also works fine for unsupported browsers

23 |

24 |
25 |

26 |
27 |

Form result:

28 |
29 |
30 | 31 |

Set/Empty value to the first input programatically using jQuery's .val() function

32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 68 | 69 | Fork me on GitHub 70 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Placeholder Enhanced 1.6.9 2 | 3 | ### This jQuery Placeholder plugin is an enhanced polyfill for the HTML5 placeholder attribute. 4 | 5 | ## Features 6 | 7 | - Cross-browser & Cross-styling 8 | - Support for all input types, password, textarea, text, email, search, url, etc... 9 | - Robust: it heavely behave as the HTML5 placeholder defined in the specs 10 | - Normalize placeholder behaviour in modern browsers (optional). This means the placeholder will 11 | hide on input focus. 12 | - Fix jQuery.val() function to work as expected to set/get the value of inputs with placeholder 13 | - Lightweight: **970 bytes** minified & gzipped 14 | 15 | *Requires jQuery 1.4.4 or higher* 16 | 17 | ## Installation 18 | 19 | ``` 20 | bower install placeholder-enhanced 21 | ``` 22 | 23 | or download this repo 24 | 25 | ## Usage 26 | 27 | Just include the js file after jQuery on your HTML page and the plugin will be automatically initialized 28 | 29 | ```html 30 | 31 | 32 | ``` 33 | 34 | If you want to initialize the plugin yourself after the first auto-initialize (for example after ajax content being 35 | loaded), just call the plugin like this: 36 | 37 | ```javascript 38 | $('input[placeholder], textarea[placeholder]').placeholderEnhanced(); 39 | ``` 40 | 41 | ### Example: 42 | 43 | Initialize the plugin after loading an HTML page via AJAX, call the plugin after the content is loaded. 44 | 45 | ```javascript 46 | $(function () { 47 | $.get('file.html', function (html) { 48 | $('#container') 49 | // append the html 50 | .append(html) 51 | // find any inputs or textareas with placeholder and initialize the plugin 52 | .find('input[placeholder], textarea[placeholder]').placeholderEnhanced(); 53 | }); 54 | }) 55 | ``` 56 | 57 | ### Destroy 58 | 59 | If you want to destroy the plugin call: 60 | 61 | ```javascript 62 | $('input[placeholder], textarea[placeholder]').placeholderEnhanced('destroy'); 63 | ``` 64 | 65 | It will automatically clean all what the plugin first created as if it was never initialized, only for the selected elements. 66 | 67 | ## CSS 68 | 69 | Customize the style of the placeholder with CSS in a cross-browser manner: 70 | 71 | See [placeholder-enhanced.css](https://github.com/dciccale/placeholder-enhanced/blob/master/css/placeholder-enhanced.css) 72 | 73 | ## Demo 74 | 75 | For a demo see [demo.html](https://github.com/dciccale/placeholder-enhanced/blob/master/demo.html) **[online](http://dciccale.github.com/placeholder-enhanced/)** 76 | 77 | ## Build 78 | 79 | If you want to work on the plugin there is a Makefile with two targets: 80 | 81 | To lint with jshint 82 | 83 | ```sh 84 | $ make lint 85 | ``` 86 | 87 | Minify the js file 88 | 89 | ```sh 90 | $ make build 91 | ``` 92 | 93 | ## TODO 94 | 95 | These are not major tasks, but nice to have: 96 | 97 | - Create a [kimbo.js](http://kimbojs.com) plugin version. 98 | - Create a plain JavaScript version? 99 | - Create two separate versions. 100 | - Version 1.x to give *full* cross-browser support and normalization. (current version) 101 | - Version 2.x only to normalize *modern browsers* placeholder behaviour. 102 | 103 | ## License 104 | 105 | See [LICENSE.txt](https://raw.github.com/dciccale/placeholder-enhanced/master/LICENSE.txt) 106 | -------------------------------------------------------------------------------- /js/jquery.placeholder-enhanced.js: -------------------------------------------------------------------------------- 1 | /*! 2 | * jQuery Placeholder Enhanced 1.6.9 3 | * Copyright (c) 2013-2015 Denis Ciccale (@tdecs) 4 | * Released under MIT license 5 | * https://raw.github.com/dciccale/placeholder-enhanced/master/LICENSE.txt 6 | */ 7 | 8 | /* jshint jquery: true */ 9 | (function ($, doc) { 10 | 'use strict'; 11 | 12 | var PLUGIN_NAME = 'placeholderEnhanced'; 13 | 14 | var input = doc.createElement('input'); 15 | var textarea = doc.createElement('textarea'); 16 | 17 | // Check for support 18 | var HAS_NATIVE_SUPPORT = 'placeholder' in input && 'placeholder' in textarea; 19 | 20 | // Event namespaces 21 | var EVENT = { 22 | FOCUS: 'focus.placeholder', 23 | BLUR: 'blur.placeholder' 24 | }; 25 | 26 | /* 27 | * Define defaults here as some options are needed before initialization 28 | * it also merges with an options object when you call the plugin 29 | */ 30 | var DEFAULTS = { 31 | cssClass: 'placeholder', 32 | 33 | /* 34 | * Normalize behaviour & style across browsers 35 | * (remove placeholder on focus, show on blur) 36 | * if false, each browser wil handle behaviour & style natively 37 | * i.e. in case of Chrome placeholder is still visible on focus 38 | */ 39 | normalize: true 40 | }; 41 | 42 | // Save original jQuery .val() function 43 | var $val = $.fn.val; 44 | 45 | // Checks if the node is valid to use with the fixed jQuery .val() function 46 | var isValidNode = function (el) { 47 | return ($.nodeName(el, 'input') || $.nodeName(el, 'textarea')); 48 | }; 49 | 50 | // Copy attributes from a DOM node to a plain object to use later 51 | var copyAttrs = function (el) { 52 | var exclude = ['placeholder', 'name', 'id']; 53 | var attrs = {}; 54 | var attr; 55 | 56 | for (var i = 0, l = el.attributes.length; i < l; i++) { 57 | attr = el.attributes[i]; 58 | if (attr.specified && $.inArray(attr.name, exclude) < 0) { 59 | attrs[attr.name] = attr.value; 60 | } 61 | } 62 | 63 | return attrs; 64 | }; 65 | 66 | // Shows specified password input 67 | var showInput = function ($input) { 68 | $input.css({position: '', left: ''}); 69 | }; 70 | 71 | // Hides specified password input 72 | var hideInput = function ($input) { 73 | $input.css({position: 'absolute', left: '-9999em'}); 74 | }; 75 | 76 | // Don't do anything if there is native placeholder support and normalize mode is off by default 77 | if (HAS_NATIVE_SUPPORT && !DEFAULTS.normalize) { 78 | return; 79 | } 80 | 81 | /* 82 | * Handle the use of jQuery .val(), if placeholder is not supported, the .val() function 83 | * returns the placeholder value, wrap the val function to fix this, also useful when 84 | * using .serialize() or any other jQuery method that uses .val() 85 | */ 86 | 87 | // Fix .val() function for unsupported browsers 88 | if (!HAS_NATIVE_SUPPORT) { 89 | $.fn.val = function () { 90 | var args = arguments; 91 | var el = this[0]; 92 | var placeholderTxt; 93 | 94 | if (!el) { 95 | return; 96 | } 97 | 98 | // Handle .val() 99 | if (!args.length) { 100 | placeholderTxt = $(el).attr('placeholder'); 101 | 102 | // Handle get if the node has a placeholder 103 | if (placeholderTxt && isValidNode(el)) { 104 | return (el.value === placeholderTxt ? '' : el.value); 105 | 106 | // No placeholder, call native 107 | } else { 108 | return $val.apply(this, args); 109 | } 110 | } 111 | 112 | // Handle .val(...) 113 | return this.each(function (i, el) { 114 | var $el = $(el); 115 | var settings = $.data(el, PLUGIN_NAME); 116 | var placeholderTxt = $el.attr('placeholder'); 117 | 118 | if (settings && placeholderTxt && isValidNode(el)) { 119 | 120 | // Handle .val(''), .val(null), .val(undefined) 121 | if (!args[0] && el.value !== placeholderTxt) { 122 | el.value = $el.addClass(settings.cssClass).attr('placeholder'); 123 | 124 | // Handle .val('value') 125 | } else if (args[0]) { 126 | if ($el.hasClass(settings.cssClass)) { 127 | $el.removeClass(settings.cssClass); 128 | } 129 | $val.apply($el, args); 130 | } 131 | 132 | } else { 133 | $val.apply($el, args); 134 | } 135 | }); 136 | }; 137 | 138 | // Fix .val() function for modern browsers when normalize mode is on 139 | } else if (HAS_NATIVE_SUPPORT && DEFAULTS.normalize) { 140 | $.fn.val = function () { 141 | var args = arguments; 142 | var el = this[0]; 143 | 144 | if (!el) { 145 | return; 146 | } 147 | 148 | // Handle .val() 149 | if (!args.length) { 150 | return $val.apply(this, args); 151 | } 152 | 153 | // Handle .val(...) 154 | return this.each(function (i, el) { 155 | var $el = $(el); 156 | var settings = $.data(el, PLUGIN_NAME); 157 | var placeholderTxt = el._placeholder; 158 | 159 | if (settings && placeholderTxt && isValidNode(el)) { 160 | 161 | // Handle .val(''), .val(null), .val(undefined) 162 | if (!args[0] && el.value !== placeholderTxt) { 163 | 164 | // Restore the placeholder 165 | $el.addClass(settings.cssClass).attr('placeholder', placeholderTxt); 166 | 167 | // Handle .val('value') 168 | } else if (args[0]) { 169 | if ($el.hasClass(settings.cssClass)) { 170 | $el.removeClass(settings.cssClass); 171 | } 172 | } 173 | } 174 | 175 | $val.apply($el, args); 176 | }); 177 | }; 178 | } 179 | 180 | // Placeholder Enhanced plugin 181 | $.fn[PLUGIN_NAME] = function (options) { 182 | 183 | // Merge passed options with defaults 184 | var settings = $.extend(DEFAULTS, options); 185 | 186 | // Don't do anything if empty set or if placeholder is supported but 187 | // don't want to normalize modern browsers 188 | if (!this.length || (HAS_NATIVE_SUPPORT && !settings.normalize)) { 189 | return; 190 | } 191 | 192 | // Check if options param is destroy method 193 | if (options === 'destroy') { 194 | 195 | // Completely destroy the plugin 196 | return this 197 | 198 | // Get the elements where the plugin was initialized 199 | .filter(function (i, el) { 200 | return $.data(el, PLUGIN_NAME); 201 | }) 202 | 203 | // Remove class 204 | .removeClass(settings.cssClass) 205 | 206 | // Clean other stuff 207 | .each(function (i, el) { 208 | var $el = $(el).unbind('.placeholder'); 209 | var isPassword = (el.type === 'password'); 210 | var placeholderTxt = $el.attr('placeholder'); 211 | 212 | // Do all this only for unsupported browsers 213 | if (!HAS_NATIVE_SUPPORT) { 214 | if (el.value === placeholderTxt) { 215 | el.value = ''; 216 | } 217 | 218 | // Remove fake password input 219 | if (isPassword) { 220 | showInput($el); 221 | $el.prev().unbind('.placeholder').remove(); 222 | } 223 | 224 | // Delete backup prop 225 | } else { 226 | delete el._placeholder; 227 | } 228 | 229 | // Restore original jQuery .val() function 230 | $.fn.val = $val; 231 | 232 | // Plugin off 233 | $.removeData(el, PLUGIN_NAME); 234 | }); 235 | } 236 | 237 | return this.each(function (i, el) { 238 | 239 | // Check if the plugin was already initialized for this element 240 | if ($.data(el, PLUGIN_NAME)) { 241 | return; 242 | } 243 | 244 | // Mark plugin as initialized for the current element at the begining to 245 | // prevent multiple calls of the plugin for the same set of elements 246 | $.data(el, PLUGIN_NAME, settings); 247 | 248 | // jQuery object 249 | var $el = $(el); 250 | 251 | // Passwords have different treatment 252 | var isPassword = (el.type === 'password'); 253 | 254 | // Current placeholder text 255 | var placeholderTxt = $el.attr('placeholder'); 256 | 257 | // A fake input will be created for passwords 258 | var fakePassw = null; 259 | 260 | var setPlaceholder = null; 261 | var removePlaceholder = null; 262 | 263 | // Placeholder support for unsupported browsers 264 | if (!HAS_NATIVE_SUPPORT) { 265 | 266 | setPlaceholder = function () { 267 | 268 | // If there is no initial value or initial value is equal to the 269 | // placeholder (done in the $.fn.val wrapper) show the placeholder 270 | if (!$el.val()) { 271 | if (isPassword) { 272 | showInput(fakePassw); 273 | hideInput($el); 274 | } else { 275 | $el.val(placeholderTxt).addClass(settings.cssClass); 276 | } 277 | } else if ($el.val() && isPassword) { 278 | 279 | // If there is a value already, we want to remove the fake 280 | // placeholder. Otherwise, we'll have both the fake placeholder 281 | // and the actual input visible 282 | removePlaceholder(); 283 | } 284 | }; 285 | 286 | // Remove function for inputs and textareas 287 | if (!isPassword) { 288 | 289 | removePlaceholder = function () { 290 | if ($el.hasClass(settings.cssClass)) { 291 | el.value = ''; 292 | $el.removeClass(settings.cssClass); 293 | } 294 | }; 295 | 296 | // And for password inputs 297 | } else { 298 | 299 | removePlaceholder = function () { 300 | showInput($el); 301 | hideInput(fakePassw); 302 | }; 303 | 304 | // Create a fake password input 305 | fakePassw = $('', $.extend(copyAttrs(el), { 306 | 'type': 'text', 307 | value: placeholderTxt, 308 | tabindex: -1 // Skip tabbing 309 | })) 310 | .addClass(settings.cssClass) 311 | 312 | // When focus, trigger real input focus 313 | .bind(EVENT.FOCUS, function () { 314 | $el.trigger(EVENT.FOCUS); 315 | }) 316 | 317 | // Insert the fake input 318 | .insertBefore($el); 319 | } 320 | 321 | // Normalize placeholder behaviour and style in modern browsers if normalize mode is on 322 | } else if (HAS_NATIVE_SUPPORT && settings.normalize) { 323 | 324 | // Save the placeholder to restore it when needed 325 | el._placeholder = $el.attr('placeholder'); 326 | 327 | setPlaceholder = function () { 328 | if (!el.value) { 329 | $el.addClass(settings.cssClass).attr('placeholder', placeholderTxt); 330 | } 331 | }; 332 | 333 | removePlaceholder = function () { 334 | $el.removeAttr('placeholder').removeClass(settings.cssClass); 335 | }; 336 | 337 | } 338 | 339 | // Bind events and trigger blur the first time 340 | $el 341 | .bind(EVENT.BLUR, setPlaceholder) 342 | .bind(EVENT.FOCUS, removePlaceholder) 343 | .trigger(EVENT.BLUR); 344 | }); 345 | }; 346 | 347 | // Auto-initialize the plugin 348 | $(function () { 349 | $('input[placeholder], textarea[placeholder]')[PLUGIN_NAME](); 350 | }); 351 | 352 | }(jQuery, document)); 353 | --------------------------------------------------------------------------------