2 * jQuery Migrate - v1.2.1 - 2013-05-08
3 * https://github.com/jquery/jquery-migrate
4 * Copyright 2005, 2013 jQuery Foundation, Inc. and other contributors; Licensed MIT
6 * Patched for MediaWiki to add mw.track calls. --Krinkle 2014-04-14
8 (function( jQuery
, window
, undefined ) {
9 // See http://bugs.jquery.com/ticket/13335
15 // List of warnings already given; public read only
16 jQuery
.migrateWarnings
= [];
18 // Set to true to prevent console output; migrateWarnings still maintained
19 // jQuery.migrateMute = false;
21 // Show a message on the console so devs know we're active
22 if ( !jQuery
.migrateMute
&& window
.console
&& window
.console
.log
) {
23 window
.console
.log("JQMIGRATE: Logging is active");
26 // Set to false to disable traces that appear with warnings
27 if ( jQuery
.migrateTrace
=== undefined ) {
28 jQuery
.migrateTrace
= true;
31 // Forget any warnings we've already given; public
32 jQuery
.migrateReset = function() {
34 jQuery
.migrateWarnings
.length
= 0;
37 function migrateWarn( msg
, key
) {
38 var console
= window
.console
;
40 MediaWiki patch for tracking usage.
65 mw
.track( "jquery.migrate", key
|| "unknown" );
67 if ( !warnedAbout
[ msg
] ) {
68 warnedAbout
[ msg
] = true;
69 jQuery
.migrateWarnings
.push( msg
);
70 if ( console
&& console
.warn
&& !jQuery
.migrateMute
) {
71 console
.warn( "JQMIGRATE: " + msg
);
72 if ( jQuery
.migrateTrace
&& console
.trace
) {
79 function migrateWarnProp( obj
, prop
, value
, msg
, key
) {
80 if ( Object
.defineProperty
) {
81 // On ES5 browsers (non-oldIE), warn if the code tries to get prop;
82 // allow property to be overwritten in case some other plugin wants it
84 Object
.defineProperty( obj
, prop
, {
88 migrateWarn( msg
, key
|| prop
);
91 set: function( newValue
) {
92 migrateWarn( msg
, key
|| prop
);
98 // IE8 is a dope about Object.defineProperty, can't warn there
102 // Non-ES5 (or broken) browser; just set the property
103 jQuery
._definePropertyBroken
= true;
107 if ( document
.compatMode
=== "BackCompat" ) {
108 // jQuery has never supported or tested Quirks Mode
109 migrateWarn( "jQuery is not compatible with Quirks Mode" );
113 var attrFn
= jQuery( "<input/>", { size
: 1 } ).attr("size") && jQuery
.attrFn
,
114 oldAttr
= jQuery
.attr
,
115 valueAttrGet
= jQuery
.attrHooks
.value
&& jQuery
.attrHooks
.value
.get ||
116 function() { return null; },
117 valueAttrSet
= jQuery
.attrHooks
.value
&& jQuery
.attrHooks
.value
.set ||
118 function() { return undefined; },
119 rnoType
= /^(?:input|button)$/i,
120 rnoAttrNodeType
= /^[238]$/,
121 rboolean
= /^(?:autofocus|autoplay|async|checked|controls|defer|disabled|hidden|loop|multiple|open|readonly|required|scoped|selected)$/i,
122 ruseDefault
= /^(?:checked|selected)$/i;
125 migrateWarnProp( jQuery
, "attrFn", attrFn
|| {}, "jQuery.attrFn is deprecated" );
127 jQuery
.attr = function( elem
, name
, value
, pass
) {
128 var lowerName
= name
.toLowerCase(),
129 nType
= elem
&& elem
.nodeType
;
132 // Since pass is used internally, we only warn for new jQuery
133 // versions where there isn't a pass arg in the formal params
134 if ( oldAttr
.length
< 4 ) {
135 migrateWarn("jQuery.fn.attr( props, pass ) is deprecated", "attr-pass" );
137 if ( elem
&& !rnoAttrNodeType
.test( nType
) &&
138 (attrFn
? name
in attrFn
: jQuery
.isFunction(jQuery
.fn
[name
])) ) {
139 return jQuery( elem
)[ name
]( value
);
143 // Warn if user tries to set `type`, since it breaks on IE 6/7/8; by checking
144 // for disconnected elements we don't warn on $( "<button>", { type: "button" } ).
145 if ( name
=== "type" && value
!== undefined && rnoType
.test( elem
.nodeName
) && elem
.parentNode
) {
146 migrateWarn("Can't change the 'type' of an input or button in IE 6/7/8", "input-type");
149 // Restore boolHook for boolean property/attribute synchronization
150 if ( !jQuery
.attrHooks
[ lowerName
] && rboolean
.test( lowerName
) ) {
151 jQuery
.attrHooks
[ lowerName
] = {
152 get: function( elem
, name
) {
153 // Align boolean attributes with corresponding properties
154 // Fall back to attribute presence where some booleans are not supported
156 property
= jQuery
.prop( elem
, name
);
157 return property
=== true || typeof property
!== "boolean" &&
158 ( attrNode
= elem
.getAttributeNode(name
) ) && attrNode
.nodeValue
!== false ?
163 set: function( elem
, value
, name
) {
165 if ( value
=== false ) {
166 // Remove boolean attributes when set to false
167 jQuery
.removeAttr( elem
, name
);
169 // value is true since we know at this point it's type boolean and not false
170 // Set boolean attributes to the same name and set the DOM property
171 propName
= jQuery
.propFix
[ name
] || name
;
172 if ( propName
in elem
) {
173 // Only set the IDL specifically if it already exists on the element
174 elem
[ propName
] = true;
177 elem
.setAttribute( name
, name
.toLowerCase() );
183 // Warn only for attributes that can remain distinct from their properties post-1.9
184 if ( ruseDefault
.test( lowerName
) ) {
185 migrateWarn( "jQuery.fn.attr('" + lowerName
+ "') may use property instead of attribute", "attr-prop" );
189 return oldAttr
.call( jQuery
, elem
, name
, value
);
193 jQuery
.attrHooks
.value
= {
194 get: function( elem
, name
) {
195 var nodeName
= ( elem
.nodeName
|| "" ).toLowerCase();
196 if ( nodeName
=== "button" ) {
197 return valueAttrGet
.apply( this, arguments
);
199 if ( nodeName
!== "input" && nodeName
!== "option" ) {
200 migrateWarn("jQuery.fn.attr('value') no longer gets properties", "attr-prop");
202 return name
in elem
?
206 set: function( elem
, value
) {
207 var nodeName
= ( elem
.nodeName
|| "" ).toLowerCase();
208 if ( nodeName
=== "button" ) {
209 return valueAttrSet
.apply( this, arguments
);
211 if ( nodeName
!== "input" && nodeName
!== "option" ) {
212 migrateWarn("jQuery.fn.attr('value', val) no longer sets properties", "attr-prop");
214 // Does not return so that setAttribute is also used
220 var matched
, browser
,
221 oldInit
= jQuery
.fn
.init
,
222 oldParseJSON
= jQuery
.parseJSON
,
223 // Note: XSS check is done below after string is trimmed
224 rquickExpr
= /^([^<]*)(<[\w\W]+>)([^>]*)$/;
226 // $(html) "looks like html" rule change
227 jQuery
.fn
.init = function( selector
, context
, rootjQuery
) {
230 if ( selector
&& typeof selector
=== "string" && !jQuery
.isPlainObject( context
) &&
231 (match
= rquickExpr
.exec( jQuery
.trim( selector
) )) && match
[ 0 ] ) {
232 // This is an HTML string according to the "old" rules; is it still?
233 if ( selector
.charAt( 0 ) !== "<" ) {
234 migrateWarn("$(html) HTML strings must start with '<' character", "create-html");
237 migrateWarn("$(html) HTML text after last tag is ignored", "create-html");
239 // Consistently reject any HTML-like string starting with a hash (#9521)
240 // Note that this may break jQuery 1.6.x code that otherwise would work.
241 if ( match
[ 0 ].charAt( 0 ) === "#" ) {
242 migrateWarn("HTML string cannot start with a '#' character", "create-html");
243 jQuery
.error("JQMIGRATE: Invalid selector string (XSS)");
245 // Now process using loose rules; let pre-1.8 play too
246 if ( context
&& context
.context
) {
247 // jQuery object as context; parseHTML expects a DOM object
248 context
= context
.context
;
250 if ( jQuery
.parseHTML
) {
251 return oldInit
.call( this, jQuery
.parseHTML( match
[ 2 ], context
, true ),
252 context
, rootjQuery
);
255 return oldInit
.apply( this, arguments
);
257 jQuery
.fn
.init
.prototype = jQuery
.fn
;
259 // Let $.parseJSON(falsy_value) return null
260 jQuery
.parseJSON = function( json
) {
261 if ( !json
&& json
!== null ) {
262 migrateWarn("jQuery.parseJSON requires a valid JSON string", "json-invalid");
265 return oldParseJSON
.apply( this, arguments
);
268 jQuery
.uaMatch = function( ua
) {
269 ua
= ua
.toLowerCase();
271 var match
= /(chrome)[ \/]([\w.]+)/.exec( ua
) ||
272 /(webkit)[ \/]([\w.]+)/.exec( ua
) ||
273 /(opera)(?:.*version|)[ \/]([\w.]+)/.exec( ua
) ||
274 /(msie) ([\w.]+)/.exec( ua
) ||
275 ua
.indexOf("compatible") < 0 && /(mozilla)(?:.*? rv:([\w.]+)|)/.exec( ua
) ||
279 browser
: match
[ 1 ] || "",
280 version
: match
[ 2 ] || "0"
284 // Don't clobber any existing jQuery.browser in case it's different
285 if ( !jQuery
.browser
) {
286 matched
= jQuery
.uaMatch( navigator
.userAgent
);
289 if ( matched
.browser
) {
290 browser
[ matched
.browser
] = true;
291 browser
.version
= matched
.version
;
294 // Chrome is Webkit, but Webkit is also Safari.
295 if ( browser
.chrome
) {
296 browser
.webkit
= true;
297 } else if ( browser
.webkit
) {
298 browser
.safari
= true;
301 jQuery
.browser
= browser
;
304 // Warn if the code tries to get jQuery.browser
305 migrateWarnProp( jQuery
, "browser", jQuery
.browser
, "jQuery.browser is deprecated" );
307 jQuery
.sub = function() {
308 function jQuerySub( selector
, context
) {
309 return new jQuerySub
.fn
.init( selector
, context
);
311 jQuery
.extend( true, jQuerySub
, this );
312 jQuerySub
.superclass
= this;
313 jQuerySub
.fn
= jQuerySub
.prototype = this();
314 jQuerySub
.fn
.constructor = jQuerySub
;
315 jQuerySub
.sub
= this.sub
;
316 jQuerySub
.fn
.init
= function init( selector
, context
) {
317 if ( context
&& context
instanceof jQuery
&& !(context
instanceof jQuerySub
) ) {
318 context
= jQuerySub( context
);
321 return jQuery
.fn
.init
.call( this, selector
, context
, rootjQuerySub
);
323 jQuerySub
.fn
.init
.prototype = jQuerySub
.fn
;
324 var rootjQuerySub
= jQuerySub(document
);
325 migrateWarn( "jQuery.sub() is deprecated", "sub" );
330 // Ensure that $.ajax gets the new parseJSON defined in core.js
333 "text json": jQuery
.parseJSON
338 var oldFnData
= jQuery
.fn
.data
;
340 jQuery
.fn
.data = function( name
) {
344 // Handles 1.7 which has this behavior and 1.8 which doesn't
345 if ( elem
&& name
=== "events" && arguments
.length
=== 1 ) {
346 ret
= jQuery
.data( elem
, name
);
347 evt
= jQuery
._data( elem
, name
);
348 if ( ( ret
=== undefined || ret
=== evt
) && evt
!== undefined ) {
349 migrateWarn("Use of jQuery.fn.data('events') is deprecated", "data-events");
353 return oldFnData
.apply( this, arguments
);
357 var rscriptType
= /\/(java|ecma)script/i,
358 oldSelf
= jQuery
.fn
.andSelf
|| jQuery
.fn
.addBack
;
360 jQuery
.fn
.andSelf = function() {
361 migrateWarn("jQuery.fn.andSelf() replaced by jQuery.fn.addBack()", "andSelf");
362 return oldSelf
.apply( this, arguments
);
365 // Since jQuery.clean is used internally on older versions, we only shim if it's missing
366 if ( !jQuery
.clean
) {
367 jQuery
.clean = function( elems
, context
, fragment
, scripts
) {
368 // Set context per 1.8 logic
369 context
= context
|| document
;
370 context
= !context
.nodeType
&& context
[0] || context
;
371 context
= context
.ownerDocument
|| context
;
373 migrateWarn("jQuery.clean() is deprecated", "clean");
375 var i
, elem
, handleScript
, jsTags
,
378 jQuery
.merge( ret
, jQuery
.buildFragment( elems
, context
).childNodes
);
380 // Complex logic lifted directly from jQuery 1.8
382 // Special handling of each script element
383 handleScript = function( elem
) {
384 // Check if we consider it executable
385 if ( !elem
.type
|| rscriptType
.test( elem
.type
) ) {
386 // Detach the script and store it in the scripts array (if provided) or the fragment
387 // Return truthy to indicate that it has been handled
389 scripts
.push( elem
.parentNode
? elem
.parentNode
.removeChild( elem
) : elem
) :
390 fragment
.appendChild( elem
);
394 for ( i
= 0; (elem
= ret
[i
]) != null; i
++ ) {
395 // Check if we're done after handling an executable script
396 if ( !( jQuery
.nodeName( elem
, "script" ) && handleScript( elem
) ) ) {
397 // Append to fragment and handle embedded scripts
398 fragment
.appendChild( elem
);
399 if ( typeof elem
.getElementsByTagName
!== "undefined" ) {
400 // handleScript alters the DOM, so use jQuery.merge to ensure snapshot iteration
401 jsTags
= jQuery
.grep( jQuery
.merge( [], elem
.getElementsByTagName("script") ), handleScript
);
403 // Splice the scripts into ret after their former ancestor and advance our index beyond them
404 ret
.splice
.apply( ret
, [i
+ 1, 0].concat( jsTags
) );
415 var eventAdd
= jQuery
.event
.add
,
416 eventRemove
= jQuery
.event
.remove
,
417 eventTrigger
= jQuery
.event
.trigger
,
418 oldToggle
= jQuery
.fn
.toggle
,
419 oldLive
= jQuery
.fn
.live
,
420 oldDie
= jQuery
.fn
.die
,
421 ajaxEvents
= "ajaxStart|ajaxStop|ajaxSend|ajaxComplete|ajaxError|ajaxSuccess",
422 rajaxEvent
= new RegExp( "\\b(?:" + ajaxEvents
+ ")\\b" ),
423 rhoverHack
= /(?:^|\s)hover(\.\S+|)\b/,
424 hoverHack = function( events
) {
425 if ( typeof( events
) !== "string" || jQuery
.event
.special
.hover
) {
428 if ( rhoverHack
.test( events
) ) {
429 migrateWarn("'hover' pseudo-event is deprecated, use 'mouseenter mouseleave'", "event-hover");
431 return events
&& events
.replace( rhoverHack
, "mouseenter$1 mouseleave$1" );
434 // Event props removed in 1.9, put them back if needed; no practical way to warn them
435 if ( jQuery
.event
.props
&& jQuery
.event
.props
[ 0 ] !== "attrChange" ) {
436 jQuery
.event
.props
.unshift( "attrChange", "attrName", "relatedNode", "srcElement" );
439 // Undocumented jQuery.event.handle was "deprecated" in jQuery 1.7
440 if ( jQuery
.event
.dispatch
) {
441 migrateWarnProp( jQuery
.event
, "handle", jQuery
.event
.dispatch
, "jQuery.event.handle is undocumented and deprecated", "event-handle" );
444 // Support for 'hover' pseudo-event and ajax event warnings
445 jQuery
.event
.add = function( elem
, types
, handler
, data
, selector
){
446 if ( elem
!== document
&& rajaxEvent
.test( types
) ) {
447 migrateWarn( "AJAX events should be attached to document: " + types
, "event-ajax" );
449 eventAdd
.call( this, elem
, hoverHack( types
|| "" ), handler
, data
, selector
);
451 jQuery
.event
.remove = function( elem
, types
, handler
, selector
, mappedTypes
){
452 eventRemove
.call( this, elem
, hoverHack( types
) || "", handler
, selector
, mappedTypes
);
455 jQuery
.fn
.error = function() {
456 var args
= Array
.prototype.slice
.call( arguments
, 0);
457 migrateWarn("jQuery.fn.error() is deprecated", "bind-error");
458 args
.splice( 0, 0, "error" );
459 if ( arguments
.length
) {
460 return this.bind
.apply( this, args
);
462 // error event should not bubble to window, although it does pre-1.7
463 this.triggerHandler
.apply( this, args
);
467 jQuery
.fn
.toggle = function( fn
, fn2
) {
469 // Don't mess with animation or css toggles
470 if ( !jQuery
.isFunction( fn
) || !jQuery
.isFunction( fn2
) ) {
471 return oldToggle
.apply( this, arguments
);
473 migrateWarn("jQuery.fn.toggle(handler, handler...) is deprecated", "toggle-handle");
475 // Save reference to arguments for access in closure
476 var args
= arguments
,
477 guid
= fn
.guid
|| jQuery
.guid
++,
479 toggler = function( event
) {
480 // Figure out which function to execute
481 var lastToggle
= ( jQuery
._data( this, "lastToggle" + fn
.guid
) || 0 ) % i
;
482 jQuery
._data( this, "lastToggle" + fn
.guid
, lastToggle
+ 1 );
484 // Make sure that clicks stop
485 event
.preventDefault();
487 // and execute the function
488 return args
[ lastToggle
].apply( this, arguments
) || false;
491 // link all the functions, so any of them can unbind this click handler
493 while ( i
< args
.length
) {
494 args
[ i
++ ].guid
= guid
;
497 return this.click( toggler
);
500 jQuery
.fn
.live = function( types
, data
, fn
) {
501 migrateWarn("jQuery.fn.live() is deprecated", "live");
503 return oldLive
.apply( this, arguments
);
505 jQuery( this.context
).on( types
, this.selector
, data
, fn
);
509 jQuery
.fn
.die = function( types
, fn
) {
510 migrateWarn("jQuery.fn.die() is deprecated", "die");
512 return oldDie
.apply( this, arguments
);
514 jQuery( this.context
).off( types
, this.selector
|| "**", fn
);
518 // Turn global events into document-triggered events
519 jQuery
.event
.trigger = function( event
, data
, elem
, onlyHandlers
){
520 if ( !elem
&& !rajaxEvent
.test( event
) ) {
521 migrateWarn( "Global events are undocumented and deprecated", "event-global" );
523 return eventTrigger
.call( this, event
, data
, elem
|| document
, onlyHandlers
);
525 jQuery
.each( ajaxEvents
.split("|"),
526 function( _
, name
) {
527 jQuery
.event
.special
[ name
] = {
531 // The document needs no shimming; must be !== for oldIE
532 if ( elem
!== document
) {
533 jQuery
.event
.add( document
, name
+ "." + jQuery
.guid
, function() {
534 jQuery
.event
.trigger( name
, null, elem
, true );
536 jQuery
._data( this, name
, jQuery
.guid
++ );
540 teardown: function() {
541 if ( this !== document
) {
542 jQuery
.event
.remove( document
, name
+ "." + jQuery
._data( this, name
) );
551 })( jQuery
, window
);