From: Krinkle Date: Fri, 12 Aug 2011 06:41:55 +0000 (+0000) Subject: Apply lowerCamelCase to files for constructors as well. X-Git-Tag: 1.31.0-rc.0~28334 X-Git-Url: https://git.cyclocoop.org/%7B%24www_url%7Dadmin/compta/banques/ajouter.php?a=commitdiff_plain;h=b7ac406fd9ce8ec2b52666757ce5e4c43dd6be5b;p=lhc%2Fweb%2Fwiklou.git Apply lowerCamelCase to files for constructors as well. (Follows-up r94230) --- diff --git a/resources/Resources.php b/resources/Resources.php index e352bad78f..a07331f57c 100644 --- a/resources/Resources.php +++ b/resources/Resources.php @@ -462,10 +462,10 @@ return array( 'scripts' => 'resources/mediawiki/mediawiki.htmlform.js', ), 'mediawiki.Title' => array( - 'scripts' => 'resources/mediawiki/mediawiki.Title.js', + 'scripts' => 'resources/mediawiki/mediawiki.title.js', ), '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 deleted file mode 100644 index 34f85abfa4..0000000000 --- a/resources/mediawiki/mediawiki.Title.js +++ /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 */ - - /** - * Wether 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() ); - }, - - /** - * Wether 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 index 7ff8dda47a..0000000000 --- a/resources/mediawiki/mediawiki.Uri.js +++ /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 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 new file mode 100644 index 0000000000..34f85abfa4 --- /dev/null +++ b/resources/mediawiki/mediawiki.title.js @@ -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 */ + + /** + * Wether 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() ); + }, + + /** + * Wether 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 index 0000000000..7ff8dda47a --- /dev/null +++ b/resources/mediawiki/mediawiki.uri.js @@ -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 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/tests/jasmine/SpecRunner.html b/tests/jasmine/SpecRunner.html index 02e174f73f..923b95d08e 100644 --- a/tests/jasmine/SpecRunner.html +++ b/tests/jasmine/SpecRunner.html @@ -10,10 +10,10 @@ - + - + diff --git a/tests/jasmine/spec/mediawiki.Uri.spec.js b/tests/jasmine/spec/mediawiki.Uri.spec.js deleted file mode 100644 index 9171cdc2df..0000000000 --- a/tests/jasmine/spec/mediawiki.Uri.spec.js +++ /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" ); - } ); - - - } ); - -} )(); diff --git a/tests/jasmine/spec/mediawiki.uri.spec.js b/tests/jasmine/spec/mediawiki.uri.spec.js new file mode 100644 index 0000000000..9171cdc2df --- /dev/null +++ b/tests/jasmine/spec/mediawiki.uri.spec.js @@ -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/qunit/index.html b/tests/qunit/index.html index a88a662140..7eb8fba59a 100644 --- a/tests/qunit/index.html +++ b/tests/qunit/index.html @@ -48,7 +48,7 @@ - + @@ -75,7 +75,7 @@ - + diff --git a/tests/qunit/suites/resources/mediawiki/mediawiki.Title.js b/tests/qunit/suites/resources/mediawiki/mediawiki.Title.js deleted file mode 100644 index 9a765ee3f4..0000000000 --- a/tests/qunit/suites/resources/mediawiki/mediawiki.Title.js +++ /dev/null @@ -1,195 +0,0 @@ -module( 'mediawiki.Title.js' ); - -// 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 diff --git a/tests/qunit/suites/resources/mediawiki/mediawiki.title.js b/tests/qunit/suites/resources/mediawiki/mediawiki.title.js new file mode 100644 index 0000000000..9a765ee3f4 --- /dev/null +++ b/tests/qunit/suites/resources/mediawiki/mediawiki.title.js @@ -0,0 +1,195 @@ +module( 'mediawiki.Title.js' ); + +// 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