Index: branches/resourceloader/phase3/includes/ResourceLoaderContext.php |
— | — | @@ -26,18 +26,35 @@ |
27 | 27 | |
28 | 28 | protected $request; |
29 | 29 | protected $server; |
30 | | - protected $lang; |
| 30 | + protected $modules; |
| 31 | + protected $language; |
| 32 | + protected $direction; |
31 | 33 | protected $skin; |
32 | 34 | protected $debug; |
33 | 35 | protected $only; |
34 | 36 | |
35 | | - public function __construct( WebRequest $request, $server, $lang, $skin, $debug, $only ) { |
| 37 | + public function __construct( WebRequest $request, $server ) { |
| 38 | + global $wgUser, $wgLang, $wgDefaultSkin; |
| 39 | + |
36 | 40 | $this->request = $request; |
37 | 41 | $this->server = $server; |
38 | | - $this->lang = $lang; |
39 | | - $this->skin = $skin; |
40 | | - $this->debug = $debug; |
41 | | - $this->only = $only; |
| 42 | + // Interperet request |
| 43 | + $this->modules = explode( '|', $request->getVal( 'modules' ) ); |
| 44 | + $this->language = $request->getVal( 'lang' ); |
| 45 | + $this->direction = $request->getVal( 'dir' ); |
| 46 | + $this->skin = $request->getVal( 'skin' ); |
| 47 | + $this->debug = $request->getVal( 'debug' ) === 'true' || $request->getBool( 'debug' ); |
| 48 | + $this->only = $request->getVal( 'only' ); |
| 49 | + // Fallback on system defaults |
| 50 | + if ( !$this->language ) { |
| 51 | + $this->language = $wgLang->getCode(); |
| 52 | + } |
| 53 | + if ( !$this->direction ) { |
| 54 | + $this->direction = Language::factory( $this->language )->getDir(); |
| 55 | + } |
| 56 | + if ( !$this->skin ) { |
| 57 | + $this->skin = $wgDefaultSkin; |
| 58 | + } |
42 | 59 | } |
43 | 60 | public function getRequest() { |
44 | 61 | return $this->request; |
— | — | @@ -45,11 +62,17 @@ |
46 | 63 | public function getServer() { |
47 | 64 | return $this->server; |
48 | 65 | } |
| 66 | + public function getModules() { |
| 67 | + return $this->modules; |
| 68 | + } |
49 | 69 | public function getLanguage() { |
50 | | - return $this->lang; |
| 70 | + return $this->language; |
51 | 71 | } |
| 72 | + public function getDirection() { |
| 73 | + return $this->direction; |
| 74 | + } |
52 | 75 | public function getSkin() { |
53 | | - return $this->request; |
| 76 | + return $this->skin; |
54 | 77 | } |
55 | 78 | public function getDebug() { |
56 | 79 | return $this->debug; |
— | — | @@ -57,4 +80,13 @@ |
58 | 81 | public function getOnly() { |
59 | 82 | return $this->only; |
60 | 83 | } |
| 84 | + public function shouldIncludeScripts() { |
| 85 | + return !isset( $this->only ) || $this->only === 'scripts'; |
| 86 | + } |
| 87 | + public function shouldIncludeStyles() { |
| 88 | + return !isset( $this->only ) || $this->only === 'styles'; |
| 89 | + } |
| 90 | + public function shouldIncludeMessages() { |
| 91 | + return !isset( $this->only ) || $this->only === 'messages'; |
| 92 | + } |
61 | 93 | } |
\ No newline at end of file |
Index: branches/resourceloader/phase3/includes/ResourceLoader.php |
— | — | @@ -179,7 +179,7 @@ |
180 | 180 | * @param $debug bool Debug mode flag |
181 | 181 | * @return {string} JavaScript code for registering all modules with the client loader |
182 | 182 | */ |
183 | | - public static function getModuleRegistrations( $lang, $skin, $debug ) { |
| 183 | + public static function getModuleRegistrations( ResourceLoaderContext $context ) { |
184 | 184 | $scripts = ''; |
185 | 185 | $registrations = array(); |
186 | 186 | foreach ( self::$modules as $name => $module ) { |
— | — | @@ -191,12 +191,11 @@ |
192 | 192 | else { |
193 | 193 | // Modules without dependencies pass two arguments (name, timestamp) to mediaWiki.loader.register() |
194 | 194 | if ( !count( $module->getDependencies() ) ) { |
195 | | - $registrations[] = array( $name, $module->getModifiedTime( $lang, $skin, $debug ) ); |
| 195 | + $registrations[] = array( $name, $module->getModifiedTime( $context ) ); |
196 | 196 | } |
197 | 197 | // Modules with dependencies pass three arguments (name, timestamp, dependencies) to mediaWiki.loader.register() |
198 | 198 | else { |
199 | | - $registrations[] = array( $name, $module->getModifiedTime( $lang, $skin, $debug ), |
200 | | - $module->getDependencies() ); |
| 199 | + $registrations[] = array( $name, $module->getModifiedTime( $context ), $module->getDependencies() ); |
201 | 200 | } |
202 | 201 | } |
203 | 202 | } |
— | — | @@ -211,12 +210,12 @@ |
212 | 211 | * @param $debug bool Debug mode flag |
213 | 212 | * @return int UNIX timestamp |
214 | 213 | */ |
215 | | - public static function getHighestModifiedTime( $lang, $skin, $debug ) { |
216 | | - $retval = 1; // wfTimestamp() treats 0 as 'now', so that's not a suitable choice |
| 214 | + public static function getHighestModifiedTime( ResourceLoaderContext $context ) { |
| 215 | + $time = 1; // wfTimestamp() treats 0 as 'now', so that's not a suitable choice |
217 | 216 | foreach ( self::$modules as $module ) { |
218 | | - $retval = max( $retval, $module->getModifiedTime( $lang, $skin, $debug ) ); |
| 217 | + $time = max( $time, $module->getModifiedTime( $context ) ); |
219 | 218 | } |
220 | | - return $retval; |
| 219 | + return $time; |
221 | 220 | } |
222 | 221 | |
223 | 222 | /* |
— | — | @@ -234,47 +233,11 @@ |
235 | 234 | * 'only' => [string: 'scripts', 'styles' or 'messages', optional, if set only get part of the requested module] |
236 | 235 | * ) |
237 | 236 | */ |
238 | | - public static function respond( WebRequest $request, $server ) { |
239 | | - global $wgUser, $wgLang, $wgDefaultSkin; |
240 | | - // Fallback on system settings |
241 | | - // FIXME: Unnecessary unstubbing going on here, work around that |
242 | | - $parameters = array( |
243 | | - 'lang' => $request->getVal( 'lang', $wgLang->getCode() ), |
244 | | - 'skin' => $request->getVal( 'skin', $wgDefaultSkin ), |
245 | | - 'debug' => $request->getVal( 'debug' ), |
246 | | - 'only' => $request->getVal( 'only' ), |
247 | | - ); |
248 | | - // Mediawiki's WebRequest::getBool is a bit on the annoying side - we need to allow 'true' and 'false' values |
249 | | - // to be converted to boolean true and false |
250 | | - $parameters['debug'] = $parameters['debug'] === 'true' || $parameters['debug']; |
251 | | - // Get the direction from the requested language |
252 | | - if ( !isset( $parameters['dir'] ) ) { |
253 | | - $lang = Language::factory( $parameters['lang'] ); |
254 | | - $parameters['dir'] = $lang->getDir(); |
255 | | - } |
256 | | - $includeScripts = false; |
257 | | - $includeStyles = false; |
258 | | - $includeMessages = false; |
259 | | - switch ( $parameters['only'] ) { |
260 | | - case 'scripts': |
261 | | - $includeScripts = true; |
262 | | - break; |
263 | | - case 'styles': |
264 | | - $includeStyles = true; |
265 | | - break; |
266 | | - case 'messages': |
267 | | - $includeMessages = true; |
268 | | - break; |
269 | | - default: |
270 | | - $includeScripts = true; |
271 | | - $includeStyles = true; |
272 | | - $includeMessages = true; |
273 | | - } |
274 | | - |
275 | | - // Build a list of requested modules excluding unrecognized ones |
| 237 | + public static function respond( ResourceLoaderContext $context ) { |
| 238 | + // Split requested modules into two groups, modules and missing |
276 | 239 | $modules = array(); |
277 | 240 | $missing = array(); |
278 | | - foreach ( explode( '|', $request->getVal( 'modules' ) ) as $name ) { |
| 241 | + foreach ( $context->getModules() as $name ) { |
279 | 242 | if ( isset( self::$modules[$name] ) ) { |
280 | 243 | $modules[] = $name; |
281 | 244 | } else { |
— | — | @@ -287,12 +250,9 @@ |
288 | 251 | $maxage = PHP_INT_MAX; |
289 | 252 | $smaxage = PHP_INT_MAX; |
290 | 253 | foreach ( $modules as $name ) { |
291 | | - $module = self::getModule( $name ); |
292 | | - $mtime = max( $mtime, $module->getModifiedTime( |
293 | | - $parameters['lang'], $parameters['skin'], $parameters['debug'] |
294 | | - ) ); |
295 | | - $maxage = min( $maxage, $module->getClientMaxage() ); |
296 | | - $smaxage = min( $smaxage, $module->getServerMaxage() ); |
| 254 | + $mtime = max( $mtime, self::$modules[$name]->getModifiedTime( $context ) ); |
| 255 | + $maxage = min( $maxage, self::$modules[$name]->getClientMaxage() ); |
| 256 | + $smaxage = min( $smaxage, self::$modules[$name]->getServerMaxage() ); |
297 | 257 | } |
298 | 258 | header( 'Last-Modified: ' . wfTimestamp( TS_RFC2822, $mtime ) ); |
299 | 259 | $expires = wfTimestamp( TS_RFC2822, min( $maxage, $smaxage ) + time() ); |
— | — | @@ -300,7 +260,7 @@ |
301 | 261 | header( "Expires: $expires" ); |
302 | 262 | |
303 | 263 | // Check if there's an If-Modified-Since header and respond with a 304 Not Modified if possible |
304 | | - $ims = $request->getHeader( 'If-Modified-Since' ); |
| 264 | + $ims = $context->getRequest()->getHeader( 'If-Modified-Since' ); |
305 | 265 | if ( $ims !== false && wfTimestamp( TS_UNIX, $ims ) == $mtime ) { |
306 | 266 | header( 'HTTP/1.0 304 Not Modified' ); |
307 | 267 | header( 'Status: 304 Not Modified' ); |
— | — | @@ -309,68 +269,69 @@ |
310 | 270 | |
311 | 271 | // Use output buffering |
312 | 272 | ob_start(); |
313 | | - $blobs = $includeMessages ? MessageBlobStore::get( $modules, $parameters['lang'] ) : array(); |
314 | 273 | |
| 274 | + // Pre-fetch blobs |
| 275 | + $blobs = $context->shouldIncludeMessages() ? |
| 276 | + MessageBlobStore::get( $modules, $context->getLanguage() ) : array(); |
| 277 | + |
315 | 278 | // Generate output |
316 | 279 | foreach ( $modules as $name ) { |
317 | 280 | // Scripts |
318 | 281 | $scripts = ''; |
319 | | - if ( $includeScripts ) { |
320 | | - $scripts .= self::$modules[$name]->getScript( |
321 | | - $parameters['lang'], $parameters['skin'], $parameters['debug'] |
322 | | - ); |
| 282 | + if ( $context->shouldIncludeScripts() ) { |
| 283 | + $scripts .= self::$modules[$name]->getScript( $context ); |
323 | 284 | // Special meta-information for the 'startup' module |
324 | | - if ( $name === 'startup' && $parameters['only'] === 'scripts' ) { |
| 285 | + if ( $name === 'startup' && $context->getOnly() === 'scripts' ) { |
325 | 286 | // Get all module registrations |
326 | | - $registration = self::getModuleRegistrations( |
327 | | - $parameters['lang'], $parameters['skin'], $parameters['debug'] |
328 | | - ); |
| 287 | + $registration = self::getModuleRegistrations( $context ); |
329 | 288 | // Build configuration |
330 | | - $config = FormatJson::encode( array( 'server' => $server, 'debug' => $parameters['debug'] ) ); |
| 289 | + $config = FormatJson::encode( |
| 290 | + array( 'server' => $context->getServer(), 'debug' => $context->getDebug() ) |
| 291 | + ); |
331 | 292 | // Add a well-known start-up function |
332 | | - $scripts .= "window.startUp = function() { {$registration} mediaWiki.config.set( {$config} ); };"; |
| 293 | + $scripts .= "window.startUp = function() { $registration mediaWiki.config.set( $config ); };"; |
333 | 294 | // Build load query for jquery and mediawiki modules |
334 | | - $query = wfArrayToCGI( $parameters + array( |
335 | | - 'modules' => implode( '|', array( 'jquery', 'mediawiki' ) ), |
336 | | - 'version' => wfTimestamp( |
337 | | - TS_ISO_8601, |
338 | | - round( |
339 | | - max( |
340 | | - self::$modules['jquery']->getModifiedTime( |
341 | | - $parameters['lang'], $parameters['skin'], $parameters['debug'] |
342 | | - ), |
343 | | - self::$modules['mediawiki']->getModifiedTime( |
344 | | - $parameters['lang'], $parameters['skin'], $parameters['debug'] |
345 | | - ) |
346 | | - ), |
347 | | - -2 |
348 | | - ) |
| 295 | + $query = wfArrayToCGI( |
| 296 | + array( |
| 297 | + 'modules' => implode( '|', array( 'jquery', 'mediawiki' ) ), |
| 298 | + 'only' => 'scripts', |
| 299 | + 'lang' => $context->getLanguage(), |
| 300 | + 'dir' => $context->getDirection(), |
| 301 | + 'skin' => $context->getSkin(), |
| 302 | + 'debug' => $context->getDebug(), |
| 303 | + 'version' => wfTimestamp( TS_ISO_8601, round( max( |
| 304 | + self::$modules['jquery']->getModifiedTime( $context ), |
| 305 | + self::$modules['mediawiki']->getModifiedTime( $context ) |
| 306 | + ), -2 ) ) |
349 | 307 | ) |
350 | | - ) ); |
| 308 | + ); |
351 | 309 | // Build HTML code for loading jquery and mediawiki modules |
352 | | - $linkedScript = Html::linkedScript( "{$server}?{$query}" ); |
| 310 | + $loadScript = Html::linkedScript( $context->getServer() . "?$query" ); |
353 | 311 | // Add code to add jquery and mediawiki loading code; only if the current client is compatible |
354 | | - $scripts .= "if ( isCompatible() ) { document.write( '{$linkedScript}' ); }"; |
| 312 | + $scripts .= "if ( isCompatible() ) { document.write( '$loadScript' ); }"; |
355 | 313 | // Delete the compatible function - it's not needed anymore |
356 | 314 | $scripts .= "delete window['isCompatible'];"; |
357 | 315 | } |
358 | 316 | } |
359 | 317 | // Styles |
360 | 318 | $styles = ''; |
361 | | - if ( $includeStyles && ( $styles .= self::$modules[$name]->getStyle( $parameters['skin'] ) ) !== '' ) { |
362 | | - if ( $parameters['dir'] == 'rtl' ) { |
| 319 | + if ( |
| 320 | + $context->shouldIncludeStyles() && |
| 321 | + ( $styles .= self::$modules[$name]->getStyle( $context ) ) !== '' |
| 322 | + ) { |
| 323 | + if ( $context->getDirection() == 'rtl' ) { |
363 | 324 | $styles = self::filter( 'flip-css', $styles ); |
364 | 325 | } |
365 | | - $styles = $parameters['debug'] ? $styles : self::filter( 'minify-css', $styles ); |
| 326 | + $styles = $context->getDebug() ? $styles : self::filter( 'minify-css', $styles ); |
366 | 327 | } |
367 | 328 | // Messages |
368 | 329 | $messages = isset( $blobs[$name] ) ? $blobs[$name] : '{}'; |
369 | 330 | // Output |
370 | | - if ( $parameters['only'] === 'styles' ) { |
| 331 | + if ( $context->getOnly() === 'styles' ) { |
371 | 332 | echo $styles; |
372 | | - } else if ( $parameters['only'] === 'scripts' ) { |
| 333 | + } else if ( $context->getOnly() === 'scripts' ) { |
373 | 334 | echo $scripts; |
374 | | - } else if ( $parameters['only'] === 'messages' ) { |
| 335 | + } else if ( $context->getOnly() === 'messages' ) { |
375 | 336 | echo "mediaWiki.msg.set( $messages );\n"; |
376 | 337 | } else { |
377 | 338 | $styles = Xml::escapeJsString( $styles ); |
— | — | @@ -378,7 +339,7 @@ |
379 | 340 | } |
380 | 341 | } |
381 | 342 | // Update the status of script-only modules |
382 | | - if ( $parameters['only'] === 'scripts' && !in_array( 'startup', $modules ) ) { |
| 343 | + if ( $context->getOnly() === 'scripts' && !in_array( 'startup', $modules ) ) { |
383 | 344 | $statuses = array(); |
384 | 345 | foreach ( $modules as $name ) { |
385 | 346 | $statuses[$name] = 'ready'; |
— | — | @@ -387,15 +348,17 @@ |
388 | 349 | echo "mediaWiki.loader.state( {$statuses} );"; |
389 | 350 | } |
390 | 351 | // Register missing modules |
391 | | - foreach ( $missing as $name ) { |
392 | | - echo "mediaWiki.loader.register( '{$name}', null, 'missing' );\n"; |
| 352 | + if ( $context->shouldIncludeScripts() ) { |
| 353 | + foreach ( $missing as $name ) { |
| 354 | + echo "mediaWiki.loader.register( '{$name}', null, 'missing' );\n"; |
| 355 | + } |
393 | 356 | } |
394 | | - |
395 | | - if ( $parameters['only'] === 'styles' ) { |
| 357 | + // Output the appropriate header |
| 358 | + if ( $context->getOnly() === 'styles' ) { |
396 | 359 | header( 'Content-Type: text/css' ); |
397 | 360 | } else { |
398 | 361 | header( 'Content-Type: text/javascript' ); |
399 | | - if ( $parameters['debug'] ) { |
| 362 | + if ( $context->getDebug() ) { |
400 | 363 | ob_end_flush(); |
401 | 364 | } else { |
402 | 365 | echo self::filter( 'minify-js', ob_get_clean() ); |
Index: branches/resourceloader/phase3/includes/AutoLoader.php |
— | — | @@ -198,6 +198,7 @@ |
199 | 199 | 'ReplacementArray' => 'includes/StringUtils.php', |
200 | 200 | 'Replacer' => 'includes/StringUtils.php', |
201 | 201 | 'ResourceLoader' => 'includes/ResourceLoader.php', |
| 202 | + 'ResourceLoaderContext' => 'includes/ResourceLoaderContext.php', |
202 | 203 | 'ResourceLoaderFileModule' => 'includes/ResourceLoaderModule.php', |
203 | 204 | 'ResourceLoaderModule' => 'includes/ResourceLoaderModule.php', |
204 | 205 | 'ResourceLoaderSiteModule' => 'includes/ResourceLoaderModule.php', |
Index: branches/resourceloader/phase3/includes/ResourceLoaderModule.php |
— | — | @@ -15,7 +15,6 @@ |
16 | 16 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. |
17 | 17 | * http://www.gnu.org/copyleft/gpl.html |
18 | 18 | * |
19 | | - * @author Roan Kattouw |
20 | 19 | * @author Trevor Parscal |
21 | 20 | */ |
22 | 21 | |
— | — | @@ -73,14 +72,14 @@ |
74 | 73 | * @param $debug bool Whether to include debug scripts |
75 | 74 | * @return string JS |
76 | 75 | */ |
77 | | - public abstract function getScript( $lang, $skin, $debug ); |
| 76 | + public abstract function getScript( ResourceLoaderContext $context ); |
78 | 77 | |
79 | 78 | /** |
80 | 79 | * Get all CSS for this module for a given skin. |
81 | 80 | * @param $skin string Skin name |
82 | 81 | * @return string CSS |
83 | 82 | */ |
84 | | - public abstract function getStyle( $skin ); |
| 83 | + public abstract function getStyle( ResourceLoaderContext $context ); |
85 | 84 | |
86 | 85 | /** |
87 | 86 | * Get the messages needed for this module. |
— | — | @@ -124,7 +123,7 @@ |
125 | 124 | * @param $debug bool Debug mode flag |
126 | 125 | * @return int UNIX timestamp |
127 | 126 | */ |
128 | | - public abstract function getModifiedTime( $lang, $skin, $debug ); |
| 127 | + public abstract function getModifiedTime( ResourceLoaderContext $context ); |
129 | 128 | } |
130 | 129 | |
131 | 130 | /** |
— | — | @@ -321,37 +320,37 @@ |
322 | 321 | $this->loaders = array_merge( $this->loaders, (array)$scripts ); |
323 | 322 | } |
324 | 323 | |
325 | | - public function getScript( $lang, $skin, $debug ) { |
| 324 | + public function getScript( ResourceLoaderContext $context ) { |
326 | 325 | $retval = $this->getPrimaryScript() . "\n" . |
327 | | - $this->getLanguageScript( $lang ) . "\n" . |
328 | | - $this->getSkinScript( $skin ); |
329 | | - if ( $debug ) { |
| 326 | + $this->getLanguageScript( $context->getLanguage() ) . "\n" . |
| 327 | + $this->getSkinScript( $context->getSkin() ); |
| 328 | + if ( $context->getDebug() ) { |
330 | 329 | $retval .= $this->getDebugScript(); |
331 | 330 | } |
332 | 331 | return $retval; |
333 | 332 | } |
334 | 333 | |
335 | | - public function getStyle( $skin ) { |
336 | | - $style = $this->getPrimaryStyle() . "\n" . $this->getSkinStyle( $skin ); |
| 334 | + public function getStyle( ResourceLoaderContext $context ) { |
| 335 | + $style = $this->getPrimaryStyle() . "\n" . $this->getSkinStyle( $context->getSkin() ); |
337 | 336 | |
338 | 337 | // Extract and store the list of referenced files |
339 | 338 | $files = CSSMin::getLocalFileReferences( $style ); |
340 | 339 | |
341 | 340 | // Only store if modified |
342 | | - if ( $files !== $this->getFileDependencies( $skin ) ) { |
| 341 | + if ( $files !== $this->getFileDependencies( $context->getSkin() ) ) { |
343 | 342 | $encFiles = FormatJson::encode( $files ); |
344 | 343 | $dbw = wfGetDb( DB_MASTER ); |
345 | 344 | $dbw->replace( 'module_deps', |
346 | 345 | array( array( 'md_module', 'md_skin' ) ), array( |
347 | 346 | 'md_module' => $this->getName(), |
348 | | - 'md_skin' => $skin, |
| 347 | + 'md_skin' => $context->getSkin(), |
349 | 348 | 'md_deps' => $encFiles, |
350 | 349 | ) |
351 | 350 | ); |
352 | 351 | |
353 | 352 | // Save into memcached |
354 | 353 | global $wgMemc; |
355 | | - $key = wfMemcKey( 'resourceloader', 'module_deps', $this->getName(), $skin ); |
| 354 | + $key = wfMemcKey( 'resourceloader', 'module_deps', $this->getName(), $context->getSkin() ); |
356 | 355 | $wgMemc->set( $key, $encFiles ); |
357 | 356 | } |
358 | 357 | return $style; |
— | — | @@ -384,37 +383,27 @@ |
385 | 384 | * @param $debug bool Debug mode flag |
386 | 385 | * @return int UNIX timestamp |
387 | 386 | */ |
388 | | - public function getModifiedTime( $lang, $skin, $debug ) { |
389 | | - if ( isset( $this->modifiedTime["$lang|$skin|$debug"] ) ) { |
390 | | - return $this->modifiedTime["$lang|$skin|$debug"]; |
| 387 | + public function getModifiedTime( ResourceLoaderContext $context ) { |
| 388 | + $hash = implode( '|', array( $context->getLanguage(), $context->getSkin(), $context->getDebug() ) ); |
| 389 | + if ( isset( $this->modifiedTime[$hash] ) ) { |
| 390 | + return $this->modifiedTime[$hash]; |
391 | 391 | } |
392 | 392 | |
393 | | - // Get the maximum mtime of the various files involved |
394 | | - $files = array_merge( $this->scripts, $this->styles, |
395 | | - $debug ? $this->debugScripts : array(), |
396 | | - isset( $this->languageScripts[$lang] ) ? (array)$this->languageScripts[$lang] : array(), |
397 | | - (array)self::getSkinFiles( $skin, $this->skinScripts ), |
398 | | - (array)self::getSkinFiles( $skin, $this->skinStyles ), |
| 393 | + $files = array_merge( |
| 394 | + $this->scripts, |
| 395 | + $this->styles, |
| 396 | + $context->getDebug() ? $this->debugScripts : array(), |
| 397 | + isset( $this->languageScripts[$context->getLanguage()] ) ? |
| 398 | + (array) $this->languageScripts[$context->getLanguage()] : array(), |
| 399 | + (array) self::getSkinFiles( $context->getSkin(), $this->skinScripts ), |
| 400 | + (array) self::getSkinFiles( $context->getSkin(), $this->skinStyles ), |
399 | 401 | $this->loaders, |
400 | | - $this->getFileDependencies( $skin ) |
| 402 | + $this->getFileDependencies( $context->getSkin() ) |
401 | 403 | ); |
402 | | - $maxFileMtime = max( array_map( 'filemtime', array_map( array( __CLASS__, 'remapFilename' ), $files ) ) ); |
403 | | - |
404 | | - // Get the mtime of the message blob |
405 | | - // TODO: This timestamp is queried a lot and queried separately for each module. Maybe it should be put in memcached? |
406 | | - $dbr = wfGetDb( DB_SLAVE ); |
407 | | - $msgBlobMtime = $dbr->selectField( 'msg_resource', 'mr_timestamp', array( |
408 | | - 'mr_resource' => $this->getName(), |
409 | | - 'mr_lang' => $lang |
410 | | - ), __METHOD__ |
| 404 | + $this->modifiedTime[$hash] = max( |
| 405 | + array_map( 'filemtime', array_map( array( __CLASS__, 'remapFilename' ), $files ) ) |
411 | 406 | ); |
412 | | - |
413 | | - if ( $msgBlobMtime ) { |
414 | | - $this->modifiedTime["$lang|$skin|$debug"] = max( $maxFileMtime, wfTimestamp( TS_UNIX, $msgBlobMtime ) ); |
415 | | - } else { |
416 | | - $this->modifiedTime["$lang|$skin|$debug"] = $maxFileMtime; |
417 | | - } |
418 | | - return $this->modifiedTime["$lang|$skin|$debug"]; |
| 407 | + return $this->modifiedTime[$hash]; |
419 | 408 | } |
420 | 409 | |
421 | 410 | /** |
— | — | @@ -572,20 +561,21 @@ |
573 | 562 | // In-object cache for modified time |
574 | 563 | private $modifiedTime = null; |
575 | 564 | |
576 | | - public function getScript( $lang, $skin, $debug ) { |
577 | | - return Skin::newFromKey( $skin )->generateUserJs(); |
| 565 | + public function getScript( ResourceLoaderContext $context ) { |
| 566 | + return Skin::newFromKey( $context->getSkin() )->generateUserJs(); |
578 | 567 | } |
579 | 568 | |
580 | | - public function getModifiedTime( $lang, $skin, $debug ) { |
581 | | - if ( isset( $this->modifiedTime["$lang|$skin|$debug"] ) ) { |
582 | | - return $this->modifiedTime["$lang|$skin|$debug"]; |
| 569 | + public function getModifiedTime( ResourceLoaderContext $context ) { |
| 570 | + $hash = implode( '|', array( $context->getLanguage(), $context->getSkin(), $context->getDebug() ) ); |
| 571 | + if ( isset( $this->modifiedTime[$hash] ) ) { |
| 572 | + return $this->modifiedTime[$hash]; |
583 | 573 | } |
584 | 574 | |
585 | 575 | // HACK: We duplicate the message names from generateUserJs() |
586 | 576 | // here and weird things (i.e. mtime moving backwards) can happen |
587 | 577 | // when a MediaWiki:Something.js page is deleted |
588 | 578 | $jsPages = array( Title::makeTitle( NS_MEDIAWIKI, 'Common.js' ), |
589 | | - Title::makeTitle( NS_MEDIAWIKI, ucfirst( $skin ) . '.js' ) |
| 579 | + Title::makeTitle( NS_MEDIAWIKI, ucfirst( $context->getSkin() ) . '.js' ) |
590 | 580 | ); |
591 | 581 | |
592 | 582 | // Do batch existence check |
— | — | @@ -602,7 +592,7 @@ |
603 | 593 | return $this->modifiedTime; |
604 | 594 | } |
605 | 595 | |
606 | | - public function getStyle( $skin ) { return ''; } |
| 596 | + public function getStyle( ResourceLoaderContext $context ) { return ''; } |
607 | 597 | public function getMessages() { return array(); } |
608 | 598 | public function getLoaderScript() { return ''; } |
609 | 599 | public function getDependencies() { return array(); } |
— | — | @@ -612,19 +602,19 @@ |
613 | 603 | class ResourceLoaderStartUpModule extends ResourceLoaderModule { |
614 | 604 | private $modifiedTime = null; |
615 | 605 | |
616 | | - public function getScript( $lang, $skin, $debug ) { |
| 606 | + public function getScript( ResourceLoaderContext $context ) { |
617 | 607 | global $IP; |
618 | 608 | return file_get_contents( "$IP/resources/startup.js" ); |
619 | 609 | } |
620 | 610 | |
621 | | - public function getModifiedTime( $lang, $skin, $debug ) { |
| 611 | + public function getModifiedTime( ResourceLoaderContext $context ) { |
622 | 612 | global $IP; |
623 | 613 | if ( !is_null( $this->modifiedTime ) ) { |
624 | 614 | return $this->modifiedTime; |
625 | 615 | } |
626 | 616 | // HACK getHighestModifiedTime() calls this function, so protect against infinite recursion |
627 | 617 | $this->modifiedTime = filemtime( "$IP/resources/startup.js" ); |
628 | | - $this->modifiedTime = ResourceLoader::getHighestModifiedTime( $lang, $skin, $debug ); |
| 618 | + $this->modifiedTime = ResourceLoader::getHighestModifiedTime( $context ); |
629 | 619 | return $this->modifiedTime; |
630 | 620 | } |
631 | 621 | |
— | — | @@ -636,7 +626,7 @@ |
637 | 627 | return 300; // 5 minutes |
638 | 628 | } |
639 | 629 | |
640 | | - public function getStyle( $skin ) { return ''; } |
| 630 | + public function getStyle( ResourceLoaderContext $context ) { return ''; } |
641 | 631 | public function getMessages() { return array(); } |
642 | 632 | public function getLoaderScript() { return ''; } |
643 | 633 | public function getDependencies() { return array(); } |
Index: branches/resourceloader/phase3/load.php |
— | — | @@ -47,7 +47,7 @@ |
48 | 48 | } |
49 | 49 | |
50 | 50 | // Respond to resource loading request |
51 | | -ResourceLoader::respond( $wgRequest, $wgServer . $wgScriptPath . '/load.php' ); |
| 51 | +ResourceLoader::respond( new ResourceLoaderContext( $wgRequest, $wgServer . $wgScriptPath . '/load.php' ) ); |
52 | 52 | |
53 | 53 | wfProfileOut( 'load.php' ); |
54 | 54 | wfLogProfilingData(); |