Localisation updates from https://translatewiki.net.
[mediawiki.git] / resources / src / startup / startup.js
blob303f7f52150cdc6a693a7e6c9c8b8602907a7e43
1 /**
2  * This file is where we decide whether to initialise the modern support browser run-time.
3  *
4  * - Beware: This file MUST parse without errors on even the most ancient of browsers!
5  */
6 /* eslint-disable no-implicit-globals */
7 /* global $CODE, RLQ:true, NORLQ:true */
9 /**
10  * See <https://www.mediawiki.org/wiki/Compatibility#Browsers>
11  *
12  * Browsers that pass these checks get served our modern run-time. This includes all Grade A
13  * browsers, and some Grade C and Grade X browsers.
14  *
15  * The following browsers are known to pass these checks:
16  * - Chrome 63+
17  * - Edge 79+
18  * - Opera 50+
19  * - Firefox 58+
20  * - Safari 11.1+
21  * - Mobile Safari 11.2+ (iOS 11+)
22  * - Android 5.0+
23  *
24  * @private
25  * @return {boolean} User agent is compatible with MediaWiki JS
26  */
27 function isCompatible() {
28         return !!(
29                 // Ensure DOM Level 4 features (including Selectors API).
30                 //
31                 // https://caniuse.com/#feat=queryselector
32                 'querySelector' in document &&
34                 // Ensure HTML 5 features (including Web Storage API)
35                 //
36                 // https://caniuse.com/#feat=namevalue-storage
37                 // https://blog.whatwg.org/this-week-in-html-5-episode-30
38                 'localStorage' in window &&
40                 // Ensure ES2015 grammar and runtime API (a.k.a. ES6)
41                 //
42                 // In practice, Promise.finally is a good proxy for overall ES6 support and
43                 // rejects most unsupporting browsers in one sweep. The feature itself
44                 // was specified in ES2018, however.
45                 // https://caniuse.com/promise-finally
46                 // Chrome 63+, Edge 18+, Opera 50+, Safari 11.1+, Firefox 58+, iOS 11+
47                 //
48                 // eslint-disable-next-line es-x/no-promise, es-x/no-promise-prototype-finally, dot-notation
49                 typeof Promise === 'function' && Promise.prototype[ 'finally' ] &&
50                 // ES6 Arrow Functions (with default params), this ensures
51                 // genuine syntax support for ES6 grammar, not just API coverage.
52                 //
53                 // https://caniuse.com/arrow-functions
54                 // Chrome 45+, Safari 10+, Firefox 22+, Opera 32+
55                 //
56                 // Based on Benjamin De Cock's snippet here:
57                 // https://gist.github.com/bendc/d7f3dbc83d0f65ca0433caf90378cd95
58                 ( function () {
59                         try {
60                                 // eslint-disable-next-line no-new, no-new-func
61                                 new Function( '(a = 0) => a' );
62                                 return true;
63                         } catch ( e ) {
64                                 return false;
65                         }
66                 }() ) &&
67                 // ES6 RegExp.prototype.flags
68                 //
69                 // https://caniuse.com/mdn-javascript_builtins_regexp_flags
70                 // Edge 79+ (Chromium-based, rejects MSEdgeHTML-based Edge <= 18)
71                 //
72                 // eslint-disable-next-line es-x/no-regexp-prototype-flags
73                 /./g.flags === 'g'
74         );
77 if ( !isCompatible() ) {
78         // Handle basic supported browsers (Grade C).
79         // Undo speculative modern (Grade A) root CSS class `<html class="client-js">`.
80         // See ResourceLoaderClientHtml::getDocumentAttributes().
81         document.documentElement.className = document.documentElement.className
82                 .replace( /(^|\s)client-js(\s|$)/, '$1client-nojs$2' );
84         // Process any callbacks for basic support (Grade C).
85         while ( window.NORLQ && NORLQ[ 0 ] ) {
86                 NORLQ.shift()();
87         }
88         NORLQ = {
89                 push: function ( fn ) {
90                         fn();
91                 }
92         };
94         // Clear and disable the modern (Grade A) queue.
95         RLQ = {
96                 push: function () {}
97         };
98 } else {
99         // Handle modern (Grade A).
101         if ( window.performance && performance.mark ) {
102                 performance.mark( 'mwStartup' );
103         }
105         // This embeds mediawiki.js, which defines 'mw' and 'mw.loader'.
106         $CODE.defineLoader();
108         /**
109          * The $CODE placeholder is substituted in ResourceLoaderStartUpModule.php.
110          */
111         ( function () {
112                 /* global mw */
113                 var queue;
115                 $CODE.registrations();
117                 // First set page-specific config needed by mw.loader (wgUserName)
118                 mw.config.set( window.RLCONF || {} );
119                 mw.loader.state( window.RLSTATE || {} );
120                 mw.loader.load( window.RLPAGEMODULES || [] );
122                 // Process RLQ callbacks
123                 //
124                 // The code in these callbacks could've been exposed from load.php and
125                 // requested client-side. Instead, they are pushed by the server directly
126                 // (from ResourceLoaderClientHtml and other parts of MediaWiki). This
127                 // saves the need for additional round trips. It also allows load.php
128                 // to remain stateless and sending personal data in the HTML instead.
129                 //
130                 // The HTML inline script lazy-defines the 'RLQ' array. Now that we are
131                 // processing it, replace it with an implementation where 'push' actually
132                 // considers executing the code directly. This is to ensure any late
133                 // arrivals will also be processed. Late arrival can happen because
134                 // startup.js is executed asynchronously, concurrently with the streaming
135                 // response of the HTML.
136                 queue = window.RLQ || [];
137                 // Replace RLQ with an empty array, then process the things that were
138                 // in RLQ previously. We have to do this to avoid an infinite loop:
139                 // non-function items are added back to RLQ by the processing step.
140                 RLQ = [];
141                 RLQ.push = function ( fn ) {
142                         if ( typeof fn === 'function' ) {
143                                 fn();
144                         } else {
145                                 // If the first parameter is not a function, then it is an array
146                                 // containing a list of required module names and a function.
147                                 // Do an actual push for now, as this signature is handled
148                                 // later by mediawiki.base.js.
149                                 RLQ[ RLQ.length ] = fn;
150                         }
151                 };
152                 while ( queue[ 0 ] ) {
153                         // Process all values gathered so far
154                         RLQ.push( queue.shift() );
155                 }
157                 // Clear and disable the basic (Grade C) queue.
158                 NORLQ = {
159                         push: function () {}
160                 };
161         }() );