Rename mw.uri to mw.Uri + minor fixes:
authorKrinkle <krinkle@users.mediawiki.org>
Thu, 11 Aug 2011 04:09:34 +0000 (04:09 +0000)
committerKrinkle <krinkle@users.mediawiki.org>
Thu, 11 Aug 2011 04:09:34 +0000 (04:09 +0000)
* Renaming mw.uri to mw.Uri (since it's a constructor)
* Leaked global variable 'g' in _parse() fixed
* Removing unused local variable '_this' in getQueryString()
* Fix documentation (jQuery 'setAttr' should be 'attar')
* Making non-private variables with '@private' comment, private (or "local").
* Using strict undefined comparison (shorter and faster, [[JSPERF]])
* Moving Resources definition from MediaWiki Page section to MediaWiki main section (to reflect directory structure)
* Coding style conventions (mixed spaces and tabs, line wrapping, double/single quotes)
* Remove passing mediaWiki to mw argument (mw is a global alias)
* Passes JSHint

* Removing 404 errors from UploadWizard/test/jasmine/SpecRunner.html

(Follows-up r93781 's move)

resources/Resources.php
resources/mediawiki/mediawiki.Uri.js [new file with mode: 0644]
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]

index 6bcf5ad..18a887d 100644 (file)
@@ -460,6 +460,9 @@ return array(
        'mediawiki.Title' => array(
                'scripts' => 'resources/mediawiki/mediawiki.Title.js',
        ),
+       'mediawiki.Uri' => array( 
+               'scripts' => 'resources/mediawiki/mediawiki.Uri.js',
+       ),
        'mediawiki.user' => array(
                'scripts' => 'resources/mediawiki/mediawiki.user.js',
                'dependencies' => array(
@@ -582,9 +585,6 @@ return array(
                        'jquery.mwExtension',
                ),
        ),
-       'mediawiki.uri' => array( 
-               'scripts' => 'resources/mediawiki/mediawiki.uri.js',
-       ),
        'mediawiki.page.mwsuggest' => array(
                'scripts' => 'resources/mediawiki.page/mediawiki.page.mwsuggest.js',
                'dependencies' => array( 
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.uri.js b/resources/mediawiki/mediawiki.uri.js
deleted file mode 100644 (file)
index 0fad926..0000000
+++ /dev/null
@@ -1,261 +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' ).setAttr( 'href', uri );
- *         // anchor with id 'id1' now links to http://www.foo.com/mysite/mypage.php?bar=1&quux=2
- *
- *         $( 'a#id2' ).setAttr( 'href', uri.clone().extend( { bar: 3, pif: 'paf' } ) );
- *         // anchor with id 'id2' now links to http://www.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( mw, $ ) {
-       /** 
-        * 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 ( typeof uri !== 'undefined' && uri !== null || uri !== '' ) { 
-                       if ( typeof uri === 'string' ) { 
-                               this._parse( uri, strictMode );
-                       } else if ( typeof uri === 'object' ) {
-                               var _this = this;
-                               $.each( this._properties, function( i, property ) {
-                                       _this[property] = uri[property];
-                               } );
-                               if ( typeof 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, ' ' );
-       };
-
-       /**
-        * 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 ( typeof val === 'undefined' || val === null || val === '' ) { 
-                       return '';
-               } else {
-                       return pre + ( raw ? val : mw.uri.encode( val ) ) + post;
-               }
-       }
-
-       mw.uri.prototype = {
-       
-               // regular expressions to parse many common URIs.
-               // @private
-               _parser: {
-                       strict: /^(?:([^:\/?#]+):)?(?:\/\/(?:(?:([^:@]*)(?::([^:@]*))?)?@)?([^:\/?#]*)(?::(\d*))?)?((?:[^?#\/]*\/)*[^?#]*)(?:\?([^#]*))?(?:#(.*))?/,
-                       loose:  /^(?:(?![^:@]+:[^:@\/]*@)([^:\/?#.]+):)?(?:\/\/)?(?:(?:([^:@]*)(?::([^:@]*))?)?@)?([^:\/?#]*)(?::(\d*))?((?:\/(?:[^?#](?![^?#\/]*\.[^?#\/.]+(?:[?#]|$)))*\/?)?[^?#\/]*)(?:\?([^#]*))?(?:#(.*))?/
-               },
-
-               /* the order here matches the order of captured matches in the above parser regexes */
-               // @private
-               _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
-               ],
-
-               /**
-                * Parse a string and set our properties accordingly. 
-                * @param {String} URI
-                * @param {Boolean} strictness
-                * @return {Boolean} success
-                */
-               _parse: function( str, strictMode ) {
-                       var matches = this._parser[ strictMode ? "strict" : "loose" ].exec( str );
-                       var uri = this;
-                       $.each( uri._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.        
-                       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 === '' || typeof $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 = [];
-                       var _this = this;
-                       $.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;
-               }
-       };
-
-} )( window.mediaWiki, jQuery );
index 923b95d..02e174f 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>
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 4fd7bcc..0000000
+++ /dev/null
@@ -1,274 +0,0 @@
-( function( mw ) {
-
-       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" );
-               } );
-
-
-       } );
-
-} )( mediaWiki );