Localisation updates from https://translatewiki.net.
[mediawiki.git] / resources / src / startup / mediawiki.js
blob371abf3c2590f0faf4d2a399c1d98db8c8c74a68
1 /**
2  * Base library for MediaWiki.
3  */
4 /* global $CODE */
6 ( function () {
7         'use strict';
9         var con = window.console;
11         /**
12          * @class mw.Map
13          * @classdesc Collection of values by string keys.
14          *
15          * This is an internal class that backs the mw.config and mw.messages APIs.
16          *
17          * It allows reading and writing to the collection via public methods,
18          * and allows batch iteraction for all its methods.
19          *
20          * For mw.config, scripts sometimes choose to "import" a set of keys locally,
21          * like so:
22          *
23          * ```
24          * var conf = mw.config.get( [ 'wgServerName', 'wgUserName', 'wgPageName' ] );
25          * conf.wgServerName; // "example.org"
26          * ```
27          *
28          * Check the existence ("AND" condition) of multiple keys:
29          *
30          * ```
31          * if ( mw.config.exists( [ 'wgFoo', 'wgBar' ] ) );
32          * ```
33          *
34          * For mw.messages, the {@link mw.Map#set} method allows mw.loader and mw.Api to essentially
35          * extend the object, and batch-apply all their loaded values in one go:
36          *
37          * ```
38          * mw.messages.set( { "mon": "Monday", "tue": "Tuesday" } );
39          * ```
40          *
41          * @hideconstructor
42          */
43         function Map() {
44                 this.values = Object.create( null );
45         }
47         Map.prototype = /** @lends mw.Map.prototype */ {
48                 constructor: Map,
50                 /**
51                  * Get the value of one or more keys.
52                  *
53                  * If called with no arguments, all values are returned.
54                  *
55                  * @param {string|Array} [selection] Key or array of keys to retrieve values for.
56                  * @param {any} [fallback=null] Value for keys that don't exist.
57                  * @return {any|Object|null} If selection was a string, returns the value,
58                  *  If selection was an array, returns an object of key/values.
59                  *  If no selection is passed, a new object with all key/values is returned.
60                  */
61                 get: function ( selection, fallback ) {
62                         if ( arguments.length < 2 ) {
63                                 fallback = null;
64                         }
66                         if ( typeof selection === 'string' ) {
67                                 return selection in this.values ?
68                                         this.values[ selection ] :
69                                         fallback;
70                         }
72                         var results;
73                         if ( Array.isArray( selection ) ) {
74                                 results = {};
75                                 for ( var i = 0; i < selection.length; i++ ) {
76                                         if ( typeof selection[ i ] === 'string' ) {
77                                                 results[ selection[ i ] ] = selection[ i ] in this.values ?
78                                                         this.values[ selection[ i ] ] :
79                                                         fallback;
80                                         }
81                                 }
82                                 return results;
83                         }
85                         if ( selection === undefined ) {
86                                 results = {};
87                                 for ( var key in this.values ) {
88                                         results[ key ] = this.values[ key ];
89                                 }
90                                 return results;
91                         }
93                         // Invalid selection key
94                         return fallback;
95                 },
97                 /**
98                  * Set one or more key/value pairs.
99                  *
100                  * @param {string|Object} selection Key to set value for, or object mapping keys to values
101                  * @param {any} [value] Value to set (optional, only in use when key is a string)
102                  * @return {boolean} True on success, false on failure
103                  */
104                 set: function ( selection, value ) {
105                         // Use `arguments.length` because `undefined` is also a valid value.
106                         if ( arguments.length > 1 ) {
107                                 // Set one key
108                                 if ( typeof selection === 'string' ) {
109                                         this.values[ selection ] = value;
110                                         return true;
111                                 }
112                         } else if ( typeof selection === 'object' ) {
113                                 // Set multiple keys
114                                 for ( var key in selection ) {
115                                         this.values[ key ] = selection[ key ];
116                                 }
117                                 return true;
118                         }
119                         return false;
120                 },
122                 /**
123                  * Check if a given key exists in the map.
124                  *
125                  * @param {string} selection Key to check
126                  * @return {boolean} True if the key exists
127                  */
128                 exists: function ( selection ) {
129                         return typeof selection === 'string' && selection in this.values;
130                 }
131         };
133         /**
134          * Write a verbose message to the browser's console in debug mode.
135          *
136          * In ResourceLoader debug mode, this writes to the browser's console.
137          * In production mode, it is a no-op.
138          *
139          * See {@link mw.log} for other logging methods.
140          *
141          * @memberof mw
142          * @variation 2
143          * @param {...string} msg Messages to output to console.
144          */
145         var log = function () {
146                 $CODE.consoleLog();
147         };
149         /**
150          * Write a message to the browser console's warning channel.
151          *
152          * @memberof mw.log
153          * @method warn
154          * @param {...string} msg Messages to output to console
155          */
156         log.warn = Function.prototype.bind.call( con.warn, con );
158         /**
159          * Base library for MediaWiki.
160          *
161          * Exposed globally as `mw`, with `mediaWiki` as alias. `mw` code can be considered stable and follows the
162          * [frontend stable interface policy](https://www.mediawiki.org/wiki/Special:MyLanguage/Stable_interface_policy/Frontend).
163          *
164          * @namespace mw
165          */
166         var mw = /** @lends mw */ {
167                 /**
168                  * Get the current time, measured in milliseconds since January 1, 1970 (UTC).
169                  *
170                  * On browsers that implement the Navigation Timing API, this function will produce
171                  * floating-point values with microsecond precision that are guaranteed to be monotonic.
172                  * On all other browsers, it will fall back to using `Date`.
173                  *
174                  * @return {number} Current time
175                  */
176                 now: function () {
177                         // Optimisation: Cache and re-use the chosen implementation.
178                         // Optimisation: Avoid startup overhead by re-defining on first call instead of IIFE.
179                         var perf = window.performance;
180                         var navStart = perf && perf.timing && perf.timing.navigationStart;
182                         // Define the relevant shortcut
183                         mw.now = navStart && perf.now ?
184                                 function () {
185                                         return navStart + perf.now();
186                                 } :
187                                 Date.now;
189                         return mw.now();
190                 },
192                 /**
193                  * List of all analytic events emitted so far.
194                  *
195                  * Exposed only for use by mediawiki.base.
196                  *
197                  * @private
198                  * @property {Array}
199                  */
200                 trackQueue: [],
202                 /**
203                  * Track `'resourceloader.exception'` event and send it to the window console.
204                  *
205                  * This exists for internal use by mw.loader only, to remember and buffer
206                  * very early events for `mw.trackSubscribe( 'resourceloader.exception' )`
207                  * even while `mediawiki.base` and `mw.track` are still in-flight.
208                  *
209                  * @private
210                  * @param {Object} data
211                  * @param {Error} [data.exception]
212                  * @param {string} data.source Error source
213                  * @param {string} [data.module] Name of module which caused the error
214                  */
215                 trackError: function ( data ) {
216                         if ( mw.track ) {
217                                 mw.track( 'resourceloader.exception', data );
218                         } else {
219                                 mw.trackQueue.push( { topic: 'resourceloader.exception', args: [ data ] } );
220                         }
222                         // Log an error message to window.console, even in production mode.
223                         var e = data.exception;
224                         var msg = ( e ? 'Exception' : 'Error' ) +
225                                 ' in ' + data.source +
226                                 ( data.module ? ' in module ' + data.module : '' ) +
227                                 ( e ? ':' : '.' );
229                         con.log( msg );
231                         // If we have an exception object, log it to the warning channel to trigger
232                         // proper stacktraces in browsers that support it.
233                         if ( e ) {
234                                 con.warn( e );
235                         }
236                 },
238                 // Expose mw.Map
239                 Map: Map,
241                 /**
242                  * Map of configuration values.
243                  *
244                  * Check out [the complete list of configuration values](https://www.mediawiki.org/wiki/Manual:Interface/JavaScript#mw.config)
245                  * on mediawiki.org.
246                  *
247                  * @type {mw.Map}
248                  */
249                 config: new Map(),
251                 /**
252                  * Store for messages.
253                  *
254                  * @type {mw.Map}
255                  */
256                 messages: new Map(),
258                 /**
259                  * Store for templates associated with a module.
260                  *
261                  * @type {mw.Map}
262                  */
263                 templates: new Map(),
265                 // Expose mw.log
266                 log: log
268                 // mw.loader is defined in a separate file that is appended to this
269         };
271         // Attach to window and globally alias
272         window.mw = window.mediaWiki = mw;
274         $CODE.undefineQUnit();
275 }() );