Implement MalformedTitleException for JS and use in constructor
authorGeoffrey Mon <geofbot@gmail.com>
Fri, 15 May 2015 05:19:30 +0000 (01:19 -0400)
committerBartosz Dziewoński <matma.rex@gmail.com>
Sun, 31 May 2015 19:52:08 +0000 (21:52 +0200)
Implements MalformedTitleExceptions to provide information on
  invalid titles.  Throw these exceptions from Title constructor
  instead of generic Errors.

Bug: T89648
Change-Id: I9ed16a5a30b01df785ad736df4b84111c5939bbf

maintenance/jsduck/categories.json
resources/src/mediawiki/mediawiki.Title.js

index eab2b63..43e2d87 100644 (file)
@@ -22,6 +22,7 @@
                                "name": "General",
                                "classes": [
                                        "mw.Title",
+                                       "mw.MalformedTitleException",
                                        "mw.Uri",
                                        "mw.messagePoster.*",
                                        "mw.notification",
index 3efb7ec..8785b0b 100644 (file)
         * @param {string} title Title of the page. If no second argument given,
         *  this will be searched for a namespace
         * @param {number} [namespace=NS_MAIN] If given, will used as default namespace for the given title
-        * @throws {Error} When the title is invalid
+        * @throws {mw.MalformedTitleException} Throws when the title is invalid with details on why the title is invalid
         */
        function Title( title, namespace ) {
                var parsed = parse( title, namespace );
-               if ( !parsed ) {
-                       throw new Error( 'Unable to parse title' );
-               }
 
                this.namespace = parsed.namespace;
                this.title = parsed.title;
         * @method parse
         * @param {string} title
         * @param {number} [defaultNamespace=NS_MAIN]
-        * @return {Object|boolean}
+        * @return {Object}
+        * @throws {mw.MalformedTitleException} When the title is invalid
         */
        parse = function ( title, defaultNamespace ) {
                var namespace, m, id, i, fragment, ext;
                }
 
                if ( title === '' ) {
-                       return false;
+                       throw new MalformedTitleException( 'title-invalid-empty', title );
                }
 
                // Process namespace prefix (if any)
                                if ( namespace === NS_TALK && ( m = title.match( rSplit ) ) ) {
                                        // Disallow titles like Talk:File:x (subject should roundtrip: talk:file:x -> file:x -> file_talk:x)
                                        if ( getNsIdByName( m[1] ) !== false ) {
-                                               return false;
+                                               throw new MalformedTitleException( 'title-invalid-talk-namespace', title );
                                        }
                                }
                        }
 
                // Reject illegal characters
                if ( title.match( rInvalid ) ) {
-                       return false;
+                       throw new MalformedTitleException( 'title-invalid-characters', title, [ title.match( rInvalid )[0] ] );
                }
 
                // Disallow titles that browsers or servers might resolve as directory navigation
                                title.slice( -3 ) === '/..'
                        )
                ) {
-                       return false;
+                       throw new MalformedTitleException( 'title-invalid-relative', title );
                }
 
                // Disallow magic tilde sequence
                if ( title.indexOf( '~~~' ) !== -1 ) {
-                       return false;
+                       throw new MalformedTitleException( 'title-invalid-magic-tilde', title );
                }
 
                // Disallow titles exceeding the TITLE_MAX_BYTES byte size limit (size of underlying database field)
                // Note: The PHP implementation also asserts that even in NS_SPECIAL, the title should
                // be less than 512 bytes.
                if ( namespace !== NS_SPECIAL && $.byteLength( title ) > TITLE_MAX_BYTES ) {
-                       return false;
+                       throw new MalformedTitleException( 'title-invalid-too-long', title, [ TITLE_MAX_BYTES ] );
                }
 
                // Can't make a link to a namespace alone.
                if ( title === '' && namespace !== NS_MAIN ) {
-                       return false;
+                       throw new MalformedTitleException( 'title-invalid-empty', title );
                }
 
                // Any remaining initial :s are illegal.
                if ( title.charAt( 0 ) === ':' ) {
-                       return false;
+                       throw new MalformedTitleException( 'title-invalid-leading-colon', title );
                }
 
                // For backwards-compatibility with old mw.Title, we separate the extension from the
         * @return {mw.Title|null} A valid Title object or null if the title is invalid
         */
        Title.newFromText = function ( title, namespace ) {
-               var t, parsed = parse( title, namespace );
-               if ( !parsed ) {
+               var t, parsed;
+               try {
+                       parsed = parse( title, namespace );
+               } catch ( e ) {
                        return null;
                }
 
        // Expose
        mw.Title = Title;
 
+       /**
+        * @class mw.MalformedTitleException
+        *
+        * Custom exception class that provides parameters for additional error
+        * information regarding the reason behind the invalidity of the requested
+        * title.  The information can be used in i18n messages that can be displayed
+        * to the user.
+        *
+        * Based on MalformedTitleException.php#__construct
+        *
+        * @constructor
+        * @param {string} message Reason e.g. invalid-title-too-long for a long title
+        * @param {string} titleText The invalid title text involved
+        * @param {Array} errorMessageParameters Additional error information
+        */
+       function MalformedTitleException( message, titleText, errorMessageParameters ) {
+               this.message = message;
+               this.titleText = titleText;
+               if ( errorMessageParameters ) {
+                       this.errorMessageParameters = errorMessageParameters;
+               } else {
+                       this.errorMessageParameters = [ ];
+               }
+
+               if ( titleText ) {
+                       this.errorMessageParameters.push( titleText );
+               }
+       }
+
+       MalformedTitleException.prototype = createObject(Error.prototype);
+       MalformedTitleException.prototype.name = 'MalformedTitleException';
+       MalformedTitleException.prototype.constructor = MalformedTitleException;
+       mw.MalformedTitleException = MalformedTitleException;
+
 }( mediaWiki, jQuery ) );