Index: branches/MwEmbedStandAloneRL1_17/MwEmbedStandAlone/includes/resourceloader/ResourceLoader.php |
— | — | @@ -29,6 +29,7 @@ |
30 | 30 | class ResourceLoader { |
31 | 31 | |
32 | 32 | /* Protected Static Members */ |
| 33 | + protected static $filterCacheVersion = 4; |
33 | 34 | |
34 | 35 | /** Array: List of module name/ResourceLoaderModule object pairs */ |
35 | 36 | protected $modules = array(); |
— | — | @@ -62,7 +63,7 @@ |
63 | 64 | // Get file dependency information |
64 | 65 | $res = $dbr->select( 'module_deps', array( 'md_module', 'md_deps' ), array( |
65 | 66 | 'md_module' => $modules, |
66 | | - 'md_skin' => $skin |
| 67 | + 'md_skin' => $context->getSkin() |
67 | 68 | ), __METHOD__ |
68 | 69 | ); |
69 | 70 | |
— | — | @@ -109,7 +110,7 @@ |
110 | 111 | * Runs JavaScript or CSS data through a filter, caching the filtered result for future calls. |
111 | 112 | * |
112 | 113 | * Available filters are: |
113 | | - * - minify-js \see JavaScriptDistiller::stripWhiteSpace |
| 114 | + * - minify-js \see JavaScriptMinifier::minify |
114 | 115 | * - minify-css \see CSSMin::minify |
115 | 116 | * |
116 | 117 | * If $data is empty, only contains whitespace or the filter was unknown, |
— | — | @@ -120,8 +121,7 @@ |
121 | 122 | * @return String: Filtered data, or a comment containing an error message |
122 | 123 | */ |
123 | 124 | protected function filter( $filter, $data ) { |
124 | | - global $wgResourceLoaderMinifyJSVerticalSpace; |
125 | | - |
| 125 | + global $wgResourceLoaderMinifierStatementsOnOwnLine, $wgResourceLoaderMinifierMaxLineLength; |
126 | 126 | wfProfileIn( __METHOD__ ); |
127 | 127 | |
128 | 128 | // For empty/whitespace-only data or for unknown filters, don't perform |
— | — | @@ -135,7 +135,7 @@ |
136 | 136 | |
137 | 137 | // Try for cache hit |
138 | 138 | // Use CACHE_ANYTHING since filtering is very slow compared to DB queries |
139 | | - $key = wfMemcKey( 'resourceloader', 'filter', $filter, md5( $data ) ); |
| 139 | + $key = wfMemcKey( 'resourceloader', 'filter', $filter, self::$filterCacheVersion, md5( $data ) ); |
140 | 140 | $cache = wfGetCache( CACHE_ANYTHING ); |
141 | 141 | $cacheEntry = $cache->get( $key ); |
142 | 142 | if ( is_string( $cacheEntry ) ) { |
— | — | @@ -143,16 +143,20 @@ |
144 | 144 | return $cacheEntry; |
145 | 145 | } |
146 | 146 | |
| 147 | + $result = ''; |
147 | 148 | // Run the filter - we've already verified one of these will work |
148 | 149 | try { |
149 | 150 | switch ( $filter ) { |
150 | 151 | case 'minify-js': |
151 | | - $result = JavaScriptDistiller::stripWhiteSpace( |
152 | | - $data, $wgResourceLoaderMinifyJSVerticalSpace |
| 152 | + $result = JavaScriptMinifier::minify( $data, |
| 153 | + $wgResourceLoaderMinifierStatementsOnOwnLine, |
| 154 | + $wgResourceLoaderMinifierMaxLineLength |
153 | 155 | ); |
| 156 | + $result .= "\n\n/* cache key: $key */\n"; |
154 | 157 | break; |
155 | 158 | case 'minify-css': |
156 | 159 | $result = CSSMin::minify( $data ); |
| 160 | + $result .= "\n\n/* cache key: $key */\n"; |
157 | 161 | break; |
158 | 162 | } |
159 | 163 | |
— | — | @@ -207,6 +211,7 @@ |
208 | 212 | foreach ( $name as $key => $value ) { |
209 | 213 | $this->register( $key, $value ); |
210 | 214 | } |
| 215 | + wfProfileOut( __METHOD__ ); |
211 | 216 | return; |
212 | 217 | } |
213 | 218 | |
— | — | @@ -252,7 +257,7 @@ |
253 | 258 | * Get the ResourceLoaderModule object for a given module name. |
254 | 259 | * |
255 | 260 | * @param $name String: Module name |
256 | | - * @return Mixed: ResourceLoaderModule if module has been registered, null otherwise |
| 261 | + * @return ResourceLoaderModule if module has been registered, null otherwise |
257 | 262 | */ |
258 | 263 | public function getModule( $name ) { |
259 | 264 | if ( !isset( $this->modules[$name] ) ) { |
— | — | @@ -287,6 +292,7 @@ |
288 | 293 | */ |
289 | 294 | public function respond( ResourceLoaderContext $context ) { |
290 | 295 | global $wgResourceLoaderMaxage, $wgCacheEpoch; |
| 296 | + |
291 | 297 | // Buffer output to catch warnings. Normally we'd use ob_clean() on the |
292 | 298 | // top-level output buffer to clear warnings, but that breaks when ob_gzhandler |
293 | 299 | // is used: ob_clean() will clear the GZIP header in that case and it won't come |
— | — | @@ -354,9 +360,9 @@ |
355 | 361 | wfProfileOut( __METHOD__.'-getModifiedTime' ); |
356 | 362 | |
357 | 363 | if ( $context->getOnly() === 'styles' ) { |
358 | | - header( 'Content-Type: text/css' ); |
| 364 | + header( 'Content-Type: text/css; charset=utf-8' ); |
359 | 365 | } else { |
360 | | - header( 'Content-Type: text/javascript' ); |
| 366 | + header( 'Content-Type: text/javascript; charset=utf-8' ); |
361 | 367 | } |
362 | 368 | header( 'Last-Modified: ' . wfTimestamp( TS_RFC2822, $mtime ) ); |
363 | 369 | if ( $context->getDebug() ) { |
— | — | @@ -378,7 +384,8 @@ |
379 | 385 | // Some clients send "timestamp;length=123". Strip the part after the first ';' |
380 | 386 | // so we get a valid timestamp. |
381 | 387 | $ims = $context->getRequest()->getHeader( 'If-Modified-Since' ); |
382 | | - if ( $ims !== false ) { |
| 388 | + // Never send 304s in debug mode |
| 389 | + if ( $ims !== false && !$context->getDebug() ) { |
383 | 390 | $imsTS = strtok( $ims, ';' ); |
384 | 391 | if ( $mtime <= wfTimestamp( TS_UNIX, $imsTS ) ) { |
385 | 392 | // There's another bug in ob_gzhandler (see also the comment at |
— | — | @@ -419,7 +426,7 @@ |
420 | 427 | |
421 | 428 | // Remove the output buffer and output the response |
422 | 429 | ob_end_clean(); |
423 | | - return $response; |
| 430 | + echo $response; |
424 | 431 | |
425 | 432 | wfProfileOut( __METHOD__ ); |
426 | 433 | } |
— | — | @@ -441,6 +448,7 @@ |
442 | 449 | return '/* No modules requested. Max made me put this here */'; |
443 | 450 | } |
444 | 451 | |
| 452 | + wfProfileIn( __METHOD__ ); |
445 | 453 | // Pre-fetch blobs |
446 | 454 | if ( $context->shouldIncludeMessages() ) { |
447 | 455 | try { |
— | — | @@ -460,7 +468,9 @@ |
461 | 469 | // Scripts |
462 | 470 | $scripts = ''; |
463 | 471 | if ( $context->shouldIncludeScripts() ) { |
464 | | - $scripts .= $module->getScript( $context ) . "\n"; |
| 472 | + // bug 27054: Append semicolon to prevent weird bugs |
| 473 | + // caused by files not terminating their statements right |
| 474 | + $scripts .= $module->getScript( $context ) . ";\n"; |
465 | 475 | } |
466 | 476 | |
467 | 477 | // Styles |
— | — | @@ -484,7 +494,7 @@ |
485 | 495 | $out .= self::makeMessageSetScript( new XmlJsCode( $messagesBlob ) ); |
486 | 496 | break; |
487 | 497 | default: |
488 | | - // Minify CSS before embedding in mediaWiki.loader.implement call |
| 498 | + // Minify CSS before embedding in mw.loader.implement call |
489 | 499 | // (unless in debug mode) |
490 | 500 | if ( !$context->getDebug() ) { |
491 | 501 | foreach ( $styles as $media => $style ) { |
— | — | @@ -521,21 +531,22 @@ |
522 | 532 | } |
523 | 533 | } |
524 | 534 | |
525 | | - if ( $context->getDebug() ) { |
526 | | - return $exceptions . $out; |
527 | | - } else { |
| 535 | + if ( !$context->getDebug() ) { |
528 | 536 | if ( $context->getOnly() === 'styles' ) { |
529 | | - return $exceptions . $this->filter( 'minify-css', $out ); |
| 537 | + $out = $this->filter( 'minify-css', $out ); |
530 | 538 | } else { |
531 | | - return $exceptions . $this->filter( 'minify-js', $out ); |
| 539 | + $out = $this->filter( 'minify-js', $out ); |
532 | 540 | } |
533 | 541 | } |
| 542 | + |
| 543 | + wfProfileOut( __METHOD__ ); |
| 544 | + return $exceptions . $out; |
534 | 545 | } |
535 | 546 | |
536 | 547 | /* Static Methods */ |
537 | 548 | |
538 | 549 | /** |
539 | | - * Returns JS code to call to mediaWiki.loader.implement for a module with |
| 550 | + * Returns JS code to call to mw.loader.implement for a module with |
540 | 551 | * given properties. |
541 | 552 | * |
542 | 553 | * @param $name Module name |
— | — | @@ -551,10 +562,10 @@ |
552 | 563 | $scripts = implode( $scripts, "\n" ); |
553 | 564 | } |
554 | 565 | return Xml::encodeJsCall( |
555 | | - 'mediaWiki.loader.implement', |
| 566 | + 'mw.loader.implement', |
556 | 567 | array( |
557 | 568 | $name, |
558 | | - new XmlJsCode( "function( $, mw ) {{$scripts}}" ), |
| 569 | + new XmlJsCode( "function( $ ) {{$scripts}}" ), |
559 | 570 | (object)$styles, |
560 | 571 | (object)$messages |
561 | 572 | ) ); |
— | — | @@ -567,7 +578,7 @@ |
568 | 579 | * JSON-encoded message blob containing the same data, wrapped in an XmlJsCode object. |
569 | 580 | */ |
570 | 581 | public static function makeMessageSetScript( $messages ) { |
571 | | - return Xml::encodeJsCall( 'mediaWiki.messages.set', array( (object)$messages ) ); |
| 582 | + return Xml::encodeJsCall( 'mw.messages.set', array( (object)$messages ) ); |
572 | 583 | } |
573 | 584 | |
574 | 585 | /** |
— | — | @@ -596,7 +607,7 @@ |
597 | 608 | } |
598 | 609 | |
599 | 610 | /** |
600 | | - * Returns a JS call to mediaWiki.loader.state, which sets the state of a |
| 611 | + * Returns a JS call to mw.loader.state, which sets the state of a |
601 | 612 | * module or modules to a given value. Has two calling conventions: |
602 | 613 | * |
603 | 614 | * - ResourceLoader::makeLoaderStateScript( $name, $state ): |
— | — | @@ -607,9 +618,9 @@ |
608 | 619 | */ |
609 | 620 | public static function makeLoaderStateScript( $name, $state = null ) { |
610 | 621 | if ( is_array( $name ) ) { |
611 | | - return Xml::encodeJsCall( 'mediaWiki.loader.state', array( $name ) ); |
| 622 | + return Xml::encodeJsCall( 'mw.loader.state', array( $name ) ); |
612 | 623 | } else { |
613 | | - return Xml::encodeJsCall( 'mediaWiki.loader.state', array( $name, $state ) ); |
| 624 | + return Xml::encodeJsCall( 'mw.loader.state', array( $name, $state ) ); |
614 | 625 | } |
615 | 626 | } |
616 | 627 | |
— | — | @@ -633,7 +644,7 @@ |
634 | 645 | } |
635 | 646 | |
636 | 647 | /** |
637 | | - * Returns JS code which calls mediaWiki.loader.register with the given |
| 648 | + * Returns JS code which calls mw.loader.register with the given |
638 | 649 | * parameters. Has three calling conventions: |
639 | 650 | * |
640 | 651 | * - ResourceLoader::makeLoaderRegisterScript( $name, $version, $dependencies, $group ): |
Index: branches/MwEmbedStandAloneRL1_17/MwEmbedStandAlone/includes/resourceloader/ResourceLoaderContext.php |
— | — | @@ -91,7 +91,8 @@ |
92 | 92 | if ( $this->direction === null ) { |
93 | 93 | $this->direction = $this->request->getVal( 'dir' ); |
94 | 94 | if ( !$this->direction ) { |
95 | | - $this->direction = Language::factory( $this->language )->getDir(); |
| 95 | + global $wgContLang; |
| 96 | + $this->direction = $wgContLang->getDir(); |
96 | 97 | } |
97 | 98 | } |
98 | 99 | return $this->direction; |
— | — | @@ -130,7 +131,7 @@ |
131 | 132 | } |
132 | 133 | |
133 | 134 | public function getHash() { |
134 | | - if ( isset( $this->hash ) ) { |
| 135 | + if ( !isset( $this->hash ) ) { |
135 | 136 | $this->hash = implode( '|', array( |
136 | 137 | $this->getLanguage(), $this->getDirection(), $this->skin, $this->user, |
137 | 138 | $this->debug, $this->only, $this->version |
Index: branches/MwEmbedStandAloneRL1_17/MwEmbedStandAlone/includes/resourceloader/ResourceLoaderFileModule.php |
— | — | @@ -102,8 +102,9 @@ |
103 | 103 | * to $IP |
104 | 104 | * @param $remoteBasePath String: Base path to prepend to all remote paths in $options. Defaults |
105 | 105 | * to $wgScriptPath |
106 | | - * |
107 | | - * @example $options |
| 106 | + * |
| 107 | + * Below is a description for the $options array: |
| 108 | + * @code |
108 | 109 | * array( |
109 | 110 | * // Base path to prepend to all local paths in $options. Defaults to $IP |
110 | 111 | * 'localBasePath' => [base path], |
— | — | @@ -138,6 +139,7 @@ |
139 | 140 | * // Group which this module should be loaded together with |
140 | 141 | * 'group' => [group name string], |
141 | 142 | * ) |
| 143 | + * @endcode |
142 | 144 | */ |
143 | 145 | public function __construct( $options = array(), $localBasePath = null, |
144 | 146 | $remoteBasePath = null ) |
— | — | @@ -197,6 +199,8 @@ |
198 | 200 | break; |
199 | 201 | } |
200 | 202 | } |
| 203 | + // Make sure the remote base path is a complete valid url |
| 204 | + $this->remoteBasePath = wfExpandUrl( $this->remoteBasePath ); |
201 | 205 | } |
202 | 206 | |
203 | 207 | /** |
— | — | @@ -206,7 +210,6 @@ |
207 | 211 | * @return String: JavaScript code for $context |
208 | 212 | */ |
209 | 213 | public function getScript( ResourceLoaderContext $context ) { |
210 | | - global $wgServer; |
211 | 214 | $files = array_merge( |
212 | 215 | $this->scripts, |
213 | 216 | self::tryForKey( $this->languageScripts, $context->getLanguage() ), |
— | — | @@ -215,10 +218,10 @@ |
216 | 219 | if ( $context->getDebug() ) { |
217 | 220 | $files = array_merge( $files, $this->debugScripts ); |
218 | 221 | if ( $this->debugRaw ) { |
219 | | - $script = ''; |
| 222 | + $script = ''; |
220 | 223 | foreach ( $files as $file ) { |
221 | 224 | $path = $this->getRemotePath( $file ); |
222 | | - $script .= "\n\t" . Xml::encodeJsCall( 'mediaWiki.loader.load', array( $path ) ); |
| 225 | + $script .= "\n\t" . Xml::encodeJsCall( 'mw.loader.load', array( $path ) ); |
223 | 226 | } |
224 | 227 | return $script; |
225 | 228 | } |
— | — | @@ -354,6 +357,7 @@ |
355 | 358 | // If a module is nothing but a list of dependencies, we need to avoid |
356 | 359 | // giving max() an empty array |
357 | 360 | if ( count( $files ) === 0 ) { |
| 361 | + wfProfileOut( __METHOD__ ); |
358 | 362 | return $this->modifiedTime[$context->getHash()] = 1; |
359 | 363 | } |
360 | 364 | |
— | — | @@ -363,6 +367,7 @@ |
364 | 368 | $this->modifiedTime[$context->getHash()] = max( |
365 | 369 | $filesMtime, |
366 | 370 | $this->getMsgBlobMtime( $context->getLanguage() ) ); |
| 371 | + |
367 | 372 | wfProfileOut( __METHOD__ ); |
368 | 373 | return $this->modifiedTime[$context->getHash()]; |
369 | 374 | } |
— | — | @@ -508,4 +513,13 @@ |
509 | 514 | $style, $dir, $remoteDir, true |
510 | 515 | ); |
511 | 516 | } |
| 517 | + |
| 518 | + /** |
| 519 | + * Get whether CSS for this module should be flipped |
| 520 | + * @param $context ResourceLoaderContext |
| 521 | + * @return bool |
| 522 | + */ |
| 523 | + public function getFlip( $context ) { |
| 524 | + return $context->getDirection() === 'rtl'; |
| 525 | + } |
512 | 526 | } |
Index: branches/MwEmbedStandAloneRL1_17/MwEmbedStandAlone/includes/resourceloader/ResourceLoaderModule.php |
— | — | @@ -24,6 +24,34 @@ |
25 | 25 | * Abstraction for resource loader modules, with name registration and maxage functionality. |
26 | 26 | */ |
27 | 27 | abstract class ResourceLoaderModule { |
| 28 | + |
| 29 | + # Type of resource |
| 30 | + const TYPE_SCRIPTS = 'scripts'; |
| 31 | + const TYPE_STYLES = 'styles'; |
| 32 | + const TYPE_MESSAGES = 'messages'; |
| 33 | + const TYPE_COMBINED = 'combined'; |
| 34 | + |
| 35 | + # sitewide core module like a skin file or jQuery component |
| 36 | + const ORIGIN_CORE_SITEWIDE = 1; |
| 37 | + |
| 38 | + # per-user module generated by the software |
| 39 | + const ORIGIN_CORE_INDIVIDUAL = 2; |
| 40 | + |
| 41 | + # sitewide module generated from user-editable files, like MediaWiki:Common.js, or |
| 42 | + # modules accessible to multiple users, such as those generated by the Gadgets extension. |
| 43 | + const ORIGIN_USER_SITEWIDE = 3; |
| 44 | + |
| 45 | + # per-user module generated from user-editable files, like User:Me/vector.js |
| 46 | + const ORIGIN_USER_INDIVIDUAL = 4; |
| 47 | + |
| 48 | + # an access constant; make sure this is kept as the largest number in this group |
| 49 | + const ORIGIN_ALL = 10; |
| 50 | + |
| 51 | + # script and style modules form a hierarchy of trustworthiness, with core modules like |
| 52 | + # skins and jQuery as most trustworthy, and user scripts as least trustworthy. We can |
| 53 | + # limit the types of scripts and styles we allow to load on, say, sensitive special |
| 54 | + # pages like Special:UserLogin and Special:Preferences |
| 55 | + protected $origin = self::ORIGIN_CORE_SITEWIDE; |
28 | 56 | |
29 | 57 | /* Protected Members */ |
30 | 58 | |
— | — | @@ -57,11 +85,34 @@ |
58 | 86 | } |
59 | 87 | |
60 | 88 | /** |
61 | | - * Get whether CSS for this module should be flipped |
| 89 | + * Get this module's origin. This is set when the module is registered |
| 90 | + * with ResourceLoader::register() |
| 91 | + * |
| 92 | + * @return Int ResourceLoaderModule class constant, the subclass default |
| 93 | + * if not set manuall |
| 94 | + */ |
| 95 | + public function getOrigin() { |
| 96 | + return $this->origin; |
| 97 | + } |
| 98 | + |
| 99 | + /** |
| 100 | + * Set this module's origin. This is called by ResourceLodaer::register() |
| 101 | + * when registering the module. Other code should not call this. |
| 102 | + * |
| 103 | + * @param $name Int origin |
| 104 | + */ |
| 105 | + public function setOrigin( $origin ) { |
| 106 | + $this->origin = $origin; |
| 107 | + } |
| 108 | + |
| 109 | + /** |
62 | 110 | * @param $context ResourceLoaderContext |
| 111 | + * @return bool |
63 | 112 | */ |
64 | 113 | public function getFlip( $context ) { |
65 | | - return $context->getDirection() === 'rtl'; |
| 114 | + global $wgContLang; |
| 115 | + |
| 116 | + return $wgContLang->getDir() !== $context->getDirection(); |
66 | 117 | } |
67 | 118 | |
68 | 119 | /** |
— | — | @@ -84,7 +135,7 @@ |
85 | 136 | */ |
86 | 137 | public function getStyles( ResourceLoaderContext $context ) { |
87 | 138 | // Stub, override expected |
88 | | - return ''; |
| 139 | + return array(); |
89 | 140 | } |
90 | 141 | |
91 | 142 | /** |
— | — | @@ -180,7 +231,7 @@ |
181 | 232 | * Get the last modification timestamp of the message blob for this |
182 | 233 | * module in a given language. |
183 | 234 | * @param $lang String: Language code |
184 | | - * @return Integer: UNIX timestamp, or 0 if no blob found |
| 235 | + * @return Integer: UNIX timestamp, or 0 if the module doesn't have messages |
185 | 236 | */ |
186 | 237 | public function getMsgBlobMtime( $lang ) { |
187 | 238 | if ( !isset( $this->msgBlobMtime[$lang] ) ) { |
— | — | @@ -193,7 +244,12 @@ |
194 | 245 | 'mr_lang' => $lang |
195 | 246 | ), __METHOD__ |
196 | 247 | ); |
197 | | - $this->msgBlobMtime[$lang] = $msgBlobMtime ? wfTimestamp( TS_UNIX, $msgBlobMtime ) : 0; |
| 248 | + // If no blob was found, but the module does have messages, that means we need |
| 249 | + // to regenerate it. Return NOW |
| 250 | + if ( $msgBlobMtime === false ) { |
| 251 | + $msgBlobMtime = wfTimestampNow(); |
| 252 | + } |
| 253 | + $this->msgBlobMtime[$lang] = wfTimestamp( TS_UNIX, $msgBlobMtime ); |
198 | 254 | } |
199 | 255 | return $this->msgBlobMtime[$lang]; |
200 | 256 | } |
— | — | @@ -224,4 +280,17 @@ |
225 | 281 | // 0 would mean now |
226 | 282 | return 1; |
227 | 283 | } |
| 284 | + |
| 285 | + /** |
| 286 | + * Check whether this module is known to be empty. If a child class |
| 287 | + * has an easy and cheap way to determine that this module is |
| 288 | + * definitely going to be empty, it should override this method to |
| 289 | + * return true in that case. Callers may optimize the request for this |
| 290 | + * module away if this function returns true. |
| 291 | + * @param $context ResourceLoaderContext: Context object |
| 292 | + * @return Boolean |
| 293 | + */ |
| 294 | + public function isKnownEmpty( ResourceLoaderContext $context ) { |
| 295 | + return false; |
| 296 | + } |
228 | 297 | } |
Index: branches/MwEmbedStandAloneRL1_17/MwEmbedStandAlone/includes/resourceloader/README |
— | — | @@ -0,0 +1,3 @@ |
| 2 | + |
| 3 | +These resource loader files should support being copied directly from MediaWiki trunk without modification, |
| 4 | +this enables us to stay in-sync with resource loader updates. |
\ No newline at end of file |
Index: branches/MwEmbedStandAloneRL1_17/MwEmbedStandAlone/includes/resourceloader/ResourceLoaderStartUpModule.php |
— | — | @@ -27,13 +27,17 @@ |
28 | 28 | protected $modifiedTime = array(); |
29 | 29 | |
30 | 30 | /* Protected Methods */ |
31 | | - |
| 31 | + |
| 32 | + /** |
| 33 | + * @param $context ResourceLoaderContext |
| 34 | + * @return array |
| 35 | + */ |
32 | 36 | protected function getConfig( $context ) { |
33 | 37 | global $wgLoadScript, $wgScript, $wgStylePath, $wgScriptExtension, |
34 | 38 | $wgArticlePath, $wgScriptPath, $wgServer, $wgContLang, |
35 | 39 | $wgVariantArticlePath, $wgActionPaths, $wgUseAjax, $wgVersion, |
36 | 40 | $wgEnableAPI, $wgEnableWriteAPI, $wgDBname, $wgEnableMWSuggest, |
37 | | - $wgSitename, $wgFileExtensions; |
| 41 | + $wgSitename, $wgFileExtensions, $wgExtensionAssetsPath, $wgProto; |
38 | 42 | |
39 | 43 | // Pre-process information |
40 | 44 | $separatorTransTable = $wgContLang->separatorTransformTable(); |
— | — | @@ -75,12 +79,15 @@ |
76 | 80 | 'wgFormattedNamespaces' => $wgContLang->getFormattedNamespaces(), |
77 | 81 | 'wgNamespaceIds' => $wgContLang->getNamespaceIds(), |
78 | 82 | 'wgSiteName' => $wgSitename, |
79 | | - 'wgFileExtensions' => $wgFileExtensions, |
| 83 | + 'wgFileExtensions' => array_values( $wgFileExtensions ), |
80 | 84 | 'wgDBname' => $wgDBname, |
| 85 | + // This sucks, it is only needed on Special:Upload, but I could |
| 86 | + // not find a way to add vars only for a certain module |
| 87 | + 'wgFileCanRotate' => BitmapHandler::canRotate(), |
| 88 | + 'wgAvailableSkins' => Skin::getSkinNames(), |
| 89 | + 'wgExtensionAssetsPath' => $wgExtensionAssetsPath, |
| 90 | + 'wgProto' => $wgProto, |
81 | 91 | ); |
82 | | - if ( $wgContLang->hasVariants() ) { |
83 | | - $vars['wgUserVariant'] = $wgContLang->getPreferredVariant(); |
84 | | - } |
85 | 92 | if ( $wgUseAjax && $wgEnableMWSuggest ) { |
86 | 93 | $vars['wgMWSuggestTemplate'] = SearchEngine::getMWSuggestTemplate(); |
87 | 94 | } |
— | — | @@ -111,25 +118,28 @@ |
112 | 119 | $deps = $module->getDependencies(); |
113 | 120 | $group = $module->getGroup(); |
114 | 121 | $version = wfTimestamp( TS_ISO_8601_BASIC, |
115 | | - round( $module->getModifiedTime( $context ), -2 ) ); |
| 122 | + $module->getModifiedTime( $context ) ); |
116 | 123 | $out .= ResourceLoader::makeCustomLoaderScript( $name, $version, $deps, $group, $loader ); |
117 | 124 | } |
118 | 125 | // Automatically register module |
119 | 126 | else { |
120 | | - $mtime = max( $module->getModifiedTime( $context ), wfTimestamp( TS_UNIX, $wgCacheEpoch ) ); |
| 127 | + // getModifiedTime() is supposed to return a UNIX timestamp, but it doesn't always |
| 128 | + // seem to do that, and custom implementations might forget. Coerce it to TS_UNIX |
| 129 | + $moduleMtime = wfTimestamp( TS_UNIX, $module->getModifiedTime( $context ) ); |
| 130 | + $mtime = max( $moduleMtime, wfTimestamp( TS_UNIX, $wgCacheEpoch ) ); |
121 | 131 | // Modules without dependencies or a group pass two arguments (name, timestamp) to |
122 | | - // mediaWiki.loader.register() |
| 132 | + // mw.loader.register() |
123 | 133 | if ( !count( $module->getDependencies() && $module->getGroup() === null ) ) { |
124 | 134 | $registrations[] = array( $name, $mtime ); |
125 | 135 | } |
126 | 136 | // Modules with dependencies but no group pass three arguments |
127 | | - // (name, timestamp, dependencies) to mediaWiki.loader.register() |
| 137 | + // (name, timestamp, dependencies) to mw.loader.register() |
128 | 138 | else if ( $module->getGroup() === null ) { |
129 | 139 | $registrations[] = array( |
130 | 140 | $name, $mtime, $module->getDependencies() ); |
131 | 141 | } |
132 | 142 | // Modules with dependencies pass four arguments (name, timestamp, dependencies, group) |
133 | | - // to mediaWiki.loader.register() |
| 143 | + // to mw.loader.register() |
134 | 144 | else { |
135 | 145 | $registrations[] = array( |
136 | 146 | $name, $mtime, $module->getDependencies(), $module->getGroup() ); |
— | — | @@ -146,17 +156,21 @@ |
147 | 157 | |
148 | 158 | public function getScript( ResourceLoaderContext $context ) { |
149 | 159 | global $IP, $wgLoadScript; |
| 160 | + |
150 | 161 | $out = file_get_contents( "$IP/resources/startup.js" ); |
151 | 162 | if ( $context->getOnly() === 'scripts' ) { |
152 | | - // Get the latest version |
153 | | - $version = 0; |
154 | | - |
| 163 | + |
| 164 | + // The core modules: |
155 | 165 | $modules = array( 'jquery', 'mediawiki' ); |
156 | 166 | wfRunHooks( 'ResourceLoaderGetStartupModules', array( &$modules ) ); |
157 | | - |
158 | | - foreach( $modules as $moduleName){ |
159 | | - $version = max( $version, $context->getResourceLoader()->getModule( $moduleName )->getModifiedTime( $context ) ); |
160 | | - } |
| 167 | + |
| 168 | + // Get the latest version |
| 169 | + $version = 0; |
| 170 | + foreach ( $modules as $moduleName ) { |
| 171 | + $version = max( $version, |
| 172 | + $context->getResourceLoader()->getModule( $moduleName )->getModifiedTime( $context ) |
| 173 | + ); |
| 174 | + } |
161 | 175 | // Build load query for StartupModules |
162 | 176 | $query = array( |
163 | 177 | 'modules' => implode( '|', $modules ), |
— | — | @@ -164,7 +178,7 @@ |
165 | 179 | 'lang' => $context->getLanguage(), |
166 | 180 | 'skin' => $context->getSkin(), |
167 | 181 | 'debug' => $context->getDebug() ? 'true' : 'false', |
168 | | - 'version' => wfTimestamp( TS_ISO_8601_BASIC, round( $version, -2 ) ) |
| 182 | + 'version' => wfTimestamp( TS_ISO_8601_BASIC, $version ) |
169 | 183 | ); |
170 | 184 | // Ensure uniform query order |
171 | 185 | ksort( $query ); |
— | — | @@ -172,20 +186,22 @@ |
173 | 187 | // Startup function |
174 | 188 | $configuration = $this->getConfig( $context ); |
175 | 189 | $registrations = self::getModuleRegistrations( $context ); |
176 | | - $out .= "var mwStartUp = function() {\n" . |
177 | | - "\t" . Xml::encodeJsCall( 'mediaWiki.config.set', array( $configuration ) ) . |
| 190 | + $out .= "var startUp = function() {\n" . |
178 | 191 | "\t$registrations\n" . |
| 192 | + "\t" . Xml::encodeJsCall( 'mediaWiki.config.set', array( $configuration ) ) . |
179 | 193 | "};\n"; |
180 | 194 | |
181 | 195 | // Conditional script injection |
182 | 196 | $scriptTag = Html::linkedScript( $wgLoadScript . '?' . wfArrayToCGI( $query ) ); |
183 | | - $out .= "if ( mwIsCompatible() ) {\n" . |
| 197 | + $out .= "if ( isCompatible() ) {\n" . |
184 | 198 | "\t" . Xml::encodeJsCall( 'document.write', array( $scriptTag ) ) . |
185 | 199 | "}\n" . |
186 | | - "delete mwIsCompatible;"; |
| 200 | + "delete isCompatible;"; |
187 | 201 | } |
| 202 | + |
188 | 203 | return $out; |
189 | 204 | } |
| 205 | + |
190 | 206 | public function getModifiedTime( ResourceLoaderContext $context ) { |
191 | 207 | global $IP, $wgCacheEpoch; |
192 | 208 | |
— | — | @@ -210,12 +226,6 @@ |
211 | 227 | } |
212 | 228 | return $this->modifiedTime[$hash] = $time; |
213 | 229 | } |
214 | | - |
215 | | - public function getFlip( $context ) { |
216 | | - global $wgContLang; |
217 | | - |
218 | | - return $wgContLang->getDir() !== $context->getDirection(); |
219 | | - } |
220 | 230 | |
221 | 231 | /* Methods */ |
222 | 232 | |