Correct the name of Sanskrit Language.
[lhc/web/wiklou.git] / resources / mediawiki / mediawiki.Title.js
1 /**
2 * mediaWiki.Title
3 *
4 * @author Neil Kandalgaonkar, 2010
5 * @author Timo Tijhof, 2011
6 * @since 1.18
7 *
8 * Relies on: mw.config (wgFormattedNamespaces, wgNamespaceIds, wgCaseSensitiveNamespaces), mw.util.wikiGetlink
9 */
10 ( function( $ ) {
11
12 /* Local space */
13
14 /**
15 * Title
16 * @constructor
17 *
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
22 */
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
27
28 if ( arguments.length === 2 ) {
29 setNameAndExtension( this, title );
30 this._ns = fixNsId( namespace );
31 } else if ( arguments.length === 1 ) {
32 setAll( this, title );
33 }
34 return this;
35 },
36
37 /**
38 * Strip some illegal chars: control chars, colon, less than, greater than,
39 * brackets, braces, pipe, whitespace and normal spaces. This still leaves some insanity
40 * intact, like unicode bidi chars, but it's a good start..
41 * @param s {String}
42 * @return {String}
43 */
44 clean = function( s ) {
45 if ( s !== undefined ) {
46 return s.replace( /[\x00-\x1f\x23\x3c\x3e\x5b\x5d\x7b\x7c\x7d\x7f\s]+/g, '_' );
47 }
48 },
49
50 /**
51 * Convert db-key to readable text.
52 * @param s {String}
53 * @return {String}
54 */
55 text = function ( s ) {
56 if ( s !== null && s !== undefined ) {
57 return s.replace( /_/g, ' ' );
58 } else {
59 return '';
60 }
61 },
62
63 /**
64 * Sanitize name.
65 */
66 fixName = function( s ) {
67 return clean( $.trim( s ) );
68 },
69
70 /**
71 * Sanitize name.
72 */
73 fixExt = function( s ) {
74 return clean( s );
75 },
76
77 /**
78 * Sanitize namespace id.
79 * @param id {Number} Namespace id.
80 * @return {Number|Boolean} The id as-is or boolean false if invalid.
81 */
82 fixNsId = function( id ) {
83 // wgFormattedNamespaces is an object of *string* key-vals (ie. arr["0"] not arr[0] )
84 var ns = mw.config.get( 'wgFormattedNamespaces' )[id.toString()];
85
86 // Check only undefined (may be false-y, such as '' (main namespace) ).
87 if ( ns === undefined ) {
88 return false;
89 } else {
90 return Number( id );
91 }
92 },
93
94 /**
95 * Get namespace id from namespace name by any known namespace/id pair (localized, canonical or alias).
96 *
97 * @example On a German wiki this would return 6 for any of 'File', 'Datei', 'Image' or even 'Bild'.
98 * @param ns {String} Namespace name (case insensitive, leading/trailing space ignored).
99 * @return {Number|Boolean} Namespace id or boolean false if unrecognized.
100 */
101 getNsIdByName = function( ns ) {
102 // toLowerCase throws exception on null/undefined. Return early.
103 if ( ns == null ) {
104 return false;
105 }
106 ns = clean( $.trim( ns.toLowerCase() ) ); // Normalize
107 var id = mw.config.get( 'wgNamespaceIds' )[ns];
108 if ( id === undefined ) {
109 mw.log( 'mw.Title: Unrecognized namespace: ' + ns );
110 return false;
111 }
112 return fixNsId( id );
113 },
114
115 /**
116 * Helper to extract namespace, name and extension from a string.
117 *
118 * @param title {mw.Title}
119 * @param raw {String}
120 * @return {mw.Title}
121 */
122 setAll = function( title, s ) {
123 // In normal browsers the match-array contains null/undefined if there's no match,
124 // IE returns an empty string.
125 var matches = s.match( /^(?:([^:]+):)?(.*?)(?:\.(\w{1,5}))?$/ ),
126 ns_match = getNsIdByName( matches[1] );
127
128 // Namespace must be valid, and title must be a non-empty string.
129 if ( ns_match && typeof matches[2] === 'string' && matches[2] !== '' ) {
130 title._ns = ns_match;
131 title._name = fixName( matches[2] );
132 if ( typeof matches[3] === 'string' && matches[3] !== '' ) {
133 title._ext = fixExt( matches[3] );
134 }
135 } else {
136 // Consistency with MediaWiki PHP: Unknown namespace -> fallback to main namespace.
137 title._ns = 0;
138 setNameAndExtension( title, s );
139 }
140 return title;
141 },
142
143 /**
144 * Helper to extract name and extension from a string.
145 *
146 * @param title {mw.Title}
147 * @param raw {String}
148 * @return {mw.Title}
149 */
150 setNameAndExtension = function( title, raw ) {
151 // In normal browsers the match-array contains null/undefined if there's no match,
152 // IE returns an empty string.
153 var matches = raw.match( /^(?:)?(.*?)(?:\.(\w{1,5}))?$/ );
154
155 // Title must be a non-empty string.
156 if ( typeof matches[1] === 'string' && matches[1] !== '' ) {
157 title._name = fixName( matches[1] );
158 if ( typeof matches[2] === 'string' && matches[2] !== '' ) {
159 title._ext = fixExt( matches[2] );
160 }
161 } else {
162 throw new Error( 'mw.Title: Could not parse title "' + raw + '"' );
163 }
164 return title;
165 };
166
167
168 /* Static space */
169
170 /**
171 * Whether this title exists on the wiki.
172 * @param title {mixed} prefixed db-key name (string) or instance of Title
173 * @return {mixed} Boolean true/false if the information is available. Otherwise null.
174 */
175 Title.exists = function( title ) {
176 var type = $.type( title ), obj = Title.exist.pages, match;
177 if ( type === 'string' ) {
178 match = obj[title];
179 } else if ( type === 'object' && title instanceof Title ) {
180 match = obj[title.toString()];
181 } else {
182 throw new Error( 'mw.Title.exists: title must be a string or an instance of Title' );
183 }
184 if ( typeof match === 'boolean' ) {
185 return match;
186 }
187 return null;
188 };
189
190 /**
191 * @var Title.exist {Object}
192 */
193 Title.exist = {
194 /**
195 * @var Title.exist.pages {Object} Keyed by PrefixedDb title.
196 * Boolean true value indicates page does exist.
197 */
198 pages: {},
199 /**
200 * @example Declare existing titles: Title.exist.set(['User:John_Doe', ...]);
201 * @example Declare titles nonexistent: Title.exist.set(['File:Foo_bar.jpg', ...], false);
202 * @param titles {String|Array} Title(s) in strict prefixedDb title form.
203 * @param state {Boolean} (optional) State of the given titles. Defaults to true.
204 * @return {Boolean}
205 */
206 set: function( titles, state ) {
207 titles = $.isArray( titles ) ? titles : [titles];
208 state = state === undefined ? true : !!state;
209 var pages = this.pages, i, len = titles.length;
210 for ( i = 0; i < len; i++ ) {
211 pages[ titles[i] ] = state;
212 }
213 return true;
214 }
215 };
216
217 /* Public methods */
218
219 var fn = {
220 constructor: Title,
221
222 /**
223 * Get the namespace number.
224 * @return {Number}
225 */
226 getNamespaceId: function(){
227 return this._ns;
228 },
229
230 /**
231 * Get the namespace prefix (in the content-language).
232 * In NS_MAIN this is '', otherwise namespace name plus ':'
233 * @return {String}
234 */
235 getNamespacePrefix: function(){
236 return mw.config.get( 'wgFormattedNamespaces' )[this._ns].replace( / /g, '_' ) + (this._ns === 0 ? '' : ':');
237 },
238
239 /**
240 * The name, like "Foo_bar"
241 * @return {String}
242 */
243 getName: function() {
244 if ( $.inArray( this._ns, mw.config.get( 'wgCaseSensitiveNamespaces' ) ) !== -1 ) {
245 return this._name;
246 } else {
247 return $.ucFirst( this._name );
248 }
249 },
250
251 /**
252 * The name, like "Foo bar"
253 * @return {String}
254 */
255 getNameText: function() {
256 return text( this.getName() );
257 },
258
259 /**
260 * Get full name in prefixed DB form, like File:Foo_bar.jpg,
261 * most useful for API calls, anything that must identify the "title".
262 */
263 getPrefixedDb: function() {
264 return this.getNamespacePrefix() + this.getMain();
265 },
266
267 /**
268 * Get full name in text form, like "File:Foo bar.jpg".
269 * @return {String}
270 */
271 getPrefixedText: function() {
272 return text( this.getPrefixedDb() );
273 },
274
275 /**
276 * The main title (without namespace), like "Foo_bar.jpg"
277 * @return {String}
278 */
279 getMain: function() {
280 return this.getName() + this.getDotExtension();
281 },
282
283 /**
284 * The "text" form, like "Foo bar.jpg"
285 * @return {String}
286 */
287 getMainText: function() {
288 return text( this.getMain() );
289 },
290
291 /**
292 * Get the extension (returns null if there was none)
293 * @return {String|null} extension
294 */
295 getExtension: function() {
296 return this._ext;
297 },
298
299 /**
300 * Convenience method: return string like ".jpg", or "" if no extension
301 * @return {String}
302 */
303 getDotExtension: function() {
304 return this._ext === null ? '' : '.' + this._ext;
305 },
306
307 /**
308 * Return the URL to this title
309 * @return {String}
310 */
311 getUrl: function() {
312 return mw.util.wikiGetlink( this.toString() );
313 },
314
315 /**
316 * Whether this title exists on the wiki.
317 * @return {mixed} Boolean true/false if the information is available. Otherwise null.
318 */
319 exists: function() {
320 return Title.exists( this );
321 }
322 };
323
324 // Alias
325 fn.toString = fn.getPrefixedDb;
326 fn.toText = fn.getPrefixedText;
327
328 // Assign
329 Title.prototype = fn;
330
331 // Expose
332 mw.Title = Title;
333
334 })(jQuery);