1/* 2 Watermark plugin for jQuery 3 Version: 3.1.4 4 http://jquery-watermark.googlecode.com/ 5 6 Copyright (c) 2009-2012 Todd Northrop 7 http://www.speednet.biz/ 8 9 August 13, 2012 10 11 Requires: jQuery 1.2.3+ 12 13 Dual licensed under the MIT or GPL Version 2 licenses. 14 See mit-license.txt and gpl2-license.txt in the project root for details. 15------------------------------------------------------*/ 16 17( function ( $, window, undefined ) { 18 19var 20 // String constants for data names 21 dataFlag = "watermark", 22 dataClass = "watermarkClass", 23 dataFocus = "watermarkFocus", 24 dataFormSubmit = "watermarkSubmit", 25 dataMaxLen = "watermarkMaxLength", 26 dataPassword = "watermarkPassword", 27 dataText = "watermarkText", 28 29 // Copy of native jQuery regex use to strip return characters from element value 30 rreturn = /\r/g, 31 32 // Used to determine if type attribute of input element is a non-text type (invalid) 33 rInvalidType = /^(button|checkbox|hidden|image|radio|range|reset|submit)$/i, 34 35 // Includes only elements with watermark defined 36 selWatermarkDefined = "input:data(" + dataFlag + "),textarea:data(" + dataFlag + ")", 37 38 // Includes only elements capable of having watermark 39 selWatermarkAble = ":watermarkable", 40 41 // triggerFns: 42 // Array of function names to look for in the global namespace. 43 // Any such functions found will be hijacked to trigger a call to 44 // hideAll() any time they are called. The default value is the 45 // ASP.NET function that validates the controls on the page 46 // prior to a postback. 47 // 48 // Am I missing other important trigger function(s) to look for? 49 // Please leave me feedback: 50 // http://code.google.com/p/jquery-watermark/issues/list 51 triggerFns = [ 52 "Page_ClientValidate" 53 ], 54 55 // Holds a value of true if a watermark was displayed since the last 56 // hideAll() was executed. Avoids repeatedly calling hideAll(). 57 pageDirty = false, 58 59 // Detects if the browser can handle native placeholders 60 hasNativePlaceholder = ( "placeholder" in document.createElement( "input" ) ); 61 62// Best practice: this plugin adds only one method to the jQuery object. 63// Also ensures that the watermark code is only added once. 64$.watermark = $.watermark || { 65 66 // Current version number of the plugin 67 version: "3.1.4", 68 69 runOnce: true, 70 71 // Default options used when watermarks are instantiated. 72 // Can be changed to affect the default behavior for all 73 // new or updated watermarks. 74 options: { 75 76 // Default class name for all watermarks 77 className: "watermark", 78 79 // If true, plugin will detect and use native browser support for 80 // watermarks, if available. (e.g., WebKit's placeholder attribute.) 81 useNative: true, 82 83 // If true, all watermarks will be hidden during the window's 84 // beforeunload event. This is done mainly because WebKit 85 // browsers remember the watermark text during navigation 86 // and try to restore the watermark text after the user clicks 87 // the Back button. We can avoid this by hiding the text before 88 // the browser has a chance to save it. The regular unload event 89 // was tried, but it seems the browser saves the text before 90 // that event kicks off, because it didn't work. 91 hideBeforeUnload: true 92 }, 93 94 // Hide one or more watermarks by specifying any selector type 95 // i.e., DOM element, string selector, jQuery matched set, etc. 96 hide: function ( selector ) { 97 $( selector ).filter( selWatermarkDefined ).each( 98 function () { 99 $.watermark._hide( $( this ) ); 100 } 101 ); 102 }, 103 104 // Internal use only. 105 _hide: function ( $input, focus ) { 106 var elem = $input[ 0 ], 107 inputVal = ( elem.value || "" ).replace( rreturn, "" ), 108 inputWm = $input.data( dataText ) || "", 109 maxLen = $input.data( dataMaxLen ) || 0, 110 className = $input.data( dataClass ); 111 112 if ( ( inputWm.length ) && ( inputVal == inputWm ) ) { 113 elem.value = ""; 114 115 // Password type? 116 if ( $input.data( dataPassword ) ) { 117 118 if ( ( $input.attr( "type" ) || "" ) === "text" ) { 119 var $pwd = $input.data( dataPassword ) || [], 120 $wrap = $input.parent() || []; 121 122 if ( ( $pwd.length ) && ( $wrap.length ) ) { 123 $wrap[ 0 ].removeChild( $input[ 0 ] ); // Can't use jQuery methods, because they destroy data 124 $wrap[ 0 ].appendChild( $pwd[ 0 ] ); 125 $input = $pwd; 126 } 127 } 128 } 129 130 if ( maxLen ) { 131 $input.attr( "maxLength", maxLen ); 132 $input.removeData( dataMaxLen ); 133 } 134
135 if ( focus ) { 136 $input.attr( "autocomplete", "off" ); // Avoid NS_ERROR_XPC_JS_THREW_STRING error in Firefox 137 138 window.setTimeout( 139 function () { 140 $input.select(); // Fix missing cursor in IE 141 } 142 , 1 ); 143 } 144 } 145 146 className && $input.removeClass( className ); 147 }, 148 149 // Display one or more watermarks by specifying any selector type 150 // i.e., DOM element, string selector, jQuery matched set, etc. 151 // If conditions are not right for displaying a watermark, ensures that watermark is not shown. 152 show: function ( selector ) { 153 $( selector ).filter( selWatermarkDefined ).each( 154 function () { 155 $.watermark._show( $( this ) ); 156 } 157 ); 158 }, 159 160 // Internal use only. 161 _show: function ( $input ) { 162 var elem = $input[ 0 ], 163 val = ( elem.value || "" ).replace( rreturn, "" ), 164 text = $input.data( dataText ) || "", 165 type = $input.attr( "type" ) || "", 166 className = $input.data( dataClass ); 167 168 if ( ( ( val.length == 0 ) || ( val == text ) ) && ( !$input.data( dataFocus ) ) ) { 169 pageDirty = true; 170 171 // Password type? 172 if ( $input.data( dataPassword ) ) { 173 174 if ( type === "password" ) { 175 var $pwd = $input.data( dataPassword ) || [], 176 $wrap = $input.parent() || []; 177 178 if ( ( $pwd.length ) && ( $wrap.length ) ) { 179 $wrap[ 0 ].removeChild( $input[ 0 ] ); // Can't use jQuery methods, because they destroy data 180 $wrap[ 0 ].appendChild( $pwd[ 0 ] ); 181 $input = $pwd; 182 $input.attr( "maxLength", text.length ); 183 elem = $input[ 0 ]; 184 } 185 } 186 } 187 188 // Ensure maxLength big enough to hold watermark (input of type="text" or type="search" only) 189 if ( ( type === "text" ) || ( type === "search" ) ) { 190 var maxLen = $input.attr( "maxLength" ) || 0; 191 192 if ( ( maxLen > 0 ) && ( text.length > maxLen ) ) { 193 $input.data( dataMaxLen, maxLen ); 194 $input.attr( "maxLength", text.length ); 195 } 196 } 197 198 className && $input.addClass( className ); 199 elem.value = text; 200 } 201 else { 202 $.watermark._hide( $input ); 203 } 204 }, 205 206 // Hides all watermarks on the current page. 207 hideAll: function () { 208 if ( pageDirty ) { 209 $.watermark.hide( selWatermarkAble ); 210 pageDirty = false; 211 } 212 }, 213 214 // Displays all watermarks on the current page. 215 showAll: function () { 216 $.watermark.show( selWatermarkAble ); 217 } 218}; 219 220$.fn.watermark = $.fn.watermark || function ( text, options ) { 221 /// <summary> 222 /// Set watermark text and class name on all input elements of type="text/password/search" and 223 /// textareas within the matched set. If className is not specified in options, the default is 224 /// "watermark". Within the matched set, only input elements with type="text/password/search" 225 /// and textareas are affected; all other elements are ignored. 226 /// </summary> 227 /// <returns type="jQuery"> 228 /// Returns the original jQuery matched set (not just the input and texarea elements). 229 /// </returns> 230 /// <param name="text" type="String"> 231 /// Text to display as a watermark when the input or textarea element has an empty value and does not 232 /// have focus. The first time watermark() is called on an element, if this argument is empty (or not 233 /// a String type), then the watermark will have the net effect of only changing the class name when 234 /// the input or textarea element's value is empty and it does not have focus. 235 /// </param> 236 /// <param name="options" type="Object" optional="true"> 237 /// Provides the ability to override the default watermark options ($.watermark.options). For backward 238 /// compatibility, if a string value is supplied, it is used as the class name that overrides the class 239 /// name in $.watermark.options.className. Properties include: 240 /// className: When the watermark is visible, the element will be styled using this class name. 241 /// useNative (Boolean or Function): Specifies if native browser support for watermarks will supersede 242 /// plugin functionality. If useNative is a function, the return value from the function will 243 /// determine if native support is used. The function is passed one argument -- a jQuery object 244 /// containing the element being tested as the only element in its matched set -- and the DOM 245 /// element being tested is the object on which the function is invoked (the value of "this"). 246 /// </param> 247 /// <remarks>
248 /// The effect of changing the text and class name on an input element is called a watermark because 249 /// typically light gray text is used to provide a hint as to what type of input is required. However, 250 /// the appearance of the watermark can be something completely different: simply change the CSS style 251 /// pertaining to the supplied class name. 252 /// 253 /// The first time watermark() is called on an element, the watermark text and class name are initialized, 254 /// and the focus and blur events are hooked in order to control the display of the watermark. Also, as 255 /// of version 3.0, drag and drop events are hooked to guard against dropped text being appended to the 256 /// watermark. If native watermark support is provided by the browser, it is detected and used, unless 257 /// the useNative option is set to false. 258 /// 259 /// Subsequently, watermark() can be called again on an element in order to change the watermark text 260 /// and/or class name, and it can also be called without any arguments in order to refresh the display. 261 /// 262 /// For example, after changing the value of the input or textarea element programmatically, watermark() 263 /// should be called without any arguments to refresh the display, because the change event is only 264 /// triggered by user actions, not by programmatic changes to an input or textarea element's value. 265 /// 266 /// The one exception to programmatic updates is for password input elements: you are strongly cautioned 267 /// against changing the value of a password input element programmatically (after the page loads). 268 /// The reason is that some fairly hairy code is required behind the scenes to make the watermarks bypass 269 /// IE security and switch back and forth between clear text (for watermarks) and obscured text (for 270 /// passwords). It is *possible* to make programmatic changes, but it must be done in a certain way, and 271 /// overall it is not recommended. 272 /// </remarks> 273 274 if ( !this.length ) { 275 return this; 276 } 277 278 var hasClass = false, 279 hasText = ( typeof( text ) === "string" ); 280 281 if ( hasText ) { 282 text = text.replace( rreturn, "" ); 283 } 284 285 if ( typeof( options ) === "object" ) { 286 hasClass = ( typeof( options.className ) === "string" ); 287 options = $.extend( {}, $.watermark.options, options ); 288 } 289 else if ( typeof( options ) === "string" ) { 290 hasClass = true; 291 options = $.extend( {}, $.watermark.options, { className: options } ); 292 } 293 else { 294 options = $.watermark.options; 295 } 296 297 if ( typeof( options.useNative ) !== "function" ) { 298 options.useNative = options.useNative? function () { return true; } : function () { return false; }; 299 } 300 301 return this.each( 302 function () { 303 var $input = $( this ); 304 305 if ( !$input.is( selWatermarkAble ) ) { 306 return; 307 } 308 309 // Watermark already initialized? 310 if ( $input.data( dataFlag ) ) { 311 312 // If re-defining text or class, first remove existing watermark, then make changes 313 if ( hasText || hasClass ) { 314 $.watermark._hide( $input ); 315 316 if ( hasText ) { 317 $input.data( dataText, text ); 318 } 319 320 if ( hasClass ) { 321 $input.data( dataClass, options.className ); 322 } 323 } 324 } 325 else { 326 327 // Detect and use native browser support, if enabled in options 328 if ( 329 ( hasNativePlaceholder ) 330 && ( options.useNative.call( this, $input ) ) 331 && ( ( $input.attr( "tagName" ) || "" ) !== "TEXTAREA" ) 332 ) { 333 // className is not set because current placeholder standard doesn't 334 // have a separate class name property for placeholders (watermarks). 335 if ( hasText ) { 336 $input.attr( "placeholder", text ); 337 } 338 339 // Only set data flag for non-native watermarks 340 // [purposely commented-out] -> $input.data(dataFlag, 1); 341 return; 342 } 343 344 $input.data( dataText, hasText? text : "" ); 345 $input.data( dataClass, options.className ); 346 $input.data( dataFlag, 1 ); // Flag indicates watermark was initialized 347 348 // Special processing for password type 349 if ( ( $input.attr( "type" ) || "" ) === "password" ) { 350 var $wrap = $input.wrap( "<span>" ).parent(), 351 $wm = $( $wrap.html().replace( /type=["']?password["']?/i, 'type="text"' ) ); 352 353 $wm.data( dataText, $input.data( dataText ) ); 354 $wm.data( dataClass, $input.data( dataClass ) ); 355 $wm.data( dataFlag, 1 ); 356 $wm.attr( "maxLength", text.length ); 357
358 $wm.focus( 359 function () { 360 $.watermark._hide( $wm, true ); 361 } 362 ).bind( "dragenter", 363 function () { 364 $.watermark._hide( $wm ); 365 } 366 ).bind( "dragend", 367 function () { 368 window.setTimeout( function () { $wm.blur(); }, 1 ); 369 } 370 ); 371 372 $input.blur( 373 function () { 374 $.watermark._show( $input ); 375 } 376 ).bind( "dragleave", 377 function () { 378 $.watermark._show( $input ); 379 } 380 ); 381 382 $wm.data( dataPassword, $input ); 383 $input.data( dataPassword, $wm ); 384 } 385 else { 386 387 $input.focus( 388 function () { 389 $input.data( dataFocus, 1 ); 390 $.watermark._hide( $input, true ); 391 } 392 ).blur( 393 function () { 394 $input.data( dataFocus, 0 ); 395 $.watermark._show( $input ); 396 } 397 ).bind( "dragenter", 398 function () { 399 $.watermark._hide( $input ); 400 } 401 ).bind( "dragleave", 402 function () { 403 $.watermark._show( $input ); 404 } 405 ).bind( "dragend", 406 function () { 407 window.setTimeout( function () { $.watermark._show($input); }, 1 ); 408 } 409 ).bind( "drop", 410 // Firefox makes this lovely function necessary because the dropped text 411 // is merged with the watermark before the drop event is called. 412 function ( evt ) { 413 var elem = $input[ 0 ], 414 dropText = evt.originalEvent.dataTransfer.getData( "Text" ); 415 416 if ( ( elem.value || "" ).replace( rreturn, "" ).replace( dropText, "" ) === $input.data( dataText ) ) { 417 elem.value = dropText; 418 } 419 420 $input.focus(); 421 } 422 ); 423 } 424 425 // In order to reliably clear all watermarks before form submission, 426 // we need to replace the form's submit function with our own 427 // function. Otherwise watermarks won't be cleared when the form 428 // is submitted programmatically. 429 if ( this.form ) { 430 var form = this.form, 431 $form = $( form ); 432 433 if ( !$form.data( dataFormSubmit ) ) { 434 $form.submit( $.watermark.hideAll ); 435 436 // form.submit exists for all browsers except Google Chrome 437 // (see "else" below for explanation) 438 if ( form.submit ) { 439 $form.data( dataFormSubmit, form.submit ); 440 441 form.submit = ( function ( f, $f ) { 442 return function () { 443 var nativeSubmit = $f.data( dataFormSubmit ); 444 445 $.watermark.hideAll(); 446 447 if ( nativeSubmit.apply ) { 448 nativeSubmit.apply( f, Array.prototype.slice.call( arguments ) ); 449 } 450 else { 451 nativeSubmit(); 452 } 453 }; 454 })( form, $form ); 455 } 456 else { 457 $form.data( dataFormSubmit, 1 ); 458 459 // This strangeness is due to the fact that Google Chrome's 460 // form.submit function is not visible to JavaScript (identifies 461 // as "undefined"). I had to invent a solution here because hours 462 // of Googling (ironically) for an answer did not turn up anything 463 // useful. Within my own form.submit function I delete the form's 464 // submit function, and then call the non-existent function -- 465 // which, in the world of Google Chrome, still exists. 466 form.submit = ( function ( f ) { 467 return function () { 468 $.watermark.hideAll(); 469 delete f.submit; 470 f.submit(); 471 }; 472 })( form ); 473 } 474 } 475 } 476 } 477 478 $.watermark._show( $input ); 479 } 480 ); 481}; 482 483// The code included within the following if structure is guaranteed to only run once, 484// even if the watermark script file is included multiple times in the page. 485if ( $.watermark.runOnce ) { 486 $.watermark.runOnce = false; 487 488 $.extend( $.expr[ ":" ], { 489 490 // Extends jQuery with a custom selector - ":data(...)" 491 // :data(<name>) Includes elements that have a specific name defined in the jQuery data 492 // collection. (Only the existence of the name is checked; the value is ignored.) 493 // A more sophisticated version of the :data() custom selector originally part of this plugin 494 // was removed for compatibility with jQuery UI. The original co
494de can be found in the SVN 495 // source listing in the file, "jquery.data.js". 496 data: $.expr.createPseudo ? 497 $.expr.createPseudo( function( dataName ) { 498 return function( elem ) { 499 return !!$.data( elem, dataName ); 500 }; 501 }) : 502 // support: jQuery <1.8 503 function( elem, i, match ) { 504 return !!$.data( elem, match[ 3 ] ); 505 }, 506 507 // Extends jQuery with a custom selector - ":watermarkable" 508 // Includes elements that can be watermarked, including textareas and most input elements 509 // that accept text input. It uses a "negative" test (i.e., testing for input types that DON'T 510 // work) because the HTML spec states that you can basically use any type, and if it doesn't 511 // recognize the type it will default to type=text. So if we only looked for certain type attributes 512 // we would fail to recognize non-standard types, which are still valid and watermarkable. 513 watermarkable: function ( elem ) { 514 var type, 515 name = elem.nodeName; 516 517 if ( name === "TEXTAREA" ) { 518 return true; 519 } 520 521 if ( name !== "INPUT" ) { 522 return false; 523 } 524 525 type = elem.getAttribute( "type" ); 526 527 return ( ( !type ) || ( !rInvalidType.test( type ) ) ); 528 } 529 }); 530 531 // Overloads the jQuery .val() function to return the underlying input value on 532 // watermarked input elements. When .val() is being used to set values, this 533 // function ensures watermarks are properly set/removed after the values are set. 534 // Uses self-executing function to override the default jQuery function. 535 ( function ( valOld ) { 536 537 $.fn.val = function () { 538 var args = Array.prototype.slice.call( arguments ); 539 540 // Best practice: return immediately if empty matched set 541 if ( !this.length ) { 542 return args.length? this : undefined; 543 } 544 545 // If no args, then we're getting the value of the first element; 546 // else we're setting values for all elements in matched set 547 if ( !args.length ) { 548 549 // If element is watermarked, get the underlying value; 550 // else use native jQuery .val() 551 if ( this.data( dataFlag ) ) { 552 var v = ( this[ 0 ].value || "" ).replace( rreturn, "" ); 553 return ( v === ( this.data( dataText ) || "" ) )? "" : v; 554 } 555 else { 556 return valOld.apply( this ); 557 } 558 } 559 else { 560 valOld.apply( this, args ); 561 $.watermark.show( this ); 562 return this; 563 } 564 }; 565 566 })( $.fn.val ); 567 568 // Hijack any functions found in the triggerFns list 569 if ( triggerFns.length ) { 570 571 // Wait until DOM is ready before searching 572 $( function () { 573 var i, name, fn; 574 575 for ( i = triggerFns.length - 1; i >= 0; i-- ) { 576 name = triggerFns[ i ]; 577 fn = window[ name ]; 578 579 if ( typeof( fn ) === "function" ) { 580 window[ name ] = ( function ( origFn ) { 581 return function () { 582 $.watermark.hideAll(); 583 return origFn.apply( null, Array.prototype.slice.call( arguments ) ); 584 }; 585 })( fn ); 586 } 587 } 588 }); 589 } 590 591 $( window ).bind( "beforeunload", function () { 592 if ( $.watermark.options.hideBeforeUnload ) { 593 $.watermark.hideAll(); 594 } 595 }); 596} 597 598})( jQuery, window );
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.