Kranitor #2: Pass JSHint on resources/mediawiki/*
authorTimo Tijhof <ttijhof@wikimedia.org>
Tue, 24 Jul 2012 20:45:20 +0000 (13:45 -0700)
committerCatrope <roan.kattouw@gmail.com>
Thu, 9 Aug 2012 18:42:58 +0000 (11:42 -0700)
* .jshintrc
 - Update properties to reflect our conventions more

* Re-pass resources/jquery/*
* Pass resources/mediawiki/*
 - Trailing whitespace
 - Whitelist the one usage of document.write with
   a local /*jshint evil:true */ in the function that
   we allow to use it.
 - Get rid of dangling _ in var names and undescriptive
   instances of '_this'.
 - More code conventions

* Add a few documentation comments while at it

Change-Id: Ic4f2b5d473a440667a40e4d5f12f40877386b02f

25 files changed:
.jshintrc
resources/jquery/jquery.makeCollapsible.js
resources/jquery/jquery.textSelection.js
resources/mediawiki.action/mediawiki.action.edit.js
resources/mediawiki.action/mediawiki.action.history.js
resources/mediawiki.action/mediawiki.action.view.dblClickEdit.js
resources/mediawiki.action/mediawiki.action.view.metadata.js
resources/mediawiki.language/mediawiki.language.init.js
resources/mediawiki.language/mediawiki.language.js
resources/mediawiki.page/mediawiki.page.startup.js
resources/mediawiki.page/mediawiki.page.watch.ajax.js
resources/mediawiki.special/mediawiki.special.changeemail.js
resources/mediawiki.special/mediawiki.special.javaScriptTest.js
resources/mediawiki.special/mediawiki.special.recentchanges.js
resources/mediawiki.special/mediawiki.special.upload.js
resources/mediawiki/mediawiki.Title.js
resources/mediawiki/mediawiki.Uri.js
resources/mediawiki/mediawiki.debug.js
resources/mediawiki/mediawiki.feedback.js
resources/mediawiki/mediawiki.htmlform.js
resources/mediawiki/mediawiki.jqueryMsg.js
resources/mediawiki/mediawiki.js
resources/mediawiki/mediawiki.log.js
resources/mediawiki/mediawiki.user.js
resources/mediawiki/mediawiki.util.js

index 5fb1173..efbe54d 100644 (file)
--- a/.jshintrc
+++ b/.jshintrc
        "immed": true,
        "latedef": true,
        "newcap": true,
+       "noarg": true,
        "noempty": true,
+       "nonew": true,
+       "regexp": false,
        "undef": true,
+       "strict": false,
        "trailing": true,
 
        "laxbreak": true,
@@ -20,5 +24,8 @@
        "multistr": true,
 
        "browser": true,
-       "jquery": true
+       "jquery": true,
+
+       "nomen": true,
+       "onevar": false
 }
index 77f2639..33f8752 100644 (file)
@@ -19,7 +19,7 @@
 $.fn.makeCollapsible = function () {
 
        return this.each(function () {
-               var _fn = 'jquery.makeCollapsible> ';
+               var lpx = 'jquery.makeCollapsible> ';
 
                // Define reused variables and functions
                var $toggle,
@@ -248,7 +248,7 @@ $.fn.makeCollapsible = function () {
 
                        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 ) {
@@ -256,7 +256,7 @@ $.fn.makeCollapsible = function () {
                                        toggleLinkCustom( $(this), e, $that );
                                } );
                        } else {
-                               mw.log( _fn + '#' + thatId + ': Missing toggler!' );
+                               mw.log( lpx + '#' + thatId + ': Missing toggler!' );
                        }
 
                        // Initial state
index 9f1f3a4..583c1ed 100644 (file)
@@ -8,16 +8,16 @@
                // 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 ) )
                });
index bd07cd0..1c51c97 100644 (file)
@@ -24,7 +24,7 @@
                                selectText: selectText
                        };
                }
-               var $image = $('<img>', {
+               var $image = $( '<img>', {
                        width : 23,
                        height: 22,
                        src   : b.imageFile,
@@ -96,7 +96,7 @@
        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;
                                } );
                }
        });
index 76b0e6c..55f799e 100644 (file)
@@ -30,20 +30,20 @@ jQuery( document ).ready( function ( $ ) {
                                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' );
index b1d906f..7a9ceee 100644 (file)
@@ -1,12 +1,14 @@
 /**
  * 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 ) );
index b791cab..ce3c674 100644 (file)
@@ -1,39 +1,43 @@
-// 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
index b49823c..8d2ffae 100644 (file)
@@ -2,7 +2,7 @@
  * Base language object with methods for storing and getting
  * language data.
  */
-( function( $, mw ) {
+( function ( mw, $ ) {
 
        var language = {
                /**
@@ -58,4 +58,4 @@
 
        mw.language = language;
 
-} )( jQuery, mediaWiki );
+}( mediaWiki, jQuery ) );
index 78a6309..1234637 100644 (file)
@@ -3,7 +3,7 @@
  * Language.php in MediaWiki.
  * This adds methods for transforming message text.
  */
-( function( $, mw ) {
+( function ( mw, $ ) {
 
 var language = {
 
@@ -12,13 +12,13 @@ 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 ) {
@@ -35,6 +35,7 @@ var language = {
                }
                return '';
        },
+
        /**
         * Plural form transformations, needed for some languages.
         *
@@ -42,12 +43,13 @@ var language = {
         * @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.
         *
@@ -55,38 +57,41 @@ var language = {
         * @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 {
@@ -95,6 +100,7 @@ var language = {
                }
                return integer ? parseInt( convertedNumber, 10 ) : convertedNumber;
        },
+
        /**
         * Provides an alternative text depending on specified gender.
         * Usage {{gender:[gender|user object]|masculine|feminine|neutral}}.
@@ -107,7 +113,7 @@ var language = {
         *
         * @return string
         */
-       'gender': function( gender, forms ) {
+       gender: function( gender, forms ) {
                if ( !forms || forms.length === 0 ) {
                        return '';
                }
@@ -140,9 +146,9 @@ var language = {
        },
 
        // 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 ) );
index a5541ef..6a11d3e 100644 (file)
@@ -1,4 +1,4 @@
-( function ( $ ) {
+( function ( mw, $ ) {
 
        mw.page = {};
 
@@ -15,4 +15,4 @@
        // is defined for them.
        $( mw.util.init );
 
-} )( jQuery );
+}( mediaWiki, jQuery ) );
index d3f8433..14557d4 100644 (file)
@@ -2,16 +2,12 @@
  * 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 ) );
index 00e14fa..cab0bbd 100644 (file)
@@ -1,12 +1,12 @@
 /*
  * 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' );
 
@@ -22,21 +22,21 @@ var updateMailValidityLabel = function( mail ) {
        } 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 ) );
index d413f60..808d5fe 100644 (file)
@@ -1,33 +1,37 @@
-/*
+/**
  * 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 ) );
+
index 3d520f5..7996d93 100644 (file)
@@ -1,5 +1,5 @@
 /* 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' );
 
@@ -36,4 +36,4 @@
        // Run when document is ready
        $( rc.init );
 
-})( jQuery );
+}( mediaWiki, jQuery ) );
index f7a4b1f..63e8971 100644 (file)
-/*
+/**
  * 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 ) );
index 8d7996c..6b6e586 100644 (file)
@@ -7,7 +7,7 @@
  *
  * 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
@@ -41,7 +42,7 @@ var   Title = function( title, namespace ) {
         * @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, '_' );
                }
@@ -63,14 +64,14 @@ var Title = function( title, namespace ) {
        /**
         * Sanitize name.
         */
-       fixName = function( s ) {
+       fixName = function ( s ) {
                return clean( $.trim( s ) );
        },
 
        /**
         * Sanitize name.
         */
-       fixExt = function( s ) {
+       fixExt = function ( s ) {
                return clean( s );
        },
 
@@ -79,7 +80,7 @@ var   Title = function( title, namespace ) {
         * @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()];
 
@@ -98,9 +99,13 @@ var  Title = function( title, namespace ) {
         * @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
@@ -119,7 +124,7 @@ var Title = function( title, namespace ) {
         * @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}))?$/ ),
@@ -127,14 +132,14 @@ var       Title = function( title, namespace ) {
 
                // 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;
@@ -147,16 +152,16 @@ var       Title = function( title, namespace ) {
         * @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 + '"' );
@@ -172,7 +177,7 @@ var Title = function( title, namespace ) {
         * @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];
@@ -203,7 +208,7 @@ var Title = function( title, namespace ) {
                 * @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;
@@ -223,8 +228,8 @@ var Title = function( title, namespace ) {
                 * Get the namespace number.
                 * @return {Number}
                 */
-               getNamespaceId: function(){
-                       return this._ns;
+               getNamespaceId: function (){
+                       return this.ns;
                },
 
                /**
@@ -232,19 +237,19 @@ var       Title = function( title, namespace ) {
                 * 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 );
                        }
                },
 
@@ -252,7 +257,7 @@ var Title = function( title, namespace ) {
                 * The name, like "Foo bar"
                 * @return {String}
                 */
-               getNameText: function() {
+               getNameText: function () {
                        return text( this.getName() );
                },
 
@@ -260,7 +265,7 @@ var Title = function( title, namespace ) {
                 * 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();
                },
 
@@ -268,7 +273,7 @@ var Title = function( title, namespace ) {
                 * Get full name in text form, like "File:Foo bar.jpg".
                 * @return {String}
                 */
-               getPrefixedText: function() {
+               getPrefixedText: function () {
                        return text( this.getPrefixedDb() );
                },
 
@@ -276,7 +281,7 @@ var Title = function( title, namespace ) {
                 * The main title (without namespace), like "Foo_bar.jpg"
                 * @return {String}
                 */
-               getMain: function() {
+               getMain: function () {
                        return this.getName() + this.getDotExtension();
                },
 
@@ -284,7 +289,7 @@ var Title = function( title, namespace ) {
                 * The "text" form, like "Foo bar.jpg"
                 * @return {String}
                 */
-               getMainText: function() {
+               getMainText: function () {
                        return text( this.getMain() );
                },
 
@@ -292,23 +297,23 @@ var       Title = function( title, namespace ) {
                 * 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() );
                },
 
@@ -316,7 +321,7 @@ var Title = function( title, namespace ) {
                 * 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 );
                }
        };
@@ -331,4 +336,4 @@ var Title = function( title, namespace ) {
        // Expose
        mw.Title = Title;
 
-})(jQuery);
+}( mediaWiki, jQuery ) );
index 95e5e80..bd12b21 100644 (file)
                                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 );
        }
 
index e631c76..36628eb 100644 (file)
@@ -5,12 +5,13 @@
  * @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 ) );
index 9a4a729..f0f78c2 100644 (file)
  * 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 ) );
index 17a02cf..df62105 100644 (file)
@@ -1,7 +1,7 @@
 /**
  * Utility functions for jazzing up HTMLForm elements
  */
-( function( $ ) {
+( function ( $ ) {
 
 /**
  * jQuery plugin to fade or snap to visible state.
@@ -9,7 +9,7 @@
  * @param boolean instantToggle (optional)
  * @return jQuery
  */
-$.fn.goIn = function( instantToggle ) {
+$.fn.goIn = function ( instantToggle ) {
        if ( instantToggle === true ) {
                return $(this).show();
        }
@@ -22,7 +22,7 @@ $.fn.goIn = function( instantToggle ) {
  * @param boolean instantToggle (optional)
  * @return jQuery
  */
-$.fn.goOut = function( instantToggle ) {
+$.fn.goOut = function ( instantToggle ) {
        if ( instantToggle === true ) {
                return $(this).hide();
        }
@@ -35,20 +35,20 @@ $.fn.goOut = function( instantToggle ) {
  * @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' ) {
@@ -61,4 +61,4 @@ $( function() {
 });
 
 
-})( jQuery );
+}( jQuery ) );
index f690a1d..def1225 100644 (file)
@@ -1,22 +1,27 @@
 /**
- * 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.
@@ -24,9 +29,9 @@
                 * @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 ) );
index 41a5078..e0c65e8 100644 (file)
@@ -1,5 +1,3 @@
-/*jslint browser: true, continue: true, white: true, forin: true*/
-/*global jQuery*/
 /*
  * Core MediaWiki JavaScript Library
  */
@@ -9,7 +7,9 @@ var mw = ( function ( $, undefined ) {
 
        /* Private Members */
 
-       var hasOwn = Object.prototype.hasOwnProperty;
+       var hasOwn = Object.prototype.hasOwnProperty,
+               slice = Array.prototype.slice;
+
        /* Object constructors */
 
        /**
@@ -45,7 +45,7 @@ var mw = ( function ( $, undefined ) {
                        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 );
@@ -130,7 +130,7 @@ var mw = ( function ( $, undefined ) {
                this.format = 'plain';
                this.map = map;
                this.key = key;
-               this.parameters = parameters === undefined ? [] : $.makeArray( parameters );
+               this.parameters = parameters === undefined ? [] : slice.call( parameters );
                return this;
        }
 
@@ -141,7 +141,7 @@ var mw = ( function ( $, undefined ) {
                 *
                 * 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;
@@ -168,7 +168,7 @@ var mw = ( function ( $, undefined ) {
                 *
                 * @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() ) {
@@ -205,7 +205,7 @@ var mw = ( function ( $, undefined ) {
                 *
                 * @return {string} String form of parsed message
                 */
-               parse: function() {
+               parse: function () {
                        this.format = 'parse';
                        return this.toString();
                },
@@ -215,7 +215,7 @@ var mw = ( function ( $, undefined ) {
                 *
                 * @return {string} String form of plain message
                 */
-               plain: function() {
+               plain: function () {
                        this.format = 'plain';
                        return this.toString();
                },
@@ -225,7 +225,7 @@ var mw = ( function ( $, undefined ) {
                 *
                 * @return {string} String form of html escaped message
                 */
-               escaped: function() {
+               escaped: function () {
                        this.format = 'escaped';
                        return this.toString();
                },
@@ -235,7 +235,7 @@ var mw = ( function ( $, undefined ) {
                 *
                 * @return {string} String form of parsed message
                 */
-               exists: function() {
+               exists: function () {
                        return this.map.exists( this.key );
                }
        };
@@ -247,7 +247,7 @@ var mw = ( function ( $, undefined ) {
                 * 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.
@@ -298,7 +298,7 @@ var mw = ( function ( $, undefined ) {
                        var parameters;
                        // Support variadic arguments
                        if ( parameter_1 !== undefined ) {
-                               parameters = $.makeArray( arguments );
+                               parameters = slice.call( arguments );
                                parameters.shift();
                        } else {
                                parameters = [];
@@ -341,7 +341,7 @@ var mw = ( function ( $, undefined ) {
                         *      {
                         *              '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'
@@ -717,6 +717,7 @@ var mw = ( function ( $, undefined ) {
                         * @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;
 
@@ -731,7 +732,7 @@ var mw = ( function ( $, undefined ) {
                                        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
@@ -768,7 +769,7 @@ var mw = ( function ( $, undefined ) {
                                                // 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>
@@ -830,7 +831,7 @@ var mw = ( function ( $, undefined ) {
                                // Execute script
                                try {
                                        script = registry[module].script;
-                                       markModuleReady = function() {
+                                       markModuleReady = function () {
                                                registry[module].state = 'ready';
                                                handlePending( module );
                                        };
@@ -843,7 +844,7 @@ var mw = ( function ( $, undefined ) {
                                                        return;
                                                }
 
-                                               addScript( arr[i], function() {
+                                               addScript( arr[i], function () {
                                                        nestedAddScript( arr, callback, async, i + 1 );
                                                }, async );
                                        };
index ad4c73d..9ce8305 100644 (file)
@@ -6,7 +6,7 @@
  * @author Trevor Parscal <tparscal@wikimedia.org>
  */
 
-( function ( $ ) {
+( function ( mw, $ ) {
 
        /**
         * Logs a message to the console.
@@ -17,7 +17,7 @@
         *
         * @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)
@@ -67,4 +67,4 @@
                } );
        };
 
-})( jQuery );
+}( mediaWiki, jQuery ) );
index 48f30df..b5f124b 100644 (file)
@@ -2,7 +2,7 @@
  * 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 ) );
index 541c77a..c3e5e98 100644 (file)
@@ -1,8 +1,8 @@
 /**
  * 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 ) );