4 * @author Neil Kandalgaonkar, 2010
5 * @author Timo Tijhof, 2011
8 * Relies on: mw.config (wgFormattedNamespaces, wgNamespaceIds, wgCaseSensitiveNamespaces), mw.util.wikiGetlink
18 * @param title {String} Title of the page. If no second argument given,
19 * this will be searched for a namespace.
20 * @param namespace {Number} (optional) Namespace id. If given, title will be taken as-is.
21 * @return {Title} this
23 var Title = function( title
, namespace ) {
24 this._ns
= 0; // integer namespace id
25 this._name
= null; // name in canonical 'database' form
26 this._ext
= null; // extension
28 if ( arguments
.length
=== 2 ) {
29 this.setNameAndExtension( title
).setNamespaceById( namespace );
30 } else if ( arguments
.length
=== 1 ) {
31 // If title is like "Blabla: Hello" ignore exception by setNamespace(),
32 // and instead assume NS_MAIN and keep prefix
36 this.setNameAndExtension( title
);
43 * Strip some illegal chars: control chars, colon, less than, greater than,
44 * brackets, braces, pipe, whitespace and normal spaces. This still leaves some insanity
45 * intact, like unicode bidi chars, but it's a good start..
49 clean = function( s
) {
50 if ( s
!== undefined ) {
51 return s
.replace( /[\x00-\x1f\x23\x3c\x3e\x5b\x5d\x7b\x7c\x7d\x7f\s]+/g, '_' );
56 * Convert db-key to readable text.
60 text = function ( s
) {
61 if ( s
!== null && s
!== undefined ) {
62 return s
.replace( /_
/g
, ' ' );
71 * Wether this title exists on the wiki.
72 * @param title {mixed} prefixed db-key name (string) or instance of Title
73 * @return {mixed} Boolean true/false if the information is available. Otherwise null.
75 Title
.exists = function( title
) {
76 var type
= $.type( title
), obj
= Title
.exist
.pages
, match
;
77 if ( type
=== 'string' ) {
79 } else if ( type
=== 'object' && title
instanceof Title
) {
80 match
= obj
[title
.toString()];
82 throw new Error( 'mw.Title.exists: title must be a string or an instance of Title' );
84 if ( typeof match
=== 'boolean' ) {
91 * @var Title.exist {Object}
95 * @var Title.exist.pages {Object} Keyed by PrefixedDb title.
96 * Boolean true value indicates page does exist.
100 * @example Declare existing titles: Title.exist.set(['User:John_Doe', ...]);
101 * @example Declare titles inexisting: Title.exist.set(['File:Foo_bar.jpg', ...], false);
102 * @param titles {String|Array} Title(s) in strict prefixedDb title form.
103 * @param state {Boolean} (optional) State of the given titles. Defaults to true.
106 set: function( titles
, state
) {
107 titles
= $.isArray( titles
) ? titles
: [titles
];
108 state
= state
=== undefined ? true : !!state
;
109 var pages
= this.pages
, i
, len
= titles
.length
;
110 for ( i
= 0; i
< len
; i
++ ) {
111 pages
[ titles
[i
] ] = state
;
122 * @param id {Number} Canonical namespace id.
123 * @return {mw.Title} this
125 setNamespaceById: function( id
) {
126 // wgFormattedNamespaces is an object of *string* key-vals,
127 var ns
= mw
.config
.get( 'wgFormattedNamespaces' )[id
.toString()];
129 // Cannot cast to boolean, ns may be '' (main namespace)
130 if ( ns
=== undefined ) {
133 this._ns
= Number( id
);
139 * Set namespace by any known namespace/id pair (localized, canonical or alias)
140 * On a German wiki this could be 'File', 'Datei', 'Image' or even 'Bild' for NS_FILE.
141 * @param ns {String} A namespace name (case insensitive, space insensitive)
142 * @return {mw.Title} this
144 setNamespace: function( ns
) {
145 ns
= clean( $.trim( ns
.toLowerCase() ) ); // Normalize
146 var id
= mw
.config
.get( 'wgNamespaceIds' )[ns
];
147 if ( id
=== undefined ) {
148 throw new Error( 'mw.Title: Unrecognized canonical namespace: ' + ns
);
150 return this.setNamespaceById( id
);
154 * Get the namespace number.
157 getNamespaceId: function(){
162 * Get the namespace prefix (in the content-language).
163 * In NS_MAIN this is '', otherwise namespace name plus ':'
166 getNamespacePrefix: function(){
167 return mw
.config
.get( 'wgFormattedNamespaces' )[this._ns
].replace( / /g
, '_' ) + (this._ns
=== 0 ? '' : ':');
171 * Set the "name" portion, removing illegal characters.
172 * @param s {String} Page name (without namespace prefix)
173 * @return {mw.Title} this
175 setName: function( s
) {
176 this._name
= clean( $.trim( s
) );
181 * The name, like "Foo_bar"
184 getName: function() {
185 if ( $.inArray( this._ns
, mw
.config
.get( 'wgCaseSensitiveNamespaces' ) ) !== -1 ) {
188 return $.ucFirst( this._name
);
193 * The name, like "Foo bar"
196 getNameText: function() {
197 return text( this.getName() );
201 * Get full name in prefixed DB form, like File:Foo_bar.jpg,
202 * most useful for API calls, anything that must identify the "title".
204 getPrefixedDb: function() {
205 return this.getNamespacePrefix() + this.getMain();
209 * Get full name in text form, like "File:Foo bar.jpg".
212 getPrefixedText: function() {
213 return text( this.getPrefixedDb() );
217 * The main title (without namespace), like "Foo_bar.jpg"
220 getMain: function() {
221 return this.getName() + this.getDotExtension();
225 * The "text" form, like "Foo bar.jpg"
228 getMainText: function() {
229 return text( this.getMain() );
233 * Set the "extension" portion, removing illegal characters.
235 * @return {mw.Title} this
237 setExtension: function( s
) {
238 this._ext
= clean( s
.toLowerCase() );
243 * Get the extension (returns null if there was none)
244 * @return {String|null} extension
246 getExtension: function() {
251 * Convenience method: return string like ".jpg", or "" if no extension
254 getDotExtension: function() {
255 return this._ext
=== null ? '' : '.' + this._ext
;
260 * @return {mw.Title} this
262 setAll: function( s
) {
263 var matches
= s
.match( /^(?:([^:]+):)?(.*?)(?:\.(\w{1,5}))?$/ );
264 if ( matches
.length
) {
265 if ( matches
[1] ) { this.setNamespace( matches
[1] ); }
266 if ( matches
[2] ) { this.setName( matches
[2] ); }
267 if ( matches
[3] ) { this.setExtension( matches
[3] ); }
269 throw new Error( 'mw.Title: Could not parse title "' + s
+ '"' );
276 * @return {mw.Title} this
278 setNameAndExtension: function( s
) {
279 var matches
= s
.match( /^(?:)?(.*?)(?:\.(\w{1,5}))?$/ );
280 if ( matches
.length
) {
281 if ( matches
[1] ) { this.setName( matches
[1] ); }
282 if ( matches
[2] ) { this.setExtension( matches
[2] ); }
284 throw new Error( 'mw.Title: Could not parse title "' + s
+ '"' );
290 * Return the URL to this title
294 return mw
.util
.wikiGetlink( this.toString() );
298 * Wether this title exists on the wiki.
299 * @return {mixed} Boolean true/false if the information is available. Otherwise null.
302 return Title
.exists( this );
307 fn
.toString
= fn
.getPrefixedDb
;
308 fn
.toText
= fn
.getPrefixedText
;
311 Title
.prototype = fn
;