"immed": true,
"latedef": true,
"newcap": true,
+ "noarg": true,
"noempty": true,
+ "nonew": true,
+ "regexp": false,
"undef": true,
+ "strict": false,
"trailing": true,
"laxbreak": true,
"multistr": true,
"browser": true,
- "jquery": true
+ "jquery": true,
+
+ "nomen": true,
+ "onevar": false
}
$.fn.makeCollapsible = function () {
return this.each(function () {
- var _fn = 'jquery.makeCollapsible> ';
+ var lpx = 'jquery.makeCollapsible> ';
// Define reused variables and functions
var $toggle,
var thatId = $that.attr( 'id' ),
$customTogglers = $( '.' + thatId.replace( 'mw-customcollapsible', 'mw-customtoggle' ) );
- mw.log( _fn + 'Found custom collapsible: #' + thatId );
+ mw.log( lpx + 'Found custom collapsible: #' + thatId );
// Double check that there is actually a customtoggle link
if ( $customTogglers.length ) {
toggleLinkCustom( $(this), e, $that );
} );
} else {
- mw.log( _fn + '#' + thatId + ': Missing toggler!' );
+ mw.log( lpx + '#' + thatId + ': Missing toggler!' );
}
// Initial state
// On IE, patch the focus() method to restore the windows' scroll position
// (bug 32241)
$.fn.extend({
- focus : ( function ( _focus ) {
+ focus: ( function ( jqFocus ) {
return function () {
if ( arguments.length === 0 ) {
var $w = $( window );
var state = {top: $w.scrollTop(), left: $w.scrollLeft()};
- var result = _focus.apply( this, arguments );
+ var result = jqFocus.apply( this, arguments );
window.scrollTo( state.top, state.left );
return result;
}
- return _focus.apply( this, arguments );
+ return jqFocus.apply( this, arguments );
};
}( $.fn.focus ) )
});
selectText: selectText
};
}
- var $image = $('<img>', {
+ var $image = $( '<img>', {
width : 23,
height: 22,
src : b.imageFile,
mw.toolbar = toolbar;
$( document ).ready( function () {
- var buttons, i, b, iframe;
+ var buttons, i, b, $iframe;
// currentFocus is used to determine where to insert tags
currentFocused = $( '#wpTextbox1' );
// HACK: make currentFocused work with the usability iframe
// With proper focus detection support (HTML 5!) this'll be much cleaner
- iframe = $( '.wikiEditor-ui-text iframe' );
- if ( iframe.length > 0 ) {
- $( iframe.get( 0 ).contentWindow.document )
+ // TODO: Get rid of this WikiEditor code from MediaWiki core!
+ $iframe = $( '.wikiEditor-ui-text iframe' );
+ if ( $iframe.length > 0 ) {
+ $( $iframe.get( 0 ).contentWindow.document )
// for IE
- .add( iframe.get( 0 ).contentWindow.document.body )
+ .add( $iframe.get( 0 ).contentWindow.document.body )
.focus( function () {
- currentFocused = iframe;
+ currentFocused = $iframe;
} );
}
});
return true;
}
- if ( $oldidRadio.prop( 'checked' ) ) {
+ if ( $oldidRadio.prop( 'checked' ) ) {
oldLi = true;
$li.addClass( 'selected' );
$oldidRadio.css( 'visibility', 'visible' );
$diffRadio.css( 'visibility', 'hidden' );
- } else if ( $diffRadio.prop( 'checked' ) ) {
+ } else if ( $diffRadio.prop( 'checked' ) ) {
diffLi = true;
$li.addClass( 'selected' );
$oldidRadio.css( 'visibility', 'hidden' );
$diffRadio.css( 'visibility', 'visible' );
// This list item has neither checked
- } else {
+ } else {
// We're below the selected radios
if ( diffLi && oldLi ) {
$oldidRadio.css( 'visibility', 'visible' );
/**
* This module enables double-click-to-edit functionality
*/
-jQuery( document ).ready( function( $ ) {
- var url = $( '#ca-edit a' ).attr( 'href' );
- if ( url ) {
- mw.util.$content.dblclick( function( e ) {
- e.preventDefault();
- window.location = url;
- } );
- }
-} );
+( function ( mw, $ ) {
+ $( function () {
+ var url = $( '#ca-edit a' ).attr( 'href' );
+ if ( url ) {
+ mw.util.$content.dblclick( function ( e ) {
+ e.preventDefault();
+ window.location = url;
+ } );
+ }
+ } );
+}( mediaWiki, jQuery ) );
-// Exif metadata display for MediaWiki file uploads
-//
-// Add an expand/collapse link and collapse by default if set to
-// (with JS disabled, user will see all items)
-//
+/**
+ * Exif metadata display for MediaWiki file uploads
+ *
+ * Add an expand/collapse link and collapse by default if set to
+ * (with JS disabled, user will see all items)
+ */
+( function ( mw, $ ) {
+ $( function () {
+ var $row, $col, $link,
+ showText = mw.msg( 'metadata-expand' ),
+ hideText = mw.msg( 'metadata-collapse' ),
+ $table = $( '#mw_metadata' ),
+ $tbody = $table.find( 'tbody' );
-jQuery( document ).ready( function( $ ) {
- var showText = mw.msg( 'metadata-expand' );
- var hideText = mw.msg( 'metadata-collapse' );
+ if ( !$tbody.length ) {
+ return;
+ }
- var $table = $( '#mw_metadata' );
- var $tbody = $table.find( 'tbody' );
- if ( !$tbody.length ) {
- return;
- }
+ $row = $( '<tr class="mw-metadata-show-hide-extended"></tr>' );
+ $col = $( '<td colspan="2"></td>' );
- var $row = $( '<tr class="mw-metadata-show-hide-extended"></tr>' );
- var $col = $( '<td colspan="2"></td>' );
+ $link = $( '<a>', {
+ text: showText,
+ href: '#'
+ }).click(function () {
+ if ( $table.hasClass( 'collapsed' ) ) {
+ $( this ).text( hideText );
+ } else {
+ $( this ).text( showText );
+ }
+ $table.toggleClass( 'expanded collapsed' );
+ return false;
+ });
- var $link = $( '<a></a>', {
- 'text': showText,
- 'href': '#'
- }).click(function() {
- if ( $table.hasClass( 'collapsed' ) ) {
- $( this ).text( hideText );
- } else {
- $( this ).text( showText );
- }
- $table.toggleClass( 'expanded collapsed' );
- return false;
- });
+ $col.append( $link );
+ $row.append( $col );
+ $tbody.append( $row );
- $col.append( $link );
- $row.append( $col );
- $tbody.append( $row );
+ // And collapse!
+ $table.addClass( 'collapsed' );
+ } );
- // And collapse!
- $table.addClass( 'collapsed' );
-} );
+}( mediaWiki, jQuery ) );
\ No newline at end of file
* Base language object with methods for storing and getting
* language data.
*/
-( function( $, mw ) {
+( function ( mw, $ ) {
var language = {
/**
mw.language = language;
-} )( jQuery, mediaWiki );
+}( mediaWiki, jQuery ) );
* Language.php in MediaWiki.
* This adds methods for transforming message text.
*/
-( function( $, mw ) {
+( function ( mw, $ ) {
var language = {
*
* @param {object} template Template object
* @format template
- * {
- * 'title': [title of template],
- * 'parameters': [template parameters]
- * }
+ * {
+ * 'title': [title of template],
+ * 'parameters': [template parameters]
+ * }
* @example {{Template:title|params}}
*/
- 'procPLURAL': function( template ) {
+ procPLURAL: function ( template ) {
if ( template.title && template.parameters && mw.language.convertPlural ) {
// Check if we have forms to replace
if ( template.parameters.length === 0 ) {
}
return '';
},
+
/**
* Plural form transformations, needed for some languages.
*
* @param forms array List of plural forms
* @return string Correct form for quantifier in this language
*/
- 'convertPlural': function( count, forms ){
+ convertPlural: function ( count, forms ){
if ( !forms || forms.length === 0 ) {
return '';
}
- return ( parseInt( count, 10 ) == 1 ) ? forms[0] : forms[1];
+ return ( parseInt( count, 10 ) === 1 ) ? forms[0] : forms[1];
},
+
/**
* Pads an array to a specific length by copying the last one element.
*
* @param count integer Number of forms required
* @return array Padded array of forms
*/
- 'preConvertPlural': function( forms, count ) {
+ preConvertPlural: function ( forms, count ) {
while ( forms.length < count ) {
forms.push( forms[ forms.length-1 ] );
}
return forms;
},
+
/**
* Converts a number using digitTransformTable.
*
* @param {num} number Value to be converted
* @param {boolean} integer Convert the return value to an integer
*/
- 'convertNumber': function( num, integer ) {
+ convertNumber: function( num, integer ) {
+ var i, tmp, transformTable;
+
if ( !mw.language.digitTransformTable ) {
return num;
}
// Set the target Transform table:
- var transformTable = mw.language.digitTransformTable;
+ transformTable = mw.language.digitTransformTable;
// Check if the "restore" to Latin number flag is set:
if ( integer ) {
- if ( parseInt( num, 10 ) == num ) {
+ if ( parseInt( num, 10 ) === num ) {
return num;
}
- var tmp = [];
- for ( var i in transformTable ) {
+ tmp = [];
+ for ( i in transformTable ) {
tmp[ transformTable[ i ] ] = i;
}
transformTable = tmp;
}
- var numberString = '' + num;
+ var numberString = '' + num;
var convertedNumber = '';
- for ( var i = 0; i < numberString.length; i++ ) {
+ for ( i = 0; i < numberString.length; i++ ) {
if ( transformTable[ numberString[i] ] ) {
convertedNumber += transformTable[numberString[i]];
} else {
}
return integer ? parseInt( convertedNumber, 10 ) : convertedNumber;
},
+
/**
* Provides an alternative text depending on specified gender.
* Usage {{gender:[gender|user object]|masculine|feminine|neutral}}.
*
* @return string
*/
- 'gender': function( gender, forms ) {
+ gender: function( gender, forms ) {
if ( !forms || forms.length === 0 ) {
return '';
}
},
// Digit Transform Table, populated by language classes where applicable
- 'digitTransformTable': mw.language.getData( mw.config.get( 'wgUserLanguage' ), 'digitTransformTable' )
+ digitTransformTable: mw.language.getData( mw.config.get( 'wgUserLanguage' ), 'digitTransformTable' )
};
$.extend( mw.language, language );
-} )( jQuery, mediaWiki );
+}( mediaWiki, jQuery ) );
-( function ( $ ) {
+( function ( mw, $ ) {
mw.page = {};
// is defined for them.
$( mw.util.init );
-} )( jQuery );
+}( mediaWiki, jQuery ) );
* Animate watch/unwatch links to use asynchronous API requests to
* watch pages, rather than navigating to a different URI.
*/
-( function ( $, mw, undefined ) {
+( function ( mw, $ ) {
/**
* The name of the page to watch or unwatch.
*/
var title = mw.config.get( 'wgRelevantPageName', mw.config.get( 'wgPageName' ) );
- // Expose local methods
- mw.page.watch = {
- 'updateWatchLink': updateWatchLink
- };
/**
* Update the link text, link href attribute and (if applicable)
* "loading" class.
return 'view';
}
+ // Expose local methods
+ mw.page.watch = {
+ 'updateWatchLink': updateWatchLink
+ };
+
$( document ).ready( function () {
var $links = $( '.mw-watchlink a, a.mw-watchlink, ' +
'#ca-watch a, #ca-unwatch a, #mw-unwatch-link1, ' +
});
});
-}( jQuery, mediaWiki ) );
+}( mediaWiki, jQuery ) );
/*
* JavaScript for Special:ChangeEmail
*/
-( function( $, mw ) {
+( function ( mw, $ ) {
/**
* Given an email validity status (true, false, null) update the label CSS class
*/
-var updateMailValidityLabel = function( mail ) {
+function updateMailValidityLabel( mail ) {
var isValid = mw.util.validateEmail( mail ),
$label = $( '#mw-emailaddress-validity' );
} else {
$label.text( mw.msg( 'email-address-validity-invalid' ) ).addClass( 'invalid' ).removeClass( 'valid' );
}
-};
+}
-$( document ).ready( function() {
+$( document ).ready( function () {
// Lame tip to let user know if its email is valid. See bug 22449
// Only bind once for 'blur' so that the user can fill it in without errors
// After that look at every keypress for direct feedback if it was invalid onblur
- $( '#wpNewEmail' ).one( 'blur', function() {
+ $( '#wpNewEmail' ).one( 'blur', function () {
if ( $( '#mw-emailaddress-validity' ).length === 0 ) {
$(this).after( '<label for="wpNewEmail" id="mw-emailaddress-validity"></label>' );
}
updateMailValidityLabel( $(this).val() );
- $(this).keyup( function() {
+ $(this).keyup( function () {
updateMailValidityLabel( $(this).val() );
} );
} );
} );
-} )( jQuery, mediaWiki );
+}( mediaWiki, jQuery ) );
-/*
+/**
* JavaScript for Special:JavaScriptTest
*/
-jQuery( document ).ready( function( $ ) {
+( function ( mw, $ ) {
+ $( function () {
- // Create useskin dropdown menu and reload onchange to the selected skin
- // (only if a framework was found, not on error pages).
- $( '#mw-javascripttest-summary.mw-javascripttest-frameworkfound' ).append( function() {
+ // Create useskin dropdown menu and reload onchange to the selected skin
+ // (only if a framework was found, not on error pages).
+ $( '#mw-javascripttest-summary.mw-javascripttest-frameworkfound' ).append( function () {
- var $html = $( '<p><label for="useskin">'
- + mw.message( 'javascripttest-pagetext-skins' ).escaped()
- + ' '
- + '</label></p>' ),
- select = '<select name="useskin" id="useskin">';
+ var $html = $( '<p><label for="useskin">'
+ + mw.message( 'javascripttest-pagetext-skins' ).escaped()
+ + ' '
+ + '</label></p>' ),
+ select = '<select name="useskin" id="useskin">';
- // Build <select> further
- $.each( mw.config.get( 'wgAvailableSkins' ), function( id ) {
- select += '<option value="' + id + '"'
- + ( mw.config.get( 'skin' ) === id ? ' selected="selected"' : '' )
- + '>' + mw.message( 'skinname-' + id ).escaped() + '</option>';
- } );
- select += '</select>';
+ // Build <select> further
+ $.each( mw.config.get( 'wgAvailableSkins' ), function ( id ) {
+ select += '<option value="' + id + '"'
+ + ( mw.config.get( 'skin' ) === id ? ' selected="selected"' : '' )
+ + '>' + mw.message( 'skinname-' + id ).escaped() + '</option>';
+ } );
+ select += '</select>';
- // Bind onchange event handler and append to form
- $html.append(
- $( select ).change( function() {
- window.location = QUnit.url( { useskin: $(this).val() } );
- } )
- );
+ // Bind onchange event handler and append to form
+ $html.append(
+ $( select ).change( function () {
+ window.location = QUnit.url( { useskin: $(this).val() } );
+ } )
+ );
- return $html;
+ return $html;
+ } );
} );
-} );
+
+}( mediaWiki, jQuery ) );
+
/* JavaScript for Special:RecentChanges */
-( function( $ ) {
+( function ( mw, $ ) {
var checkboxes = [ 'nsassociated', 'nsinvert' ];
* Handler to disable/enable the namespace selector checkboxes when the
* special 'all' namespace is selected/unselected respectively.
*/
- updateCheckboxes: function() {
+ updateCheckboxes: function () {
// The option element for the 'all' namespace has an empty value
- var isAllNS = ('' === $select.find('option:selected').val() );
+ var isAllNS = $select.find('option:selected').val() === '';
// Iterates over checkboxes and propagate the selected option
- $.each( checkboxes, function( i, id ) {
+ $.each( checkboxes, function ( i, id ) {
$( '#' + id ).prop( 'disabled', isAllNS );
});
},
- init: function() {
+ init: function () {
// Populate
$select = $( '#namespace' );
// Run when document is ready
$( rc.init );
-})( jQuery );
+}( mediaWiki, jQuery ) );
-/*
+/**
* JavaScript for Special:Upload
* Note that additional code still lives in skins/common/upload.js
*/
-
-/**
- * Add a preview to the upload form
- */
-jQuery( function( $ ) {
- /**
- * Is the FileAPI available with sufficient functionality?
- */
- function hasFileAPI(){
- return typeof window.FileReader !== 'undefined';
- }
-
+( function ( mw, $ ) {
/**
- * Check if this is a recognizable image type...
- * Also excludes files over 10M to avoid going insane on memory usage.
- *
- * @todo is there a way we can ask the browser what's supported in <img>s?
- * @todo put SVG back after working around Firefox 7 bug <https://bugzilla.wikimedia.org/show_bug.cgi?id=31643>
- *
- * @param {File} file
- * @return boolean
+ * Add a preview to the upload form
*/
- function fileIsPreviewable( file ) {
- var known = ['image/png', 'image/gif', 'image/jpeg', 'image/svg+xml'],
- tooHuge = 10 * 1024 * 1024;
- return ( $.inArray( file.type, known ) !== -1 ) && file.size > 0 && file.size < tooHuge;
- }
+ $( function ( $ ) {
+ /**
+ * Is the FileAPI available with sufficient functionality?
+ */
+ function hasFileAPI() {
+ return typeof window.FileReader !== 'undefined';
+ }
- /**
- * Show a thumbnail preview of PNG, JPEG, GIF, and SVG files prior to upload
- * in browsers supporting HTML5 FileAPI.
- *
- * As of this writing, known good:
- * - Firefox 3.6+
- * - Chrome 7.something
- *
- * @todo check file size limits and warn of likely failures
- *
- * @param {File} file
- */
- function showPreview( file ) {
- var previewSize = 180,
- thumb = $( '<div id="mw-upload-thumbnail" class="thumb tright">' +
- '<div class="thumbinner">' +
- '<div class="mw-small-spinner" style="width: 180px; height: 180px"></div>' +
- '<div class="thumbcaption"><div class="filename"></div><div class="fileinfo"></div></div>' +
- '</div>' +
- '</div>' );
- thumb.find( '.filename' ).text( file.name ).end()
- .find( '.fileinfo' ).text( prettySize( file.size ) ).end();
+ /**
+ * Check if this is a recognizable image type...
+ * Also excludes files over 10M to avoid going insane on memory usage.
+ *
+ * @todo is there a way we can ask the browser what's supported in <img>s?
+ * @todo put SVG back after working around Firefox 7 bug <https://bugzilla.wikimedia.org/show_bug.cgi?id=31643>
+ *
+ * @param {File} file
+ * @return boolean
+ */
+ function fileIsPreviewable( file ) {
+ var known = ['image/png', 'image/gif', 'image/jpeg', 'image/svg+xml'],
+ tooHuge = 10 * 1024 * 1024;
+ return ( $.inArray( file.type, known ) !== -1 ) && file.size > 0 && file.size < tooHuge;
+ }
- var $canvas = $('<canvas width="' + previewSize + '" height="' + previewSize + '" ></canvas>'),
- ctx = $canvas[0].getContext( '2d' );
- $( '#mw-htmlform-source' ).parent().prepend( thumb );
+ /**
+ * Show a thumbnail preview of PNG, JPEG, GIF, and SVG files prior to upload
+ * in browsers supporting HTML5 FileAPI.
+ *
+ * As of this writing, known good:
+ * - Firefox 3.6+
+ * - Chrome 7.something
+ *
+ * @todo check file size limits and warn of likely failures
+ *
+ * @param {File} file
+ */
+ function showPreview( file ) {
+ var previewSize = 180,
+ thumb = $( '<div id="mw-upload-thumbnail" class="thumb tright">' +
+ '<div class="thumbinner">' +
+ '<div class="mw-small-spinner" style="width: 180px; height: 180px"></div>' +
+ '<div class="thumbcaption"><div class="filename"></div><div class="fileinfo"></div></div>' +
+ '</div>' +
+ '</div>' );
+ thumb.find( '.filename' ).text( file.name ).end()
+ .find( '.fileinfo' ).text( prettySize( file.size ) ).end();
- var meta;
- fetchPreview( file, function( dataURL ) {
- var img = new Image(),
- rotation = 0;
+ var $canvas = $('<canvas width="' + previewSize + '" height="' + previewSize + '" ></canvas>'),
+ ctx = $canvas[0].getContext( '2d' );
+ $( '#mw-htmlform-source' ).parent().prepend( thumb );
- if ( meta && meta.tiff && meta.tiff.Orientation ) {
- rotation = (360 - function () {
- // See includes/media/Bitmap.php
- switch ( meta.tiff.Orientation.value ) {
- case 8:
- return 90;
- case 3:
- return 180;
- case 6:
- return 270;
- default:
- return 0;
- }
- }() ) % 360;
- }
+ var meta;
+ fetchPreview( file, function( dataURL ) {
+ var img = new Image(),
+ rotation = 0;
- img.onload = function() {
- var width, height, x, y, dx, dy, logicalWidth, logicalHeight;
- // Fit the image within the previewSizexpreviewSize box
- if ( img.width > img.height ) {
- width = previewSize;
- height = img.height / img.width * previewSize;
- } else {
- height = previewSize;
- width = img.width / img.height * previewSize;
+ if ( meta && meta.tiff && meta.tiff.Orientation ) {
+ rotation = ( 360 - ( function () {
+ // See includes/media/Bitmap.php
+ switch ( meta.tiff.Orientation.value ) {
+ case 8:
+ return 90;
+ case 3:
+ return 180;
+ case 6:
+ return 270;
+ default:
+ return 0;
+ }
+ }() ) ) % 360;
}
- // Determine the offset required to center the image
- dx = (180 - width) / 2;
- dy = (180 - height) / 2;
- switch ( rotation ) {
- // If a rotation is applied, the direction of the axis
- // changes as well. You can derive the values below by
- // drawing on paper an axis system, rotate it and see
- // where the positive axis direction is
- case 0:
- x = dx;
- y = dy;
- logicalWidth = img.width;
- logicalHeight = img.height;
- break;
- case 90:
- x = dx;
- y = dy - previewSize;
- logicalWidth = img.height;
- logicalHeight = img.width;
- break;
- case 180:
- x = dx - previewSize;
- y = dy - previewSize;
- logicalWidth = img.width;
- logicalHeight = img.height;
- break;
- case 270:
- x = dx - previewSize;
- y = dy;
- logicalWidth = img.height;
- logicalHeight = img.width;
- break;
- }
-
- ctx.clearRect( 0, 0, 180, 180 );
- ctx.rotate( rotation / 180 * Math.PI );
- ctx.drawImage( img, x, y, width, height );
- thumb.find('.mw-small-spinner').replaceWith($canvas);
+ img.onload = function () {
+ var width, height, x, y, dx, dy, logicalWidth, logicalHeight;
+ // Fit the image within the previewSizexpreviewSize box
+ if ( img.width > img.height ) {
+ width = previewSize;
+ height = img.height / img.width * previewSize;
+ } else {
+ height = previewSize;
+ width = img.width / img.height * previewSize;
+ }
+ // Determine the offset required to center the image
+ dx = (180 - width) / 2;
+ dy = (180 - height) / 2;
+ switch ( rotation ) {
+ // If a rotation is applied, the direction of the axis
+ // changes as well. You can derive the values below by
+ // drawing on paper an axis system, rotate it and see
+ // where the positive axis direction is
+ case 0:
+ x = dx;
+ y = dy;
+ logicalWidth = img.width;
+ logicalHeight = img.height;
+ break;
+ case 90:
- // Image size
- var info = mw.msg( 'widthheight', logicalWidth, logicalHeight ) +
- ', ' + prettySize( file.size );
- $( '#mw-upload-thumbnail .fileinfo' ).text( info );
- };
- img.src = dataURL;
- }, mw.config.get( 'wgFileCanRotate' ) ? function ( data ) {
- try {
- meta = mw.libs.jpegmeta( data, file.fileName );
- meta._binary_data = null;
- } catch ( e ) {
- meta = null;
- }
- } : null );
- }
+ x = dx;
+ y = dy - previewSize;
+ logicalWidth = img.height;
+ logicalHeight = img.width;
+ break;
+ case 180:
+ x = dx - previewSize;
+ y = dy - previewSize;
+ logicalWidth = img.width;
+ logicalHeight = img.height;
+ break;
+ case 270:
+ x = dx - previewSize;
+ y = dy;
+ logicalWidth = img.height;
+ logicalHeight = img.width;
+ break;
+ }
- /**
- * Start loading a file into memory; when complete, pass it as a
- * data URL to the callback function. If the callbackBinary is set it will
- * first be read as binary and afterwards as data URL. Useful if you want
- * to do preprocessing on the binary data first.
- *
- * @param {File} file
- * @param {function} callback
- * @param {function} callbackBinary
- */
- function fetchPreview( file, callback, callbackBinary ) {
- var reader = new FileReader();
- if ( callbackBinary && 'readAsBinaryString' in reader ) {
- // To fetch JPEG metadata we need a binary string; start there.
- // todo:
- reader.onload = function() {
- callbackBinary( reader.result );
+ ctx.clearRect( 0, 0, 180, 180 );
+ ctx.rotate( rotation / 180 * Math.PI );
+ ctx.drawImage( img, x, y, width, height );
+ thumb.find('.mw-small-spinner').replaceWith($canvas);
- // Now run back through the regular code path.
- fetchPreview( file, callback );
- };
- reader.readAsBinaryString( file );
- } else if ( callbackBinary && 'readAsArrayBuffer' in reader ) {
- // readAsArrayBuffer replaces readAsBinaryString
- // However, our JPEG metadata library wants a string.
- // So, this is going to be an ugly conversion.
- reader.onload = function() {
- var buffer = new Uint8Array( reader.result ),
- string = '';
- for ( var i = 0; i < buffer.byteLength; i++ ) {
- string += String.fromCharCode( buffer[i] );
+ // Image size
+ var info = mw.msg( 'widthheight', logicalWidth, logicalHeight ) +
+ ', ' + prettySize( file.size );
+ $( '#mw-upload-thumbnail .fileinfo' ).text( info );
+ };
+ img.src = dataURL;
+ }, mw.config.get( 'wgFileCanRotate' ) ? function ( data ) {
+ try {
+ meta = mw.libs.jpegmeta( data, file.fileName );
+ meta._binary_data = null;
+ } catch ( e ) {
+ meta = null;
}
- callbackBinary( string );
-
- // Now run back through the regular code path.
- fetchPreview( file, callback );
- };
- reader.readAsArrayBuffer( file );
- } else if ( 'URL' in window && 'createObjectURL' in window.URL ) {
- // Supported in Firefox 4.0 and above <https://developer.mozilla.org/en/DOM/window.URL.createObjectURL>
- // WebKit has it in a namespace for now but that's ok. ;)
- //
- // Lifetime of this URL is until document close, which is fine
- // for Special:Upload -- if this code gets used on longer-running
- // pages, add a revokeObjectURL() when it's no longer needed.
- //
- // Prefer this over readAsDataURL for Firefox 7 due to bug reading
- // some SVG files from data URIs <https://bugzilla.mozilla.org/show_bug.cgi?id=694165>
- callback( window.URL.createObjectURL( file ) );
- } else {
- // This ends up decoding the file to base-64 and back again, which
- // feels horribly inefficient.
- reader.onload = function() {
- callback( reader.result );
- };
- reader.readAsDataURL( file );
+ } : null );
}
- }
- /**
- * Format a file size attractively.
- * @todo match numeric formatting
- *
- * @param {number} s
- * @return string
- */
- function prettySize( s ) {
- var sizes = ['size-bytes', 'size-kilobytes', 'size-megabytes', 'size-gigabytes'];
- while ( s >= 1024 && sizes.length > 1 ) {
- s /= 1024;
- sizes = sizes.slice( 1 );
- }
- return mw.msg( sizes[0], Math.round( s ) );
- }
+ /**
+ * Start loading a file into memory; when complete, pass it as a
+ * data URL to the callback function. If the callbackBinary is set it will
+ * first be read as binary and afterwards as data URL. Useful if you want
+ * to do preprocessing on the binary data first.
+ *
+ * @param {File} file
+ * @param {function} callback
+ * @param {function} callbackBinary
+ */
+ function fetchPreview( file, callback, callbackBinary ) {
+ var reader = new FileReader();
+ if ( callbackBinary && 'readAsBinaryString' in reader ) {
+ // To fetch JPEG metadata we need a binary string; start there.
+ // todo:
+ reader.onload = function() {
+ callbackBinary( reader.result );
- /**
- * Clear the file upload preview area.
- */
- function clearPreview() {
- $( '#mw-upload-thumbnail' ).remove();
- }
+ // Now run back through the regular code path.
+ fetchPreview( file, callback );
+ };
+ reader.readAsBinaryString( file );
+ } else if ( callbackBinary && 'readAsArrayBuffer' in reader ) {
+ // readAsArrayBuffer replaces readAsBinaryString
+ // However, our JPEG metadata library wants a string.
+ // So, this is going to be an ugly conversion.
+ reader.onload = function() {
+ var buffer = new Uint8Array( reader.result ),
+ string = '';
+ for ( var i = 0; i < buffer.byteLength; i++ ) {
+ string += String.fromCharCode( buffer[i] );
+ }
+ callbackBinary( string );
- /**
- * Check if the file does not exceed the maximum size
- */
- function checkMaxUploadSize( file ) {
- function getMaxUploadSize( type ) {
- var sizes = mw.config.get( 'wgMaxUploadSize' );
- if ( sizes[type] !== undefined ) {
- return sizes[type];
+ // Now run back through the regular code path.
+ fetchPreview( file, callback );
+ };
+ reader.readAsArrayBuffer( file );
+ } else if ( 'URL' in window && 'createObjectURL' in window.URL ) {
+ // Supported in Firefox 4.0 and above <https://developer.mozilla.org/en/DOM/window.URL.createObjectURL>
+ // WebKit has it in a namespace for now but that's ok. ;)
+ //
+ // Lifetime of this URL is until document close, which is fine
+ // for Special:Upload -- if this code gets used on longer-running
+ // pages, add a revokeObjectURL() when it's no longer needed.
+ //
+ // Prefer this over readAsDataURL for Firefox 7 due to bug reading
+ // some SVG files from data URIs <https://bugzilla.mozilla.org/show_bug.cgi?id=694165>
+ callback( window.URL.createObjectURL( file ) );
+ } else {
+ // This ends up decoding the file to base-64 and back again, which
+ // feels horribly inefficient.
+ reader.onload = function() {
+ callback( reader.result );
+ };
+ reader.readAsDataURL( file );
}
- return sizes['*'];
}
- $( '.mw-upload-source-error' ).remove();
- var maxSize = getMaxUploadSize( 'file' );
- if ( file.size > maxSize ) {
- var error = $( '<p class="error mw-upload-source-error" id="wpSourceTypeFile-error">' +
- mw.message( 'largefileserver', file.size, maxSize ).escaped() + '</p>' );
- $( '#wpUploadFile' ).after( error );
- return false;
+ /**
+ * Format a file size attractively.
+ * @todo match numeric formatting
+ *
+ * @param {number} s
+ * @return string
+ */
+ function prettySize( s ) {
+ var sizeMsgs = ['size-bytes', 'size-kilobytes', 'size-megabytes', 'size-gigabytes'];
+ while ( s >= 1024 && sizeMsgs.length > 1 ) {
+ s /= 1024;
+ sizeMsgs = sizeMsgs.slice( 1 );
+ }
+ return mw.msg( sizeMsgs[0], Math.round( s ) );
}
- return true;
- }
-
- /**
- * Initialization
- */
- if ( hasFileAPI() ) {
- // Update thumbnail when the file selection control is updated.
- $( '#wpUploadFile' ).change( function() {
- clearPreview();
- if ( this.files && this.files.length ) {
- // Note: would need to be updated to handle multiple files.
- var file = this.files[0];
+ /**
+ * Clear the file upload preview area.
+ */
+ function clearPreview() {
+ $( '#mw-upload-thumbnail' ).remove();
+ }
- if ( !checkMaxUploadSize( file ) ) {
- return;
+ /**
+ * Check if the file does not exceed the maximum size
+ */
+ function checkMaxUploadSize( file ) {
+ function getMaxUploadSize( type ) {
+ var sizes = mw.config.get( 'wgMaxUploadSize' );
+ if ( sizes[type] !== undefined ) {
+ return sizes[type];
}
+ return sizes['*'];
+ }
+ $( '.mw-upload-source-error' ).remove();
- if ( fileIsPreviewable( file ) ) {
- showPreview( file );
- }
+ var maxSize = getMaxUploadSize( 'file' );
+ if ( file.size > maxSize ) {
+ var error = $( '<p class="error mw-upload-source-error" id="wpSourceTypeFile-error">' +
+ mw.message( 'largefileserver', file.size, maxSize ).escaped() + '</p>' );
+ $( '#wpUploadFile' ).after( error );
+ return false;
}
- } );
- }
-} );
+ return true;
+ }
-/**
- * Disable all upload source fields except the selected one
- */
-jQuery( function ( $ ) {
- var rows = $( '.mw-htmlform-field-UploadSourceField' );
- for ( var i = rows.length; i; i-- ) {
- var row = rows[i - 1];
- $( 'input[name="wpSourceType"]', row ).change( function () {
- var currentRow = row; // Store current row in our own scope
- return function () {
- $( '.mw-upload-source-error' ).remove();
- if ( this.checked ) {
- // Disable all inputs
- $( 'input[name!="wpSourceType"]', rows ).prop( 'disabled', 'disabled' );
- // Re-enable the current one
- $( 'input', currentRow ).prop( 'disabled', false );
+
+ /**
+ * Initialization
+ */
+ if ( hasFileAPI() ) {
+ // Update thumbnail when the file selection control is updated.
+ $( '#wpUploadFile' ).change( function () {
+ clearPreview();
+ if ( this.files && this.files.length ) {
+ // Note: would need to be updated to handle multiple files.
+ var file = this.files[0];
+
+ if ( !checkMaxUploadSize( file ) ) {
+ return;
+ }
+
+ if ( fileIsPreviewable( file ) ) {
+ showPreview( file );
+ }
}
- };
- }() );
- }
-} );
+ } );
+ }
+ } );
+
+ /**
+ * Disable all upload source fields except the selected one
+ */
+ $( function ( $ ) {
+ var i, row,
+ rows = $( '.mw-htmlform-field-UploadSourceField' );
+ for ( i = rows.length; i; i-- ) {
+ row = rows[i - 1];
+ $( 'input[name="wpSourceType"]', row ).change( ( function () {
+ var currentRow = row; // Store current row in our own scope
+ return function () {
+ $( '.mw-upload-source-error' ).remove();
+ if ( this.checked ) {
+ // Disable all inputs
+ $( 'input[name!="wpSourceType"]', rows ).prop( 'disabled', true );
+ // Re-enable the current one
+ $( 'input', currentRow ).prop( 'disabled', false );
+ }
+ };
+ }() ) );
+ }
+ } );
+}( mediaWiki, jQuery ) );
*
* Relies on: mw.config (wgFormattedNamespaces, wgNamespaceIds, wgCaseSensitiveNamespaces), mw.util.wikiGetlink
*/
-( function( $ ) {
+( function ( mw, $ ) {
/* Local space */
* @param namespace {Number} (optional) Namespace id. If given, title will be taken as-is.
* @return {Title} this
*/
-var Title = function( title, namespace ) {
- this._ns = 0; // integer namespace id
- this._name = null; // name in canonical 'database' form
- this._ext = null; // extension
+ function Title( title, namespace ) {
+ this.ns = 0; // integer namespace id
+ this.name = null; // name in canonical 'database' form
+ this.ext = null; // extension
if ( arguments.length === 2 ) {
setNameAndExtension( this, title );
- this._ns = fixNsId( namespace );
+ this.ns = fixNsId( namespace );
} else if ( arguments.length === 1 ) {
setAll( this, title );
}
return this;
- },
+ }
+var
/**
* Strip some illegal chars: control chars, colon, less than, greater than,
* brackets, braces, pipe, whitespace and normal spaces. This still leaves some insanity
* @param s {String}
* @return {String}
*/
- clean = function( s ) {
+ clean = function ( s ) {
if ( s !== undefined ) {
return s.replace( /[\x00-\x1f\x23\x3c\x3e\x5b\x5d\x7b\x7c\x7d\x7f\s]+/g, '_' );
}
/**
* Sanitize name.
*/
- fixName = function( s ) {
+ fixName = function ( s ) {
return clean( $.trim( s ) );
},
/**
* Sanitize name.
*/
- fixExt = function( s ) {
+ fixExt = function ( s ) {
return clean( s );
},
* @param id {Number} Namespace id.
* @return {Number|Boolean} The id as-is or boolean false if invalid.
*/
- fixNsId = function( id ) {
+ fixNsId = function ( id ) {
// wgFormattedNamespaces is an object of *string* key-vals (ie. arr["0"] not arr[0] )
var ns = mw.config.get( 'wgFormattedNamespaces' )[id.toString()];
* @param ns {String} Namespace name (case insensitive, leading/trailing space ignored).
* @return {Number|Boolean} Namespace id or boolean false if unrecognized.
*/
- getNsIdByName = function( ns ) {
- // toLowerCase throws exception on null/undefined. Return early.
- if ( ns == null ) {
+ getNsIdByName = function ( ns ) {
+ // Don't cast non-strings to strings, because null or undefined
+ // should not result in returning the id of a potential namespace
+ // called "Null:" (e.g. on nullwiki.example.org)
+ // Also, toLowerCase throws exception on null/undefined, because
+ // it is a String.prototype method.
+ if ( typeof ns !== 'string' ) {
return false;
}
ns = clean( $.trim( ns.toLowerCase() ) ); // Normalize
* @param raw {String}
* @return {mw.Title}
*/
- setAll = function( title, s ) {
+ setAll = function ( title, s ) {
// In normal browsers the match-array contains null/undefined if there's no match,
// IE returns an empty string.
var matches = s.match( /^(?:([^:]+):)?(.*?)(?:\.(\w{1,5}))?$/ ),
// Namespace must be valid, and title must be a non-empty string.
if ( ns_match && typeof matches[2] === 'string' && matches[2] !== '' ) {
- title._ns = ns_match;
- title._name = fixName( matches[2] );
+ title.ns = ns_match;
+ title.name = fixName( matches[2] );
if ( typeof matches[3] === 'string' && matches[3] !== '' ) {
- title._ext = fixExt( matches[3] );
+ title.ext = fixExt( matches[3] );
}
} else {
// Consistency with MediaWiki PHP: Unknown namespace -> fallback to main namespace.
- title._ns = 0;
+ title.ns = 0;
setNameAndExtension( title, s );
}
return title;
* @param raw {String}
* @return {mw.Title}
*/
- setNameAndExtension = function( title, raw ) {
+ setNameAndExtension = function ( title, raw ) {
// In normal browsers the match-array contains null/undefined if there's no match,
// IE returns an empty string.
var matches = raw.match( /^(?:)?(.*?)(?:\.(\w{1,5}))?$/ );
// Title must be a non-empty string.
if ( typeof matches[1] === 'string' && matches[1] !== '' ) {
- title._name = fixName( matches[1] );
+ title.name = fixName( matches[1] );
if ( typeof matches[2] === 'string' && matches[2] !== '' ) {
- title._ext = fixExt( matches[2] );
+ title.ext = fixExt( matches[2] );
}
} else {
throw new Error( 'mw.Title: Could not parse title "' + raw + '"' );
* @param title {mixed} prefixed db-key name (string) or instance of Title
* @return {mixed} Boolean true/false if the information is available. Otherwise null.
*/
- Title.exists = function( title ) {
+ Title.exists = function ( title ) {
var type = $.type( title ), obj = Title.exist.pages, match;
if ( type === 'string' ) {
match = obj[title];
* @param state {Boolean} (optional) State of the given titles. Defaults to true.
* @return {Boolean}
*/
- set: function( titles, state ) {
+ set: function ( titles, state ) {
titles = $.isArray( titles ) ? titles : [titles];
state = state === undefined ? true : !!state;
var pages = this.pages, i, len = titles.length;
* Get the namespace number.
* @return {Number}
*/
- getNamespaceId: function(){
- return this._ns;
+ getNamespaceId: function (){
+ return this.ns;
},
/**
* In NS_MAIN this is '', otherwise namespace name plus ':'
* @return {String}
*/
- getNamespacePrefix: function(){
- return mw.config.get( 'wgFormattedNamespaces' )[this._ns].replace( / /g, '_' ) + (this._ns === 0 ? '' : ':');
+ getNamespacePrefix: function (){
+ return mw.config.get( 'wgFormattedNamespaces' )[this.ns].replace( / /g, '_' ) + (this.ns === 0 ? '' : ':');
},
/**
* The name, like "Foo_bar"
* @return {String}
*/
- getName: function() {
- if ( $.inArray( this._ns, mw.config.get( 'wgCaseSensitiveNamespaces' ) ) !== -1 ) {
- return this._name;
+ getName: function () {
+ if ( $.inArray( this.ns, mw.config.get( 'wgCaseSensitiveNamespaces' ) ) !== -1 ) {
+ return this.name;
} else {
- return $.ucFirst( this._name );
+ return $.ucFirst( this.name );
}
},
* The name, like "Foo bar"
* @return {String}
*/
- getNameText: function() {
+ getNameText: function () {
return text( this.getName() );
},
* Get full name in prefixed DB form, like File:Foo_bar.jpg,
* most useful for API calls, anything that must identify the "title".
*/
- getPrefixedDb: function() {
+ getPrefixedDb: function () {
return this.getNamespacePrefix() + this.getMain();
},
* Get full name in text form, like "File:Foo bar.jpg".
* @return {String}
*/
- getPrefixedText: function() {
+ getPrefixedText: function () {
return text( this.getPrefixedDb() );
},
* The main title (without namespace), like "Foo_bar.jpg"
* @return {String}
*/
- getMain: function() {
+ getMain: function () {
return this.getName() + this.getDotExtension();
},
* The "text" form, like "Foo bar.jpg"
* @return {String}
*/
- getMainText: function() {
+ getMainText: function () {
return text( this.getMain() );
},
* Get the extension (returns null if there was none)
* @return {String|null} extension
*/
- getExtension: function() {
- return this._ext;
+ getExtension: function () {
+ return this.ext;
},
/**
* Convenience method: return string like ".jpg", or "" if no extension
* @return {String}
*/
- getDotExtension: function() {
- return this._ext === null ? '' : '.' + this._ext;
+ getDotExtension: function () {
+ return this.ext === null ? '' : '.' + this.ext;
},
/**
* Return the URL to this title
* @return {String}
*/
- getUrl: function() {
+ getUrl: function () {
return mw.util.wikiGetlink( this.toString() );
},
* Whether this title exists on the wiki.
* @return {mixed} Boolean true/false if the information is available. Otherwise null.
*/
- exists: function() {
+ exists: function () {
return Title.exists( this );
}
};
// Expose
mw.Title = Title;
-})(jQuery);
+}( mediaWiki, jQuery ) );
var args = [];
$.each( this.query, function ( key, val ) {
var k = Uri.encode( key ),
- vals = val === null ? [ null ] : $.makeArray( val );
+ vals = $.isArray( val ) ? val : [ val ];
$.each( vals, function ( i, v ) {
args.push( k + ( v === null ? '' : '=' + Uri.encode( v ) ) );
} );
defaultUri = new Uri( documentLocation );
- return Uri;
+ return Uri;
};
// if we are running in a browser, inject the current document location, for relative URLs
- if ( document && document.location && document.location.href ) {
+ if ( document && document.location && document.location.href ) {
mw.Uri = mw.UriRelative( document.location.href );
}
* @since 1.19
*/
-( function ( $, mw, undefined ) {
-"use strict";
+( function ( mw, $ ) {
+ 'use strict';
- var hovzer = $.getFootHovzer();
+ var debug,
+ hovzer = $.getFootHovzer();
- var debug = mw.Debug = {
+ debug = mw.Debug = {
/**
* Toolbar container element
*
paneTriggerBitDiv( 'includes', 'PHP includes', this.data.includes.length );
var gitInfo = '';
- if ( this.data.gitRevision != false ) {
+ if ( this.data.gitRevision !== false ) {
gitInfo = '(' + this.data.gitRevision.substring( 0, 7 ) + ')';
- if ( this.data.gitViewUrl != false ) {
- gitInfo = $( '<a></a>' ).attr( 'href', this.data.gitViewUrl ).text( gitInfo );
+ if ( this.data.gitViewUrl !== false ) {
+ gitInfo = $( '<a>' ).attr( 'href', this.data.gitViewUrl ).text( gitInfo );
}
}
.append( ': ' + this.data.mwVersion + ' ' )
.append( gitInfo );
- if ( this.data.gitBranch != false ) {
+ if ( this.data.gitBranch !== false ) {
bitDiv( 'gitbranch' ).text( 'Git branch: ' + this.data.gitBranch );
}
$table = $( '<table id="mw-debug-console">' );
- $('<colgroup>').css( 'width', /*padding=*/20 + ( 10*/*fontSize*/11 ) ).appendTo( $table );
+ $('<colgroup>').css( 'width', /*padding=*/20 + ( 10 * /*fontSize*/11 ) ).appendTo( $table );
$('<colgroup>').appendTo( $table );
$('<colgroup>').css( 'width', 350 ).appendTo( $table );
}
};
-} )( jQuery, mediaWiki );
+}( mediaWiki, jQuery ) );
* Minimal example in how to use it:
*
* var feedback = new mw.Feedback();
- * $( '#myButton' ).click( function() { feedback.launch(); } );
+ * $( '#myButton' ).click( function () { feedback.launch(); } );
*
* You can also launch the feedback form with a prefilled subject and body.
* See the docs for the launch() method.
*/
-( function( mw, $, undefined ) {
+( function ( mw, $ ) {
/**
* Thingy for collecting user feedback on a wiki page
* @param {Array} options -- optional, all properties optional.
- * api: {mw.Api} if omitted, will just create a standard API
- * title: {mw.Title} the title of the page where you collect feedback. Defaults to "Feedback".
- * dialogTitleMessageKey: {String} message key for the title of the dialog box
- * bugsLink: {mw.Uri|String} url where bugs can be posted
- * bugsListLink: {mw.Uri|String} url where bugs can be listed
+ * api: {mw.Api} if omitted, will just create a standard API
+ * title: {mw.Title} the title of the page where you collect feedback. Defaults to "Feedback".
+ * dialogTitleMessageKey: {String} message key for the title of the dialog box
+ * bugsLink: {mw.Uri|String} url where bugs can be posted
+ * bugsListLink: {mw.Uri|String} url where bugs can be listed
*/
- mw.Feedback = function( options ) {
+ mw.Feedback = function ( options ) {
if ( options === undefined ) {
options = {};
}
};
mw.Feedback.prototype = {
- setup: function() {
- var _this = this;
+ setup: function () {
+ var fb = this;
- var $feedbackPageLink = $( '<a></a>' )
- .attr( { 'href': _this.title.getUrl(), 'target': '_blank' } )
+ var $feedbackPageLink = $( '<a>' )
+ .attr( { 'href': fb.title.getUrl(), 'target': '_blank' } )
.css( { 'white-space': 'nowrap' } );
- var $bugNoteLink = $( '<a></a>' ).attr( { 'href': '#' } ).click( function() { _this.displayBugs(); } );
+ var $bugNoteLink = $( '<a>' ).attr( { 'href': '#' } ).click( function () {
+ fb.displayBugs();
+ } );
- var $bugsListLink = $( '<a></a>' ).attr( { 'href': _this.bugsListLink, 'target': '_blank' } );
+ var $bugsListLink = $( '<a>' ).attr( { 'href': fb.bugsListLink, 'target': '_blank' } );
+ // TODO: Use a stylesheet instead of these inline styles
this.$dialog =
- $( '<div style="position:relative;"></div>' ).append(
+ $( '<div style="position: relative;"></div>' ).append(
$( '<div class="feedback-mode feedback-form"></div>' ).append(
- $( '<small></small>' ).append(
- $( '<p></p>' ).msg(
+ $( '<small>' ).append(
+ $( '<p>' ).msg(
'feedback-bugornote',
$bugNoteLink,
- _this.title.getNameText(),
+ fb.title.getNameText(),
$feedbackPageLink.clone()
)
),
- $( '<div style="margin-top:1em;"></div>' ).append(
+ $( '<div style="margin-top: 1em;"></div>' ).append(
mw.msg( 'feedback-subject' ),
- $( '<br/>' ),
- $( '<input type="text" class="feedback-subject" name="subject" maxlength="60" style="width:99%;"/>' )
+ $( '<br>' ),
+ $( '<input type="text" class="feedback-subject" name="subject" maxlength="60" style="width: 99%;"/>' )
),
- $( '<div style="margin-top:0.4em;"></div>' ).append(
+ $( '<div style="margin-top: 0.4em;"></div>' ).append(
mw.msg( 'feedback-message' ),
- $( '<br/>' ),
- $( '<textarea name="message" class="feedback-message" style="width:99%;" rows="5" cols="60"></textarea>' )
+ $( '<br>' ),
+ $( '<textarea name="message" class="feedback-message" style="width: 99%;" rows="5" cols="60"></textarea>' )
)
),
$( '<div class="feedback-mode feedback-bugs"></div>' ).append(
$( '<p>' ).msg( 'feedback-bugcheck', $bugsListLink )
),
- $( '<div class="feedback-mode feedback-submitting" style="text-align:center;margin:3em 0;"></div>' ).append(
+ $( '<div class="feedback-mode feedback-submitting" style="text-align: center; margin: 3em 0;"></div>' ).append(
mw.msg( 'feedback-adding' ),
$( '<br/>' ),
$( '<span class="feedback-spinner"></span>' )
),
- $( '<div class="feedback-mode feedback-thanks" style="text-align:center;margin:1em"></div>' ).msg(
- 'feedback-thanks', _this.title.getNameText(), $feedbackPageLink.clone()
+ $( '<div class="feedback-mode feedback-thanks" style="text-align: center; margin:1em"></div>' ).msg(
+ 'feedback-thanks', fb.title.getNameText(), $feedbackPageLink.clone()
),
- $( '<div class="feedback-mode feedback-error" style="position:relative;"></div>' ).append(
- $( '<div class="feedback-error-msg style="color:#990000;margin-top:0.4em;"></div>' )
+ $( '<div class="feedback-mode feedback-error" style="position: relative;"></div>' ).append(
+ $( '<div class="feedback-error-msg style="color: #990000; margin-top: 0.4em;"></div>' )
)
);
// undo some damage from dialog css
- this.$dialog.find( 'a' ).css( { 'color': '#0645ad' } );
+ this.$dialog.find( 'a' ).css( {
+ color: '#0645ad'
+ } );
this.$dialog.dialog({
width: 500,
autoOpen: false,
title: mw.msg( this.dialogTitleMessageKey ),
modal: true,
- buttons: _this.buttons
+ buttons: fb.buttons
});
this.subjectInput = this.$dialog.find( 'input.feedback-subject' ).get(0);
},
- display: function( s ) {
+ display: function ( s ) {
this.$dialog.dialog( { buttons:{} } ); // hide the buttons
this.$dialog.find( '.feedback-mode' ).hide(); // hide everything
this.$dialog.find( '.feedback-' + s ).show(); // show the desired div
},
- displaySubmitting: function() {
+ displaySubmitting: function () {
this.display( 'submitting' );
},
- displayBugs: function() {
- var _this = this;
+ displayBugs: function () {
+ var fb = this;
this.display( 'bugs' );
var bugsButtons = {};
- bugsButtons[ mw.msg( 'feedback-bugnew' ) ] = function() { window.open( _this.bugsLink, '_blank' ); };
- bugsButtons[ mw.msg( 'feedback-cancel' ) ] = function() { _this.cancel(); };
- this.$dialog.dialog( { buttons: bugsButtons } );
+ bugsButtons[ mw.msg( 'feedback-bugnew' ) ] = function () {
+ window.open( fb.bugsLink, '_blank' );
+ };
+ bugsButtons[ mw.msg( 'feedback-cancel' ) ] = function () {
+ fb.cancel();
+ };
+ this.$dialog.dialog( {
+ buttons: bugsButtons
+ } );
},
- displayThanks: function() {
- var _this = this;
+ displayThanks: function () {
+ var fb = this;
this.display( 'thanks' );
var closeButton = {};
- closeButton[ mw.msg( 'feedback-close' ) ] = function() { _this.$dialog.dialog( 'close' ); };
- this.$dialog.dialog( { buttons: closeButton } );
+ closeButton[ mw.msg( 'feedback-close' ) ] = function () {
+ fb.$dialog.dialog( 'close' );
+ };
+ this.$dialog.dialog( {
+ buttons: closeButton
+ } );
},
/**
* Display the feedback form
* @param {Object} optional prefilled contents for the feedback form. Object with properties:
- * subject: {String}
- * message: {String}
+ * subject: {String}
+ * message: {String}
*/
- displayForm: function( contents ) {
- var _this = this;
- this.subjectInput.value = (contents && contents.subject) ? contents.subject : '';
- this.messageInput.value = (contents && contents.message) ? contents.message : '';
+ displayForm: function ( contents ) {
+ var fb = this;
+ this.subjectInput.value = ( contents && contents.subject ) ? contents.subject : '';
+ this.messageInput.value = ( contents && contents.message ) ? contents.message : '';
this.display( 'form' );
// Set up buttons for dialog box. We have to do it the hard way since the json keys are localized
var formButtons = {};
- formButtons[ mw.msg( 'feedback-submit' ) ] = function() { _this.submit(); };
- formButtons[ mw.msg( 'feedback-cancel' ) ] = function() { _this.cancel(); };
+ formButtons[ mw.msg( 'feedback-submit' ) ] = function () {
+ fb.submit();
+ };
+ formButtons[ mw.msg( 'feedback-cancel' ) ] = function () {
+ fb.cancel();
+ };
this.$dialog.dialog( { buttons: formButtons } ); // put the buttons back
},
- displayError: function( message ) {
- var _this = this;
+ displayError: function ( message ) {
+ var fb = this;
this.display( 'error' );
this.$dialog.find( '.feedback-error-msg' ).msg( message );
var closeButton = {};
- closeButton[ mw.msg( 'feedback-close' ) ] = function() { _this.$dialog.dialog( 'close' ); };
+ closeButton[ mw.msg( 'feedback-close' ) ] = function () {
+ fb.$dialog.dialog( 'close' );
+ };
this.$dialog.dialog( { buttons: closeButton } );
},
- cancel: function() {
+ cancel: function () {
this.$dialog.dialog( 'close' );
},
- submit: function() {
- var _this = this;
+ submit: function () {
+ var fb = this;
// get the values to submit
var subject = this.subjectInput.value;
- var message = "<small>User agent: " + navigator.userAgent + "</small>\n\n"
+ var message = '<small>User agent: ' + mw.html.escape( navigator.userAgent ) + '</small>\n\n'
+ this.messageInput.value;
- if ( message.indexOf( '~~~' ) == -1 ) {
- message += " ~~~~";
+ if ( message.indexOf( '~~~' ) === -1 ) {
+ message += ' ~~~~';
}
this.displaySubmitting();
- var ok = function( result ) {
+ var ok = function ( result ) {
if ( result.edit !== undefined ) {
if ( result.edit.result === 'Success' ) {
- _this.displayThanks();
+ fb.displayThanks();
} else {
- _this.displayError( 'feedback-error1' ); // unknown API result
+ // unknown API result
+ fb.displayError( 'feedback-error1' );
}
} else {
- _this.displayError( 'feedback-error2' ); // edit failed
+ // edit failed
+ fb.displayError( 'feedback-error2' );
}
};
- var err = function( code, info ) {
- _this.displayError( 'feedback-error3' ); // ajax request failed
+ var err = function ( code, info ) {
+ // ajax request failed
+ fb.displayError( 'feedback-error3' );
};
this.api.newSection( this.title, subject, message, ok, err );
* subject: {String}
* message: {String}
*/
- launch: function( contents ) {
+ launch: function ( contents ) {
this.displayForm( contents );
this.$dialog.dialog( 'open' );
this.subjectInput.focus();
};
-} )( window.mediaWiki, jQuery );
+}( mediaWiki, jQuery ) );
/**
* Utility functions for jazzing up HTMLForm elements
*/
-( function( $ ) {
+( function ( $ ) {
/**
* jQuery plugin to fade or snap to visible state.
* @param boolean instantToggle (optional)
* @return jQuery
*/
-$.fn.goIn = function( instantToggle ) {
+$.fn.goIn = function ( instantToggle ) {
if ( instantToggle === true ) {
return $(this).show();
}
* @param boolean instantToggle (optional)
* @return jQuery
*/
-$.fn.goOut = function( instantToggle ) {
+$.fn.goOut = function ( instantToggle ) {
if ( instantToggle === true ) {
return $(this).hide();
}
* @param callback function taking one paramter, which is Bool true when the event
* is called immediately, and the EventArgs object when triggered from an event
*/
-$.fn.liveAndTestAtStart = function( callback ){
+$.fn.liveAndTestAtStart = function ( callback ){
$(this)
.live( 'change', callback )
- .each( function( index, element ){
+ .each( function ( index, element ){
callback.call( this, true );
} );
};
// Document ready:
-$( function() {
+$( function () {
// Animate the SelectOrOther fields, to only show the text field when
// 'other' is selected.
- $( '.mw-htmlform-select-or-other' ).liveAndTestAtStart( function( instant ) {
+ $( '.mw-htmlform-select-or-other' ).liveAndTestAtStart( function ( instant ) {
var $other = $( '#' + $(this).attr( 'id' ) + '-other' );
$other = $other.add( $other.siblings( 'br' ) );
if ( $(this).val() === 'other' ) {
});
-})( jQuery );
+}( jQuery ) );
/**
- * Experimental advanced wikitext parser-emitter.
- * See: http://www.mediawiki.org/wiki/Extension:UploadWizard/MessageParser for docs
- *
- * @author neilk@wikimedia.org
- */
-
-( function( mw, $, undefined ) {
-
- mw.jqueryMsg = {};
+* Experimental advanced wikitext parser-emitter.
+* See: http://www.mediawiki.org/wiki/Extension:UploadWizard/MessageParser for docs
+*
+* @author neilk@wikimedia.org
+*/
+( function ( mw, $ ) {
+ var slice = Array.prototype.slice,
+ parserDefaults = {
+ magic : {
+ 'SITENAME' : mw.config.get( 'wgSiteName' )
+ },
+ messages : mw.messages,
+ language : mw.language
+ };
/**
* Given parser options, return a function that parses a key and replacements, returning jQuery object
* @param {Object} parser options
* @return {Function} accepting ( String message key, String replacement1, String replacement2 ... ) and returning {jQuery}
*/
- function getFailableParserFn( options ) {
- var parser = new mw.jqueryMsg.parser( options );
- /**
+ function getFailableParserFn( options ) {
+ var parser = new mw.jqueryMsg.parser( options );
+ /**
* Try to parse a key and optional replacements, returning a jQuery object that may be a tree of jQuery nodes.
* If there was an error parsing, return the key and the error message (wrapped in jQuery). This should put the error right into
* the interface, without causing the page to halt script execution, and it hopefully should be clearer how to fix it.
* @param {Array} first element is the key, replacements may be in array in 2nd element, or remaining elements.
* @return {jQuery}
*/
- return function( args ) {
+ return function ( args ) {
var key = args[0];
- var argsArray = $.isArray( args[1] ) ? args[1] : $.makeArray( args ).slice( 1 );
+ var argsArray = $.isArray( args[1] ) ? args[1] : slice.call( args, 1 );
try {
return parser.parse( key, argsArray );
} catch ( e ) {
};
}
+ mw.jqueryMsg = {};
+
/**
- * Class method.
+ * Class method.
* Returns a function suitable for use as a global, to construct strings from the message key (and optional replacements).
- * e.g.
+ * e.g.
* window.gM = mediaWiki.parser.getMessageFunction( options );
* $( 'p#headline' ).html( gM( 'hello-user', username ) );
*
* @param {Array} parser options
* @return {Function} function suitable for assigning to window.gM
*/
- mw.jqueryMsg.getMessageFunction = function( options ) {
+ mw.jqueryMsg.getMessageFunction = function ( options ) {
var failableParserFn = getFailableParserFn( options );
- /**
+ /**
* N.B. replacements are variadic arguments or an array in second parameter. In other words:
- * somefunction(a, b, c, d)
- * is equivalent to
+ * somefunction(a, b, c, d)
+ * is equivalent to
* somefunction(a, [b, c, d])
*
* @param {String} message key
* @param {Array} optional replacements (can also specify variadically)
* @return {String} rendered HTML as string
*/
- return function( /* key, replacements */ ) {
+ return function ( /* key, replacements */ ) {
return failableParserFn( arguments ).html();
};
};
/**
- * Class method.
- * Returns a jQuery plugin which parses the message in the message key, doing replacements optionally, and appends the nodes to
- * the current selector. Bindings to passed-in jquery elements are preserved. Functions become click handlers for [$1 linktext] links.
- * e.g.
+ * Class method.
+ * Returns a jQuery plugin which parses the message in the message key, doing replacements optionally, and appends the nodes to
+ * the current selector. Bindings to passed-in jquery elements are preserved. Functions become click handlers for [$1 linktext] links.
+ * e.g.
* $.fn.msg = mediaWiki.parser.getJqueryPlugin( options );
- * var userlink = $( '<a>' ).click( function() { alert( "hello!!") } );
+ * var userlink = $( '<a>' ).click( function () { alert( "hello!!") } );
* $( 'p#headline' ).msg( 'hello-user', userlink );
*
* @param {Array} parser options
* @return {Function} function suitable for assigning to jQuery plugin, such as $.fn.msg
*/
- mw.jqueryMsg.getPlugin = function( options ) {
+ mw.jqueryMsg.getPlugin = function ( options ) {
var failableParserFn = getFailableParserFn( options );
- /**
+ /**
* N.B. replacements are variadic arguments or an array in second parameter. In other words:
- * somefunction(a, b, c, d)
- * is equivalent to
+ * somefunction(a, b, c, d)
+ * is equivalent to
* somefunction(a, [b, c, d])
- *
+ *
* We append to 'this', which in a jQuery plugin context will be the selected elements.
* @param {String} message key
* @param {Array} optional replacements (can also specify variadically)
* @return {jQuery} this
*/
- return function( /* key, replacements */ ) {
+ return function ( /* key, replacements */ ) {
var $target = this.empty();
- $.each( failableParserFn( arguments ).contents(), function( i, node ) {
+ $.each( failableParserFn( arguments ).contents(), function ( i, node ) {
$target.append( node );
} );
return $target;
};
};
- var parserDefaults = {
- 'magic' : {
- 'SITENAME' : mw.config.get( 'wgSiteName' )
- },
- 'messages' : mw.messages,
- 'language' : mw.language
- };
-
/**
* The parser itself.
* Describes an object, whose primary duty is to .parse() message keys.
* @param {Array} options
*/
- mw.jqueryMsg.parser = function( options ) {
+ mw.jqueryMsg.parser = function ( options ) {
this.settings = $.extend( {}, parserDefaults, options );
this.emitter = new mw.jqueryMsg.htmlEmitter( this.settings.language, this.settings.magic );
};
mw.jqueryMsg.parser.prototype = {
-
// cache, map of mediaWiki message key to the AST of the message. In most cases, the message is a string so this is identical.
// (This is why we would like to move this functionality server-side).
astCache: {},
* @param {Array} replacements for $1, $2... $n
* @return {jQuery}
*/
- parse: function( key, replacements ) {
+ parse: function ( key, replacements ) {
return this.emitter.emit( this.getAst( key ), replacements );
},
-
/**
* Fetch the message string associated with a key, return parsed structure. Memoized.
- * Note that we pass '[' + key + ']' back for a missing message here.
+ * Note that we pass '[' + key + ']' back for a missing message here.
* @param {String} key
* @return {String|Array} string of '[key]' if message missing, simple string if possible, array of arrays if needs parsing
*/
- getAst: function( key ) {
- if ( this.astCache[ key ] === undefined ) {
+ getAst: function ( key ) {
+ if ( this.astCache[ key ] === undefined ) {
var wikiText = this.settings.messages.get( key );
if ( typeof wikiText !== 'string' ) {
wikiText = "\\[" + key + "\\]";
}
this.astCache[ key ] = this.wikiTextToAst( wikiText );
}
- return this.astCache[ key ];
+ return this.astCache[ key ];
},
-
/*
* Parses the input wikiText into an abstract syntax tree, essentially an s-expression.
*
* CAVEAT: This does not parse all wikitext. It could be more efficient, but it's pretty good already.
* n.b. We want to move this functionality to the server. Nothing here is required to be on the client.
- *
+ *
* @param {String} message string wikitext
* @throws Error
* @return {Mixed} abstract syntax tree
*/
- wikiTextToAst: function( input ) {
-
- // Indicates current position in input as we parse through it.
- // Shared among all parsing functions below.
- var pos = 0;
+ wikiTextToAst: function ( input ) {
+ // Indicates current position in input as we parse through it.
+ // Shared among all parsing functions below.
+ var pos = 0;
// =========================================================
// parsing combinators - could be a library on its own
// =========================================================
-
-
- // Try parsers until one works, if none work return null
+ // Try parsers until one works, if none work return null
function choice( ps ) {
- return function() {
+ return function () {
for ( var i = 0; i < ps.length; i++ ) {
var result = ps[i]();
if ( result !== null ) {
return null;
};
}
-
// try several ps in a row, all must succeed or return null
// this is the only eager one
function sequence( ps ) {
var originalPos = pos;
var result = [];
- for ( var i = 0; i < ps.length; i++ ) {
+ for ( var i = 0; i < ps.length; i++ ) {
var res = ps[i]();
if ( res === null ) {
pos = originalPos;
return null;
- }
+ }
result.push( res );
}
return result;
}
-
// run the same parser over and over until it fails.
// must succeed a minimum of n times or return null
function nOrMore( n, p ) {
- return function() {
+ return function () {
var originalPos = pos;
var result = [];
var parsed = p();
if ( result.length < n ) {
pos = originalPos;
return null;
- }
+ }
return result;
};
}
-
// There is a general pattern -- parse a thing, if that worked, apply transform, otherwise return null.
// But using this as a combinator seems to cause problems when combined with nOrMore().
// May be some scoping issue
function transform( p, fn ) {
- return function() {
+ return function () {
var result = p();
return result === null ? null : fn( result );
};
}
-
// Helpers -- just make ps out of simpler JS builtin types
-
- function makeStringParser( s ) {
+ function makeStringParser( s ) {
var len = s.length;
- return function() {
+ return function () {
var result = null;
if ( input.substr( pos, len ) === s ) {
result = s;
return result;
};
}
-
function makeRegexParser( regex ) {
- return function() {
+ return function () {
var matches = input.substr( pos ).match( regex );
- if ( matches === null ) {
+ if ( matches === null ) {
return null;
- }
+ }
pos += matches[0].length;
return matches[0];
};
}
-
- /**
- * ===================================================================
+ /**
+ * ===================================================================
* General patterns above this line -- wikitext specific parsers below
- * ===================================================================
+ * ===================================================================
*/
-
// Parsing functions follow. All parsing functions work like this:
// They don't accept any arguments.
// Instead, they just operate non destructively on the string 'input'
// As they can consume parts of the string, they advance the shared variable pos,
// and return tokens (or whatever else they want to return).
-
// some things are defined as closures and other things as ordinary functions
// converting everything to a closure makes it a lot harder to debug... errors pop up
// but some debuggers can't tell you exactly where they come from. Also the mutually
// recursive functions seem not to work in all browsers then. (Tested IE6-7, Opera, Safari, FF)
// This may be because, to save code, memoization was removed
-
-
- var regularLiteral = makeRegexParser( /^[^{}[\]$\\]/ );
- var regularLiteralWithoutBar = makeRegexParser(/^[^{}[\]$\\|]/);
- var regularLiteralWithoutSpace = makeRegexParser(/^[^{}[\]$\s]/);
-
+ var regularLiteral = makeRegexParser( /^[^{}\[\]$\\]/ );
+ var regularLiteralWithoutBar = makeRegexParser(/^[^{}\[\]$\\|]/);
+ var regularLiteralWithoutSpace = makeRegexParser(/^[^{}\[\]$\s]/);
var backslash = makeStringParser( "\\" );
var anyCharacter = makeRegexParser( /^./ );
-
function escapedLiteral() {
var result = sequence( [
- backslash,
+ backslash,
anyCharacter
] );
return result === null ? null : result[1];
}
-
var escapedOrLiteralWithoutSpace = choice( [
escapedLiteral,
regularLiteralWithoutSpace
] );
-
var escapedOrLiteralWithoutBar = choice( [
escapedLiteral,
regularLiteralWithoutBar
] );
-
- var escapedOrRegularLiteral = choice( [
+ var escapedOrRegularLiteral = choice( [
escapedLiteral,
regularLiteral
] );
-
// Used to define "literals" without spaces, in space-delimited situations
function literalWithoutSpace() {
var result = nOrMore( 1, escapedOrLiteralWithoutSpace )();
return result === null ? null : result.join('');
}
-
- // Used to define "literals" within template parameters. The pipe character is the parameter delimeter, so by default
+ // Used to define "literals" within template parameters. The pipe character is the parameter delimeter, so by default
// it is not a literal in the parameter
function literalWithoutBar() {
var result = nOrMore( 1, escapedOrLiteralWithoutBar )();
return result === null ? null : result.join('');
}
-
function literal() {
var result = nOrMore( 1, escapedOrRegularLiteral )();
return result === null ? null : result.join('');
}
-
- var whitespace = makeRegexParser( /^\s+/ );
+ var whitespace = makeRegexParser( /^\s+/ );
var dollar = makeStringParser( '$' );
- var digits = makeRegexParser( /^\d+/ );
+ var digits = makeRegexParser( /^\d+/ );
function replacement() {
var result = sequence( [
dollar,
digits
] );
- if ( result === null ) {
+ if ( result === null ) {
return null;
}
return [ 'REPLACE', parseInt( result[1], 10 ) - 1 ];
}
-
-
var openExtlink = makeStringParser( '[' );
var closeExtlink = makeStringParser( ']' );
-
// this extlink MUST have inner text, e.g. [foo] not allowed; [foo bar] is allowed
function extlink() {
var result = null;
}
return result;
}
-
// this is the same as the above extlink, except that the url is being passed on as a parameter
function extLinkParam() {
var result = sequence( [
}
return [ 'LINKPARAM', parseInt( result[2], 10 ) - 1, result[4] ];
}
-
var openLink = makeStringParser( '[[' );
var closeLink = makeStringParser( ']]' );
-
function link() {
var result = null;
var parsedResult = sequence( [
}
return result;
}
-
- var templateName = transform(
+ var templateName = transform(
// see $wgLegalTitleChars
// not allowing : due to the need to catch "PLURAL:$1"
- makeRegexParser( /^[ !"$&'()*,.\/0-9;=?@A-Z\^_`a-z~\x80-\xFF+-]+/ ),
- function( result ) { return result.toString(); }
+ makeRegexParser( /^[ !"$&'()*,.\/0-9;=?@A-Z\^_`a-z~\x80-\xFF+\-]+/ ),
+ function ( result ) { return result.toString(); }
);
-
function templateParam() {
- var result = sequence( [
+ var result = sequence( [
pipe,
nOrMore( 0, paramExpression )
] );
// use a "CONCAT" operator if there are multiple nodes, otherwise return the first node, raw.
return expr.length > 1 ? [ "CONCAT" ].concat( expr ) : expr[0];
}
-
var pipe = makeStringParser( '|' );
-
function templateWithReplacement() {
var result = sequence( [
templateName,
] );
return result === null ? null : [ result[0], result[2] ];
}
-
function templateWithOutReplacement() {
var result = sequence( [
templateName,
] );
return result === null ? null : [ result[0], result[2] ];
}
-
var colon = makeStringParser(':');
-
var templateContents = choice( [
- function() {
+ function () {
var res = sequence( [
// templates can have placeholders for dynamic replacement eg: {{PLURAL:$1|one car|$1 cars}}
// or no placeholders eg: {{GRAMMAR:genitive|{{SITENAME}}}
] );
return res === null ? null : res[0].concat( res[1] );
},
- function() {
+ function () {
var res = sequence( [
templateName,
- nOrMore( 0, templateParam )
+ nOrMore( 0, templateParam )
] );
if ( res === null ) {
return null;
return [ res[0] ].concat( res[1] );
}
] );
-
var openTemplate = makeStringParser('{{');
var closeTemplate = makeStringParser('}}');
-
function template() {
var result = sequence( [
openTemplate,
] );
return result === null ? null : result[1];
}
-
var nonWhitespaceExpression = choice( [
template,
link,
replacement,
literalWithoutSpace
] );
-
var paramExpression = choice( [
template,
link,
replacement,
literalWithoutBar
] );
-
- var expression = choice( [
+ var expression = choice( [
template,
link,
extLinkParam,
extlink,
replacement,
- literal
+ literal
] );
-
function start() {
var result = nOrMore( 0, expression )();
if ( result === null ) {
}
return [ "CONCAT" ].concat( result );
}
-
// everything above this point is supposed to be stateless/static, but
// I am deferring the work of turning it into prototypes & objects. It's quite fast enough
-
// finally let's do some actual work...
-
var result = start();
-
+
/*
- * For success, the p must have gotten to the end of the input
+ * For success, the p must have gotten to the end of the input
* and returned a non-null.
* n.b. This is part of language infrastructure, so we do not throw an internationalizable message.
*/
}
return result;
}
-
- };
+ };
/**
* htmlEmitter - object which primarily exists to emit HTML from parser ASTs
*/
- mw.jqueryMsg.htmlEmitter = function( language, magic ) {
+ mw.jqueryMsg.htmlEmitter = function ( language, magic ) {
this.language = language;
- var _this = this;
-
- $.each( magic, function( key, val ) {
- _this[ key.toLowerCase() ] = function() { return val; };
+ var jmsg = this;
+ $.each( magic, function ( key, val ) {
+ jmsg[ key.toLowerCase() ] = function () {
+ return val;
+ };
} );
-
/**
* (We put this method definition here, and not in prototype, to make sure it's not overwritten by any magic.)
* Walk entire node structure, applying replacements and template functions when appropriate
* @param {Array} replacements for $1, $2, ... $n
* @return {Mixed} single-string node or array of nodes suitable for jQuery appending
*/
- this.emit = function( node, replacements ) {
+ this.emit = function ( node, replacements ) {
var ret = null;
- var _this = this;
- switch( typeof node ) {
+ var jmsg = this;
+ switch ( typeof node ) {
case 'string':
case 'number':
ret = node;
break;
case 'object': // node is an array of nodes
- var subnodes = $.map( node.slice( 1 ), function( n ) {
- return _this.emit( n, replacements );
+ var subnodes = $.map( node.slice( 1 ), function ( n ) {
+ return jmsg.emit( n, replacements );
} );
var operation = node[0].toLowerCase();
- if ( typeof _this[operation] === 'function' ) {
- ret = _this[ operation ]( subnodes, replacements );
+ if ( typeof jmsg[operation] === 'function' ) {
+ ret = jmsg[ operation ]( subnodes, replacements );
} else {
- throw new Error( 'unknown operation "' + operation + '"' );
+ throw new Error( 'Unknown operation "' + operation + '"' );
}
break;
case 'undefined':
ret = '';
break;
default:
- throw new Error( 'unexpected type in AST: ' + typeof node );
+ throw new Error( 'Unexpected type in AST: ' + typeof node );
}
return ret;
};
-
};
-
// For everything in input that follows double-open-curly braces, there should be an equivalent parser
- // function. For instance {{PLURAL ... }} will be processed by 'plural'.
+ // function. For instance {{PLURAL ... }} will be processed by 'plural'.
// If you have 'magic words' then configure the parser to have them upon creation.
//
// An emitter method takes the parent node, the array of subnodes and the array of replacements (the values that $1, $2... should translate to).
// Note: all such functions must be pure, with the exception of referring to other pure functions via this.language (convertPlural and so on)
mw.jqueryMsg.htmlEmitter.prototype = {
-
/**
* Parsing has been applied depth-first we can assume that all nodes here are single nodes
* Must return a single node to parents -- a jQuery with synthetic span
* @param {Array} nodes - mixed, some single nodes, some arrays of nodes
* @return {jQuery}
*/
- concat: function( nodes ) {
- var span = $( '<span>' ).addClass( 'mediaWiki_htmlEmitter' );
- $.each( nodes, function( i, node ) {
+ concat: function ( nodes ) {
+ var $span = $( '<span>' ).addClass( 'mediaWiki_htmlEmitter' );
+ $.each( nodes, function ( i, node ) {
if ( node instanceof jQuery && node.hasClass( 'mediaWiki_htmlEmitter' ) ) {
- $.each( node.contents(), function( j, childNode ) {
- span.append( childNode );
+ $.each( node.contents(), function ( j, childNode ) {
+ $span.append( childNode );
} );
} else {
// strings, integers, anything else
- span.append( node );
+ $span.append( node );
}
} );
- return span;
+ return $span;
},
/**
* @param {Array} of one element, integer, n >= 0
* @return {String} replacement
*/
- replace: function( nodes, replacements ) {
+ replace: function ( nodes, replacements ) {
var index = parseInt( nodes[0], 10 );
-
+
if ( index < replacements.length ) {
if ( typeof arg === 'string' ) {
// replacement is a string, escape it
}
},
- /**
+ /**
* Transform wiki-link
- * TODO unimplemented
+ * TODO unimplemented
*/
- wlink: function( nodes ) {
- return "unimplemented";
+ wlink: function ( nodes ) {
+ return 'unimplemented';
},
/**
* If the href is a jQuery object, treat it as "enclosing" the link text.
* ... function, treat it as the click handler
* ... string, treat it as a URI
- * TODO: throw an error if nodes.length > 2 ?
+ * TODO: throw an error if nodes.length > 2 ?
* @param {Array} of two elements, {jQuery|Function|String} and {String}
* @return {jQuery}
*/
- link: function( nodes ) {
+ link: function ( nodes ) {
var arg = nodes[0];
var contents = nodes[1];
- var $el;
+ var $el;
if ( arg instanceof jQuery ) {
$el = arg;
} else {
$el.attr( 'href', arg.toString() );
}
}
- $el.append( contents );
+ $el.append( contents );
return $el;
},
* @param {Array} of one element, integer, n >= 0
* @return {String} replacement
*/
- linkparam: function( nodes, replacements ) {
+ linkparam: function ( nodes, replacements ) {
var replacement,
index = parseInt( nodes[0], 10 );
if ( index < replacements.length) {
* Transform parsed structure into pluralization
* n.b. The first node may be a non-integer (for instance, a string representing an Arabic number).
* So convert it back with the current language's convertNumber.
- * @param {Array} of nodes, [ {String|Number}, {String}, {String} ... ]
+ * @param {Array} of nodes, [ {String|Number}, {String}, {String} ... ]
* @return {String} selected pluralized form according to current language
*/
- plural: function( nodes ) {
+ plural: function ( nodes ) {
var count = parseInt( this.language.convertNumber( nodes[0], true ), 10 );
var forms = nodes.slice(1);
return forms.length ? this.language.convertPlural( count, forms ) : '';
/**
* Transform parsed structure into gender
* Usage {{gender:[gender| mw.user object ] | masculine|feminine|neutral}}.
- * @param {Array} of nodes, [ {String|mw.User}, {String}, {String} , {String} ]
+ * @param {Array} of nodes, [ {String|mw.User}, {String}, {String} , {String} ]
* @return {String} selected gender form according to current language
*/
- gender: function( nodes ) {
+ gender: function ( nodes ) {
var gender;
if ( nodes[0] && nodes[0].options instanceof mw.Map ){
gender = nodes[0].options.get( 'gender' );
* @param {Array} of nodes [{Grammar case eg: genitive}, {String word}]
* @return {String} selected grammatical form according to current language
*/
- grammar: function( nodes ) {
+ grammar: function ( nodes ) {
var form = nodes[0];
var word = nodes[1];
return word && form && this.language.convertGrammar( word, form );
}
};
-
- // deprecated! don't rely on gM existing.
- // the window.gM ought not to be required - or if required, not required here. But moving it to extensions breaks it (?!)
+ // Deprecated! don't rely on gM existing.
+ // The window.gM ought not to be required - or if required, not required here.
+ // But moving it to extensions breaks it (?!)
// Need to fix plugin so it could do attributes as well, then will be okay to remove this.
- window.gM = mw.jqueryMsg.getMessageFunction();
-
+ window.gM = mw.jqueryMsg.getMessageFunction();
$.fn.msg = mw.jqueryMsg.getPlugin();
-
+
// Replace the default message parser with jqueryMsg
var oldParser = mw.Message.prototype.parser;
- mw.Message.prototype.parser = function() {
+ mw.Message.prototype.parser = function () {
// TODO: should we cache the message function so we don't create a new one every time? Benchmark this maybe?
// Caching is somewhat problematic, because we do need different message functions for different maps, so
// we'd have to cache the parser as a member of this.map, which sounds a bit ugly.
-
// Do not use mw.jqueryMsg unless required
if ( this.map.get( this.key ).indexOf( '{{' ) < 0 ) {
// Fall back to mw.msg's simple parser
return oldParser.apply( this );
}
-
var messageFunction = mw.jqueryMsg.getMessageFunction( { 'messages': this.map } );
return messageFunction( this.key, this.parameters );
};
-} )( mediaWiki, jQuery );
+}( mediaWiki, jQuery ) );
-/*jslint browser: true, continue: true, white: true, forin: true*/
-/*global jQuery*/
/*
* Core MediaWiki JavaScript Library
*/
/* Private Members */
- var hasOwn = Object.prototype.hasOwnProperty;
+ var hasOwn = Object.prototype.hasOwnProperty,
+ slice = Array.prototype.slice;
+
/* Object constructors */
/**
var results, i;
if ( $.isArray( selection ) ) {
- selection = $.makeArray( selection );
+ selection = slice.call( selection );
results = {};
for ( i = 0; i < selection.length; i += 1 ) {
results[selection[i]] = this.get( selection[i], fallback );
this.format = 'plain';
this.map = map;
this.key = key;
- this.parameters = parameters === undefined ? [] : $.makeArray( parameters );
+ this.parameters = parameters === undefined ? [] : slice.call( parameters );
return this;
}
*
* This function will not be called for nonexistent messages.
*/
- parser: function() {
+ parser: function () {
var parameters = this.parameters;
return this.map.get( this.key ).replace( /\$(\d+)/g, function ( str, match ) {
var index = parseInt( match, 10 ) - 1;
*
* @return string Message as a string in the current form or <key> if key does not exist.
*/
- toString: function() {
+ toString: function () {
var text;
if ( !this.exists() ) {
*
* @return {string} String form of parsed message
*/
- parse: function() {
+ parse: function () {
this.format = 'parse';
return this.toString();
},
*
* @return {string} String form of plain message
*/
- plain: function() {
+ plain: function () {
this.format = 'plain';
return this.toString();
},
*
* @return {string} String form of html escaped message
*/
- escaped: function() {
+ escaped: function () {
this.format = 'escaped';
return this.toString();
},
*
* @return {string} String form of parsed message
*/
- exists: function() {
+ exists: function () {
return this.map.exists( this.key );
}
};
* Dummy function which in debug mode can be replaced with a function that
* emulates console.log in console-less environments.
*/
- log: function() { },
+ log: function () { },
/**
* @var constructor Make the Map constructor publicly available.
var parameters;
// Support variadic arguments
if ( parameter_1 !== undefined ) {
- parameters = $.makeArray( arguments );
+ parameters = slice.call( arguments );
parameters.shift();
} else {
parameters = [];
* {
* 'moduleName': {
* 'version': ############## (unix timestamp),
- * 'dependencies': ['required.foo', 'bar.also', ...], (or) function() {}
+ * 'dependencies': ['required.foo', 'bar.also', ...], (or) function () {}
* 'group': 'somegroup', (or) null,
* 'source': 'local', 'someforeignwiki', (or) null
* 'state': 'registered', 'loading', 'loaded', 'ready', 'error' or 'missing'
* @param callback Function: Optional callback which will be run when the script is done
*/
function addScript( src, callback, async ) {
+ /*jshint evil:true */
var script, head,
done = false;
script.setAttribute( 'type', 'text/javascript' );
if ( $.isFunction( callback ) ) {
// Attach handlers for all browsers (based on jQuery.ajax)
- script.onload = script.onreadystatechange = function() {
+ script.onload = script.onreadystatechange = function () {
if (
!done
// scripts only start loading after the document has been rendered,
// but so be it. Opera users don't deserve faster web pages if their
// browser makes it impossible
- $( function() { document.body.appendChild( script ); } );
+ $( function () { document.body.appendChild( script ); } );
} else {
// IE-safe way of getting the <head> . document.documentElement.head doesn't
// work in scripts that run in the <head>
// Execute script
try {
script = registry[module].script;
- markModuleReady = function() {
+ markModuleReady = function () {
registry[module].state = 'ready';
handlePending( module );
};
return;
}
- addScript( arr[i], function() {
+ addScript( arr[i], function () {
nestedAddScript( arr, callback, async, i + 1 );
}, async );
};
* @author Trevor Parscal <tparscal@wikimedia.org>
*/
-( function ( $ ) {
+( function ( mw, $ ) {
/**
* Logs a message to the console.
*
* @param {String} First in list of variadic messages to output to console.
*/
- mw.log = function( /* logmsg, logmsg, */ ) {
+ mw.log = function ( /* logmsg, logmsg, */ ) {
// Turn arguments into an array
var args = Array.prototype.slice.call( arguments ),
// Allow log messages to use a configured prefix to identify the source window (ie. frame)
} );
};
-})( jQuery );
+}( mediaWiki, jQuery ) );
* Implementation for mediaWiki.user
*/
-( function ( $ ) {
+( function ( mw, $ ) {
/**
* User object
id = generateId();
}
// Set cookie if not set, or renew it if already set
- $.cookie( 'mediaWiki.user.id', id, { 'expires': 365, 'path': '/' } );
+ $.cookie( 'mediaWiki.user.id', id, {
+ expires: 365,
+ path: '/'
+ } );
return id;
};
* 'expires': 7
* } );
*/
- this.bucket = function( key, options ) {
+ this.bucket = function ( key, options ) {
options = $.extend( {
'buckets': {},
'version': 0,
// Bucket information is stored as 2 integers, together as version:bucket like: "1:2"
if ( typeof cookie === 'string' && cookie.length > 2 && cookie.indexOf( ':' ) > 0 ) {
var parts = cookie.split( ':' );
- if ( parts.length > 1 && parts[0] == options.version ) {
+ if ( parts.length > 1 && Number( parts[0] ) === options.version ) {
version = Number( parts[0] );
bucket = String( parts[1] );
}
}
}
if ( options.tracked ) {
- mw.loader.using( 'jquery.clickTracking', function() {
+ mw.loader.using( 'jquery.clickTracking', function () {
$.trackAction(
'mediaWiki.user.bucket:' + key + '@' + version + ':' + bucket
);
// This is kind of ugly but we're stuck with this for b/c reasons
mw.user = new User( mw.user.options, mw.user.tokens );
-}( jQuery ) );
+}( mediaWiki, jQuery ) );
/**
* Implements mediaWiki.util library
*/
-( function ( $, mw ) {
- "use strict";
+( function ( mw, $ ) {
+ 'use strict';
// Local cache and alias
var util = {
mw.util = util;
-} )( jQuery, mediaWiki );
+}( mediaWiki, jQuery ) );