Make file names match module names.
authorKrinkle <krinkle@users.mediawiki.org>
Mon, 29 Aug 2011 23:36:48 +0000 (23:36 +0000)
committerKrinkle <krinkle@users.mediawiki.org>
Mon, 29 Aug 2011 23:36:48 +0000 (23:36 +0000)
* See [[Coding conventions#File naming]]
* This pretty much undos r94325.

resources/Resources.php
resources/mediawiki/mediawiki.Title.js [new file with mode: 0644]
resources/mediawiki/mediawiki.Uri.js [new file with mode: 0644]
resources/mediawiki/mediawiki.title.js [deleted file]
resources/mediawiki/mediawiki.uri.js [deleted file]
tests/jasmine/SpecRunner.html
tests/jasmine/spec/mediawiki.Uri.spec.js [new file with mode: 0644]
tests/jasmine/spec/mediawiki.uri.spec.js [deleted file]
tests/qunit/index.html
tests/qunit/suites/resources/mediawiki/mediawiki.Title.test.js [new file with mode: 0644]
tests/qunit/suites/resources/mediawiki/mediawiki.title.test.js [deleted file]

index 4d4b8f5..dfbd9e6 100644 (file)
@@ -466,11 +466,11 @@ return array(
                'scripts' => 'resources/mediawiki/mediawiki.htmlform.js',
        ),
        'mediawiki.Title' => array(
-               'scripts' => 'resources/mediawiki/mediawiki.title.js',
+               'scripts' => 'resources/mediawiki/mediawiki.Title.js',
                'dependencies' => 'mediawiki.util',
        ),
        'mediawiki.Uri' => array( 
-               'scripts' => 'resources/mediawiki/mediawiki.uri.js',
+               'scripts' => 'resources/mediawiki/mediawiki.Uri.js',
        ),
        'mediawiki.user' => array(
                'scripts' => 'resources/mediawiki/mediawiki.user.js',
diff --git a/resources/mediawiki/mediawiki.Title.js b/resources/mediawiki/mediawiki.Title.js
new file mode 100644 (file)
index 0000000..b79caea
--- /dev/null
@@ -0,0 +1,334 @@
+/**
+ * mediaWiki.Title
+ *
+ * @author Neil Kandalgaonkar, 2010
+ * @author Timo Tijhof, 2011
+ * @since 1.18
+ *
+ * Relies on: mw.config (wgFormattedNamespaces, wgNamespaceIds, wgCaseSensitiveNamespaces), mw.util.wikiGetlink
+ */
+( function( $ ) {
+
+       /* Local space */
+
+       /**
+        * Title
+        * @constructor
+        *
+        * @param title {String} Title of the page. If no second argument given,
+        * this will be searched for a namespace.
+        * @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
+
+               if ( arguments.length === 2 ) {
+                       setNameAndExtension( this, title );
+                       this._ns = fixNsId( namespace );
+               } else if ( arguments.length === 1 ) {
+                       setAll( this, title );
+               }
+               return this;
+       },
+
+       /**
+        * Strip some illegal chars: control chars, colon, less than, greater than,
+        * brackets, braces, pipe, whitespace and normal spaces. This still leaves some insanity
+        * intact, like unicode bidi chars, but it's a good start..
+        * @param s {String}
+        * @return {String}
+        */
+       clean = function( s ) {
+               if ( s !== undefined ) {
+                       return s.replace( /[\x00-\x1f\x23\x3c\x3e\x5b\x5d\x7b\x7c\x7d\x7f\s]+/g, '_' );
+               }
+       },
+
+       /**
+        * Convert db-key to readable text.
+        * @param s {String}
+        * @return {String}
+        */
+       text = function ( s ) {
+               if ( s !== null && s !== undefined ) {
+                       return s.replace( /_/g, ' ' );
+               } else {
+                       return '';
+               }
+       },
+
+       /**
+        * Sanitize name.
+        */
+       fixName = function( s ) {
+               return clean( $.trim( s ) );
+       },
+
+       /**
+        * Sanitize name.
+        */
+       fixExt = function( s ) {
+               return clean( s.toLowerCase() );
+       },
+
+       /**
+        * Sanitize namespace id.
+        * @param id {Number} Namespace id.
+        * @return {Number|Boolean} The id as-is or boolean false if invalid.
+        */
+       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()];
+
+               // Check only undefined (may be false-y, such as '' (main namespace) ).
+               if ( ns === undefined ) {
+                       return false;
+               } else {
+                       return Number( id );
+               }
+       },
+
+       /**
+        * Get namespace id from namespace name by any known namespace/id pair (localized, canonical or alias).
+        *
+        * @example On a German wiki this would return 6 for any of 'File', 'Datei', 'Image' or even 'Bild'.
+        * @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 ) {
+                       return false;
+               }
+               ns = clean( $.trim( ns.toLowerCase() ) ); // Normalize
+               var id = mw.config.get( 'wgNamespaceIds' )[ns];
+               if ( id === undefined ) {
+                       mw.log( 'mw.Title: Unrecognized namespace: ' + ns );
+                       return false;
+               }
+               return fixNsId( id );
+       },
+
+       /**
+        * Helper to extract namespace, name and extension from a string.
+        *
+        * @param title {mw.Title}
+        * @param raw {String}
+        * @return {mw.Title}
+        */
+       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}))?$/ ),
+                       ns_match = getNsIdByName( matches[1] );
+
+               // 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] );
+                       if ( typeof matches[3] === 'string' && matches[3] !== '' ) {
+                               title._ext = fixExt( matches[3] );
+                       }
+               } else {
+                       // Consistency with MediaWiki PHP: Unknown namespace -> fallback to main namespace.
+                       title._ns = 0;
+                       setNameAndExtension( title, s );
+               }
+               return title;
+       },
+
+       /**
+        * Helper to extract name and extension from a string.
+        *
+        * @param title {mw.Title}
+        * @param raw {String}
+        * @return {mw.Title}
+        */
+       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] );
+                       if ( typeof matches[2] === 'string' && matches[2] !== '' ) {
+                               title._ext = fixExt( matches[2] );
+                       }
+               } else {
+                       throw new Error( 'mw.Title: Could not parse title "' + raw + '"' );
+               }
+               return title;
+       };
+
+
+       /* Static space */
+
+       /**
+        * Whether this title exists on the wiki.
+        * @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 ) {
+               var type = $.type( title ), obj = Title.exist.pages, match;
+               if ( type === 'string' ) {
+                       match = obj[title];
+               } else if ( type === 'object' && title instanceof Title ) {
+                       match = obj[title.toString()];
+               } else {
+                       throw new Error( 'mw.Title.exists: title must be a string or an instance of Title' );
+               }
+               if ( typeof match === 'boolean' ) {
+                       return match;
+               }
+               return null;
+       };
+
+       /**
+        * @var Title.exist {Object}
+        */
+       Title.exist = {
+               /**
+                * @var Title.exist.pages {Object} Keyed by PrefixedDb title.
+                * Boolean true value indicates page does exist.
+                */
+               pages: {},
+               /**
+                * @example Declare existing titles: Title.exist.set(['User:John_Doe', ...]);
+                * @example Declare titles inexisting: Title.exist.set(['File:Foo_bar.jpg', ...], false);
+                * @param titles {String|Array} Title(s) in strict prefixedDb title form.
+                * @param state {Boolean} (optional) State of the given titles. Defaults to true.
+                * @return {Boolean}
+                */
+               set: function( titles, state ) {
+                       titles = $.isArray( titles ) ? titles : [titles];
+                       state = state === undefined ? true : !!state;
+                       var pages = this.pages, i, len = titles.length;
+                       for ( i = 0; i < len; i++ ) {
+                               pages[ titles[i] ] = state;
+                       }
+                       return true;
+               }
+       };
+
+       /* Public methods */
+
+       var fn = {
+               constructor: Title,
+
+               /**
+                * Get the namespace number.
+                * @return {Number}
+                */
+               getNamespaceId: function(){
+                       return this._ns;
+               },
+
+               /**
+                * Get the namespace prefix (in the content-language).
+                * 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 ? '' : ':');
+               },
+
+               /**
+                * The name, like "Foo_bar"
+                * @return {String}
+                */
+               getName: function() {
+                       if ( $.inArray( this._ns, mw.config.get( 'wgCaseSensitiveNamespaces' ) ) !== -1 ) {
+                               return this._name;
+                       } else {
+                               return $.ucFirst( this._name );
+                       }
+               },
+
+               /**
+                * The name, like "Foo bar"
+                * @return {String}
+                */
+               getNameText: function() {
+                       return text( this.getName() );
+               },
+
+               /**
+                * Get full name in prefixed DB form, like File:Foo_bar.jpg,
+                * most useful for API calls, anything that must identify the "title".
+                */
+               getPrefixedDb: function() {
+                       return this.getNamespacePrefix() + this.getMain();
+               },
+
+               /**
+                * Get full name in text form, like "File:Foo bar.jpg".
+                * @return {String}
+                */
+               getPrefixedText: function() {
+                       return text( this.getPrefixedDb() );
+               },
+
+               /**
+                * The main title (without namespace), like "Foo_bar.jpg"
+                * @return {String}
+                */
+               getMain: function() {
+                       return this.getName() + this.getDotExtension();
+               },
+
+               /**
+                * The "text" form, like "Foo bar.jpg"
+                * @return {String}
+                */
+               getMainText: function() {
+                       return text( this.getMain() );
+               },
+
+               /**
+                * Get the extension (returns null if there was none)
+                * @return {String|null} extension
+                */
+               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;
+               },
+
+               /**
+                * Return the URL to this title
+                * @return {String}
+                */
+               getUrl: function() {
+                       return mw.util.wikiGetlink( this.toString() );
+               },
+
+               /**
+                * Whether this title exists on the wiki.
+                * @return {mixed} Boolean true/false if the information is available. Otherwise null.
+                */
+               exists: function() {
+                       return Title.exists( this );
+               }
+       };
+
+       // Alias
+       fn.toString = fn.getPrefixedDb;
+       fn.toText = fn.getPrefixedText;
+
+       // Assign
+       Title.prototype = fn;
+
+       // Expose
+       mw.Title = Title;
+
+})(jQuery);
diff --git a/resources/mediawiki/mediawiki.Uri.js b/resources/mediawiki/mediawiki.Uri.js
new file mode 100644 (file)
index 0000000..7ff8dda
--- /dev/null
@@ -0,0 +1,260 @@
+/**
+ * Library for simple URI parsing and manipulation.  Requires jQuery.
+ *
+ * Do not expect full RFC 3986 compliance. Intended to be minimal, but featureful.
+ * The use cases we have in mind are constructing 'next page' or 'previous page' URLs,
+ * detecting whether we need to use cross-domain proxies for an API, constructing
+ * simple URL-based API calls, etc.
+ *
+ * Intended to compress very well if you use a JS-parsing minifier.
+ *
+ * Dependencies: mw, jQuery
+ *
+ * Example:
+ *
+ *     var uri = new mw.Uri( 'http://foo.com/mysite/mypage.php?quux=2' );
+ *
+ *     if ( uri.host == 'foo.com' ) {
+ *         uri.host = 'www.foo.com';
+ *         uri.extend( { bar: 1 } );
+ *
+ *         $( 'a#id1' ).attr( 'href', uri );
+ *         // anchor with id 'id1' now links to http://foo.com/mysite/mypage.php?bar=1&quux=2
+ *
+ *         $( 'a#id2' ).attr( 'href', uri.clone().extend( { bar: 3, pif: 'paf' } ) );
+ *         // anchor with id 'id2' now links to http://foo.com/mysite/mypage.php?bar=3&quux=2&pif=paf
+ *     }
+ *
+ * Parsing here is regex based, so may not work on all URIs, but is good enough for most.
+ *
+ * Given a URI like
+ * 'http://usr:pwd@www.test.com:81/dir/dir.2/index.htm?q1=0&&test1&test2=&test3=value+%28escaped%29&r=1&r=2#top':
+ * The returned object will have the following properties:
+ *
+ *    protocol  'http'
+ *    user      'usr'
+ *    password  'pwd'
+ *    host      'www.test.com'
+ *    port      '81'
+ *    path      '/dir/dir.2/index.htm'
+ *    query     {
+ *                  q1: 0,
+ *                  test1: null,
+ *                  test2: '',
+ *                  test3: 'value (escaped)'
+ *                  r: [1, 2]
+ *              }
+ *    fragment  'top'
+ *
+ * n.b. 'password' is not technically allowed for HTTP URIs, but it is possible with other
+ * sorts of URIs.
+ * You can modify the properties directly. Then use the toString() method to extract the
+ * full URI string again.
+ *
+ * Parsing based on parseUri 1.2.2 (c) Steven Levithan <stevenlevithan.com> MIT License
+ * http://stevenlevithan.com/demo/parseuri/js/
+ *
+ */
+
+( function( $ ) {
+
+       /**
+        * Function that's useful when constructing the URI string -- we frequently encounter the pattern of
+        * having to add something to the URI as we go, but only if it's present, and to include a character before or after if so.
+        * @param {String} to prepend, if value not empty
+        * @param {String} value to include, if not empty
+        * @param {String} to append, if value not empty
+        * @param {Boolean} raw -- if true, do not URI encode
+        * @return {String}
+        */
+       function cat( pre, val, post, raw ) {
+               if ( val === undefined || val === null || val === '' ) {
+                       return '';
+               } else {
+                       return pre + ( raw ? val : mw.Uri.encode( val ) ) + post;
+               }
+       }
+
+       // Regular expressions to parse many common URIs.
+       var parser = {
+               strict: /^(?:([^:\/?#]+):)?(?:\/\/(?:(?:([^:@]*)(?::([^:@]*))?)?@)?([^:\/?#]*)(?::(\d*))?)?((?:[^?#\/]*\/)*[^?#]*)(?:\?([^#]*))?(?:#(.*))?/,
+               loose:  /^(?:(?![^:@]+:[^:@\/]*@)([^:\/?#.]+):)?(?:\/\/)?(?:(?:([^:@]*)(?::([^:@]*))?)?@)?([^:\/?#]*)(?::(\d*))?((?:\/(?:[^?#](?![^?#\/]*\.[^?#\/.]+(?:[?#]|$)))*\/?)?[^?#\/]*)(?:\?([^#]*))?(?:#(.*))?/
+       },
+
+       // The order here matches the order of captured matches in the above parser regexes.
+       properties = [
+               'protocol',  // http
+               'user',      // usr
+               'password',  // pwd
+               'host',      // www.test.com
+               'port',      // 81
+               'path',      // /dir/dir.2/index.htm
+               'query',     // q1=0&&test1&test2=value (will become { q1: 0, test1: '', test2: 'value' } )
+               'fragment'   // top
+       ];
+
+       /**
+        * Constructs URI object. Throws error if arguments are illegal/impossible, or otherwise don't parse.
+        * @constructor
+        * @param {!Object|String} URI string, or an Object with appropriate properties (especially another URI object to clone). Object must have non-blank 'protocol', 'host', and 'path' properties.
+        * @param {Boolean} strict mode (when parsing a string)
+        */
+       mw.Uri = function( uri, strictMode ) {
+               strictMode = !!strictMode;
+               if ( uri !== undefined && uri !== null || uri !== '' ) {
+                       if ( typeof uri === 'string' ) {
+                               this._parse( uri, strictMode );
+                       } else if ( typeof uri === 'object' ) {
+                               var _this = this;
+                               $.each( properties, function( i, property ) {
+                                       _this[property] = uri[property];
+                               } );
+                               if ( this.query === undefined ) {
+                                       this.query = {};
+                               }
+                       }
+               }
+               if ( !( this.protocol && this.host && this.path ) ) {
+                       throw new Error( 'Bad constructor arguments' );
+               }
+       };
+
+       /**
+        * Standard encodeURIComponent, with extra stuff to make all browsers work similarly and more compliant with RFC 3986
+        * Similar to rawurlencode from PHP and our JS library mw.util.rawurlencode, but we also replace space with a +
+        * @param {String} string
+        * @return {String} encoded for URI
+        */
+       mw.Uri.encode = function( s ) {
+               return encodeURIComponent( s )
+                       .replace( /!/g, '%21').replace( /'/g, '%27').replace( /\(/g, '%28')
+                       .replace( /\)/g, '%29').replace( /\*/g, '%2A')
+                       .replace( /%20/g, '+' );
+       };
+
+       /**
+        * Standard decodeURIComponent, with '+' to space
+        * @param {String} string encoded for URI
+        * @return {String} decoded string
+        */
+       mw.Uri.decode = function( s ) {
+               return decodeURIComponent( s ).replace( /\+/g, ' ' );
+       };
+
+       mw.Uri.prototype = {
+
+               /**
+                * Parse a string and set our properties accordingly.
+                * @param {String} URI
+                * @param {Boolean} strictness
+                * @return {Boolean} success
+                */
+               _parse: function( str, strictMode ) {
+                       var matches = parser[ strictMode ? 'strict' : 'loose' ].exec( str );
+                       var uri = this;
+                       $.each( properties, function( i, property ) {
+                               uri[ property ] = matches[ i+1 ];
+                       } );
+
+                       // uri.query starts out as the query string; we will parse it into key-val pairs then make
+                       // that object the "query" property.
+                       // we overwrite query in uri way to make cloning easier, it can use the same list of properties.
+                       var q = {};
+                       // using replace to iterate over a string
+                       if ( uri.query ) {
+                               uri.query.replace( /(?:^|&)([^&=]*)(?:(=)([^&]*))?/g, function ($0, $1, $2, $3) {
+                                       if ( $1 ) {
+                                               var k = mw.Uri.decode( $1 );
+                                               var v = ( $2 === '' || $2 === undefined ) ? null : mw.Uri.decode( $3 );
+                                               if ( typeof q[ k ] === 'string' ) {
+                                                       q[ k ] = [ q[ k ] ];
+                                               }
+                                               if ( typeof q[ k ] === 'object' ) {
+                                                       q[ k ].push( v );
+                                               } else {
+                                                       q[ k ] = v;
+                                               }
+                                       }
+                               } );
+                       }
+                       this.query = q;
+               },
+
+               /**
+                * Returns user and password portion of a URI.
+                * @return {String}
+                */
+               getUserInfo: function() {
+                       return cat( '', this.user, cat( ':', this.password, '' ) );
+               },
+
+               /**
+                * Gets host and port portion of a URI.
+                * @return {String}
+                */
+               getHostPort: function() {
+                       return this.host + cat( ':', this.port, '' );
+               },
+
+               /**
+                * Returns the userInfo and host and port portion of the URI.
+                * In most real-world URLs, this is simply the hostname, but it is more general.
+                * @return {String}
+                */
+               getAuthority: function() {
+                       return cat( '', this.getUserInfo(), '@' ) + this.getHostPort();
+               },
+
+               /**
+                * Returns the query arguments of the URL, encoded into a string
+                * Does not preserve the order of arguments passed into the URI. Does handle escaping.
+                * @return {String}
+                */
+               getQueryString: function() {
+                       var args = [];
+                       $.each( this.query, function( key, val ) {
+                               var k = mw.Uri.encode( key );
+                               var vals = val === null ? [ null ] : $.makeArray( val );
+                               $.each( vals, function( i, v ) {
+                                       args.push( k + ( v === null ? '' : '=' + mw.Uri.encode( v ) ) );
+                               } );
+                       } );
+                       return args.join( '&' );
+               },
+
+               /**
+                * Returns everything after the authority section of the URI
+                * @return {String}
+                */
+               getRelativePath: function() {
+                       return this.path + cat( '?', this.getQueryString(), '', true ) + cat( '#', this.fragment, '' );
+               },
+
+               /**
+                * Gets the entire URI string. May not be precisely the same as input due to order of query arguments.
+                * @return {String} the URI string
+                */
+               toString: function() {
+                       return this.protocol + '://' + this.getAuthority() + this.getRelativePath();
+               },
+
+               /**
+                * Clone this URI
+                * @return {Object} new URI object with same properties
+                */
+               clone: function() {
+                       return new mw.Uri( this );
+               },
+
+               /**
+                * Extend the query -- supply query parameters to override or add to ours
+                * @param {Object} query parameters in key-val form to override or add
+                * @return {Object} this URI object
+                */
+               extend: function( parameters ) {
+                       $.extend( this.query, parameters );
+                       return this;
+               }
+       };
+
+} )( jQuery );
diff --git a/resources/mediawiki/mediawiki.title.js b/resources/mediawiki/mediawiki.title.js
deleted file mode 100644 (file)
index b79caea..0000000
+++ /dev/null
@@ -1,334 +0,0 @@
-/**
- * mediaWiki.Title
- *
- * @author Neil Kandalgaonkar, 2010
- * @author Timo Tijhof, 2011
- * @since 1.18
- *
- * Relies on: mw.config (wgFormattedNamespaces, wgNamespaceIds, wgCaseSensitiveNamespaces), mw.util.wikiGetlink
- */
-( function( $ ) {
-
-       /* Local space */
-
-       /**
-        * Title
-        * @constructor
-        *
-        * @param title {String} Title of the page. If no second argument given,
-        * this will be searched for a namespace.
-        * @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
-
-               if ( arguments.length === 2 ) {
-                       setNameAndExtension( this, title );
-                       this._ns = fixNsId( namespace );
-               } else if ( arguments.length === 1 ) {
-                       setAll( this, title );
-               }
-               return this;
-       },
-
-       /**
-        * Strip some illegal chars: control chars, colon, less than, greater than,
-        * brackets, braces, pipe, whitespace and normal spaces. This still leaves some insanity
-        * intact, like unicode bidi chars, but it's a good start..
-        * @param s {String}
-        * @return {String}
-        */
-       clean = function( s ) {
-               if ( s !== undefined ) {
-                       return s.replace( /[\x00-\x1f\x23\x3c\x3e\x5b\x5d\x7b\x7c\x7d\x7f\s]+/g, '_' );
-               }
-       },
-
-       /**
-        * Convert db-key to readable text.
-        * @param s {String}
-        * @return {String}
-        */
-       text = function ( s ) {
-               if ( s !== null && s !== undefined ) {
-                       return s.replace( /_/g, ' ' );
-               } else {
-                       return '';
-               }
-       },
-
-       /**
-        * Sanitize name.
-        */
-       fixName = function( s ) {
-               return clean( $.trim( s ) );
-       },
-
-       /**
-        * Sanitize name.
-        */
-       fixExt = function( s ) {
-               return clean( s.toLowerCase() );
-       },
-
-       /**
-        * Sanitize namespace id.
-        * @param id {Number} Namespace id.
-        * @return {Number|Boolean} The id as-is or boolean false if invalid.
-        */
-       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()];
-
-               // Check only undefined (may be false-y, such as '' (main namespace) ).
-               if ( ns === undefined ) {
-                       return false;
-               } else {
-                       return Number( id );
-               }
-       },
-
-       /**
-        * Get namespace id from namespace name by any known namespace/id pair (localized, canonical or alias).
-        *
-        * @example On a German wiki this would return 6 for any of 'File', 'Datei', 'Image' or even 'Bild'.
-        * @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 ) {
-                       return false;
-               }
-               ns = clean( $.trim( ns.toLowerCase() ) ); // Normalize
-               var id = mw.config.get( 'wgNamespaceIds' )[ns];
-               if ( id === undefined ) {
-                       mw.log( 'mw.Title: Unrecognized namespace: ' + ns );
-                       return false;
-               }
-               return fixNsId( id );
-       },
-
-       /**
-        * Helper to extract namespace, name and extension from a string.
-        *
-        * @param title {mw.Title}
-        * @param raw {String}
-        * @return {mw.Title}
-        */
-       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}))?$/ ),
-                       ns_match = getNsIdByName( matches[1] );
-
-               // 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] );
-                       if ( typeof matches[3] === 'string' && matches[3] !== '' ) {
-                               title._ext = fixExt( matches[3] );
-                       }
-               } else {
-                       // Consistency with MediaWiki PHP: Unknown namespace -> fallback to main namespace.
-                       title._ns = 0;
-                       setNameAndExtension( title, s );
-               }
-               return title;
-       },
-
-       /**
-        * Helper to extract name and extension from a string.
-        *
-        * @param title {mw.Title}
-        * @param raw {String}
-        * @return {mw.Title}
-        */
-       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] );
-                       if ( typeof matches[2] === 'string' && matches[2] !== '' ) {
-                               title._ext = fixExt( matches[2] );
-                       }
-               } else {
-                       throw new Error( 'mw.Title: Could not parse title "' + raw + '"' );
-               }
-               return title;
-       };
-
-
-       /* Static space */
-
-       /**
-        * Whether this title exists on the wiki.
-        * @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 ) {
-               var type = $.type( title ), obj = Title.exist.pages, match;
-               if ( type === 'string' ) {
-                       match = obj[title];
-               } else if ( type === 'object' && title instanceof Title ) {
-                       match = obj[title.toString()];
-               } else {
-                       throw new Error( 'mw.Title.exists: title must be a string or an instance of Title' );
-               }
-               if ( typeof match === 'boolean' ) {
-                       return match;
-               }
-               return null;
-       };
-
-       /**
-        * @var Title.exist {Object}
-        */
-       Title.exist = {
-               /**
-                * @var Title.exist.pages {Object} Keyed by PrefixedDb title.
-                * Boolean true value indicates page does exist.
-                */
-               pages: {},
-               /**
-                * @example Declare existing titles: Title.exist.set(['User:John_Doe', ...]);
-                * @example Declare titles inexisting: Title.exist.set(['File:Foo_bar.jpg', ...], false);
-                * @param titles {String|Array} Title(s) in strict prefixedDb title form.
-                * @param state {Boolean} (optional) State of the given titles. Defaults to true.
-                * @return {Boolean}
-                */
-               set: function( titles, state ) {
-                       titles = $.isArray( titles ) ? titles : [titles];
-                       state = state === undefined ? true : !!state;
-                       var pages = this.pages, i, len = titles.length;
-                       for ( i = 0; i < len; i++ ) {
-                               pages[ titles[i] ] = state;
-                       }
-                       return true;
-               }
-       };
-
-       /* Public methods */
-
-       var fn = {
-               constructor: Title,
-
-               /**
-                * Get the namespace number.
-                * @return {Number}
-                */
-               getNamespaceId: function(){
-                       return this._ns;
-               },
-
-               /**
-                * Get the namespace prefix (in the content-language).
-                * 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 ? '' : ':');
-               },
-
-               /**
-                * The name, like "Foo_bar"
-                * @return {String}
-                */
-               getName: function() {
-                       if ( $.inArray( this._ns, mw.config.get( 'wgCaseSensitiveNamespaces' ) ) !== -1 ) {
-                               return this._name;
-                       } else {
-                               return $.ucFirst( this._name );
-                       }
-               },
-
-               /**
-                * The name, like "Foo bar"
-                * @return {String}
-                */
-               getNameText: function() {
-                       return text( this.getName() );
-               },
-
-               /**
-                * Get full name in prefixed DB form, like File:Foo_bar.jpg,
-                * most useful for API calls, anything that must identify the "title".
-                */
-               getPrefixedDb: function() {
-                       return this.getNamespacePrefix() + this.getMain();
-               },
-
-               /**
-                * Get full name in text form, like "File:Foo bar.jpg".
-                * @return {String}
-                */
-               getPrefixedText: function() {
-                       return text( this.getPrefixedDb() );
-               },
-
-               /**
-                * The main title (without namespace), like "Foo_bar.jpg"
-                * @return {String}
-                */
-               getMain: function() {
-                       return this.getName() + this.getDotExtension();
-               },
-
-               /**
-                * The "text" form, like "Foo bar.jpg"
-                * @return {String}
-                */
-               getMainText: function() {
-                       return text( this.getMain() );
-               },
-
-               /**
-                * Get the extension (returns null if there was none)
-                * @return {String|null} extension
-                */
-               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;
-               },
-
-               /**
-                * Return the URL to this title
-                * @return {String}
-                */
-               getUrl: function() {
-                       return mw.util.wikiGetlink( this.toString() );
-               },
-
-               /**
-                * Whether this title exists on the wiki.
-                * @return {mixed} Boolean true/false if the information is available. Otherwise null.
-                */
-               exists: function() {
-                       return Title.exists( this );
-               }
-       };
-
-       // Alias
-       fn.toString = fn.getPrefixedDb;
-       fn.toText = fn.getPrefixedText;
-
-       // Assign
-       Title.prototype = fn;
-
-       // Expose
-       mw.Title = Title;
-
-})(jQuery);
diff --git a/resources/mediawiki/mediawiki.uri.js b/resources/mediawiki/mediawiki.uri.js
deleted file mode 100644 (file)
index 7ff8dda..0000000
+++ /dev/null
@@ -1,260 +0,0 @@
-/**
- * Library for simple URI parsing and manipulation.  Requires jQuery.
- *
- * Do not expect full RFC 3986 compliance. Intended to be minimal, but featureful.
- * The use cases we have in mind are constructing 'next page' or 'previous page' URLs,
- * detecting whether we need to use cross-domain proxies for an API, constructing
- * simple URL-based API calls, etc.
- *
- * Intended to compress very well if you use a JS-parsing minifier.
- *
- * Dependencies: mw, jQuery
- *
- * Example:
- *
- *     var uri = new mw.Uri( 'http://foo.com/mysite/mypage.php?quux=2' );
- *
- *     if ( uri.host == 'foo.com' ) {
- *         uri.host = 'www.foo.com';
- *         uri.extend( { bar: 1 } );
- *
- *         $( 'a#id1' ).attr( 'href', uri );
- *         // anchor with id 'id1' now links to http://foo.com/mysite/mypage.php?bar=1&quux=2
- *
- *         $( 'a#id2' ).attr( 'href', uri.clone().extend( { bar: 3, pif: 'paf' } ) );
- *         // anchor with id 'id2' now links to http://foo.com/mysite/mypage.php?bar=3&quux=2&pif=paf
- *     }
- *
- * Parsing here is regex based, so may not work on all URIs, but is good enough for most.
- *
- * Given a URI like
- * 'http://usr:pwd@www.test.com:81/dir/dir.2/index.htm?q1=0&&test1&test2=&test3=value+%28escaped%29&r=1&r=2#top':
- * The returned object will have the following properties:
- *
- *    protocol  'http'
- *    user      'usr'
- *    password  'pwd'
- *    host      'www.test.com'
- *    port      '81'
- *    path      '/dir/dir.2/index.htm'
- *    query     {
- *                  q1: 0,
- *                  test1: null,
- *                  test2: '',
- *                  test3: 'value (escaped)'
- *                  r: [1, 2]
- *              }
- *    fragment  'top'
- *
- * n.b. 'password' is not technically allowed for HTTP URIs, but it is possible with other
- * sorts of URIs.
- * You can modify the properties directly. Then use the toString() method to extract the
- * full URI string again.
- *
- * Parsing based on parseUri 1.2.2 (c) Steven Levithan <stevenlevithan.com> MIT License
- * http://stevenlevithan.com/demo/parseuri/js/
- *
- */
-
-( function( $ ) {
-
-       /**
-        * Function that's useful when constructing the URI string -- we frequently encounter the pattern of
-        * having to add something to the URI as we go, but only if it's present, and to include a character before or after if so.
-        * @param {String} to prepend, if value not empty
-        * @param {String} value to include, if not empty
-        * @param {String} to append, if value not empty
-        * @param {Boolean} raw -- if true, do not URI encode
-        * @return {String}
-        */
-       function cat( pre, val, post, raw ) {
-               if ( val === undefined || val === null || val === '' ) {
-                       return '';
-               } else {
-                       return pre + ( raw ? val : mw.Uri.encode( val ) ) + post;
-               }
-       }
-
-       // Regular expressions to parse many common URIs.
-       var parser = {
-               strict: /^(?:([^:\/?#]+):)?(?:\/\/(?:(?:([^:@]*)(?::([^:@]*))?)?@)?([^:\/?#]*)(?::(\d*))?)?((?:[^?#\/]*\/)*[^?#]*)(?:\?([^#]*))?(?:#(.*))?/,
-               loose:  /^(?:(?![^:@]+:[^:@\/]*@)([^:\/?#.]+):)?(?:\/\/)?(?:(?:([^:@]*)(?::([^:@]*))?)?@)?([^:\/?#]*)(?::(\d*))?((?:\/(?:[^?#](?![^?#\/]*\.[^?#\/.]+(?:[?#]|$)))*\/?)?[^?#\/]*)(?:\?([^#]*))?(?:#(.*))?/
-       },
-
-       // The order here matches the order of captured matches in the above parser regexes.
-       properties = [
-               'protocol',  // http
-               'user',      // usr
-               'password',  // pwd
-               'host',      // www.test.com
-               'port',      // 81
-               'path',      // /dir/dir.2/index.htm
-               'query',     // q1=0&&test1&test2=value (will become { q1: 0, test1: '', test2: 'value' } )
-               'fragment'   // top
-       ];
-
-       /**
-        * Constructs URI object. Throws error if arguments are illegal/impossible, or otherwise don't parse.
-        * @constructor
-        * @param {!Object|String} URI string, or an Object with appropriate properties (especially another URI object to clone). Object must have non-blank 'protocol', 'host', and 'path' properties.
-        * @param {Boolean} strict mode (when parsing a string)
-        */
-       mw.Uri = function( uri, strictMode ) {
-               strictMode = !!strictMode;
-               if ( uri !== undefined && uri !== null || uri !== '' ) {
-                       if ( typeof uri === 'string' ) {
-                               this._parse( uri, strictMode );
-                       } else if ( typeof uri === 'object' ) {
-                               var _this = this;
-                               $.each( properties, function( i, property ) {
-                                       _this[property] = uri[property];
-                               } );
-                               if ( this.query === undefined ) {
-                                       this.query = {};
-                               }
-                       }
-               }
-               if ( !( this.protocol && this.host && this.path ) ) {
-                       throw new Error( 'Bad constructor arguments' );
-               }
-       };
-
-       /**
-        * Standard encodeURIComponent, with extra stuff to make all browsers work similarly and more compliant with RFC 3986
-        * Similar to rawurlencode from PHP and our JS library mw.util.rawurlencode, but we also replace space with a +
-        * @param {String} string
-        * @return {String} encoded for URI
-        */
-       mw.Uri.encode = function( s ) {
-               return encodeURIComponent( s )
-                       .replace( /!/g, '%21').replace( /'/g, '%27').replace( /\(/g, '%28')
-                       .replace( /\)/g, '%29').replace( /\*/g, '%2A')
-                       .replace( /%20/g, '+' );
-       };
-
-       /**
-        * Standard decodeURIComponent, with '+' to space
-        * @param {String} string encoded for URI
-        * @return {String} decoded string
-        */
-       mw.Uri.decode = function( s ) {
-               return decodeURIComponent( s ).replace( /\+/g, ' ' );
-       };
-
-       mw.Uri.prototype = {
-
-               /**
-                * Parse a string and set our properties accordingly.
-                * @param {String} URI
-                * @param {Boolean} strictness
-                * @return {Boolean} success
-                */
-               _parse: function( str, strictMode ) {
-                       var matches = parser[ strictMode ? 'strict' : 'loose' ].exec( str );
-                       var uri = this;
-                       $.each( properties, function( i, property ) {
-                               uri[ property ] = matches[ i+1 ];
-                       } );
-
-                       // uri.query starts out as the query string; we will parse it into key-val pairs then make
-                       // that object the "query" property.
-                       // we overwrite query in uri way to make cloning easier, it can use the same list of properties.
-                       var q = {};
-                       // using replace to iterate over a string
-                       if ( uri.query ) {
-                               uri.query.replace( /(?:^|&)([^&=]*)(?:(=)([^&]*))?/g, function ($0, $1, $2, $3) {
-                                       if ( $1 ) {
-                                               var k = mw.Uri.decode( $1 );
-                                               var v = ( $2 === '' || $2 === undefined ) ? null : mw.Uri.decode( $3 );
-                                               if ( typeof q[ k ] === 'string' ) {
-                                                       q[ k ] = [ q[ k ] ];
-                                               }
-                                               if ( typeof q[ k ] === 'object' ) {
-                                                       q[ k ].push( v );
-                                               } else {
-                                                       q[ k ] = v;
-                                               }
-                                       }
-                               } );
-                       }
-                       this.query = q;
-               },
-
-               /**
-                * Returns user and password portion of a URI.
-                * @return {String}
-                */
-               getUserInfo: function() {
-                       return cat( '', this.user, cat( ':', this.password, '' ) );
-               },
-
-               /**
-                * Gets host and port portion of a URI.
-                * @return {String}
-                */
-               getHostPort: function() {
-                       return this.host + cat( ':', this.port, '' );
-               },
-
-               /**
-                * Returns the userInfo and host and port portion of the URI.
-                * In most real-world URLs, this is simply the hostname, but it is more general.
-                * @return {String}
-                */
-               getAuthority: function() {
-                       return cat( '', this.getUserInfo(), '@' ) + this.getHostPort();
-               },
-
-               /**
-                * Returns the query arguments of the URL, encoded into a string
-                * Does not preserve the order of arguments passed into the URI. Does handle escaping.
-                * @return {String}
-                */
-               getQueryString: function() {
-                       var args = [];
-                       $.each( this.query, function( key, val ) {
-                               var k = mw.Uri.encode( key );
-                               var vals = val === null ? [ null ] : $.makeArray( val );
-                               $.each( vals, function( i, v ) {
-                                       args.push( k + ( v === null ? '' : '=' + mw.Uri.encode( v ) ) );
-                               } );
-                       } );
-                       return args.join( '&' );
-               },
-
-               /**
-                * Returns everything after the authority section of the URI
-                * @return {String}
-                */
-               getRelativePath: function() {
-                       return this.path + cat( '?', this.getQueryString(), '', true ) + cat( '#', this.fragment, '' );
-               },
-
-               /**
-                * Gets the entire URI string. May not be precisely the same as input due to order of query arguments.
-                * @return {String} the URI string
-                */
-               toString: function() {
-                       return this.protocol + '://' + this.getAuthority() + this.getRelativePath();
-               },
-
-               /**
-                * Clone this URI
-                * @return {Object} new URI object with same properties
-                */
-               clone: function() {
-                       return new mw.Uri( this );
-               },
-
-               /**
-                * Extend the query -- supply query parameters to override or add to ours
-                * @param {Object} query parameters in key-val form to override or add
-                * @return {Object} this URI object
-                */
-               extend: function( parameters ) {
-                       $.extend( this.query, parameters );
-                       return this;
-               }
-       };
-
-} )( jQuery );
index 923b95d..5f49b28 100644 (file)
   <!-- include source files here... -->
   <script type="text/javascript" src="../../load.php?debug=true&lang=en&modules=jquery%7Cmediawiki&only=scripts&skin=vector"></script>
   
-  <script type="text/javascript" src="../../resources/mediawiki/mediawiki.uri.js"></script>
+  <script type="text/javascript" src="../../resources/mediawiki/mediawiki.Uri.js"></script>
 
   <!-- include spec files here... -->
-  <script type="text/javascript" src="spec/mediawiki.uri.spec.js"></script>
+  <script type="text/javascript" src="spec/mediawiki.Uri.spec.js"></script>
 
 </head>
 <body>
 <script type="text/javascript">
-  jasmine.getEnv().addReporter(new jasmine.TrivialReporter());
+  jasmine.getEnv().addReporter( new jasmine.TrivialReporter() );
   jasmine.getEnv().execute();
 </script>
 
 </body>
 </html>
-  
diff --git a/tests/jasmine/spec/mediawiki.Uri.spec.js b/tests/jasmine/spec/mediawiki.Uri.spec.js
new file mode 100644 (file)
index 0000000..9171cdc
--- /dev/null
@@ -0,0 +1,274 @@
+( function() {
+
+       describe( "mw.Uri", function() {
+
+               describe( "should work well in loose and strict mode", function() {
+
+                       function basicTests( strict ) {
+                       
+                               describe( "should parse a simple HTTP URI correctly", function() { 
+                                       
+                                       var uriString = 'http://www.ietf.org/rfc/rfc2396.txt';
+                                       var uri;
+                                       if ( strict ) {
+                                               uri = new mw.Uri( uriString, strict );
+                                       } else {
+                                               uri = new mw.Uri( uriString );
+                                       }
+
+                                       it( "should have basic object properties", function() {
+                                               expect( uri.protocol ).toEqual( 'http' );
+                                               expect( uri.host ).toEqual( 'www.ietf.org' );
+                                               expect( uri.port ).not.toBeDefined();
+                                               expect( uri.path ).toEqual( '/rfc/rfc2396.txt' );
+                                               expect( uri.query ).toEqual( {} );
+                                               expect( uri.fragment ).not.toBeDefined();
+                                       } );
+
+                                       describe( "should construct composite components of URI on request", function() { 
+                                               it( "should have empty userinfo", function() { 
+                                                       expect( uri.getUserInfo() ).toEqual( '' );
+                                               } );
+
+                                               it( "should have authority equal to host", function() { 
+                                                       expect( uri.getAuthority() ).toEqual( 'www.ietf.org' );
+                                               } );
+
+                                               it( "should have hostport equal to host", function() { 
+                                                       expect( uri.getHostPort() ).toEqual( 'www.ietf.org' );
+                                               } );
+
+                                               it( "should have empty string as query string", function() { 
+                                                       expect( uri.getQueryString() ).toEqual( '' );
+                                               } );
+
+                                               it( "should have path as relative path", function() { 
+                                                       expect( uri.getRelativePath() ).toEqual( '/rfc/rfc2396.txt' );
+                                               } );
+
+                                               it( "should return a uri string equivalent to original", function() { 
+                                                       expect( uri.toString() ).toEqual( uriString );
+                                               } );
+                                       } );
+                               } );
+                       }
+
+                       describe( "should work in loose mode", function() { 
+                               basicTests( false );
+                       } );
+
+                       describe( "should work in strict mode", function() {
+                               basicTests( true );
+                       } );
+
+               } );
+
+               it( "should parse a simple ftp URI correctly with user and password", function() {
+                       var uri = new mw.Uri( 'ftp://usr:pwd@192.0.2.16/' );
+                       expect( uri.protocol ).toEqual( 'ftp' );
+                       expect( uri.user ).toEqual( 'usr' );
+                       expect( uri.password ).toEqual( 'pwd' );
+                       expect( uri.host ).toEqual( '192.0.2.16' );
+                       expect( uri.port ).not.toBeDefined();
+                       expect( uri.path ).toEqual( '/' );
+                       expect( uri.query ).toEqual( {} );
+                       expect( uri.fragment ).not.toBeDefined();
+               } );
+
+               it( "should parse a simple querystring", function() {
+                       var uri = new mw.Uri( 'http://www.google.com/?q=uri' );
+                       expect( uri.protocol ).toEqual( 'http' );
+                       expect( uri.host ).toEqual( 'www.google.com' );
+                       expect( uri.port ).not.toBeDefined();
+                       expect( uri.path ).toEqual( '/' );
+                       expect( uri.query ).toBeDefined();
+                       expect( uri.query ).toEqual( { q: 'uri' } );
+                       expect( uri.fragment ).not.toBeDefined();
+                       expect( uri.getQueryString() ).toEqual( 'q=uri' );
+               } );
+
+               describe( "should handle multiple value query args", function() {
+                       var uri = new mw.Uri( 'http://www.sample.com/dir/?m=foo&m=bar&n=1' );
+                       it ( "should parse with multiple values", function() {
+                               expect( uri.query.m.length ).toEqual( 2 );
+                               expect( uri.query.m[0] ).toEqual( 'foo' );
+                               expect( uri.query.m[1] ).toEqual( 'bar' );
+                               expect( uri.query.n ).toEqual( '1' );
+                       } );
+                       it ( "should accept multiple values", function() {
+                               uri.query.n = [ "x", "y", "z" ];
+                               expect( uri.toString() ).toContain( 'm=foo&m=bar' );
+                               expect( uri.toString() ).toContain( 'n=x&n=y&n=z' );
+                               expect( uri.toString().length ).toEqual( 'http://www.sample.com/dir/?m=foo&m=bar&n=x&n=y&n=z'.length );
+                       } );
+                       it ( "should be okay with removing values", function() {
+                               uri.query.m.splice( 0, 1 );
+                               delete uri.query.n;
+                               expect( uri.toString() ).toEqual( 'http://www.sample.com/dir/?m=bar' );
+                               uri.query.m.splice( 0, 1 );
+                               expect( uri.toString() ).toEqual( 'http://www.sample.com/dir/' );
+                       } );
+               } );
+
+               describe( "should deal with an all-dressed URI with everything", function() {
+                       var uri = new mw.Uri( 'http://auth@www.sample.com:81/dir/dir.2/index.htm?q1=0&&test1&test2=value+%28escaped%29#top' );
+
+                       it( "should have basic object properties", function() {
+                               expect( uri.protocol ).toEqual( 'http' );
+                               expect( uri.user ).toEqual( 'auth' );
+                               expect( uri.password ).not.toBeDefined();
+                               expect( uri.host ).toEqual( 'www.sample.com' );
+                               expect( uri.port ).toEqual( '81' );
+                               expect( uri.path ).toEqual( '/dir/dir.2/index.htm' );
+                               expect( uri.query ).toEqual( { q1: '0', test1: null, test2: 'value (escaped)' } );
+                               expect( uri.fragment ).toEqual( 'top' );
+                       } );
+
+                       describe( "should construct composite components of URI on request", function() { 
+                               it( "should have userinfo", function() { 
+                                       expect( uri.getUserInfo() ).toEqual( 'auth' );
+                               } );
+
+                               it( "should have authority equal to auth@hostport", function() { 
+                                       expect( uri.getAuthority() ).toEqual( 'auth@www.sample.com:81' );
+                               } );
+
+                               it( "should have hostport equal to host:port", function() { 
+                                       expect( uri.getHostPort() ).toEqual( 'www.sample.com:81' );
+                               } );
+
+                               it( "should have query string which contains all components", function() { 
+                                       var queryString = uri.getQueryString();
+                                       expect( queryString ).toContain( 'q1=0' );
+                                       expect( queryString ).toContain( 'test1' );
+                                       expect( queryString ).not.toContain( 'test1=' );
+                                       expect( queryString ).toContain( 'test2=value+%28escaped%29' );
+                               } );
+
+                               it( "should have path as relative path", function() { 
+                                       expect( uri.getRelativePath() ).toContain( uri.path );
+                                       expect( uri.getRelativePath() ).toContain( uri.getQueryString() );
+                                       expect( uri.getRelativePath() ).toContain( uri.fragment );
+                               } );
+
+                       } );
+               } );
+
+               describe( "should be able to clone itself", function() {
+                       var original = new mw.Uri( 'http://en.wiki.local/w/api.php?action=query&foo=bar' );                     
+                       var clone = original.clone();
+
+                       it( "should make clones equivalent", function() { 
+                               expect( original ).toEqual( clone );
+                               expect( original.toString() ).toEqual( clone.toString() );
+                       } );
+
+                       it( "should be able to manipulate clones independently", function() { 
+                               // but they are still different objects
+                               expect( original ).not.toBe( clone );
+                               // and can diverge
+                               clone.host = 'fr.wiki.local';
+                               expect( original.host ).not.toEqual( clone.host );
+                               expect( original.toString() ).not.toEqual( clone.toString() );
+                       } );
+               } );
+
+               describe( "should be able to construct URL from object", function() {
+                       it ( "should construct given basic arguments", function() {  
+                               var uri = new mw.Uri( { protocol: 'http', host: 'www.foo.local',  path: '/this' } );
+                               expect( uri.toString() ).toEqual( 'http://www.foo.local/this' );
+                       } );
+               
+                       it ( "should construct given more complex arguments", function() {  
+                               var uri = new mw.Uri( { 
+                                       protocol: 'http', 
+                                       host: 'www.foo.local',  
+                                       path: '/this', 
+                                       query: { hi: 'there' },
+                                       fragment: 'blah'  
+                               } );
+                               expect( uri.toString() ).toEqual( 'http://www.foo.local/this?hi=there#blah' );
+                       } );    
+
+                       it ( "should fail to construct without required properties", function() {  
+                               expect( function() { 
+                                       var uri = new mw.Uri( { protocol: 'http', host: 'www.foo.local' } );
+                               } ).toThrow( "Bad constructor arguments" );
+                       } );
+               } );
+
+               describe( "should be able to manipulate properties", function() { 
+                       var uri;
+
+                       beforeEach( function() { 
+                               uri = new mw.Uri( 'http://en.wiki.local/w/api.php' );                   
+                       } );
+
+                       it( "can add a fragment", function() {
+                               uri.fragment = 'frag';
+                               expect( uri.toString() ).toEqual( 'http://en.wiki.local/w/api.php#frag' );
+                       } );
+
+                       it( "can change host and port", function() {
+                               uri.host = 'fr.wiki.local';
+                               uri.port = '8080';
+                               expect( uri.toString() ).toEqual( 'http://fr.wiki.local:8080/w/api.php' );
+                       } );
+
+                       it ( "can add query arguments", function() {
+                               uri.query.foo = 'bar';
+                               expect( uri.toString() ).toEqual( 'http://en.wiki.local/w/api.php?foo=bar' );
+                       } );
+
+                       it ( "can extend query arguments", function() {
+                               uri.query.foo = 'bar';
+                               expect( uri.toString() ).toEqual( 'http://en.wiki.local/w/api.php?foo=bar' );
+                               uri.extend( { foo: 'quux', pif: 'paf' } );
+                               expect( uri.toString() ).toContain( 'foo=quux' );
+                               expect( uri.toString() ).not.toContain( 'foo=bar' );
+                               expect( uri.toString() ).toContain( 'pif=paf' );
+                       } );
+
+                       it ( "can remove query arguments", function() {
+                               uri.query.foo = 'bar';
+                               expect( uri.toString() ).toEqual( 'http://en.wiki.local/w/api.php?foo=bar' );   
+                               delete( uri.query.foo );
+                               expect( uri.toString() ).toEqual( 'http://en.wiki.local/w/api.php' );   
+                       } );
+
+               } );
+
+               it( "should throw error on no arguments to constructor", function() {
+                       expect( function() { 
+                               uri = new mw.Uri();
+                       } ).toThrow( "Bad constructor arguments" );
+               } );
+
+               it( "should throw error on empty string as argument to constructor", function() {
+                       expect( function() { 
+                               uri = new mw.Uri( '' );
+                       } ).toThrow( "Bad constructor arguments" );
+               } );
+
+               it( "should throw error on non-URI as argument to constructor", function() {
+                       expect( function() { 
+                               uri = new mw.Uri( 'glaswegian penguins' );
+                       } ).toThrow( "Bad constructor arguments" );
+               } );
+
+               it( "should throw error on improper URI as argument to constructor", function() {
+                       expect( function() { 
+                               uri = new mw.Uri( 'http:/foo.com' );
+                       } ).toThrow( "Bad constructor arguments" );
+               } );
+
+               it( "should throw error on URI without protocol as argument to constructor", function() {
+                       expect( function() { 
+                               uri = new mw.Uri( 'foo.com/bar/baz' );
+                       } ).toThrow( "Bad constructor arguments" );
+               } );
+
+
+       } );
+
+} )();
diff --git a/tests/jasmine/spec/mediawiki.uri.spec.js b/tests/jasmine/spec/mediawiki.uri.spec.js
deleted file mode 100644 (file)
index 9171cdc..0000000
+++ /dev/null
@@ -1,274 +0,0 @@
-( function() {
-
-       describe( "mw.Uri", function() {
-
-               describe( "should work well in loose and strict mode", function() {
-
-                       function basicTests( strict ) {
-                       
-                               describe( "should parse a simple HTTP URI correctly", function() { 
-                                       
-                                       var uriString = 'http://www.ietf.org/rfc/rfc2396.txt';
-                                       var uri;
-                                       if ( strict ) {
-                                               uri = new mw.Uri( uriString, strict );
-                                       } else {
-                                               uri = new mw.Uri( uriString );
-                                       }
-
-                                       it( "should have basic object properties", function() {
-                                               expect( uri.protocol ).toEqual( 'http' );
-                                               expect( uri.host ).toEqual( 'www.ietf.org' );
-                                               expect( uri.port ).not.toBeDefined();
-                                               expect( uri.path ).toEqual( '/rfc/rfc2396.txt' );
-                                               expect( uri.query ).toEqual( {} );
-                                               expect( uri.fragment ).not.toBeDefined();
-                                       } );
-
-                                       describe( "should construct composite components of URI on request", function() { 
-                                               it( "should have empty userinfo", function() { 
-                                                       expect( uri.getUserInfo() ).toEqual( '' );
-                                               } );
-
-                                               it( "should have authority equal to host", function() { 
-                                                       expect( uri.getAuthority() ).toEqual( 'www.ietf.org' );
-                                               } );
-
-                                               it( "should have hostport equal to host", function() { 
-                                                       expect( uri.getHostPort() ).toEqual( 'www.ietf.org' );
-                                               } );
-
-                                               it( "should have empty string as query string", function() { 
-                                                       expect( uri.getQueryString() ).toEqual( '' );
-                                               } );
-
-                                               it( "should have path as relative path", function() { 
-                                                       expect( uri.getRelativePath() ).toEqual( '/rfc/rfc2396.txt' );
-                                               } );
-
-                                               it( "should return a uri string equivalent to original", function() { 
-                                                       expect( uri.toString() ).toEqual( uriString );
-                                               } );
-                                       } );
-                               } );
-                       }
-
-                       describe( "should work in loose mode", function() { 
-                               basicTests( false );
-                       } );
-
-                       describe( "should work in strict mode", function() {
-                               basicTests( true );
-                       } );
-
-               } );
-
-               it( "should parse a simple ftp URI correctly with user and password", function() {
-                       var uri = new mw.Uri( 'ftp://usr:pwd@192.0.2.16/' );
-                       expect( uri.protocol ).toEqual( 'ftp' );
-                       expect( uri.user ).toEqual( 'usr' );
-                       expect( uri.password ).toEqual( 'pwd' );
-                       expect( uri.host ).toEqual( '192.0.2.16' );
-                       expect( uri.port ).not.toBeDefined();
-                       expect( uri.path ).toEqual( '/' );
-                       expect( uri.query ).toEqual( {} );
-                       expect( uri.fragment ).not.toBeDefined();
-               } );
-
-               it( "should parse a simple querystring", function() {
-                       var uri = new mw.Uri( 'http://www.google.com/?q=uri' );
-                       expect( uri.protocol ).toEqual( 'http' );
-                       expect( uri.host ).toEqual( 'www.google.com' );
-                       expect( uri.port ).not.toBeDefined();
-                       expect( uri.path ).toEqual( '/' );
-                       expect( uri.query ).toBeDefined();
-                       expect( uri.query ).toEqual( { q: 'uri' } );
-                       expect( uri.fragment ).not.toBeDefined();
-                       expect( uri.getQueryString() ).toEqual( 'q=uri' );
-               } );
-
-               describe( "should handle multiple value query args", function() {
-                       var uri = new mw.Uri( 'http://www.sample.com/dir/?m=foo&m=bar&n=1' );
-                       it ( "should parse with multiple values", function() {
-                               expect( uri.query.m.length ).toEqual( 2 );
-                               expect( uri.query.m[0] ).toEqual( 'foo' );
-                               expect( uri.query.m[1] ).toEqual( 'bar' );
-                               expect( uri.query.n ).toEqual( '1' );
-                       } );
-                       it ( "should accept multiple values", function() {
-                               uri.query.n = [ "x", "y", "z" ];
-                               expect( uri.toString() ).toContain( 'm=foo&m=bar' );
-                               expect( uri.toString() ).toContain( 'n=x&n=y&n=z' );
-                               expect( uri.toString().length ).toEqual( 'http://www.sample.com/dir/?m=foo&m=bar&n=x&n=y&n=z'.length );
-                       } );
-                       it ( "should be okay with removing values", function() {
-                               uri.query.m.splice( 0, 1 );
-                               delete uri.query.n;
-                               expect( uri.toString() ).toEqual( 'http://www.sample.com/dir/?m=bar' );
-                               uri.query.m.splice( 0, 1 );
-                               expect( uri.toString() ).toEqual( 'http://www.sample.com/dir/' );
-                       } );
-               } );
-
-               describe( "should deal with an all-dressed URI with everything", function() {
-                       var uri = new mw.Uri( 'http://auth@www.sample.com:81/dir/dir.2/index.htm?q1=0&&test1&test2=value+%28escaped%29#top' );
-
-                       it( "should have basic object properties", function() {
-                               expect( uri.protocol ).toEqual( 'http' );
-                               expect( uri.user ).toEqual( 'auth' );
-                               expect( uri.password ).not.toBeDefined();
-                               expect( uri.host ).toEqual( 'www.sample.com' );
-                               expect( uri.port ).toEqual( '81' );
-                               expect( uri.path ).toEqual( '/dir/dir.2/index.htm' );
-                               expect( uri.query ).toEqual( { q1: '0', test1: null, test2: 'value (escaped)' } );
-                               expect( uri.fragment ).toEqual( 'top' );
-                       } );
-
-                       describe( "should construct composite components of URI on request", function() { 
-                               it( "should have userinfo", function() { 
-                                       expect( uri.getUserInfo() ).toEqual( 'auth' );
-                               } );
-
-                               it( "should have authority equal to auth@hostport", function() { 
-                                       expect( uri.getAuthority() ).toEqual( 'auth@www.sample.com:81' );
-                               } );
-
-                               it( "should have hostport equal to host:port", function() { 
-                                       expect( uri.getHostPort() ).toEqual( 'www.sample.com:81' );
-                               } );
-
-                               it( "should have query string which contains all components", function() { 
-                                       var queryString = uri.getQueryString();
-                                       expect( queryString ).toContain( 'q1=0' );
-                                       expect( queryString ).toContain( 'test1' );
-                                       expect( queryString ).not.toContain( 'test1=' );
-                                       expect( queryString ).toContain( 'test2=value+%28escaped%29' );
-                               } );
-
-                               it( "should have path as relative path", function() { 
-                                       expect( uri.getRelativePath() ).toContain( uri.path );
-                                       expect( uri.getRelativePath() ).toContain( uri.getQueryString() );
-                                       expect( uri.getRelativePath() ).toContain( uri.fragment );
-                               } );
-
-                       } );
-               } );
-
-               describe( "should be able to clone itself", function() {
-                       var original = new mw.Uri( 'http://en.wiki.local/w/api.php?action=query&foo=bar' );                     
-                       var clone = original.clone();
-
-                       it( "should make clones equivalent", function() { 
-                               expect( original ).toEqual( clone );
-                               expect( original.toString() ).toEqual( clone.toString() );
-                       } );
-
-                       it( "should be able to manipulate clones independently", function() { 
-                               // but they are still different objects
-                               expect( original ).not.toBe( clone );
-                               // and can diverge
-                               clone.host = 'fr.wiki.local';
-                               expect( original.host ).not.toEqual( clone.host );
-                               expect( original.toString() ).not.toEqual( clone.toString() );
-                       } );
-               } );
-
-               describe( "should be able to construct URL from object", function() {
-                       it ( "should construct given basic arguments", function() {  
-                               var uri = new mw.Uri( { protocol: 'http', host: 'www.foo.local',  path: '/this' } );
-                               expect( uri.toString() ).toEqual( 'http://www.foo.local/this' );
-                       } );
-               
-                       it ( "should construct given more complex arguments", function() {  
-                               var uri = new mw.Uri( { 
-                                       protocol: 'http', 
-                                       host: 'www.foo.local',  
-                                       path: '/this', 
-                                       query: { hi: 'there' },
-                                       fragment: 'blah'  
-                               } );
-                               expect( uri.toString() ).toEqual( 'http://www.foo.local/this?hi=there#blah' );
-                       } );    
-
-                       it ( "should fail to construct without required properties", function() {  
-                               expect( function() { 
-                                       var uri = new mw.Uri( { protocol: 'http', host: 'www.foo.local' } );
-                               } ).toThrow( "Bad constructor arguments" );
-                       } );
-               } );
-
-               describe( "should be able to manipulate properties", function() { 
-                       var uri;
-
-                       beforeEach( function() { 
-                               uri = new mw.Uri( 'http://en.wiki.local/w/api.php' );                   
-                       } );
-
-                       it( "can add a fragment", function() {
-                               uri.fragment = 'frag';
-                               expect( uri.toString() ).toEqual( 'http://en.wiki.local/w/api.php#frag' );
-                       } );
-
-                       it( "can change host and port", function() {
-                               uri.host = 'fr.wiki.local';
-                               uri.port = '8080';
-                               expect( uri.toString() ).toEqual( 'http://fr.wiki.local:8080/w/api.php' );
-                       } );
-
-                       it ( "can add query arguments", function() {
-                               uri.query.foo = 'bar';
-                               expect( uri.toString() ).toEqual( 'http://en.wiki.local/w/api.php?foo=bar' );
-                       } );
-
-                       it ( "can extend query arguments", function() {
-                               uri.query.foo = 'bar';
-                               expect( uri.toString() ).toEqual( 'http://en.wiki.local/w/api.php?foo=bar' );
-                               uri.extend( { foo: 'quux', pif: 'paf' } );
-                               expect( uri.toString() ).toContain( 'foo=quux' );
-                               expect( uri.toString() ).not.toContain( 'foo=bar' );
-                               expect( uri.toString() ).toContain( 'pif=paf' );
-                       } );
-
-                       it ( "can remove query arguments", function() {
-                               uri.query.foo = 'bar';
-                               expect( uri.toString() ).toEqual( 'http://en.wiki.local/w/api.php?foo=bar' );   
-                               delete( uri.query.foo );
-                               expect( uri.toString() ).toEqual( 'http://en.wiki.local/w/api.php' );   
-                       } );
-
-               } );
-
-               it( "should throw error on no arguments to constructor", function() {
-                       expect( function() { 
-                               uri = new mw.Uri();
-                       } ).toThrow( "Bad constructor arguments" );
-               } );
-
-               it( "should throw error on empty string as argument to constructor", function() {
-                       expect( function() { 
-                               uri = new mw.Uri( '' );
-                       } ).toThrow( "Bad constructor arguments" );
-               } );
-
-               it( "should throw error on non-URI as argument to constructor", function() {
-                       expect( function() { 
-                               uri = new mw.Uri( 'glaswegian penguins' );
-                       } ).toThrow( "Bad constructor arguments" );
-               } );
-
-               it( "should throw error on improper URI as argument to constructor", function() {
-                       expect( function() { 
-                               uri = new mw.Uri( 'http:/foo.com' );
-                       } ).toThrow( "Bad constructor arguments" );
-               } );
-
-               it( "should throw error on URI without protocol as argument to constructor", function() {
-                       expect( function() { 
-                               uri = new mw.Uri( 'foo.com/bar/baz' );
-                       } ).toThrow( "Bad constructor arguments" );
-               } );
-
-
-       } );
-
-} )();
index 1fa3103..25806e0 100644 (file)
@@ -68,7 +68,7 @@
        <script src="../../resources/jquery/jquery.tabIndex.js"></script>
        <script src="../../resources/jquery/jquery.tablesorter.js"></script>
        <script src="../../resources/jquery/jquery.textSelection.js"></script>
-       <script src="../../resources/mediawiki/mediawiki.title.js"></script>
+       <script src="../../resources/mediawiki/mediawiki.Title.js"></script>
        <script src="../../resources/mediawiki.special/mediawiki.special.js"></script>
        <script src="../../resources/mediawiki.special/mediawiki.special.recentchanges.js"></script>
 
@@ -96,7 +96,7 @@
        <script src="suites/resources/jquery/jquery.tabIndex.test.js"></script>
        <script src="suites/resources/jquery/jquery.tablesorter.test.js" charset="UTF-8"></script>
        <script src="suites/resources/jquery/jquery.textSelection.test.js" charset="UTF-8"></script>
-       <script src="suites/resources/mediawiki/mediawiki.title.test.js"></script>
+       <script src="suites/resources/mediawiki/mediawiki.Title.test.js"></script>
        <script src="suites/resources/mediawiki.special/mediawiki.special.recentchanges.test.js"></script>
 </head>
 <body>
diff --git a/tests/qunit/suites/resources/mediawiki/mediawiki.Title.test.js b/tests/qunit/suites/resources/mediawiki/mediawiki.Title.test.js
new file mode 100644 (file)
index 0000000..157db4d
--- /dev/null
@@ -0,0 +1,195 @@
+module( 'mediawiki.Title' );
+
+// mw.Title relies on these three config vars
+// Restore them after each test run
+var _titleConfig = function() {
+
+       mw.config.set({
+               "wgFormattedNamespaces": {
+                       "-2": "Media",
+                       "-1": "Special",
+                       "0": "",
+                       "1": "Talk",
+                       "2": "User",
+                       "3": "User talk",
+                       "4": "Wikipedia",
+                       "5": "Wikipedia talk",
+                       "6": "File",
+                       "7": "File talk",
+                       "8": "MediaWiki",
+                       "9": "MediaWiki talk",
+                       "10": "Template",
+                       "11": "Template talk",
+                       "12": "Help",
+                       "13": "Help talk",
+                       "14": "Category",
+                       "15": "Category talk",
+                       /* testing custom / localized */
+                       "100": "Penguins"
+               },
+               "wgNamespaceIds": {
+                       "media": -2,
+                       "special": -1,
+                       "": 0,
+                       "talk": 1,
+                       "user": 2,
+                       "user_talk": 3,
+                       "wikipedia": 4,
+                       "wikipedia_talk": 5,
+                       "file": 6,
+                       "file_talk": 7,
+                       "mediawiki": 8,
+                       "mediawiki_talk": 9,
+                       "template": 10,
+                       "template_talk": 11,
+                       "help": 12,
+                       "help_talk": 13,
+                       "category": 14,
+                       "category_talk": 15,
+                       "image": 6,
+                       "image_talk": 7,
+                       "project": 4,
+                       "project_talk": 5,
+                       /* testing custom / alias */
+                       "penguins": 100,
+                       "antarctic_waterfowl": 100
+               },
+               "wgCaseSensitiveNamespaces": []
+       });
+};
+
+test( '-- Initial check', function() {
+       expect(1);
+       ok( mw.Title, 'mw.Title defined' );
+});
+
+test( 'Transform between Text and Db', function() {
+       expect(2);
+       _titleConfig();
+
+       var title;
+
+       title = new mw.Title( 'File:quux pif.jpg' );
+       equal( title.getName(), 'Quux_pif' );
+
+       title = new mw.Title( 'File:Glarg_foo_glang.jpg' );
+       equal( title.getNameText(), 'Glarg foo glang' );
+});
+
+test( 'Main text for filename', function() {
+       expect(8);
+       _titleConfig();
+
+       var title = new mw.Title( 'File:foo_bar.JPG' );
+
+       equal( title.getNamespaceId(), 6 );
+       equal( title.getNamespacePrefix(), 'File:' );
+       equal( title.getName(), 'Foo_bar' );
+       equal( title.getNameText(), 'Foo bar' );
+       equal( title.getMain(), 'Foo_bar.jpg' );
+       equal( title.getMainText(), 'Foo bar.jpg' );
+       equal( title.getExtension(), 'jpg' );
+       equal( title.getDotExtension(), '.jpg' );
+});
+
+test( 'Namespace detection and conversion', function() {
+       expect(6);
+       _titleConfig();
+
+       var title;
+
+       title = new mw.Title( 'something.PDF', 6 );
+       equal( title.toString(), 'File:Something.pdf' );
+
+       title = new mw.Title( 'NeilK', 3 );
+       equal( title.toString(), 'User_talk:NeilK' );
+       equal( title.toText(), 'User talk:NeilK' );
+
+       title = new mw.Title( 'Frobisher', 100 );
+       equal( title.toString(), 'Penguins:Frobisher' );
+
+       title = new mw.Title( 'antarctic_waterfowl:flightless_yet_cute.jpg' );
+       equal( title.toString(), 'Penguins:Flightless_yet_cute.jpg' );
+
+       title = new mw.Title( 'Penguins:flightless_yet_cute.jpg' );
+       equal( title.toString(), 'Penguins:Flightless_yet_cute.jpg' );
+});
+
+test( 'Throw error on invalid title', function() {
+       expect(1);
+       _titleConfig();
+
+       raises(function() {
+               var title = new mw.Title( '' );
+       }, 'Throw error on empty string' );
+});
+
+test( 'Case-sensivity', function() {
+       expect(3);
+       _titleConfig();
+
+       var title;
+
+       // Default config
+       mw.config.set( 'wgCaseSensitiveNamespaces', [] );
+
+       title = new mw.Title( 'article' );
+       equal( title.toString(), 'Article', 'Default config: No sensitive namespaces by default. First-letter becomes uppercase' );
+
+       // $wgCapitalLinks = false;
+       mw.config.set( 'wgCaseSensitiveNamespaces', [0, -2, 1, 4, 5, 6, 7, 10, 11, 12, 13, 14, 15] );
+
+       title = new mw.Title( 'article' );
+       equal( title.toString(), 'article', '$wgCapitalLinks=false: Article namespace is sensitive, first-letter case stays lowercase' );
+
+       title = new mw.Title( 'john', 2 );
+       equal( title.toString(), 'User:John', '$wgCapitalLinks=false: User namespace is insensitive, first-letter becomes uppercase' );
+});
+
+test( 'toString / toText', function() {
+       expect(2);
+       _titleConfig();
+
+       var title = new mw.Title( 'Some random page' );
+
+       equal( title.toString(), title.getPrefixedDb() );
+       equal( title.toText(), title.getPrefixedText() );
+});
+
+test( 'Exists', function() {
+       expect(3);
+       _titleConfig();
+
+       var title;
+
+       // Empty registry, checks default to null
+
+       title = new mw.Title( 'Some random page', 4 );
+       strictEqual( title.exists(), null, 'Return null with empty existance registry' );
+
+       // Basic registry, checks default to boolean
+       mw.Title.exist.set( ['Does_exist', 'User_talk:NeilK', 'Wikipedia:Sandbox_rules'], true );
+       mw.Title.exist.set( ['Does_not_exist', 'User:John', 'Foobar'], false );
+
+       title = new mw.Title( 'Project:Sandbox rules' );
+       assertTrue( title.exists(), 'Return true for page titles marked as existing' );
+       title = new mw.Title( 'Foobar' );
+       assertFalse( title.exists(), 'Return false for page titles marked as inexisting' );
+
+});
+
+test( 'Url', function() {
+       expect(2);
+       _titleConfig();
+
+       var title;
+
+       // Config
+       mw.config.set( 'wgArticlePath', '/wiki/$1' );
+
+       title = new mw.Title( 'Foobar' );
+       equal( title.getUrl(), '/wiki/Foobar', 'Basic functionally, toString passing to wikiGetlink' );
+
+       title = new mw.Title( 'John Doe', 3 );
+       equal( title.getUrl(), '/wiki/User_talk:John_Doe', 'Escaping in title and namespace for urls' );
+});
diff --git a/tests/qunit/suites/resources/mediawiki/mediawiki.title.test.js b/tests/qunit/suites/resources/mediawiki/mediawiki.title.test.js
deleted file mode 100644 (file)
index 9d1c517..0000000
+++ /dev/null
@@ -1,195 +0,0 @@
-module( 'mediawiki.title' );
-
-// mw.Title relies on these three config vars
-// Restore them after each test run
-var _titleConfig = function() {
-
-       mw.config.set({
-               "wgFormattedNamespaces": {
-                       "-2": "Media",
-                       "-1": "Special",
-                       "0": "",
-                       "1": "Talk",
-                       "2": "User",
-                       "3": "User talk",
-                       "4": "Wikipedia",
-                       "5": "Wikipedia talk",
-                       "6": "File",
-                       "7": "File talk",
-                       "8": "MediaWiki",
-                       "9": "MediaWiki talk",
-                       "10": "Template",
-                       "11": "Template talk",
-                       "12": "Help",
-                       "13": "Help talk",
-                       "14": "Category",
-                       "15": "Category talk",
-                       /* testing custom / localized */
-                       "100": "Penguins"
-               },
-               "wgNamespaceIds": {
-                       "media": -2,
-                       "special": -1,
-                       "": 0,
-                       "talk": 1,
-                       "user": 2,
-                       "user_talk": 3,
-                       "wikipedia": 4,
-                       "wikipedia_talk": 5,
-                       "file": 6,
-                       "file_talk": 7,
-                       "mediawiki": 8,
-                       "mediawiki_talk": 9,
-                       "template": 10,
-                       "template_talk": 11,
-                       "help": 12,
-                       "help_talk": 13,
-                       "category": 14,
-                       "category_talk": 15,
-                       "image": 6,
-                       "image_talk": 7,
-                       "project": 4,
-                       "project_talk": 5,
-                       /* testing custom / alias */
-                       "penguins": 100,
-                       "antarctic_waterfowl": 100
-               },
-               "wgCaseSensitiveNamespaces": []
-       });
-};
-
-test( '-- Initial check', function() {
-       expect(1);
-       ok( mw.Title, 'mw.Title defined' );
-});
-
-test( 'Transform between Text and Db', function() {
-       expect(2);
-       _titleConfig();
-
-       var title;
-
-       title = new mw.Title( 'File:quux pif.jpg' );
-       equal( title.getName(), 'Quux_pif' );
-
-       title = new mw.Title( 'File:Glarg_foo_glang.jpg' );
-       equal( title.getNameText(), 'Glarg foo glang' );
-});
-
-test( 'Main text for filename', function() {
-       expect(8);
-       _titleConfig();
-
-       var title = new mw.Title( 'File:foo_bar.JPG' );
-
-       equal( title.getNamespaceId(), 6 );
-       equal( title.getNamespacePrefix(), 'File:' );
-       equal( title.getName(), 'Foo_bar' );
-       equal( title.getNameText(), 'Foo bar' );
-       equal( title.getMain(), 'Foo_bar.jpg' );
-       equal( title.getMainText(), 'Foo bar.jpg' );
-       equal( title.getExtension(), 'jpg' );
-       equal( title.getDotExtension(), '.jpg' );
-});
-
-test( 'Namespace detection and conversion', function() {
-       expect(6);
-       _titleConfig();
-
-       var title;
-
-       title = new mw.Title( 'something.PDF', 6 );
-       equal( title.toString(), 'File:Something.pdf' );
-
-       title = new mw.Title( 'NeilK', 3 );
-       equal( title.toString(), 'User_talk:NeilK' );
-       equal( title.toText(), 'User talk:NeilK' );
-
-       title = new mw.Title( 'Frobisher', 100 );
-       equal( title.toString(), 'Penguins:Frobisher' );
-
-       title = new mw.Title( 'antarctic_waterfowl:flightless_yet_cute.jpg' );
-       equal( title.toString(), 'Penguins:Flightless_yet_cute.jpg' );
-
-       title = new mw.Title( 'Penguins:flightless_yet_cute.jpg' );
-       equal( title.toString(), 'Penguins:Flightless_yet_cute.jpg' );
-});
-
-test( 'Throw error on invalid title', function() {
-       expect(1);
-       _titleConfig();
-
-       raises(function() {
-               var title = new mw.Title( '' );
-       }, 'Throw error on empty string' );
-});
-
-test( 'Case-sensivity', function() {
-       expect(3);
-       _titleConfig();
-
-       var title;
-
-       // Default config
-       mw.config.set( 'wgCaseSensitiveNamespaces', [] );
-
-       title = new mw.Title( 'article' );
-       equal( title.toString(), 'Article', 'Default config: No sensitive namespaces by default. First-letter becomes uppercase' );
-
-       // $wgCapitalLinks = false;
-       mw.config.set( 'wgCaseSensitiveNamespaces', [0, -2, 1, 4, 5, 6, 7, 10, 11, 12, 13, 14, 15] );
-
-       title = new mw.Title( 'article' );
-       equal( title.toString(), 'article', '$wgCapitalLinks=false: Article namespace is sensitive, first-letter case stays lowercase' );
-
-       title = new mw.Title( 'john', 2 );
-       equal( title.toString(), 'User:John', '$wgCapitalLinks=false: User namespace is insensitive, first-letter becomes uppercase' );
-});
-
-test( 'toString / toText', function() {
-       expect(2);
-       _titleConfig();
-
-       var title = new mw.Title( 'Some random page' );
-
-       equal( title.toString(), title.getPrefixedDb() );
-       equal( title.toText(), title.getPrefixedText() );
-});
-
-test( 'Exists', function() {
-       expect(3);
-       _titleConfig();
-
-       var title;
-
-       // Empty registry, checks default to null
-
-       title = new mw.Title( 'Some random page', 4 );
-       strictEqual( title.exists(), null, 'Return null with empty existance registry' );
-
-       // Basic registry, checks default to boolean
-       mw.Title.exist.set( ['Does_exist', 'User_talk:NeilK', 'Wikipedia:Sandbox_rules'], true );
-       mw.Title.exist.set( ['Does_not_exist', 'User:John', 'Foobar'], false );
-
-       title = new mw.Title( 'Project:Sandbox rules' );
-       assertTrue( title.exists(), 'Return true for page titles marked as existing' );
-       title = new mw.Title( 'Foobar' );
-       assertFalse( title.exists(), 'Return false for page titles marked as inexisting' );
-
-});
-
-test( 'Url', function() {
-       expect(2);
-       _titleConfig();
-
-       var title;
-
-       // Config
-       mw.config.set( 'wgArticlePath', '/wiki/$1' );
-
-       title = new mw.Title( 'Foobar' );
-       equal( title.getUrl(), '/wiki/Foobar', 'Basic functionally, toString passing to wikiGetlink' );
-
-       title = new mw.Title( 'John Doe', 3 );
-       equal( title.getUrl(), '/wiki/User_talk:John_Doe', 'Escaping in title and namespace for urls' );
-});
\ No newline at end of file