return null;
};
+ /**
+ * Check if a given namespace is a talk namespace
+ * @param {number} namespaceId Namespace ID
+ * @return {boolean} Namespace is a talk namespace
+ */
+ Title.isTalkNamespace = function ( namespaceId ) {
+ return !!( namespaceId > NS_MAIN && namespaceId % 2 );
+ };
+
/**
* Whether this title exists on the wiki.
*
* @static
* @param {string|mw.Title} title prefixed db-key name (string) or instance of Title
* @return {boolean|null} Boolean if the information is available, otherwise null
+ * @throws {Error} If title is not a string or mw.Title
*/
Title.exists = function ( title ) {
var match,
}
},
+ /**
+ * Check if the title is in a talk namespace
+ *
+ * @return {boolean} The title is in a talk namespace
+ */
+ isTalkPage: function () {
+ return Title.isTalkNamespace( this.getNamespaceId() );
+ },
+
+ /**
+ * Get the title for the associated talk page
+ *
+ * @return {mw.Title|null} The title for the associated talk page, null if not available
+ */
+ getTalkPage: function () {
+ if ( !this.canHaveTalkPage() ) {
+ return null;
+ }
+ return this.isTalkPage() ?
+ this :
+ Title.makeTitle( this.getNamespaceId() + 1, this.getMainText() );
+ },
+
+ /**
+ * Get the title for the subject page of a talk page
+ *
+ * @return {mw.Title|null} The title for the subject page of a talk page, null if not available
+ */
+ getSubjectPage: function () {
+ return this.isTalkPage() ?
+ Title.makeTitle( this.getNamespaceId() - 1, this.getMainText() ) :
+ this;
+ },
+
+ /**
+ * Check the the title can have an associated talk page
+ *
+ * @return {boolean} The title can have an associated talk page
+ */
+ canHaveTalkPage: function () {
+ return this.getNamespaceId() >= NS_MAIN;
+ },
+
/**
* Whether this title exists on the wiki.
*
assert.strictEqual( title.toString(), 'Penguins:Flightless_yet_cute.jpg' );
} );
+ QUnit.test( 'isTalkPage/getTalkPage/getSubjectPage', function ( assert ) {
+ var title;
+
+ title = new mw.Title( 'User:Foo' );
+ assert.strictEqual( title.isTalkPage(), false, 'Non-talk page detected as such' );
+ assert.strictEqual( title.getSubjectPage().getPrefixedText(), 'User:Foo', 'getSubjectPage on a subject page is a no-op' );
+
+ title = title.getTalkPage();
+ assert.strictEqual( title.getPrefixedText(), 'User talk:Foo', 'getTalkPage creates correct title' );
+ assert.strictEqual( title.getTalkPage().getPrefixedText(), 'User talk:Foo', 'getTalkPage on a talk page is a no-op' );
+ assert.strictEqual( title.isTalkPage(), true, 'Talk page is detected as such' );
+
+ title = title.getSubjectPage();
+ assert.strictEqual( title.getPrefixedText(), 'User:Foo', 'getSubjectPage creates correct title' );
+
+ title = new mw.Title( 'Special:AllPages' );
+ assert.strictEqual( title.isTalkPage(), false, 'Special page is not a talk page' );
+ assert.strictEqual( title.getTalkPage(), null, 'getTalkPage not valid for this namespace' );
+ assert.strictEqual( title.getSubjectPage().getPrefixedText(), 'Special:AllPages', 'getSubjectPage is self for special pages' );
+
+ title = new mw.Title( 'Category:Project:Maintenance' );
+ assert.strictEqual( title.getTalkPage().getPrefixedText(), 'Category talk:Project:Maintenance', 'getTalkPage is not confused by colon in main text' );
+ title = new mw.Title( 'Category talk:Project:Maintenance' );
+ assert.strictEqual( title.getSubjectPage().getPrefixedText(), 'Category:Project:Maintenance', 'getSubjectPage is not confused by colon in main text' );
+
+ title = new mw.Title( 'Foo#Caption' );
+ assert.strictEqual( title.getFragment(), 'Caption', 'Subject page has a fragment' );
+ title = title.getTalkPage();
+ assert.strictEqual( title.getPrefixedText(), 'Talk:Foo', 'getTalkPage creates correct title' );
+ assert.strictEqual( title.getFragment(), null, 'getTalkPage does not copy the fragment' );
+ } );
+
QUnit.test( 'Throw error on invalid title', function ( assert ) {
assert.throws( function () {
return new mw.Title( '' );