summaryrefslogtreecommitdiff
path: root/resources/src/jquery
diff options
context:
space:
mode:
Diffstat (limited to 'resources/src/jquery')
-rw-r--r--resources/src/jquery/jquery.accessKeyLabel.js6
-rw-r--r--resources/src/jquery/jquery.autoEllipsis.js38
-rw-r--r--resources/src/jquery/jquery.byteLimit.js29
-rw-r--r--resources/src/jquery/jquery.color.js12
-rw-r--r--resources/src/jquery/jquery.colorUtil.js150
-rw-r--r--resources/src/jquery/jquery.expandableField.js23
-rw-r--r--resources/src/jquery/jquery.farbtastic.js8
-rw-r--r--resources/src/jquery/jquery.getAttrs.js4
-rw-r--r--resources/src/jquery/jquery.hidpi.js59
-rw-r--r--resources/src/jquery/jquery.highlightText.js21
-rw-r--r--resources/src/jquery/jquery.localize.js8
-rw-r--r--resources/src/jquery/jquery.makeCollapsible.js9
-rw-r--r--resources/src/jquery/jquery.mwExtension.js37
-rw-r--r--resources/src/jquery/jquery.placeholder.js279
-rw-r--r--resources/src/jquery/jquery.qunit.completenessTest.js31
-rw-r--r--resources/src/jquery/jquery.spinner.js2
-rw-r--r--resources/src/jquery/jquery.suggestions.js58
-rw-r--r--resources/src/jquery/jquery.tablesorter.js419
-rw-r--r--resources/src/jquery/jquery.textSelection.js11
19 files changed, 679 insertions, 525 deletions
diff --git a/resources/src/jquery/jquery.accessKeyLabel.js b/resources/src/jquery/jquery.accessKeyLabel.js
index 867c25e7..92f8eb9c 100644
--- a/resources/src/jquery/jquery.accessKeyLabel.js
+++ b/resources/src/jquery/jquery.accessKeyLabel.js
@@ -112,7 +112,7 @@ function getAccessKeyLabel( element ) {
*/
function updateTooltipOnElement( element, titleElement ) {
var array = ( mw.msg( 'word-separator' ) + mw.msg( 'brackets' ) ).split( '$1' ),
- regexp = new RegExp( $.map( array, $.escapeRE ).join( '.*?' ) + '$' ),
+ regexp = new RegExp( $.map( array, mw.RegExp.escape ).join( '.*?' ) + '$' ),
oldTitle = titleElement.title,
rawTitle = oldTitle.replace( regexp, '' ),
newTitle = rawTitle,
@@ -150,14 +150,14 @@ function updateTooltip( element ) {
if ( id ) {
$label = $( 'label[for="' + id + '"]' );
if ( $label.length === 1 ) {
- updateTooltipOnElement( element, $label[0] );
+ updateTooltipOnElement( element, $label[ 0 ] );
}
}
// Search it as parent, because the form control can also be inside the label element itself
$labelParent = $element.parents( 'label' );
if ( $labelParent.length === 1 ) {
- updateTooltipOnElement( element, $labelParent[0] );
+ updateTooltipOnElement( element, $labelParent[ 0 ] );
}
}
}
diff --git a/resources/src/jquery/jquery.autoEllipsis.js b/resources/src/jquery/jquery.autoEllipsis.js
index 9a196b5d..e1115d65 100644
--- a/resources/src/jquery/jquery.autoEllipsis.js
+++ b/resources/src/jquery/jquery.autoEllipsis.js
@@ -69,16 +69,16 @@ $.fn.autoEllipsis = function ( options ) {
// Try cache
if ( options.matchText ) {
if ( !( text in matchTextCache ) ) {
- matchTextCache[text] = {};
+ matchTextCache[ text ] = {};
}
- if ( !( options.matchText in matchTextCache[text] ) ) {
- matchTextCache[text][options.matchText] = {};
+ if ( !( options.matchText in matchTextCache[ text ] ) ) {
+ matchTextCache[ text ][ options.matchText ] = {};
}
- if ( !( w in matchTextCache[text][options.matchText] ) ) {
- matchTextCache[text][options.matchText][w] = {};
+ if ( !( w in matchTextCache[ text ][ options.matchText ] ) ) {
+ matchTextCache[ text ][ options.matchText ][ w ] = {};
}
- if ( options.position in matchTextCache[text][options.matchText][w] ) {
- $container.html( matchTextCache[text][options.matchText][w][options.position] );
+ if ( options.position in matchTextCache[ text ][ options.matchText ][ w ] ) {
+ $container.html( matchTextCache[ text ][ options.matchText ][ w ][ options.position ] );
if ( options.tooltip ) {
$container.attr( 'title', text );
}
@@ -86,13 +86,13 @@ $.fn.autoEllipsis = function ( options ) {
}
} else {
if ( !( text in cache ) ) {
- cache[text] = {};
+ cache[ text ] = {};
}
- if ( !( w in cache[text] ) ) {
- cache[text][w] = {};
+ if ( !( w in cache[ text ] ) ) {
+ cache[ text ][ w ] = {};
}
- if ( options.position in cache[text][w] ) {
- $container.html( cache[text][w][options.position] );
+ if ( options.position in cache[ text ][ w ] ) {
+ $container.html( cache[ text ][ w ][ options.position ] );
if ( options.tooltip ) {
$container.attr( 'title', text );
}
@@ -120,19 +120,19 @@ $.fn.autoEllipsis = function ( options ) {
break;
case 'center':
// TODO: Use binary search like for 'right'
- i = [Math.round( trimmableText.length / 2 ), Math.round( trimmableText.length / 2 )];
+ i = [ Math.round( trimmableText.length / 2 ), Math.round( trimmableText.length / 2 ) ];
// Begin with making the end shorter
side = 1;
- while ( $trimmableText.outerWidth() + pw > w && i[0] > 0 ) {
- $trimmableText.text( trimmableText.slice( 0, i[0] ) + '...' + trimmableText.slice( i[1] ) );
+ while ( $trimmableText.outerWidth() + pw > w && i[ 0 ] > 0 ) {
+ $trimmableText.text( trimmableText.slice( 0, i[ 0 ] ) + '...' + trimmableText.slice( i[ 1 ] ) );
// Alternate between trimming the end and begining
if ( side === 0 ) {
// Make the begining shorter
- i[0]--;
+ i[ 0 ]--;
side = 1;
} else {
// Make the end shorter
- i[1]++;
+ i[ 1 ]++;
side = 0;
}
}
@@ -152,9 +152,9 @@ $.fn.autoEllipsis = function ( options ) {
}
if ( options.matchText ) {
$container.highlightText( options.matchText );
- matchTextCache[text][options.matchText][w][options.position] = $container.html();
+ matchTextCache[ text ][ options.matchText ][ w ][ options.position ] = $container.html();
} else {
- cache[text][w][options.position] = $container.html();
+ cache[ text ][ w ][ options.position ] = $container.html();
}
} );
diff --git a/resources/src/jquery/jquery.byteLimit.js b/resources/src/jquery/jquery.byteLimit.js
index 5551232a..dd71a2bc 100644
--- a/resources/src/jquery/jquery.byteLimit.js
+++ b/resources/src/jquery/jquery.byteLimit.js
@@ -10,17 +10,17 @@
* "fobo", not "foba". Basically emulating the native maxlength by
* reconstructing where the insertion occurred.
*
- * @private
+ * @static
* @param {string} safeVal Known value that was previously returned by this
* function, if none, pass empty string.
* @param {string} newVal New value that may have to be trimmed down.
* @param {number} byteLimit Number of bytes the value may be in size.
- * @param {Function} [fn] See jQuery.byteLimit.
+ * @param {Function} [fn] See jQuery#byteLimit.
* @return {Object}
* @return {string} return.newVal
* @return {boolean} return.trimmed
*/
- function trimValForByteLength( safeVal, newVal, byteLimit, fn ) {
+ $.trimByteLength = function ( safeVal, newVal, byteLimit, fn ) {
var startMatches, endMatches, matchesLen, inpParts,
oldVal = safeVal;
@@ -77,22 +77,22 @@
// until the limit is statisfied.
if ( fn ) {
// stop, when there is nothing to slice - bug 41450
- while ( $.byteLength( fn( inpParts.join( '' ) ) ) > byteLimit && inpParts[1].length > 0 ) {
- inpParts[1] = inpParts[1].slice( 0, -1 );
+ while ( $.byteLength( fn( inpParts.join( '' ) ) ) > byteLimit && inpParts[ 1 ].length > 0 ) {
+ inpParts[ 1 ] = inpParts[ 1 ].slice( 0, -1 );
}
} else {
while ( $.byteLength( inpParts.join( '' ) ) > byteLimit ) {
- inpParts[1] = inpParts[1].slice( 0, -1 );
+ inpParts[ 1 ] = inpParts[ 1 ].slice( 0, -1 );
}
}
- newVal = inpParts.join( '' );
-
return {
- newVal: newVal,
- trimmed: true
+ newVal: inpParts.join( '' ),
+ // For pathological fn() that always returns a value longer than the limit, we might have
+ // ended up not trimming - check for this case to avoid infinite loops
+ trimmed: newVal !== inpParts.join( '' )
};
- }
+ };
var eventKeys = [
'keyup.byteLimit',
@@ -206,7 +206,7 @@
// See http://www.w3.org/TR/DOM-Level-3-Events/#events-keyboard-event-order for
// the order and characteristics of the key events.
$el.on( eventKeys, function () {
- var res = trimValForByteLength(
+ var res = $.trimByteLength(
prevSafeVal,
this.value,
elLimit,
@@ -219,9 +219,12 @@
// This is a side-effect of limiting after the fact.
if ( res.trimmed === true ) {
this.value = res.newVal;
+ // Trigger a 'change' event to let other scripts attached to this node know that the value
+ // was changed. This will also call ourselves again, but that's okay, it'll be a no-op.
+ $el.trigger( 'change' );
}
// Always adjust prevSafeVal to reflect the input value. Not doing this could cause
- // trimValForByteLength to compare the new value to an empty string instead of the
+ // trimByteLength to compare the new value to an empty string instead of the
// old value, resulting in trimming always from the end (bug 40850).
prevSafeVal = res.newVal;
} );
diff --git a/resources/src/jquery/jquery.color.js b/resources/src/jquery/jquery.color.js
index 04f8047b..a3cc8fc3 100644
--- a/resources/src/jquery/jquery.color.js
+++ b/resources/src/jquery/jquery.color.js
@@ -28,7 +28,7 @@
}
// We override the animation for all of these color styles
- $.each([
+ $.each( [
'backgroundColor',
'borderBottomColor',
'borderLeftColor',
@@ -37,17 +37,17 @@
'color',
'outlineColor'
], function ( i, attr ) {
- $.fx.step[attr] = function ( fx ) {
+ $.fx.step[ attr ] = function ( fx ) {
if ( !fx.colorInit ) {
fx.start = getColor( fx.elem, attr );
fx.end = $.colorUtil.getRGB( fx.end );
fx.colorInit = true;
}
- fx.elem.style[attr] = 'rgb(' + [
- Math.max( Math.min( parseInt( (fx.pos * (fx.end[0] - fx.start[0])) + fx.start[0], 10 ), 255 ), 0 ),
- Math.max( Math.min( parseInt( (fx.pos * (fx.end[1] - fx.start[1])) + fx.start[1], 10 ), 255 ), 0 ),
- Math.max( Math.min( parseInt( (fx.pos * (fx.end[2] - fx.start[2])) + fx.start[2], 10 ), 255 ), 0 )
+ fx.elem.style[ attr ] = 'rgb(' + [
+ Math.max( Math.min( parseInt( ( fx.pos * ( fx.end[ 0 ] - fx.start[ 0 ] ) ) + fx.start[ 0 ], 10 ), 255 ), 0 ),
+ Math.max( Math.min( parseInt( ( fx.pos * ( fx.end[ 1 ] - fx.start[ 1 ] ) ) + fx.start[ 1 ], 10 ), 255 ), 0 ),
+ Math.max( Math.min( parseInt( ( fx.pos * ( fx.end[ 2 ] - fx.start[ 2 ] ) ) + fx.start[ 2 ], 10 ), 255 ), 0 )
].join( ',' ) + ')';
};
} );
diff --git a/resources/src/jquery/jquery.colorUtil.js b/resources/src/jquery/jquery.colorUtil.js
index a6ff8bc8..c14f2c86 100644
--- a/resources/src/jquery/jquery.colorUtil.js
+++ b/resources/src/jquery/jquery.colorUtil.js
@@ -32,48 +32,48 @@
}
// Look for rgb(num,num,num)
- if (result = /rgb\(\s*([0-9]{1,3})\s*,\s*([0-9]{1,3})\s*,\s*([0-9]{1,3})\s*\)/.exec(color)) {
+ if ( result = /rgb\(\s*([0-9]{1,3})\s*,\s*([0-9]{1,3})\s*,\s*([0-9]{1,3})\s*\)/.exec( color ) ) {
return [
- parseInt( result[1], 10 ),
- parseInt( result[2], 10 ),
- parseInt( result[3], 10 )
+ parseInt( result[ 1 ], 10 ),
+ parseInt( result[ 2 ], 10 ),
+ parseInt( result[ 3 ], 10 )
];
}
// Look for rgb(num%,num%,num%)
- if (result = /rgb\(\s*([0-9]+(?:\.[0-9]+)?)\%\s*,\s*([0-9]+(?:\.[0-9]+)?)\%\s*,\s*([0-9]+(?:\.[0-9]+)?)\%\s*\)/.exec(color)) {
+ if ( result = /rgb\(\s*([0-9]+(?:\.[0-9]+)?)\%\s*,\s*([0-9]+(?:\.[0-9]+)?)\%\s*,\s*([0-9]+(?:\.[0-9]+)?)\%\s*\)/.exec( color ) ) {
return [
- parseFloat( result[1] ) * 2.55,
- parseFloat( result[2] ) * 2.55,
- parseFloat( result[3] ) * 2.55
+ parseFloat( result[ 1 ] ) * 2.55,
+ parseFloat( result[ 2 ] ) * 2.55,
+ parseFloat( result[ 3 ] ) * 2.55
];
}
// Look for #a0b1c2
- if (result = /#([a-fA-F0-9]{2})([a-fA-F0-9]{2})([a-fA-F0-9]{2})/.exec(color)) {
+ if ( result = /#([a-fA-F0-9]{2})([a-fA-F0-9]{2})([a-fA-F0-9]{2})/.exec( color ) ) {
return [
- parseInt( result[1], 16 ),
- parseInt( result[2], 16 ),
- parseInt( result[3], 16 )
+ parseInt( result[ 1 ], 16 ),
+ parseInt( result[ 2 ], 16 ),
+ parseInt( result[ 3 ], 16 )
];
}
// Look for #fff
- if (result = /#([a-fA-F0-9])([a-fA-F0-9])([a-fA-F0-9])/.exec(color)) {
+ if ( result = /#([a-fA-F0-9])([a-fA-F0-9])([a-fA-F0-9])/.exec( color ) ) {
return [
- parseInt( result[1] + result[1], 16 ),
- parseInt( result[2] + result[2], 16 ),
- parseInt( result[3] + result[3], 16)
+ parseInt( result[ 1 ] + result[ 1 ], 16 ),
+ parseInt( result[ 2 ] + result[ 2 ], 16 ),
+ parseInt( result[ 3 ] + result[ 3 ], 16 )
];
}
// Look for rgba(0, 0, 0, 0) == transparent in Safari 3
- if (result = /rgba\(0, 0, 0, 0\)/.exec(color)) {
+ if ( result = /rgba\(0, 0, 0, 0\)/.exec( color ) ) {
return $.colorUtil.colors.transparent;
}
// Otherwise, we're most likely dealing with a named color
- return $.colorUtil.colors[$.trim(color).toLowerCase()];
+ return $.colorUtil.colors[ $.trim( color ).toLowerCase() ];
},
/**
@@ -85,50 +85,50 @@
* @property {Object}
*/
colors: {
- aqua: [0, 255, 255],
- azure: [240, 255, 255],
- beige: [245, 245, 220],
- black: [0, 0, 0],
- blue: [0, 0, 255],
- brown: [165, 42, 42],
- cyan: [0, 255, 255],
- darkblue: [0, 0, 139],
- darkcyan: [0, 139, 139],
- darkgrey: [169, 169, 169],
- darkgreen: [0, 100, 0],
- darkkhaki: [189, 183, 107],
- darkmagenta: [139, 0, 139],
- darkolivegreen: [85, 107, 47],
- darkorange: [255, 140, 0],
- darkorchid: [153, 50, 204],
- darkred: [139, 0, 0],
- darksalmon: [233, 150, 122],
- darkviolet: [148, 0, 211],
- fuchsia: [255, 0, 255],
- gold: [255, 215, 0],
- green: [0, 128, 0],
- indigo: [75, 0, 130],
- khaki: [240, 230, 140],
- lightblue: [173, 216, 230],
- lightcyan: [224, 255, 255],
- lightgreen: [144, 238, 144],
- lightgrey: [211, 211, 211],
- lightpink: [255, 182, 193],
- lightyellow: [255, 255, 224],
- lime: [0, 255, 0],
- magenta: [255, 0, 255],
- maroon: [128, 0, 0],
- navy: [0, 0, 128],
- olive: [128, 128, 0],
- orange: [255, 165, 0],
- pink: [255, 192, 203],
- purple: [128, 0, 128],
- violet: [128, 0, 128],
- red: [255, 0, 0],
- silver: [192, 192, 192],
- white: [255, 255, 255],
- yellow: [255, 255, 0],
- transparent: [255, 255, 255]
+ aqua: [ 0, 255, 255 ],
+ azure: [ 240, 255, 255 ],
+ beige: [ 245, 245, 220 ],
+ black: [ 0, 0, 0 ],
+ blue: [ 0, 0, 255 ],
+ brown: [ 165, 42, 42 ],
+ cyan: [ 0, 255, 255 ],
+ darkblue: [ 0, 0, 139 ],
+ darkcyan: [ 0, 139, 139 ],
+ darkgrey: [ 169, 169, 169 ],
+ darkgreen: [ 0, 100, 0 ],
+ darkkhaki: [ 189, 183, 107 ],
+ darkmagenta: [ 139, 0, 139 ],
+ darkolivegreen: [ 85, 107, 47 ],
+ darkorange: [ 255, 140, 0 ],
+ darkorchid: [ 153, 50, 204 ],
+ darkred: [ 139, 0, 0 ],
+ darksalmon: [ 233, 150, 122 ],
+ darkviolet: [ 148, 0, 211 ],
+ fuchsia: [ 255, 0, 255 ],
+ gold: [ 255, 215, 0 ],
+ green: [ 0, 128, 0 ],
+ indigo: [ 75, 0, 130 ],
+ khaki: [ 240, 230, 140 ],
+ lightblue: [ 173, 216, 230 ],
+ lightcyan: [ 224, 255, 255 ],
+ lightgreen: [ 144, 238, 144 ],
+ lightgrey: [ 211, 211, 211 ],
+ lightpink: [ 255, 182, 193 ],
+ lightyellow: [ 255, 255, 224 ],
+ lime: [ 0, 255, 0 ],
+ magenta: [ 255, 0, 255 ],
+ maroon: [ 128, 0, 0 ],
+ navy: [ 0, 0, 128 ],
+ olive: [ 128, 128, 0 ],
+ orange: [ 255, 165, 0 ],
+ pink: [ 255, 192, 203 ],
+ purple: [ 128, 0, 128 ],
+ violet: [ 128, 0, 128 ],
+ red: [ 255, 0, 0 ],
+ silver: [ 192, 192, 192 ],
+ white: [ 255, 255, 255 ],
+ yellow: [ 255, 255, 0 ],
+ transparent: [ 255, 255, 255 ]
},
/**
@@ -157,29 +157,29 @@
min = Math.min( r, g, b ),
h,
s,
- l = (max + min) / 2;
+ l = ( max + min ) / 2;
if ( max === min ) {
// achromatic
h = s = 0;
} else {
d = max - min;
- s = l > 0.5 ? d / (2 - max - min) : d / (max + min);
+ s = l > 0.5 ? d / ( 2 - max - min ) : d / ( max + min );
switch ( max ) {
case r:
- h = (g - b) / d + (g < b ? 6 : 0);
+ h = ( g - b ) / d + ( g < b ? 6 : 0 );
break;
case g:
- h = (b - r) / d + 2;
+ h = ( b - r ) / d + 2;
break;
case b:
- h = (r - g) / d + 4;
+ h = ( r - g ) / d + 4;
break;
}
h /= 6;
}
- return [h, s, l];
+ return [ h, s, l ];
},
/**
@@ -212,25 +212,25 @@
t -= 1;
}
if ( t < 1 / 6 ) {
- return p + (q - p) * 6 * t;
+ return p + ( q - p ) * 6 * t;
}
if ( t < 1 / 2 ) {
return q;
}
if ( t < 2 / 3 ) {
- return p + (q - p) * (2 / 3 - t) * 6;
+ return p + ( q - p ) * ( 2 / 3 - t ) * 6;
}
return p;
};
- q = l < 0.5 ? l * (1 + s) : l + s - l * s;
+ q = l < 0.5 ? l * ( 1 + s ) : l + s - l * s;
p = 2 * l - q;
r = hue2rgb( p, q, h + 1 / 3 );
g = hue2rgb( p, q, h );
b = hue2rgb( p, q, h - 1 / 3 );
}
- return [r * 255, g * 255, b * 255];
+ return [ r * 255, g * 255, b * 255 ];
},
/**
@@ -249,11 +249,11 @@
*/
getColorBrightness: function ( currentColor, mod ) {
var rgbArr = $.colorUtil.getRGB( currentColor ),
- hslArr = $.colorUtil.rgbToHsl(rgbArr[0], rgbArr[1], rgbArr[2] );
- rgbArr = $.colorUtil.hslToRgb(hslArr[0], hslArr[1], hslArr[2] + mod);
+ hslArr = $.colorUtil.rgbToHsl( rgbArr[ 0 ], rgbArr[ 1 ], rgbArr[ 2 ] );
+ rgbArr = $.colorUtil.hslToRgb( hslArr[ 0 ], hslArr[ 1 ], hslArr[ 2 ] + mod );
return 'rgb(' +
- [parseInt( rgbArr[0], 10), parseInt( rgbArr[1], 10 ), parseInt( rgbArr[2], 10 )].join( ',' ) +
+ [ parseInt( rgbArr[ 0 ], 10 ), parseInt( rgbArr[ 1 ], 10 ), parseInt( rgbArr[ 2 ], 10 ) ].join( ',' ) +
')';
}
diff --git a/resources/src/jquery/jquery.expandableField.js b/resources/src/jquery/jquery.expandableField.js
index 48341bc5..221e6bbe 100644
--- a/resources/src/jquery/jquery.expandableField.js
+++ b/resources/src/jquery/jquery.expandableField.js
@@ -23,7 +23,7 @@
expandField: function ( e, context ) {
context.config.beforeExpand.call( context.data.$field, context );
context.data.$field
- .animate( { 'width': context.data.expandedWidth }, 'fast', function () {
+ .animate( { width: context.data.expandedWidth }, 'fast', function () {
context.config.afterExpand.call( this, context );
} );
},
@@ -33,18 +33,19 @@
condenseField: function ( e, context ) {
context.config.beforeCondense.call( context.data.$field, context );
context.data.$field
- .animate( { 'width': context.data.condensedWidth }, 'fast', function () {
+ .animate( { width: context.data.condensedWidth }, 'fast', function () {
context.config.afterCondense.call( this, context );
} );
},
/**
* Sets the value of a property, and updates the widget accordingly
- * @param property String Name of property
- * @param value Mixed Value to set property with
+ *
+ * @param {String} property Name of property
+ * @param {Mixed} value Value to set property with
*/
configure: function ( context, property, value ) {
// TODO: Validate creation using fallback values
- context.config[property] = value;
+ context.config[ property ] = value;
}
};
@@ -87,20 +88,20 @@
/* API */
// Handle various calling styles
if ( args.length > 0 ) {
- if ( typeof args[0] === 'object' ) {
+ if ( typeof args[ 0 ] === 'object' ) {
// Apply set of properties
- for ( key in args[0] ) {
- $.expandableField.configure( context, key, args[0][key] );
+ for ( key in args[ 0 ] ) {
+ $.expandableField.configure( context, key, args[ 0 ][ key ] );
}
- } else if ( typeof args[0] === 'string' ) {
+ } else if ( typeof args[ 0 ] === 'string' ) {
if ( args.length > 1 ) {
// Set property values
- $.expandableField.configure( context, args[0], args[1] );
+ $.expandableField.configure( context, args[ 0 ], args[ 1 ] );
// TODO: Do we need to check both null and undefined?
} else if ( returnValue === null || returnValue === undefined ) {
// Get property values, but don't give access to internal data - returns only the first
- returnValue = ( args[0] in context.config ? undefined : context.config[args[0]] );
+ returnValue = ( args[ 0 ] in context.config ? undefined : context.config[ args[ 0 ] ] );
}
}
}
diff --git a/resources/src/jquery/jquery.farbtastic.js b/resources/src/jquery/jquery.farbtastic.js
index d7024cc8..f70913f9 100644
--- a/resources/src/jquery/jquery.farbtastic.js
+++ b/resources/src/jquery/jquery.farbtastic.js
@@ -52,10 +52,10 @@ jQuery._farbtastic = function (container, callback) {
if (this.currentStyle.backgroundImage != 'none') {
var image = this.currentStyle.backgroundImage;
image = this.currentStyle.backgroundImage.slice(5, image.length - 2);
- $(this).css({
- 'backgroundImage': 'none',
- 'filter': "progid:DXImageTransform.Microsoft.AlphaImageLoader(enabled=true, sizingMethod=crop, src='" + image + "')"
- });
+ $(this).css( {
+ backgroundImage: 'none',
+ filter: "progid:DXImageTransform.Microsoft.AlphaImageLoader(enabled=true, sizingMethod=crop, src='" + image + "')"
+ } );
}
});
}
diff --git a/resources/src/jquery/jquery.getAttrs.js b/resources/src/jquery/jquery.getAttrs.js
index 64827fb7..3064b423 100644
--- a/resources/src/jquery/jquery.getAttrs.js
+++ b/resources/src/jquery/jquery.getAttrs.js
@@ -8,7 +8,7 @@ function serializeControls( controls ) {
len = controls.length;
for ( i = 0; i < len; i++ ) {
- data[ controls[i].name ] = controls[i].value;
+ data[ controls[ i ].name ] = controls[ i ].value;
}
return data;
@@ -23,7 +23,7 @@ function serializeControls( controls ) {
* @return {Object}
*/
jQuery.fn.getAttrs = function () {
- return serializeControls( this[0].attributes );
+ return serializeControls( this[ 0 ].attributes );
};
/**
diff --git a/resources/src/jquery/jquery.hidpi.js b/resources/src/jquery/jquery.hidpi.js
index 8fca0567..aa6590bf 100644
--- a/resources/src/jquery/jquery.hidpi.js
+++ b/resources/src/jquery/jquery.hidpi.js
@@ -27,14 +27,15 @@
$.devicePixelRatio = function () {
if ( window.devicePixelRatio !== undefined ) {
// Most web browsers:
- // * WebKit (Safari, Chrome, Android browser, etc)
+ // * WebKit/Blink (Safari, Chrome, Android browser, etc)
// * Opera
// * Firefox 18+
+ // * Microsoft Edge (Windows 10)
return window.devicePixelRatio;
} else if ( window.msMatchMedia !== undefined ) {
// Windows 8 desktops / tablets, probably Windows Phone 8
//
- // IE 10 doesn't report pixel ratio directly, but we can get the
+ // IE 10/11 doesn't report pixel ratio directly, but we can get the
// screen DPI and divide by 96. We'll bracket to [1, 1.5, 2.0] for
// simplicity, but you may get different values depending on zoom
// factor, size of screen and orientation in Metro IE.
@@ -53,6 +54,52 @@ $.devicePixelRatio = function () {
};
/**
+ * Bracket a given device pixel ratio to one of [1, 1.5, 2].
+ *
+ * This is useful for grabbing images on the fly with sizes based on the display
+ * density, without causing slowdown and extra thumbnail renderings on devices
+ * that are slightly different from the most common sizes.
+ *
+ * The bracketed ratios match the default 'srcset' output on MediaWiki thumbnails,
+ * so will be consistent with default renderings.
+ *
+ * @static
+ * @inheritable
+ * @return {number} Device pixel ratio
+ */
+$.bracketDevicePixelRatio = function ( baseRatio ) {
+ if ( baseRatio > 1.5 ) {
+ return 2;
+ } else if ( baseRatio > 1 ) {
+ return 1.5;
+ } else {
+ return 1;
+ }
+};
+
+/**
+ * Get reported or approximate device pixel ratio, bracketed to [1, 1.5, 2].
+ *
+ * This is useful for grabbing images on the fly with sizes based on the display
+ * density, without causing slowdown and extra thumbnail renderings on devices
+ * that are slightly different from the most common sizes.
+ *
+ * The bracketed ratios match the default 'srcset' output on MediaWiki thumbnails,
+ * so will be consistent with default renderings.
+ *
+ * - 1.0 means 1 CSS pixel is 1 hardware pixel
+ * - 1.5 means 1 CSS pixel is 1.5 hardware pixels
+ * - 2.0 means 1 CSS pixel is 2 hardware pixels
+ *
+ * @static
+ * @inheritable
+ * @return {number} Device pixel ratio
+ */
+$.bracketedDevicePixelRatio = function () {
+ return $.bracketDevicePixelRatio( $.devicePixelRatio() );
+};
+
+/**
* Implement responsive images based on srcset attributes, if browser has no
* native srcset support.
*
@@ -106,11 +153,11 @@ $.matchSrcSet = function ( devicePixelRatio, srcset ) {
selectedSrc = null;
candidates = srcset.split( / *, */ );
for ( i = 0; i < candidates.length; i++ ) {
- candidate = candidates[i];
+ candidate = candidates[ i ];
bits = candidate.split( / +/ );
- src = bits[0];
- if ( bits.length > 1 && bits[1].charAt( bits[1].length - 1 ) === 'x' ) {
- ratioStr = bits[1].slice( 0, -1 );
+ src = bits[ 0 ];
+ if ( bits.length > 1 && bits[ 1 ].charAt( bits[ 1 ].length - 1 ) === 'x' ) {
+ ratioStr = bits[ 1 ].slice( 0, -1 );
ratio = parseFloat( ratioStr );
if ( ratio <= devicePixelRatio && ratio > selectedRatio ) {
selectedRatio = ratio;
diff --git a/resources/src/jquery/jquery.highlightText.js b/resources/src/jquery/jquery.highlightText.js
index 13382182..e37f19b0 100644
--- a/resources/src/jquery/jquery.highlightText.js
+++ b/resources/src/jquery/jquery.highlightText.js
@@ -3,7 +3,7 @@
* TODO: Add a function for restoring the previous text.
* TODO: Accept mappings for converting shortcuts like WP: to Wikipedia:.
*/
-( function ( $ ) {
+( function ( $, mw ) {
$.highlightText = {
@@ -12,10 +12,10 @@
var i,
patArray = pat.split( ' ' );
for ( i = 0; i < patArray.length; i++ ) {
- if ( patArray[i].length === 0 ) {
+ if ( patArray[ i ].length === 0 ) {
continue;
}
- $.highlightText.innerHighlight( node, patArray[i] );
+ $.highlightText.innerHighlight( node, patArray[ i ] );
}
return node;
},
@@ -23,15 +23,14 @@
// scans a node looking for the pattern and wraps a span around each match
innerHighlight: function ( node, pat ) {
var i, match, pos, spannode, middlebit, middleclone;
- // if this is a text node
- if ( node.nodeType === 3 ) {
+ if ( node.nodeType === Node.TEXT_NODE ) {
// TODO - need to be smarter about the character matching here.
// non latin characters can make regex think a new word has begun: do not use \b
// http://stackoverflow.com/questions/3787072/regex-wordwrap-with-utf8-characters-in-js
// look for an occurrence of our pattern and store the starting position
- match = node.data.match( new RegExp( '(^|\\s)' + $.escapeRE( pat ), 'i' ) );
+ match = node.data.match( new RegExp( '(^|\\s)' + mw.RegExp.escape( pat ), 'i' ) );
if ( match ) {
- pos = match.index + match[1].length; // include length of any matched spaces
+ pos = match.index + match[ 1 ].length; // include length of any matched spaces
// create the span wrapper for the matched text
spannode = document.createElement( 'span' );
spannode.className = 'highlight';
@@ -46,8 +45,8 @@
// replace the matched node, with our span-wrapped clone of the matched node
middlebit.parentNode.replaceChild( spannode, middlebit );
}
- // if this is an element with childnodes, and not a script, style or an element we created
- } else if ( node.nodeType === 1
+ } else if ( node.nodeType === Node.ELEMENT_NODE
+ // element with childnodes, and not a script, style or an element we created
&& node.childNodes
&& !/(script|style)/i.test( node.tagName )
&& !( node.tagName.toLowerCase() === 'span'
@@ -56,7 +55,7 @@
) {
for ( i = 0; i < node.childNodes.length; ++i ) {
// call the highlight function for each child node
- $.highlightText.innerHighlight( node.childNodes[i], pat );
+ $.highlightText.innerHighlight( node.childNodes[ i ], pat );
}
}
}
@@ -70,4 +69,4 @@
} );
};
-}( jQuery ) );
+}( jQuery, mediaWiki ) );
diff --git a/resources/src/jquery/jquery.localize.js b/resources/src/jquery/jquery.localize.js
index 0b423545..f5932b24 100644
--- a/resources/src/jquery/jquery.localize.js
+++ b/resources/src/jquery/jquery.localize.js
@@ -5,16 +5,16 @@
/**
* Gets a localized message, using parameters from options if present.
- * @ignore
*
+ * @ignore
* @param {Object} options
* @param {string} key
* @return {string} Localized message
*/
function msg( options, key ) {
- var args = options.params[key] || [];
+ var args = options.params[ key ] || [];
// Format: mw.msg( key [, p1, p2, ...] )
- args.unshift( options.prefix + ( options.keys[key] || key ) );
+ args.unshift( options.prefix + ( options.keys[ key ] || key ) );
return mw.msg.apply( mw, args );
}
@@ -108,7 +108,7 @@ function msg( options, key ) {
*/
$.fn.localize = function ( options ) {
var $target = this,
- attributes = ['title', 'alt', 'placeholder'];
+ attributes = [ 'title', 'alt', 'placeholder' ];
// Extend options
options = $.extend( {
diff --git a/resources/src/jquery/jquery.makeCollapsible.js b/resources/src/jquery/jquery.makeCollapsible.js
index f7c42177..19fdb263 100644
--- a/resources/src/jquery/jquery.makeCollapsible.js
+++ b/resources/src/jquery/jquery.makeCollapsible.js
@@ -159,8 +159,13 @@
}
if ( e ) {
- if ( e.type === 'click' && options.linksPassthru && $.nodeName( e.target, 'a' ) ) {
- // Don't fire if a link was clicked, if requested (for premade togglers by default)
+ if (
+ e.type === 'click' &&
+ options.linksPassthru &&
+ $.nodeName( e.target, 'a' ) &&
+ $( e.target ).attr( 'href' ) !== '#'
+ ) {
+ // Don't fire if a link with href !== '#' was clicked, if requested (for premade togglers by default)
return;
} else if ( e.type === 'keypress' && e.which !== 13 && e.which !== 32 ) {
// Only handle keypresses on the "Enter" or "Space" keys
diff --git a/resources/src/jquery/jquery.mwExtension.js b/resources/src/jquery/jquery.mwExtension.js
index e6e33ade..27ceb2bc 100644
--- a/resources/src/jquery/jquery.mwExtension.js
+++ b/resources/src/jquery/jquery.mwExtension.js
@@ -1,9 +1,11 @@
/*
* JavaScript backwards-compatibility alternatives and other convenience functions
+ *
+ * @deprecated since 1.26 Dated collection of miscellaneous utilities. Methods are
+ * either trivially inline, obsolete, or have a better place elsewhere.
*/
-( function ( $ ) {
-
- $.extend( {
+( function ( $, mw ) {
+ $.each( {
trimLeft: function ( str ) {
return str === null ? '' : str.toString().replace( /^\s+/, '' );
},
@@ -14,9 +16,6 @@
ucFirst: function ( str ) {
return str.charAt( 0 ).toUpperCase() + str.slice( 1 );
},
- escapeRE: function ( str ) {
- return str.replace( /([\\{}()|.?*+\-\^$\[\]])/g, '\\$1' );
- },
isDomElement: function ( el ) {
return !!el && !!el.nodeType;
},
@@ -28,7 +27,7 @@
return true;
}
// the for-loop could potentially contain prototypes
- // to avoid that we check it's length first
+ // to avoid that we check its length first
if ( v.length === 0 ) {
return true;
}
@@ -45,11 +44,11 @@
return false;
}
for ( var i = 0; i < arrThis.length; i++ ) {
- if ( $.isArray( arrThis[i] ) ) {
- if ( !$.compareArray( arrThis[i], arrAgainst[i] ) ) {
+ if ( $.isArray( arrThis[ i ] ) ) {
+ if ( !$.compareArray( arrThis[ i ], arrAgainst[ i ] ) ) {
return false;
}
- } else if ( arrThis[i] !== arrAgainst[i] ) {
+ } else if ( arrThis[ i ] !== arrAgainst[ i ] ) {
return false;
}
}
@@ -72,24 +71,24 @@
// Check if this property is also present in the other object
if ( prop in objectB ) {
// Compare the types of the properties
- type = typeof objectA[prop];
- if ( type === typeof objectB[prop] ) {
+ type = typeof objectA[ prop ];
+ if ( type === typeof objectB[ prop ] ) {
// Recursively check objects inside this one
switch ( type ) {
case 'object' :
- if ( !$.compareObject( objectA[prop], objectB[prop] ) ) {
+ if ( !$.compareObject( objectA[ prop ], objectB[ prop ] ) ) {
return false;
}
break;
case 'function' :
// Functions need to be strings to compare them properly
- if ( objectA[prop].toString() !== objectB[prop].toString() ) {
+ if ( objectA[ prop ].toString() !== objectB[ prop ].toString() ) {
return false;
}
break;
default:
// Strings, numbers
- if ( objectA[prop] !== objectB[prop] ) {
+ if ( objectA[ prop ] !== objectB[ prop ] ) {
return false;
}
break;
@@ -117,6 +116,12 @@
}
return true;
}
+ }, function ( key, value ) {
+ mw.log.deprecate( $, key, value );
} );
-}( jQuery ) );
+ mw.log.deprecate( $, 'escapeRE', function ( str ) {
+ return str.replace( /([\\{}()|.?*+\-\^$\[\]])/g, '\\$1' );
+ }, 'Use mediawiki.RegExp instead.' );
+
+} )( jQuery, mediaWiki );
diff --git a/resources/src/jquery/jquery.placeholder.js b/resources/src/jquery/jquery.placeholder.js
index d50422e2..9c18a919 100644
--- a/resources/src/jquery/jquery.placeholder.js
+++ b/resources/src/jquery/jquery.placeholder.js
@@ -13,23 +13,115 @@
* @version 2.1.0
* @license MIT
*/
-( function ($) {
+( function ( $ ) {
- var isInputSupported = 'placeholder' in document.createElement('input'),
- isTextareaSupported = 'placeholder' in document.createElement('textarea'),
+ var isInputSupported = 'placeholder' in document.createElement( 'input' ),
+ isTextareaSupported = 'placeholder' in document.createElement( 'textarea' ),
prototype = $.fn,
valHooks = $.valHooks,
propHooks = $.propHooks,
hooks,
placeholder;
- if (isInputSupported && isTextareaSupported) {
+ function safeActiveElement() {
+ // Avoid IE9 `document.activeElement` of death
+ // https://github.com/mathiasbynens/jquery-placeholder/pull/99
+ try {
+ return document.activeElement;
+ } catch ( err ) {}
+ }
+
+ function args( elem ) {
+ // Return an object of element attributes
+ var newAttrs = {},
+ rinlinejQuery = /^jQuery\d+$/;
+ $.each( elem.attributes, function ( i, attr ) {
+ if ( attr.specified && !rinlinejQuery.test( attr.name ) ) {
+ newAttrs[ attr.name ] = attr.value;
+ }
+ } );
+ return newAttrs;
+ }
+
+ function clearPlaceholder( event, value ) {
+ var input = this,
+ $input = $( input );
+ if ( input.value === $input.attr( 'placeholder' ) && $input.hasClass( 'placeholder' ) ) {
+ if ( $input.data( 'placeholder-password' ) ) {
+ $input = $input.hide().next().show().attr( 'id', $input.removeAttr( 'id' ).data( 'placeholder-id' ) );
+ // If `clearPlaceholder` was called from `$.valHooks.input.set`
+ if ( event === true ) {
+ $input[ 0 ].value = value;
+ return value;
+ }
+ $input.focus();
+ } else {
+ input.value = '';
+ $input.removeClass( 'placeholder' );
+ if ( input === safeActiveElement() ) {
+ input.select();
+ }
+ }
+ }
+ }
- placeholder = prototype.placeholder = function (text) {
+ function setPlaceholder() {
+ var $replacement,
+ input = this,
+ $input = $( input ),
+ id = this.id;
+ if ( !input.value ) {
+ if ( input.type === 'password' ) {
+ if ( !$input.data( 'placeholder-textinput' ) ) {
+ try {
+ $replacement = $input.clone().attr( { type: 'text' } );
+ } catch ( e ) {
+ $replacement = $( '<input>' ).attr( $.extend( args( this ), { type: 'text' } ) );
+ }
+ $replacement
+ .removeAttr( 'name' )
+ .data( {
+ 'placeholder-password': $input,
+ 'placeholder-id': id
+ } )
+ .bind( 'focus.placeholder drop.placeholder', clearPlaceholder );
+ $input
+ .data( {
+ 'placeholder-textinput': $replacement,
+ 'placeholder-id': id
+ } )
+ .before( $replacement );
+ }
+ $input = $input.removeAttr( 'id' ).hide().prev().attr( 'id', id ).show();
+ // Note: `$input[0] != input` now!
+ }
+ $input.addClass( 'placeholder' );
+ $input[ 0 ].value = $input.attr( 'placeholder' );
+ } else {
+ $input.removeClass( 'placeholder' );
+ }
+ }
+
+ function changePlaceholder( text ) {
+ var hasArgs = arguments.length,
+ $input = this;
+ if ( hasArgs ) {
+ if ( $input.attr( 'placeholder' ) !== text ) {
+ $input.prop( 'placeholder', text );
+ if ( $input.hasClass( 'placeholder' ) ) {
+ $input[ 0 ].value = text;
+ }
+ }
+ }
+ }
+
+ if ( isInputSupported && isTextareaSupported ) {
+
+ placeholder = prototype.placeholder = function ( text ) {
var hasArgs = arguments.length;
- if (hasArgs) {
- changePlaceholder.call(this, text);
+ if ( hasArgs ) {
+ changePlaceholder.call( this, text );
}
return this;
@@ -39,25 +131,25 @@
} else {
- placeholder = prototype.placeholder = function (text) {
+ placeholder = prototype.placeholder = function ( text ) {
var $this = this,
hasArgs = arguments.length;
- if (hasArgs) {
- changePlaceholder.call(this, text);
+ if ( hasArgs ) {
+ changePlaceholder.call( this, text );
}
$this
- .filter((isInputSupported ? 'textarea' : ':input') + '[placeholder]')
+ .filter( ( isInputSupported ? 'textarea' : ':input' ) + '[placeholder]' )
.filter( function () {
- return !$(this).data('placeholder-enabled');
- })
- .bind({
+ return !$( this ).data( 'placeholder-enabled' );
+ } )
+ .bind( {
'focus.placeholder drop.placeholder': clearPlaceholder,
'blur.placeholder': setPlaceholder
- })
- .data('placeholder-enabled', true)
- .trigger('blur.placeholder');
+ } )
+ .data( 'placeholder-enabled', true )
+ .trigger( 'blur.placeholder' );
return $this;
};
@@ -65,36 +157,36 @@
placeholder.textarea = isTextareaSupported;
hooks = {
- 'get': function (element) {
- var $element = $(element),
- $passwordInput = $element.data('placeholder-password');
- if ($passwordInput) {
- return $passwordInput[0].value;
+ get: function ( element ) {
+ var $element = $( element ),
+ $passwordInput = $element.data( 'placeholder-password' );
+ if ( $passwordInput ) {
+ return $passwordInput[ 0 ].value;
}
- return $element.data('placeholder-enabled') && $element.hasClass('placeholder') ? '' : element.value;
+ return $element.data( 'placeholder-enabled' ) && $element.hasClass( 'placeholder' ) ? '' : element.value;
},
- 'set': function (element, value) {
- var $element = $(element),
- $passwordInput = $element.data('placeholder-password');
- if ($passwordInput) {
- $passwordInput[0].value = value;
+ set: function ( element, value ) {
+ var $element = $( element ),
+ $passwordInput = $element.data( 'placeholder-password' );
+ if ( $passwordInput ) {
+ $passwordInput[ 0 ].value = value;
return value;
}
- if (!$element.data('placeholder-enabled')) {
+ if ( !$element.data( 'placeholder-enabled' ) ) {
element.value = value;
return value;
}
- if (!value) {
+ if ( !value ) {
element.value = value;
// Issue #56: Setting the placeholder causes problems if the element continues to have focus.
- if (element !== safeActiveElement()) {
+ if ( element !== safeActiveElement() ) {
// We can't use `triggerHandler` here because of dummy text/password inputs :(
- setPlaceholder.call(element);
+ setPlaceholder.call( element );
}
- } else if ($element.hasClass('placeholder')) {
- if (!clearPlaceholder.call(element, true, value)) {
+ } else if ( $element.hasClass( 'placeholder' ) ) {
+ if ( !clearPlaceholder.call( element, true, value ) ) {
element.value = value;
}
} else {
@@ -105,125 +197,32 @@
}
};
- if (!isInputSupported) {
+ if ( !isInputSupported ) {
valHooks.input = hooks;
propHooks.value = hooks;
}
- if (!isTextareaSupported) {
+ if ( !isTextareaSupported ) {
valHooks.textarea = hooks;
propHooks.value = hooks;
}
$( function () {
// Look for forms
- $(document).delegate('form', 'submit.placeholder', function () {
+ $( document ).delegate( 'form', 'submit.placeholder', function () {
// Clear the placeholder values so they don't get submitted
- var $inputs = $('.placeholder', this).each(clearPlaceholder);
+ var $inputs = $( '.placeholder', this ).each( clearPlaceholder );
setTimeout( function () {
- $inputs.each(setPlaceholder);
- }, 10);
- });
- });
+ $inputs.each( setPlaceholder );
+ }, 10 );
+ } );
+ } );
// Clear placeholder values upon page reload
- $(window).bind('beforeunload.placeholder', function () {
- $('.placeholder').each( function () {
+ $( window ).bind( 'beforeunload.placeholder', function () {
+ $( '.placeholder' ).each( function () {
this.value = '';
- });
- });
+ } );
+ } );
}
-
- function args(elem) {
- // Return an object of element attributes
- var newAttrs = {},
- rinlinejQuery = /^jQuery\d+$/;
- $.each(elem.attributes, function (i, attr) {
- if (attr.specified && !rinlinejQuery.test(attr.name)) {
- newAttrs[attr.name] = attr.value;
- }
- });
- return newAttrs;
- }
-
- function clearPlaceholder(event, value) {
- var input = this,
- $input = $(input);
- if (input.value === $input.attr('placeholder') && $input.hasClass('placeholder')) {
- if ($input.data('placeholder-password')) {
- $input = $input.hide().next().show().attr('id', $input.removeAttr('id').data('placeholder-id'));
- // If `clearPlaceholder` was called from `$.valHooks.input.set`
- if (event === true) {
- $input[0].value = value;
- return value;
- }
- $input.focus();
- } else {
- input.value = '';
- $input.removeClass('placeholder');
- if (input === safeActiveElement()) {
- input.select();
- }
- }
- }
- }
-
- function setPlaceholder() {
- var $replacement,
- input = this,
- $input = $(input),
- id = this.id;
- if (!input.value) {
- if (input.type === 'password') {
- if (!$input.data('placeholder-textinput')) {
- try {
- $replacement = $input.clone().attr({ 'type': 'text' });
- } catch (e) {
- $replacement = $('<input>').attr($.extend(args(this), { 'type': 'text' }));
- }
- $replacement
- .removeAttr('name')
- .data({
- 'placeholder-password': $input,
- 'placeholder-id': id
- })
- .bind('focus.placeholder drop.placeholder', clearPlaceholder);
- $input
- .data({
- 'placeholder-textinput': $replacement,
- 'placeholder-id': id
- })
- .before($replacement);
- }
- $input = $input.removeAttr('id').hide().prev().attr('id', id).show();
- // Note: `$input[0] != input` now!
- }
- $input.addClass('placeholder');
- $input[0].value = $input.attr('placeholder');
- } else {
- $input.removeClass('placeholder');
- }
- }
-
- function safeActiveElement() {
- // Avoid IE9 `document.activeElement` of death
- // https://github.com/mathiasbynens/jquery-placeholder/pull/99
- try {
- return document.activeElement;
- } catch (err) {}
- }
-
- function changePlaceholder(text) {
- var hasArgs = arguments.length,
- $input = this;
- if (hasArgs) {
- if ($input.attr('placeholder') !== text) {
- $input.prop('placeholder', text);
- if ($input.hasClass('placeholder')) {
- $input[0].value = text;
- }
- }
- }
- }
-
-}(jQuery));
+}( jQuery ) );
diff --git a/resources/src/jquery/jquery.qunit.completenessTest.js b/resources/src/jquery/jquery.qunit.completenessTest.js
index 556bf8c7..785b2738 100644
--- a/resources/src/jquery/jquery.qunit.completenessTest.js
+++ b/resources/src/jquery/jquery.qunit.completenessTest.js
@@ -51,14 +51,14 @@
/**
* CompletenessTest
- * @constructor
*
+ * @constructor
* @example
* var myTester = new CompletenessTest( myLib );
- * @param masterVariable {Object} The root variable that contains all object
+ * @param {Object} masterVariable The root variable that contains all object
* members. CompletenessTest will recursively traverse objects and keep track
* of all methods.
- * @param ignoreFn {Function} Optionally pass a function to filter out certain
+ * @param {Function} [ignoreFn] Optionally pass a function to filter out certain
* methods. Example: You may want to filter out instances of jQuery or some
* other constructor. Otherwise "missingTests" will include all methods that
* were not called from that instance.
@@ -132,7 +132,7 @@
elOutputWrapper.appendChild( elContainer );
util.each( style, function ( key, value ) {
- elOutputWrapper.style[key] = value;
+ elOutputWrapper.style[ key ] = value;
} );
return elOutputWrapper;
}
@@ -186,12 +186,12 @@
* Depending on the action it either injects our listener into the methods, or
* reads from our tracker and records which methods have not been called by the test suite.
*
- * @param currName {String|Null} Name of the given object member (Initially this is null).
- * @param currVar {mixed} The variable to check (initially an object,
+ * @param {String|Null} currName Name of the given object member (Initially this is null).
+ * @param {mixed} currVar The variable to check (initially an object,
* further down it could be anything).
- * @param masterVariable {Object} Throughout our interation, always keep track of the master/root.
+ * @param {Object} masterVariable Throughout our interation, always keep track of the master/root.
* Initially this is the same as currVar.
- * @param parentPathArray {Array} Array of names that indicate our breadcrumb path starting at
+ * @param {Array} parentPathArray Array of names that indicate our breadcrumb path starting at
* masterVariable. Not including currName.
*/
walkTheObject: function ( currObj, currName, masterVariable, parentPathArray ) {
@@ -201,7 +201,7 @@
if ( currName ) {
currPathArray.push( currName );
- currVal = currObj[currName];
+ currVal = currObj[ currName ];
} else {
currName = '(root)';
currVal = currObj;
@@ -258,12 +258,12 @@
* was called during the test suite (as far as the tracker knows).
* If not it adds it to missingTests.
*
- * @param fnName {String}
+ * @param {String} fnName
* @return {Boolean}
*/
hasTest: function ( fnName ) {
if ( !( fnName in this.methodCallTracker ) ) {
- this.missingTests[fnName] = true;
+ this.missingTests[ fnName ] = true;
return false;
}
return true;
@@ -275,9 +275,9 @@
* Injects a function (such as a spy that updates methodCallTracker when
* it's called) inside another function.
*
- * @param masterVariable {Object}
- * @param objectPathArray {Array}
- * @param injectFn {Function}
+ * @param {Object} masterVariable
+ * @param {Array} objectPathArray
+ * @param {Function} injectFn
*/
injectCheck: function ( obj, key, injectFn ) {
var spy,
@@ -291,8 +291,11 @@
// Make the spy inherit from the original so that its static methods are also
// visible in the spy (e.g. when we inject a check into mw.log, mw.log.warn
// must remain accessible).
+ // XXX: https://github.com/jshint/jshint/issues/2656
+ /*jshint ignore:start */
/*jshint proto:true */
spy.__proto__ = val;
+ /*jshint ignore:end */
// Objects are by reference, members (unless objects) are not.
obj[ key ] = spy;
diff --git a/resources/src/jquery/jquery.spinner.js b/resources/src/jquery/jquery.spinner.js
index 361d3e08..41c555b7 100644
--- a/resources/src/jquery/jquery.spinner.js
+++ b/resources/src/jquery/jquery.spinner.js
@@ -67,7 +67,7 @@
opts = $.extend( {}, defaults, opts );
- var $spinner = $( '<div>', { 'class': 'mw-spinner', 'title': '...' } );
+ var $spinner = $( '<div>', { 'class': 'mw-spinner', title: '...' } );
if ( opts.id !== undefined ) {
$spinner.attr( 'id', 'mw-spinner-' + opts.id );
}
diff --git a/resources/src/jquery/jquery.suggestions.js b/resources/src/jquery/jquery.suggestions.js
index 813c37ce..dc1c7794 100644
--- a/resources/src/jquery/jquery.suggestions.js
+++ b/resources/src/jquery/jquery.suggestions.js
@@ -53,6 +53,12 @@
* @param {Function} options.result.select Called in context of the suggestions-result-current element.
* @param {jQuery} options.result.select.$textbox
*
+ * @param {Object} [options.update] Set of callbacks for listening to a change in the text input.
+ *
+ * @param {Function} options.update.before Called right after the user changes the textbox text.
+ * @param {Function} options.update.after Called after results are updated either from the cache or
+ * the API as a result of the user input.
+ *
* @param {jQuery} [options.$region=this] The element to place the suggestions below and match width of.
*
* @param {string[]} [options.suggestions] Array of suggestions to display.
@@ -83,7 +89,7 @@
* @param {boolean} [options.positionFromLeft] Sets `expandFrom=left`, for backwards
* compatibility.
*
- * @param {boolean} [options.highlightInput=false] Whether to hightlight matched portions of the
+ * @param {boolean} [options.highlightInput=false] Whether to highlight matched portions of the
* input or not.
*/
( function ( $ ) {
@@ -136,6 +142,7 @@ $.suggestions = {
* call to this function still pending will be canceled. If the value in the
* textbox is empty or hasn't changed since the last time suggestions were fetched,
* this function does nothing.
+ *
* @param {boolean} delayed Whether or not to delay this by the currently configured amount of time
*/
update: function ( context, delayed ) {
@@ -144,6 +151,10 @@ $.suggestions = {
cache = context.data.cache,
cacheHit;
+ if ( typeof context.config.update.before === 'function' ) {
+ context.config.update.before.call( context.data.$textbox );
+ }
+
// Only fetch if the value in the textbox changed and is not empty, or if the results were hidden
// if the textbox is empty then clear the result div, but leave other settings intouched
if ( val.length === 0 ) {
@@ -158,6 +169,9 @@ $.suggestions = {
if ( context.config.cache && hasOwn.call( cache, val ) ) {
if ( +new Date() - cache[ val ].timestamp < context.config.cacheMaxAge ) {
context.data.$textbox.suggestions( 'suggestions', cache[ val ].suggestions );
+ if ( typeof context.config.update.after === 'function' ) {
+ context.config.update.after.call( context.data.$textbox );
+ }
cacheHit = true;
} else {
// Cache expired
@@ -171,6 +185,9 @@ $.suggestions = {
function ( suggestions ) {
suggestions = suggestions.slice( 0, context.config.maxRows );
context.data.$textbox.suggestions( 'suggestions', suggestions );
+ if ( typeof context.config.update.after === 'function' ) {
+ context.config.update.after.call( context.data.$textbox );
+ }
if ( context.config.cache ) {
cache[ val ] = {
suggestions: suggestions,
@@ -213,6 +230,7 @@ $.suggestions = {
/**
* Sets the value of a property, and updates the widget accordingly
+ *
* @param {string} property Name of property
* @param {Mixed} value Value to set property with
*/
@@ -227,12 +245,13 @@ $.suggestions = {
case 'cancel':
case 'special':
case 'result':
+ case 'update':
case '$region':
case 'expandFrom':
- context.config[property] = value;
+ context.config[ property ] = value;
break;
case 'suggestions':
- context.config[property] = value;
+ context.config[ property ] = value;
// Update suggestions
if ( context.data !== undefined ) {
if ( context.data.$textbox.val().length === 0 ) {
@@ -260,7 +279,7 @@ $.suggestions = {
expandFrom = 'left';
// Catch invalid values, default to 'auto'
- } else if ( $.inArray( expandFrom, ['left', 'right', 'start', 'end', 'auto'] ) === -1 ) {
+ } else if ( $.inArray( expandFrom, [ 'left', 'right', 'start', 'end', 'auto' ] ) === -1 ) {
expandFrom = 'auto';
}
@@ -319,11 +338,11 @@ $.suggestions = {
expWidth = -1;
for ( i = 0; i < context.config.suggestions.length; i++ ) {
/*jshint loopfunc:true */
- text = context.config.suggestions[i];
+ text = context.config.suggestions[ i ];
$result = $( '<div>' )
.addClass( 'suggestions-result' )
.attr( 'rel', i )
- .data( 'text', context.config.suggestions[i] )
+ .data( 'text', context.config.suggestions[ i ] )
.mousemove( function () {
context.data.selectedWithMouse = true;
$.suggestions.highlight(
@@ -335,7 +354,7 @@ $.suggestions = {
.appendTo( $results );
// Allow custom rendering
if ( typeof context.config.result.render === 'function' ) {
- context.config.result.render.call( $result, context.config.suggestions[i], context );
+ context.config.result.render.call( $result, context.config.suggestions[ i ], context );
} else {
$result.text( text );
}
@@ -376,28 +395,29 @@ $.suggestions = {
}
break;
case 'maxRows':
- context.config[property] = Math.max( 1, Math.min( 100, value ) );
+ context.config[ property ] = Math.max( 1, Math.min( 100, value ) );
break;
case 'delay':
- context.config[property] = Math.max( 0, Math.min( 1200, value ) );
+ context.config[ property ] = Math.max( 0, Math.min( 1200, value ) );
break;
case 'cacheMaxAge':
- context.config[property] = Math.max( 1, value );
+ context.config[ property ] = Math.max( 1, value );
break;
case 'maxExpandFactor':
- context.config[property] = Math.max( 1, value );
+ context.config[ property ] = Math.max( 1, value );
break;
case 'cache':
case 'submitOnClick':
case 'positionFromLeft':
case 'highlightInput':
- context.config[property] = !!value;
+ context.config[ property ] = !!value;
break;
}
},
/**
* Highlight a result in the results table
+ *
* @param {jQuery|string} result `<tr>` to highlight, or 'prev' or 'next'
* @param {boolean} updateTextbox If true, put the suggestion in the textbox
*/
@@ -467,6 +487,7 @@ $.suggestions = {
/**
* Respond to keypress event
+ *
* @param {number} key Code of key pressed
*/
keypress: function ( e, context, key ) {
@@ -559,6 +580,7 @@ $.fn.suggestions = function () {
cancel: function () {},
special: {},
result: {},
+ update: {},
$region: $( this ),
suggestions: [],
maxRows: 10,
@@ -577,18 +599,18 @@ $.fn.suggestions = function () {
// Handle various calling styles
if ( args.length > 0 ) {
- if ( typeof args[0] === 'object' ) {
+ if ( typeof args[ 0 ] === 'object' ) {
// Apply set of properties
- for ( key in args[0] ) {
- $.suggestions.configure( context, key, args[0][key] );
+ for ( key in args[ 0 ] ) {
+ $.suggestions.configure( context, key, args[ 0 ][ key ] );
}
- } else if ( typeof args[0] === 'string' ) {
+ } else if ( typeof args[ 0 ] === 'string' ) {
if ( args.length > 1 ) {
// Set property values
- $.suggestions.configure( context, args[0], args[1] );
+ $.suggestions.configure( context, args[ 0 ], args[ 1 ] );
} else if ( returnValue === null || returnValue === undefined ) {
// Get property values, but don't give access to internal data - returns only the first
- returnValue = ( args[0] in context.config ? undefined : context.config[args[0]] );
+ returnValue = ( args[ 0 ] in context.config ? undefined : context.config[ args[ 0 ] ] );
}
}
}
diff --git a/resources/src/jquery/jquery.tablesorter.js b/resources/src/jquery/jquery.tablesorter.js
index ff5ff0a9..eaa138b9 100644
--- a/resources/src/jquery/jquery.tablesorter.js
+++ b/resources/src/jquery/jquery.tablesorter.js
@@ -8,7 +8,7 @@
* http://www.opensource.org/licenses/mit-license.php
* http://www.gnu.org/licenses/gpl.html
*
- * Depends on mw.config (wgDigitTransformTable, wgDefaultDateFormat, wgContentLanguage)
+ * Depends on mw.config (wgDigitTransformTable, wgDefaultDateFormat, wgPageContentLanguage)
* and mw.language.months.
*
* Uses 'tableSorterCollation' in mw.config (if available)
@@ -70,8 +70,8 @@
var i,
len = parsers.length;
for ( i = 0; i < len; i++ ) {
- if ( parsers[i].id.toLowerCase() === name.toLowerCase() ) {
- return parsers[i];
+ if ( parsers[ i ].id.toLowerCase() === name.toLowerCase() ) {
+ return parsers[ i ];
}
}
return false;
@@ -95,8 +95,7 @@
return $node.attr( 'alt' ) || ''; // handle undefined alt
} else {
return $.map( $.makeArray( node.childNodes ), function ( elem ) {
- // 1 is for document.ELEMENT_NODE (the constant is undefined on old browsers)
- if ( elem.nodeType === 1 ) {
+ if ( elem.nodeType === Node.ELEMENT_NODE ) {
return getElementSortKey( elem );
} else {
return $.text( elem );
@@ -106,69 +105,83 @@
}
}
- function detectParserForColumn( table, rows, cellIndex ) {
+ function detectParserForColumn( table, rows, column ) {
var l = parsers.length,
+ cellIndex,
nodeValue,
// Start with 1 because 0 is the fallback parser
i = 1,
+ lastRowIndex = -1,
rowIndex = 0,
concurrent = 0,
+ empty = 0,
needed = ( rows.length > 4 ) ? 5 : rows.length;
while ( i < l ) {
- if ( rows[rowIndex] && rows[rowIndex].cells[cellIndex] ) {
- nodeValue = $.trim( getElementSortKey( rows[rowIndex].cells[cellIndex] ) );
+ if ( rows[ rowIndex ] ) {
+ if ( rowIndex !== lastRowIndex ) {
+ lastRowIndex = rowIndex;
+ cellIndex = $( rows[ rowIndex ] ).data( 'columnToCell' )[ column ];
+ nodeValue = $.trim( getElementSortKey( rows[ rowIndex ].cells[ cellIndex ] ) );
+ }
} else {
nodeValue = '';
}
if ( nodeValue !== '' ) {
- if ( parsers[i].is( nodeValue, table ) ) {
+ if ( parsers[ i ].is( nodeValue, table ) ) {
concurrent++;
rowIndex++;
if ( concurrent >= needed ) {
// Confirmed the parser for multiple cells, let's return it
- return parsers[i];
+ return parsers[ i ];
}
} else {
// Check next parser, reset rows
i++;
rowIndex = 0;
concurrent = 0;
+ empty = 0;
}
} else {
// Empty cell
+ empty++;
rowIndex++;
- if ( rowIndex > rows.length ) {
- rowIndex = 0;
+ if ( rowIndex >= rows.length ) {
+ if ( concurrent >= rows.length - empty ) {
+ // Confirmed the parser for all filled cells
+ return parsers[ i ];
+ }
+ // Check next parser, reset rows
i++;
+ rowIndex = 0;
+ concurrent = 0;
+ empty = 0;
}
}
}
// 0 is always the generic parser (text)
- return parsers[0];
+ return parsers[ 0 ];
}
function buildParserCache( table, $headers ) {
- var sortType, cells, len, i, parser,
- rows = table.tBodies[0].rows,
+ var sortType, len, j, parser,
+ rows = table.tBodies[ 0 ].rows,
+ config = $( table ).data( 'tablesorter' ).config,
parsers = [];
- if ( rows[0] ) {
-
- cells = rows[0].cells;
- len = cells.length;
-
- for ( i = 0; i < len; i++ ) {
+ if ( rows[ 0 ] ) {
+ len = config.columns;
+ for ( j = 0; j < len; j++ ) {
parser = false;
- sortType = $headers.eq( i ).data( 'sortType' );
+ sortType = $headers.eq( config.columnToHeader[ j ] ).data( 'sortType' );
if ( sortType !== undefined ) {
parser = getParserById( sortType );
}
if ( parser === false ) {
- parser = detectParserForColumn( table, rows, i );
+ parser = detectParserForColumn( table, rows, j );
}
parsers.push( parser );
@@ -181,33 +194,35 @@
function buildCache( table ) {
var i, j, $row, cols,
- totalRows = ( table.tBodies[0] && table.tBodies[0].rows.length ) || 0,
- totalCells = ( table.tBodies[0].rows[0] && table.tBodies[0].rows[0].cells.length ) || 0,
+ totalRows = ( table.tBodies[ 0 ] && table.tBodies[ 0 ].rows.length ) || 0,
config = $( table ).data( 'tablesorter' ).config,
parsers = config.parsers,
+ len = parsers.length,
+ cellIndex,
cache = {
row: [],
normalized: []
};
- for ( i = 0; i < totalRows; ++i ) {
+ for ( i = 0; i < totalRows; i++ ) {
// Add the table data to main data array
- $row = $( table.tBodies[0].rows[i] );
+ $row = $( table.tBodies[ 0 ].rows[ i ] );
cols = [];
// if this is a child row, add it to the last row's children and
// continue to the next row
if ( $row.hasClass( config.cssChildRow ) ) {
- cache.row[cache.row.length - 1] = cache.row[cache.row.length - 1].add( $row );
+ cache.row[ cache.row.length - 1 ] = cache.row[ cache.row.length - 1 ].add( $row );
// go to the next for loop
continue;
}
cache.row.push( $row );
- for ( j = 0; j < totalCells; ++j ) {
- cols.push( parsers[j].format( getElementSortKey( $row[0].cells[j] ), table, $row[0].cells[j] ) );
+ for ( j = 0; j < len; j++ ) {
+ cellIndex = $row.data( 'columnToCell' )[ j ];
+ cols.push( parsers[ j ].format( getElementSortKey( $row[ 0 ].cells[ cellIndex ] ) ) );
}
cols.push( cache.normalized.length ); // add position for rowCache
@@ -223,20 +238,20 @@
row = cache.row,
normalized = cache.normalized,
totalRows = normalized.length,
- checkCell = ( normalized[0].length - 1 ),
+ checkCell = ( normalized[ 0 ].length - 1 ),
fragment = document.createDocumentFragment();
for ( i = 0; i < totalRows; i++ ) {
- pos = normalized[i][checkCell];
+ pos = normalized[ i ][ checkCell ];
- l = row[pos].length;
+ l = row[ pos ].length;
for ( j = 0; j < l; j++ ) {
- fragment.appendChild( row[pos][j] );
+ fragment.appendChild( row[ pos ][ j ] );
}
}
- table.tBodies[0].appendChild( fragment );
+ table.tBodies[ 0 ].appendChild( fragment );
$( table ).trigger( 'sortEnd.tablesorter' );
}
@@ -249,7 +264,8 @@
*
* After this, it will look at all rows at the bottom for footer rows
* And place these in a tfoot using similar rules.
- * @param $table jQuery object for a <table>
+ *
+ * @param {jQuery} $table object for a <table>
*/
function emulateTHeadAndFoot( $table ) {
var $thead, $tfoot, i, len,
@@ -270,26 +286,37 @@
$tfoot = $( '<tfoot>' );
len = $rows.length;
for ( i = len - 1; i >= 0; i-- ) {
- if ( $( $rows[i] ).children( 'td' ).length ) {
+ if ( $( $rows[ i ] ).children( 'td' ).length ) {
break;
}
- $tfoot.prepend( $( $rows[i] ) );
+ $tfoot.prepend( $( $rows[ i ] ) );
}
$table.append( $tfoot );
}
}
+ function uniqueElements( array ) {
+ var uniques = [];
+ $.each( array, function ( index, elem ) {
+ if ( elem !== undefined && $.inArray( elem, uniques ) === -1 ) {
+ uniques.push( elem );
+ }
+ } );
+ return uniques;
+ }
+
function buildHeaders( table, msg ) {
var config = $( table ).data( 'tablesorter' ).config,
maxSeen = 0,
colspanOffset = 0,
columns,
- i,
+ k,
$cell,
rowspan,
colspan,
headerCount,
longestTR,
+ headerIndex,
exploded,
$tableHeaders = $( [] ),
$tableRows = $( 'thead:eq(0) > tr', table );
@@ -308,7 +335,7 @@
colspan = Number( cell.colSpan );
// Skip the spots in the exploded matrix that are already filled
- while ( exploded[rowIndex] && exploded[rowIndex][columnIndex] !== undefined ) {
+ while ( exploded[ rowIndex ] && exploded[ rowIndex ][ columnIndex ] !== undefined ) {
++columnIndex;
}
@@ -316,10 +343,10 @@
// in the exploded matrix rowspan times colspan times, with the proper offsets
for ( matrixColumnIndex = columnIndex; matrixColumnIndex < columnIndex + colspan; ++matrixColumnIndex ) {
for ( matrixRowIndex = rowIndex; matrixRowIndex < rowIndex + rowspan; ++matrixRowIndex ) {
- if ( !exploded[matrixRowIndex] ) {
- exploded[matrixRowIndex] = [];
+ if ( !exploded[ matrixRowIndex ] ) {
+ exploded[ matrixRowIndex ] = [];
}
- exploded[matrixRowIndex][matrixColumnIndex] = cell;
+ exploded[ matrixRowIndex ][ matrixColumnIndex ] = cell;
}
}
} );
@@ -333,49 +360,65 @@
}
} );
// We cannot use $.unique() here because it sorts into dom order, which is undesirable
- $tableHeaders = $( uniqueElements( exploded[longestTR] ) ).filter( 'th' );
+ $tableHeaders = $( uniqueElements( exploded[ longestTR ] ) ).filter( 'th' );
}
// as each header can span over multiple columns (using colspan=N),
// we have to bidirectionally map headers to their columns and columns to their headers
- $tableHeaders.each( function ( headerIndex ) {
+ config.columnToHeader = [];
+ config.headerToColumns = [];
+ config.headerList = [];
+ headerIndex = 0;
+ $tableHeaders.each( function () {
$cell = $( this );
columns = [];
- for ( i = 0; i < this.colSpan; i++ ) {
- config.columnToHeader[ colspanOffset + i ] = headerIndex;
- columns.push( colspanOffset + i );
- }
-
- config.headerToColumns[ headerIndex ] = columns;
- colspanOffset += this.colSpan;
-
- $cell.data( {
- headerIndex: headerIndex,
- order: 0,
- count: 0
- } );
-
- if ( $cell.hasClass( config.unsortableClass ) ) {
- $cell.data( 'sortDisabled', true );
- }
-
- if ( !$cell.data( 'sortDisabled' ) ) {
+ if ( !$cell.hasClass( config.unsortableClass ) ) {
$cell
.addClass( config.cssHeader )
.prop( 'tabIndex', 0 )
.attr( {
role: 'columnheader button',
- title: msg[1]
+ title: msg[ 1 ]
} );
+
+ for ( k = 0; k < this.colSpan; k++ ) {
+ config.columnToHeader[ colspanOffset + k ] = headerIndex;
+ columns.push( colspanOffset + k );
+ }
+
+ config.headerToColumns[ headerIndex ] = columns;
+
+ $cell.data( {
+ headerIndex: headerIndex,
+ order: 0,
+ count: 0
+ } );
+
+ // add only sortable cells to headerList
+ config.headerList[ headerIndex ] = this;
+ headerIndex++;
}
- // add cell to headerList
- config.headerList[headerIndex] = this;
+ colspanOffset += this.colSpan;
} );
- return $tableHeaders;
+ // number of columns with extended colspan, inclusive unsortable
+ // parsers[j], cache[][j], columnToHeader[j], columnToCell[j] have so many elements
+ config.columns = colspanOffset;
+
+ return $tableHeaders.not( '.' + config.unsortableClass );
+ }
+ function isValueInArray( v, a ) {
+ var i,
+ len = a.length;
+ for ( i = 0; i < len; i++ ) {
+ if ( a[ i ][ 0 ] === v ) {
+ return true;
+ }
+ }
+ return false;
}
/**
@@ -391,7 +434,7 @@
$.each( headerToColumns, function ( headerIndex, columns ) {
$.each( columns, function ( i, columnIndex ) {
- var header = $headers[headerIndex],
+ var header = $headers[ headerIndex ],
$header = $( header );
if ( !isValueInArray( columnIndex, sortList ) ) {
@@ -403,10 +446,10 @@
} else {
// Column shall be sorted: Apply designated count and order.
$.each( sortList, function ( j, sortColumn ) {
- if ( sortColumn[0] === i ) {
+ if ( sortColumn[ 0 ] === i ) {
$header.data( {
- order: sortColumn[1],
- count: sortColumn[1] + 1
+ order: sortColumn[ 1 ],
+ count: sortColumn[ 1 ] + 1
} );
return false;
}
@@ -417,35 +460,14 @@
} );
}
- function isValueInArray( v, a ) {
- var i,
- len = a.length;
- for ( i = 0; i < len; i++ ) {
- if ( a[i][0] === v ) {
- return true;
- }
- }
- return false;
- }
-
- function uniqueElements( array ) {
- var uniques = [];
- $.each( array, function ( index, elem ) {
- if ( elem !== undefined && $.inArray( elem, uniques ) === -1 ) {
- uniques.push( elem );
- }
- } );
- return uniques;
- }
-
function setHeadersCss( table, $headers, list, css, msg, columnToHeader ) {
// Remove all header information and reset titles to default message
- $headers.removeClass( css[0] ).removeClass( css[1] ).attr( 'title', msg[1] );
+ $headers.removeClass( css[ 0 ] ).removeClass( css[ 1 ] ).attr( 'title', msg[ 1 ] );
for ( var i = 0; i < list.length; i++ ) {
- $headers.eq( columnToHeader[ list[i][0] ] )
- .addClass( css[ list[i][1] ] )
- .attr( 'title', msg[ list[i][1] ] );
+ $headers.eq( columnToHeader[ list[ i ][ 0 ] ] )
+ .addClass( css[ list[ i ][ 1 ] ] )
+ .attr( 'title', msg[ list[ i ][ 1 ] ] );
}
}
@@ -462,19 +484,19 @@
sortFn = [],
len = sortList.length;
for ( i = 0; i < len; i++ ) {
- sortFn[i] = ( sortList[i][1] ) ? sortTextDesc : sortText;
+ sortFn[ i ] = ( sortList[ i ][ 1 ] ) ? sortTextDesc : sortText;
}
cache.normalized.sort( function ( array1, array2 ) {
var i, col, ret;
for ( i = 0; i < len; i++ ) {
- col = sortList[i][0];
- ret = sortFn[i].call( this, array1[col], array2[col] );
+ col = sortList[ i ][ 0 ];
+ ret = sortFn[ i ].call( this, array1[ col ], array2[ col ] );
if ( ret !== 0 ) {
return ret;
}
}
// Fall back to index number column to ensure stable sort
- return sortText.call( this, array1[array1.length - 1], array2[array2.length - 1] );
+ return sortText.call( this, array1[ array1.length - 1 ], array2[ array2.length - 1 ] );
} );
return cache;
}
@@ -485,19 +507,19 @@
separatorTransformTable = mw.config.get( 'wgSeparatorTransformTable' ),
digitTransformTable = mw.config.get( 'wgDigitTransformTable' );
- if ( separatorTransformTable === null || ( separatorTransformTable[0] === '' && digitTransformTable[2] === '' ) ) {
+ if ( separatorTransformTable === null || ( separatorTransformTable[ 0 ] === '' && digitTransformTable[ 2 ] === '' ) ) {
ts.transformTable = false;
} else {
ts.transformTable = {};
// Unpack the transform table
- ascii = separatorTransformTable[0].split( '\t' ).concat( digitTransformTable[0].split( '\t' ) );
- localised = separatorTransformTable[1].split( '\t' ).concat( digitTransformTable[1].split( '\t' ) );
+ ascii = separatorTransformTable[ 0 ].split( '\t' ).concat( digitTransformTable[ 0 ].split( '\t' ) );
+ localised = separatorTransformTable[ 1 ].split( '\t' ).concat( digitTransformTable[ 1 ].split( '\t' ) );
// Construct regex for number identification
for ( i = 0; i < ascii.length; i++ ) {
- ts.transformTable[localised[i]] = ascii[i];
- digits.push( $.escapeRE( localised[i] ) );
+ ts.transformTable[ localised[ i ] ] = ascii[ i ];
+ digits.push( mw.RegExp.escape( localised[ i ] ) );
}
}
digitClass = '[' + digits.join( '', digits ) + ']';
@@ -516,15 +538,15 @@
ts.monthNames = {};
for ( i = 0; i < 12; i++ ) {
- name = mw.language.months.names[i].toLowerCase();
- ts.monthNames[name] = i + 1;
- regex.push( $.escapeRE( name ) );
- name = mw.language.months.genitive[i].toLowerCase();
- ts.monthNames[name] = i + 1;
- regex.push( $.escapeRE( name ) );
- name = mw.language.months.abbrev[i].toLowerCase().replace( '.', '' );
- ts.monthNames[name] = i + 1;
- regex.push( $.escapeRE( name ) );
+ name = mw.language.months.names[ i ].toLowerCase();
+ ts.monthNames[ name ] = i + 1;
+ regex.push( mw.RegExp.escape( name ) );
+ name = mw.language.months.genitive[ i ].toLowerCase();
+ ts.monthNames[ name ] = i + 1;
+ regex.push( mw.RegExp.escape( name ) );
+ name = mw.language.months.abbrev[ i ].toLowerCase().replace( '.', '' );
+ ts.monthNames[ name ] = i + 1;
+ regex.push( mw.RegExp.escape( name ) );
}
// Build piped string
@@ -532,13 +554,13 @@
// Build RegEx
// Any date formated with . , ' - or /
- ts.dateRegex[0] = new RegExp( /^\s*(\d{1,2})[\,\.\-\/'\s]{1,2}(\d{1,2})[\,\.\-\/'\s]{1,2}(\d{2,4})\s*?/i );
+ ts.dateRegex[ 0 ] = new RegExp( /^\s*(\d{1,2})[\,\.\-\/'\s]{1,2}(\d{1,2})[\,\.\-\/'\s]{1,2}(\d{2,4})\s*?/i );
// Written Month name, dmy
- ts.dateRegex[1] = new RegExp( '^\\s*(\\d{1,2})[\\,\\.\\-\\/\'\\s]+(' + regex + ')' + '[\\,\\.\\-\\/\'\\s]+(\\d{2,4})\\s*$', 'i' );
+ ts.dateRegex[ 1 ] = new RegExp( '^\\s*(\\d{1,2})[\\,\\.\\-\\/\'\\s]+(' + regex + ')' + '[\\,\\.\\-\\/\'\\s]+(\\d{2,4})\\s*$', 'i' );
// Written Month name, mdy
- ts.dateRegex[2] = new RegExp( '^\\s*(' + regex + ')' + '[\\,\\.\\-\\/\'\\s]+(\\d{1,2})[\\,\\.\\-\\/\'\\s]+(\\d{2,4})\\s*$', 'i' );
+ ts.dateRegex[ 2 ] = new RegExp( '^\\s*(' + regex + ')' + '[\\,\\.\\-\\/\'\\s]+(\\d{1,2})[\\,\\.\\-\\/\'\\s]+(\\d{2,4})\\s*$', 'i' );
}
@@ -546,7 +568,7 @@
* Replace all rowspanned cells in the body with clones in each row, so sorting
* need not worry about them.
*
- * @param $table jQuery object for a <table>
+ * @param {jQuery} $table jQuery object for a <table>
*/
function explodeRowspans( $table ) {
var spanningRealCellIndex, rowSpan, colSpan,
@@ -566,11 +588,11 @@
col = 0,
l = this.cells.length;
for ( i = 0; i < l; i++ ) {
- $( this.cells[i] ).data( 'tablesorter', {
+ $( this.cells[ i ] ).data( 'tablesorter', {
realCellIndex: col,
realRowIndex: this.rowIndex
} );
- col += this.cells[i].colSpan;
+ col += this.cells[ i ].colSpan;
}
} );
@@ -609,7 +631,7 @@
}
while ( rowspanCells.length ) {
- if ( $.data( rowspanCells[0], 'tablesorter' ).needResort ) {
+ if ( $.data( rowspanCells[ 0 ], 'tablesorter' ).needResort ) {
resortCells();
}
@@ -621,7 +643,7 @@
cell.rowSpan = 1;
$nextRows = $( cell ).parent().nextAll();
for ( i = 0; i < rowSpan - 1; i++ ) {
- $tds = $( $nextRows[i].cells ).filter( filterfunc );
+ $tds = $( $nextRows[ i ].cells ).filter( filterfunc );
$clone = $( cell ).clone();
$clone.data( 'tablesorter', {
realCellIndex: spanningRealCellIndex,
@@ -638,6 +660,49 @@
}
}
+ /**
+ * Build index to handle colspanned cells in the body.
+ * Set the cell index for each column in an array,
+ * so that colspaned cells set multiple in this array.
+ * columnToCell[collumnIndex] point at the real cell in this row.
+ *
+ * @param {jQuery} $table object for a <table>
+ */
+ function manageColspans( $table ) {
+ var i, j, k, $row,
+ $rows = $table.find( '> tbody > tr' ),
+ totalRows = $rows.length || 0,
+ config = $table.data( 'tablesorter' ).config,
+ columns = config.columns,
+ columnToCell, cellsInRow, index;
+
+ for ( i = 0; i < totalRows; i++ ) {
+
+ $row = $rows.eq( i );
+ // if this is a child row, continue to the next row (as buildCache())
+ if ( $row.hasClass( config.cssChildRow ) ) {
+ // go to the next for loop
+ continue;
+ }
+
+ columnToCell = [];
+ cellsInRow = ( $row[ 0 ].cells.length ) || 0; // all cells in this row
+ index = 0; // real cell index in this row
+ for ( j = 0; j < columns; index++ ) {
+ if ( index === cellsInRow ) {
+ // Row with cells less than columns: add empty cell
+ $row.append( '<td>' );
+ cellsInRow++;
+ }
+ for ( k = 0; k < $row[ 0 ].cells[ index ].colSpan; k++ ) {
+ columnToCell[ j++ ] = index;
+ }
+ }
+ // Store it in $row
+ $row.data( 'columnToCell', columnToCell );
+ }
+ }
+
function buildCollationTable() {
ts.collationTable = mw.config.get( 'tableSorterCollation' );
ts.collationRegex = null;
@@ -699,7 +764,7 @@
$.each( sortObjects, function ( i, sortObject ) {
$.each( sortObject, function ( columnIndex, order ) {
var orderIndex = ( order === 'desc' ) ? 1 : 0;
- sortList.push( [parseInt( columnIndex, 10 ), orderIndex] );
+ sortList.push( [ parseInt( columnIndex, 10 ), orderIndex ] );
} );
} );
return sortList;
@@ -708,7 +773,6 @@
/* Public scope */
$.tablesorter = {
-
defaultOptions: {
cssHeader: 'headerSort',
cssAsc: 'headerSortUp',
@@ -716,20 +780,21 @@
cssChildRow: 'expand-child',
sortMultiSortKey: 'shiftKey',
unsortableClass: 'unsortable',
- parsers: {},
+ parsers: [],
cancelSelection: true,
sortList: [],
headerList: [],
headerToColumns: [],
- columnToHeader: []
+ columnToHeader: [],
+ columns: 0
},
dateRegex: [],
monthNames: {},
/**
- * @param $tables {jQuery}
- * @param settings {Object} (optional)
+ * @param {jQuery} $tables
+ * @param {Object} [settings]
*/
construct: function ( $tables, settings ) {
return $tables.each( function ( i, table ) {
@@ -799,6 +864,7 @@
}
explodeRowspans( $table );
+ manageColspans( $table );
// Try to auto detect column type, and store in tables config
config.parsers = buildParserCache( table, $headers );
@@ -806,7 +872,7 @@
// Apply event handling to headers
// this is too big, perhaps break it out?
- $headers.not( '.' + config.unsortableClass ).on( 'keypress click', function ( e ) {
+ $headers.on( 'keypress click', function ( e ) {
var cell, $cell, columns, newSortList, i,
totalRows,
j, s, o;
@@ -834,8 +900,8 @@
// cells get event .change() and bubbles up to the <table> here
cache = buildCache( table );
- totalRows = ( $table[0].tBodies[0] && $table[0].tBodies[0].rows.length ) || 0;
- if ( !table.sortDisabled && totalRows > 0 ) {
+ totalRows = ( $table[ 0 ].tBodies[ 0 ] && $table[ 0 ].tBodies[ 0 ].rows.length ) || 0;
+ if ( totalRows > 0 ) {
cell = this;
$cell = $( cell );
@@ -850,12 +916,12 @@
columns = config.headerToColumns[ $cell.data( 'headerIndex' ) ];
newSortList = $.map( columns, function ( c ) {
// jQuery "helpfully" flattens the arrays...
- return [[c, $cell.data( 'order' )]];
+ return [ [ c, $cell.data( 'order' ) ] ];
} );
// Index of first column belonging to this header
- i = columns[0];
+ i = columns[ 0 ];
- if ( !e[config.sortMultiSortKey] ) {
+ if ( !e[ config.sortMultiSortKey ] ) {
// User only wants to sort on one column set
// Flush the sort list and add new columns
config.sortList = newSortList;
@@ -867,11 +933,11 @@
// The user has clicked on an already sorted column.
// Reverse the sorting direction for all tables.
for ( j = 0; j < config.sortList.length; j++ ) {
- s = config.sortList[j];
- o = config.headerList[s[0]];
- if ( isValueInArray( s[0], newSortList ) ) {
- $( o ).data( 'count', s[1] + 1 );
- s[1] = $( o ).data( 'count' ) % 2;
+ s = config.sortList[ j ];
+ o = config.headerList[ config.columnToHeader[ s[ 0 ] ] ];
+ if ( isValueInArray( s[ 0 ], newSortList ) ) {
+ $( o ).data( 'count', s[ 1 ] + 1 );
+ s[ 1 ] = $( o ).data( 'count' ) % 2;
}
}
} else {
@@ -884,9 +950,9 @@
setHeadersOrder( $headers, config.sortList, config.headerToColumns );
// Set CSS for headers
- setHeadersCss( $table[0], $headers, config.sortList, sortCSS, sortMsg, config.columnToHeader );
+ setHeadersCss( $table[ 0 ], $headers, config.sortList, sortCSS, sortMsg, config.columnToHeader );
appendToTable(
- $table[0], multisort( $table[0], config.sortList, cache )
+ $table[ 0 ], multisort( $table[ 0 ], config.sortList, cache )
);
// Stop normal event by returning false
@@ -909,7 +975,7 @@
* Passing an empty array will reset sorting (basically just reset the headers
* making the table appear unsorted).
*
- * @param sortList {Array} (optional) List of sort objects.
+ * @param {Array} [sortList] List of sort objects.
*/
$table.data( 'tablesorter' ).sort = function ( sortList ) {
@@ -939,7 +1005,6 @@
// sort initially
if ( config.sortList.length > 0 ) {
- setupForFirstSort();
config.sortList = convertSortList( config.sortList );
$table.data( 'tablesorter' ).sort();
}
@@ -952,7 +1017,7 @@
len = parsers.length,
a = true;
for ( i = 0; i < len; i++ ) {
- if ( parsers[i].id.toLowerCase() === parser.id.toLowerCase() ) {
+ if ( parsers[ i ].id.toLowerCase() === parser.id.toLowerCase() ) {
a = false;
}
}
@@ -968,7 +1033,7 @@
for ( p = 0; p < s.length; p++ ) {
c = s.charAt( p );
if ( c in ts.transformTable ) {
- out += ts.transformTable[c];
+ out += ts.transformTable[ c ];
} else {
out += c;
}
@@ -990,7 +1055,7 @@
},
clearTableBody: function ( table ) {
- $( table.tBodies[0] ).empty();
+ $( table.tBodies[ 0 ] ).empty();
},
getParser: function ( id ) {
@@ -1000,6 +1065,10 @@
buildCollationTable();
return getParserById( id );
+ },
+
+ getParsers: function () { // for table diagnosis
+ return parsers;
}
};
@@ -1022,7 +1091,7 @@
if ( ts.collationRegex ) {
var tsc = ts.collationTable;
s = s.replace( ts.collationRegex, function ( match ) {
- var r = tsc[match] ? tsc[match] : tsc[match.toUpperCase()];
+ var r = tsc[ match ] ? tsc[ match ] : tsc[ match.toUpperCase() ];
return r.toLowerCase();
} );
}
@@ -1034,7 +1103,7 @@
ts.addParser( {
id: 'IPAddress',
is: function ( s ) {
- return ts.rgx.IPAddress[0].test( s );
+ return ts.rgx.IPAddress[ 0 ].test( s );
},
format: function ( s ) {
var i, item,
@@ -1042,7 +1111,7 @@
r = '',
len = a.length;
for ( i = 0; i < len; i++ ) {
- item = a[i];
+ item = a[ i ];
if ( item.length === 1 ) {
r += '00' + item;
} else if ( item.length === 2 ) {
@@ -1059,10 +1128,10 @@
ts.addParser( {
id: 'currency',
is: function ( s ) {
- return ts.rgx.currency[0].test( s );
+ return ts.rgx.currency[ 0 ].test( s );
},
format: function ( s ) {
- return $.tablesorter.formatDigit( s.replace( ts.rgx.currency[1], '' ) );
+ return $.tablesorter.formatDigit( s.replace( ts.rgx.currency[ 1 ], '' ) );
},
type: 'numeric'
} );
@@ -1070,10 +1139,10 @@
ts.addParser( {
id: 'url',
is: function ( s ) {
- return ts.rgx.url[0].test( s );
+ return ts.rgx.url[ 0 ].test( s );
},
format: function ( s ) {
- return $.trim( s.replace( ts.rgx.url[1], '' ) );
+ return $.trim( s.replace( ts.rgx.url[ 1 ], '' ) );
},
type: 'text'
} );
@@ -1081,7 +1150,7 @@
ts.addParser( {
id: 'isoDate',
is: function ( s ) {
- return ts.rgx.isoDate[0].test( s );
+ return ts.rgx.isoDate[ 0 ].test( s );
},
format: function ( s ) {
return $.tablesorter.formatFloat( ( s !== '' ) ? new Date( s.replace(
@@ -1093,7 +1162,7 @@
ts.addParser( {
id: 'usLongDate',
is: function ( s ) {
- return ts.rgx.usLongDate[0].test( s );
+ return ts.rgx.usLongDate[ 0 ].test( s );
},
format: function ( s ) {
return $.tablesorter.formatFloat( new Date( s ).getTime() );
@@ -1104,49 +1173,49 @@
ts.addParser( {
id: 'date',
is: function ( s ) {
- return ( ts.dateRegex[0].test( s ) || ts.dateRegex[1].test( s ) || ts.dateRegex[2].test( s ) );
+ return ( ts.dateRegex[ 0 ].test( s ) || ts.dateRegex[ 1 ].test( s ) || ts.dateRegex[ 2 ].test( s ) );
},
format: function ( s ) {
var match, y;
s = $.trim( s.toLowerCase() );
- if ( ( match = s.match( ts.dateRegex[0] ) ) !== null ) {
- if ( mw.config.get( 'wgDefaultDateFormat' ) === 'mdy' || mw.config.get( 'wgContentLanguage' ) === 'en' ) {
- s = [ match[3], match[1], match[2] ];
+ if ( ( match = s.match( ts.dateRegex[ 0 ] ) ) !== null ) {
+ if ( mw.config.get( 'wgDefaultDateFormat' ) === 'mdy' || mw.config.get( 'wgPageContentLanguage' ) === 'en' ) {
+ s = [ match[ 3 ], match[ 1 ], match[ 2 ] ];
} else if ( mw.config.get( 'wgDefaultDateFormat' ) === 'dmy' ) {
- s = [ match[3], match[2], match[1] ];
+ s = [ match[ 3 ], match[ 2 ], match[ 1 ] ];
} else {
// If we get here, we don't know which order the dd-dd-dddd
// date is in. So return something not entirely invalid.
return '99999999';
}
- } else if ( ( match = s.match( ts.dateRegex[1] ) ) !== null ) {
- s = [ match[3], String( ts.monthNames[match[2]] ), match[1] ];
- } else if ( ( match = s.match( ts.dateRegex[2] ) ) !== null ) {
- s = [ match[3], String( ts.monthNames[match[1]] ), match[2] ];
+ } else if ( ( match = s.match( ts.dateRegex[ 1 ] ) ) !== null ) {
+ s = [ match[ 3 ], String( ts.monthNames[ match[ 2 ] ] ), match[ 1 ] ];
+ } else if ( ( match = s.match( ts.dateRegex[ 2 ] ) ) !== null ) {
+ s = [ match[ 3 ], String( ts.monthNames[ match[ 1 ] ] ), match[ 2 ] ];
} else {
// Should never get here
return '99999999';
}
// Pad Month and Day
- if ( s[1].length === 1 ) {
- s[1] = '0' + s[1];
+ if ( s[ 1 ].length === 1 ) {
+ s[ 1 ] = '0' + s[ 1 ];
}
- if ( s[2].length === 1 ) {
- s[2] = '0' + s[2];
+ if ( s[ 2 ].length === 1 ) {
+ s[ 2 ] = '0' + s[ 2 ];
}
- if ( ( y = parseInt( s[0], 10 ) ) < 100 ) {
+ if ( ( y = parseInt( s[ 0 ], 10 ) ) < 100 ) {
// Guestimate years without centuries
if ( y < 30 ) {
- s[0] = 2000 + y;
+ s[ 0 ] = 2000 + y;
} else {
- s[0] = 1900 + y;
+ s[ 0 ] = 1900 + y;
}
}
- while ( s[0].length < 4 ) {
- s[0] = '0' + s[0];
+ while ( s[ 0 ].length < 4 ) {
+ s[ 0 ] = '0' + s[ 0 ];
}
return parseInt( s.join( '' ), 10 );
},
@@ -1156,7 +1225,7 @@
ts.addParser( {
id: 'time',
is: function ( s ) {
- return ts.rgx.time[0].test( s );
+ return ts.rgx.time[ 0 ].test( s );
},
format: function ( s ) {
return $.tablesorter.formatFloat( new Date( '2000/01/01 ' + s ).getTime() );
diff --git a/resources/src/jquery/jquery.textSelection.js b/resources/src/jquery/jquery.textSelection.js
index 51119305..b9016424 100644
--- a/resources/src/jquery/jquery.textSelection.js
+++ b/resources/src/jquery/jquery.textSelection.js
@@ -138,7 +138,7 @@
insertText = '',
selTextArr = selText.split( '\n' );
for ( i = 0; i < selTextArr.length; i++ ) {
- insertText += pre + selTextArr[i] + post;
+ insertText += pre + selTextArr[ i ] + post;
if ( i !== selTextArr.length - 1 ) {
insertText += '\n';
}
@@ -160,7 +160,7 @@
context.fn.restoreCursorAndScrollTop();
}
if ( options.selectionStart !== undefined ) {
- $( this ).textSelection( 'setSelection', { 'start': options.selectionStart, 'end': options.selectionEnd } );
+ $( this ).textSelection( 'setSelection', { start: options.selectionStart, end: options.selectionEnd } );
}
selText = $( this ).textSelection( 'getSelection' );
@@ -203,7 +203,7 @@
$( this ).focus();
if ( options.selectionStart !== undefined ) {
- $( this ).textSelection( 'setSelection', { 'start': options.selectionStart, 'end': options.selectionEnd } );
+ $( this ).textSelection( 'setSelection', { start: options.selectionStart, end: options.selectionEnd } );
}
selText = $( this ).textSelection( 'getSelection' );
@@ -411,7 +411,8 @@
*
* Scroll a textarea to the current cursor position. You can set the cursor
* position with setSelection()
- * @param options boolean Whether to force a scroll even if the caret position
+ *
+ * @param {boolean} options Whether to force a scroll even if the caret position
* is already visible. Defaults to false
*
* @fixme document the options parameters (function body suggests options.force is a boolean, not options itself)
@@ -576,7 +577,7 @@
context.fn.restoreSelection();
needSave = true;
}
- retval = ( alternateFn && alternateFn[command] || fn[command] ).call( this, options );
+ retval = ( alternateFn && alternateFn[ command ] || fn[ command ] ).call( this, options );
if ( hasWikiEditor && needSave ) {
context.fn.saveSelection();
}