r72772 MediaWiki - Code Review archive

Repository:MediaWiki
Revision:r72771‎ | r72772 | r72773 >
Date:03:26, 11 September 2010
Author:tparscal
Status:resolved (Comments)
Tags:
Comment:
Major refactoring of site and user CSS, creating ResourceLoaderUserModule and ResourceLoaderUserPreferenceModule. Also moved as much of the global variables being generated in Skin::makeGlobalVaiablesScript into the ResourceLoaderStartupModule - which will make configuration changes effective site-wide in 5 minutes instead of whenever all pages are purged from cache - what remains embedded in the HTML is article and user specific - two things we don't know by the time we request the startup module. Also, fixed issue where debug=false was being interpreted to be equivilant to debug=true. Finally, finished integrating the introduction of $wgLoadScript, thus fixing overlooked issues in r72763.
Modified paths:
  • /trunk/phase3/includes/OutputPage.php (modified) (history)
  • /trunk/phase3/includes/ResourceLoaderContext.php (modified) (history)
  • /trunk/phase3/includes/ResourceLoaderModule.php (modified) (history)
  • /trunk/phase3/includes/Skin.php (modified) (history)
  • /trunk/phase3/load.php (modified) (history)
  • /trunk/phase3/resources/Resources.php (modified) (history)
  • /trunk/phase3/resources/mediawiki/mediawiki.js (modified) (history)

Diff [purge]

Index: trunk/phase3/includes/ResourceLoaderContext.php
@@ -31,23 +31,24 @@
3232 protected $language;
3333 protected $direction;
3434 protected $skin;
 35+ protected $user;
3536 protected $debug;
3637 protected $only;
3738 protected $hash;
3839
3940 /* Methods */
4041
41 - public function __construct( WebRequest $request, $server ) {
 42+ public function __construct( WebRequest $request ) {
4243 global $wgLang, $wgDefaultSkin;
4344
4445 $this->request = $request;
45 - $this->server = $server;
4646 // Interperet request
4747 $this->modules = explode( '|', $request->getVal( 'modules' ) );
4848 $this->language = $request->getVal( 'lang' );
4949 $this->direction = $request->getVal( 'dir' );
5050 $this->skin = $request->getVal( 'skin' );
51 - $this->debug = $request->getVal( 'debug' ) === 'true' || $request->getBool( 'debug' );
 51+ $this->user = $request->getVal( 'user' );
 52+ $this->debug = $request->getBool( 'debug' ) && $request->getVal( 'debug' ) === 'true';
5253 $this->only = $request->getVal( 'only' );
5354
5455 // Fallback on system defaults
@@ -68,10 +69,6 @@
6970 return $this->request;
7071 }
7172
72 - public function getServer() {
73 - return $this->server;
74 - }
75 -
7673 public function getModules() {
7774 return $this->modules;
7875 }
@@ -88,6 +85,10 @@
8986 return $this->skin;
9087 }
9188
 89+ public function getUser() {
 90+ return $this->skin;
 91+ }
 92+
9293 public function getDebug() {
9394 return $this->debug;
9495 }
@@ -111,6 +112,6 @@
112113 public function getHash() {
113114 return isset( $this->hash ) ?
114115 $this->hash : $this->hash =
115 - implode( '|', array( $this->language, $this->skin, $this->debug, $this->only ) );
 116+ implode( '|', array( $this->language, $this->skin, $this->user, $this->debug, $this->only ) );
116117 }
117118 }
Index: trunk/phase3/includes/OutputPage.php
@@ -2283,19 +2283,33 @@
22842284 static function makeResourceLoaderLink( $skin, $modules, $only ) {
22852285 global $wgUser, $wgLang, $wgRequest, $wgLoadScript;
22862286 // TODO: Should this be a static function of ResourceLoader instead?
 2287+ // TODO: Divide off modules starting with "user", and add the user parameter to them
22872288 $query = array(
2288 - 'modules' => implode( '|', array_unique( (array) $modules ) ),
22892289 'lang' => $wgLang->getCode(),
22902290 'debug' => $wgRequest->getBool( 'debug' ) && $wgRequest->getVal( 'debug' ) !== 'false',
22912291 'skin' => $wgUser->getSkin()->getSkinName(),
22922292 'only' => $only,
22932293 );
2294 - // Automatically select style/script elements
2295 - if ( $only === 'styles' ) {
2296 - return Html::linkedStyle( wfAppendQuery( $wgLoadScript, $query ) );
2297 - } else {
2298 - return Html::linkedScript( wfAppendQuery( $wgLoadScript, $query ) );
 2294+ $moduleGroups = array( null => array(), 'user' => array() );
 2295+ foreach ( (array) $modules as $module ) {
 2296+ $moduleGroups[strpos( $module, 'user' ) === 0 ? 'user' : null][] = $module;
22992297 }
 2298+ $links = '';
 2299+ foreach ( $moduleGroups as $group => $modules ) {
 2300+ if ( count( $modules ) ) {
 2301+ $query['modules'] = implode( '|', array_unique( (array) $modules ) );
 2302+ if ( $group === 'user' ) {
 2303+ $query['user'] = $wgUser->getName();
 2304+ }
 2305+ // Automatically select style/script elements
 2306+ if ( $only === 'styles' ) {
 2307+ $links .= Html::linkedStyle( wfAppendQuery( $wgLoadScript, $query ) );
 2308+ } else {
 2309+ $links .= Html::linkedScript( wfAppendQuery( $wgLoadScript, $query ) );
 2310+ }
 2311+ }
 2312+ }
 2313+ return $links;
23002314 }
23012315
23022316 /**
@@ -2313,8 +2327,8 @@
23142328 // Statup - this will immediately load jquery and mediawiki modules
23152329 $scripts = self::makeResourceLoaderLink( $sk, 'startup', 'scripts' );
23162330
2317 - // Configuration -- this could be merged together with the load and go, but makeGlobalVariablesScript returns a
2318 - // whole script tag -- grumble grumble
 2331+ // Configuration -- This could be merged together with the load and go, but makeGlobalVariablesScript returns a
 2332+ // whole script tag -- grumble grumble...
23192333 $scripts .= Skin::makeGlobalVariablesScript( $sk->getSkinName() ) . "\n";
23202334
23212335 // Script and Messages "only"
Index: trunk/phase3/includes/Skin.php
@@ -357,10 +357,10 @@
358358
359359 static function makeVariablesScript( $data ) {
360360 if ( $data ) {
361 - return Html::inlineScript( 'mediaWiki.config.set(' . json_encode( $data ) . ');' );
 361+ return Html::inlineScript( 'mediaWiki.config.set(' . FormatJson::encode( $data ) . ');' );
362362 } else {
363363 return '';
364 - }
 364+ }
365365 }
366366
367367 /**
@@ -368,50 +368,16 @@
369369 * @param $skinName string Name of the skin
370370 * The odd calling convention is for backwards compatibility
371371 * @todo FIXME: Make this not depend on $wgTitle!
 372+ *
 373+ * Do not add things here which can be evaluated in ResourceLoaderStartupScript - in other words, without state.
 374+ * You will only be adding bloat to the page and causing page caches to have to be purged on configuration changes.
372375 */
373376 static function makeGlobalVariablesScript( $skinName ) {
374 - if ( is_array( $skinName ) ) {
375 - # Weird back-compat stuff.
376 - $skinName = $skinName['skinname'];
377 - }
378 -
379 - global $wgScript, $wgTitle, $wgStylePath, $wgUser, $wgScriptExtension;
380 - global $wgArticlePath, $wgScriptPath, $wgServer, $wgContLang, $wgLang;
381 - global $wgOut, $wgArticle;
382 - global $wgBreakFrames, $wgRequest, $wgVariantArticlePath, $wgActionPaths;
383 - global $wgUseAjax, $wgAjaxWatch;
384 - global $wgVersion, $wgEnableAPI, $wgEnableWriteAPI;
385 - global $wgRestrictionTypes;
386 - global $wgDBname, $wgEnableMWSuggest;
387 - global $wgSitename;
388 -
 377+ global $wgTitle, $wgUser, $wgRequest, $wgArticle, $wgOut, $wgRestrictionTypes;
 378+
389379 $ns = $wgTitle->getNamespace();
390380 $nsname = MWNamespace::exists( $ns ) ? MWNamespace::getCanonicalName( $ns ) : $wgTitle->getNsText();
391 - $separatorTransTable = $wgContLang->separatorTransformTable();
392 - $separatorTransTable = $separatorTransTable ? $separatorTransTable : array();
393 - $compactSeparatorTransTable = array(
394 - implode( "\t", array_keys( $separatorTransTable ) ),
395 - implode( "\t", $separatorTransTable ),
396 - );
397 - $digitTransTable = $wgContLang->digitTransformTable();
398 - $digitTransTable = $digitTransTable ? $digitTransTable : array();
399 - $compactDigitTransTable = array(
400 - implode( "\t", array_keys( $digitTransTable ) ),
401 - implode( "\t", $digitTransTable ),
402 - );
403 -
404 - $mainPage = Title::newMainPage();
405381 $vars = array(
406 - 'skin' => $skinName,
407 - 'stylepath' => $wgStylePath,
408 - 'wgUrlProtocols' => wfUrlProtocols(),
409 - 'wgArticlePath' => $wgArticlePath,
410 - 'wgScriptPath' => $wgScriptPath,
411 - 'wgScriptExtension' => $wgScriptExtension,
412 - 'wgScript' => $wgScript,
413 - 'wgVariantArticlePath' => $wgVariantArticlePath,
414 - 'wgActionPaths' => (object)$wgActionPaths,
415 - 'wgServer' => $wgServer,
416382 'wgCanonicalNamespace' => $nsname,
417383 'wgCanonicalSpecialPageName' => $ns == NS_SPECIAL ?
418384 SpecialPage::resolveAlias( $wgTitle->getDBkey() ) : false, # bug 21115
@@ -423,56 +389,16 @@
424390 'wgIsArticle' => $wgOut->isArticle(),
425391 'wgUserName' => $wgUser->isAnon() ? null : $wgUser->getName(),
426392 'wgUserGroups' => $wgUser->getEffectiveGroups(),
427 - 'wgUserLanguage' => $wgLang->getCode(),
428 - 'wgContentLanguage' => $wgContLang->getCode(),
429 - 'wgBreakFrames' => $wgBreakFrames,
430393 'wgCurRevisionId' => isset( $wgArticle ) ? $wgArticle->getLatest() : 0,
431 - 'wgVersion' => $wgVersion,
432 - 'wgEnableAPI' => $wgEnableAPI,
433 - 'wgEnableWriteAPI' => $wgEnableWriteAPI,
434 - 'wgSeparatorTransformTable' => $compactSeparatorTransTable,
435 - 'wgDigitTransformTable' => $compactDigitTransTable,
436 - 'wgMainPageTitle' => $mainPage ? $mainPage->getPrefixedText() : null,
437 - 'wgFormattedNamespaces' => $wgContLang->getFormattedNamespaces(),
438 - 'wgNamespaceIds' => $wgContLang->getNamespaceIds(),
439 - 'wgSiteName' => $wgSitename,
440394 'wgCategories' => $wgOut->getCategories(),
441395 );
442 -
443 - if ( $wgContLang->hasVariants() ) {
444 - $vars['wgUserVariant'] = $wgContLang->getPreferredVariant();
445 - }
446 -
447 - // if on upload page output the extension list & js_upload
448 - if ( SpecialPage::resolveAlias( $wgTitle->getDBkey() ) == 'Upload' ) {
449 - global $wgFileExtensions;
450 - $vars['wgFileExtensions'] = $wgFileExtensions;
451 - }
452 -
453 - if ( $wgUseAjax && $wgEnableMWSuggest && !$wgUser->getOption( 'disablesuggest', false ) ) {
454 - $vars['wgMWSuggestTemplate'] = SearchEngine::getMWSuggestTemplate();
455 - $vars['wgDBname'] = $wgDBname;
456 - $vars['wgSearchNamespaces'] = SearchEngine::userNamespaces( $wgUser );
457 - $vars['wgMWSuggestMessages'] = array( wfMsg( 'search-mwsuggest-enabled' ), wfMsg( 'search-mwsuggest-disabled' ) );
458 - }
459 -
460396 foreach ( $wgRestrictionTypes as $type ) {
461397 $vars['wgRestriction' . ucfirst( $type )] = $wgTitle->getRestrictions( $type );
462398 }
463 -
464 - if ( $wgOut->isArticleRelated() && $wgUseAjax && $wgAjaxWatch && $wgUser->isLoggedIn() ) {
465 - $msgs = (object)array();
466 -
467 - foreach ( array( 'watch', 'unwatch', 'watching', 'unwatching',
468 - 'tooltip-ca-watch', 'tooltip-ca-unwatch' ) as $msgName ) {
469 - $msgs-> { $msgName . 'Msg' } = wfMsg( $msgName );
470 - }
471 - $vars['wgAjaxWatch'] = $msgs;
472 - }
473 -
 399+
474400 // Allow extensions to add their custom variables to the global JS variables
475401 wfRunHooks( 'MakeGlobalVariablesScript', array( &$vars ) );
476 -
 402+
477403 return self::makeVariablesScript( $vars );
478404 }
479405
@@ -521,51 +447,20 @@
522448 * @return string
523449 */
524450 public function generateUserJs( $skinName = null ) {
525 - global $wgStylePath;
526 -
527 - wfProfileIn( __METHOD__ );
528 -
529 - if ( !$skinName ) {
530 - $skinName = $this->getSkinName();
531 - }
532 -
533 - $s = "/* generated javascript */\n";
534 - $s .= "var skin = '" . Xml::escapeJsString( $skinName ) . "';\n";
535 - $s .= "var stylepath = '" . Xml::escapeJsString( $wgStylePath ) . "';";
536 - $s .= "\n\n/* MediaWiki:Common.js */\n";
537 -
538 - $commonJs = wfMsgExt( 'common.js', 'content' );
539 -
540 - if ( !wfEmptyMsg( 'common.js', $commonJs ) ) {
541 - $s .= $commonJs;
542 - }
543 -
544 - $s .= "\n\n/* MediaWiki:" . ucfirst( $skinName ) . ".js */\n";
545 -
546 - // avoid inclusion of non defined user JavaScript (with custom skins only)
547 - // by checking for default message content
548 - $msgKey = ucfirst( $skinName ) . '.js';
549 - $userJS = wfMsgExt( $msgKey, 'content' );
550 -
551 - if ( !wfEmptyMsg( $msgKey, $userJS ) ) {
552 - $s .= $userJS;
553 - }
554 -
555 - wfProfileOut( __METHOD__ );
556 - return $s;
 451+
 452+ // Stub - see ResourceLoaderSiteModule, CologneBlue, Simple and Standard skins override this
 453+
 454+ return '';
557455 }
558456
559457 /**
560458 * Generate user stylesheet for action=raw&gen=css
561459 */
562460 public function generateUserStylesheet() {
563 - wfProfileIn( __METHOD__ );
564 -
565 - $s = "/* generated user stylesheet */\n" .
566 - $this->reallyGenerateUserStylesheet();
567 -
568 - wfProfileOut( __METHOD__ );
569 - return $s;
 461+
 462+ // Stub - see ResourceLoaderUserModule, CologneBlue, Simple and Standard skins override this
 463+
 464+ return '';
570465 }
571466
572467 /**
@@ -573,53 +468,10 @@
574469 * Anything in here won't be generated if $wgAllowUserCssPrefs is false.
575470 */
576471 protected function reallyGenerateUserStylesheet() {
577 - global $wgUser;
578 -
579 - $s = '';
580 -
581 - if ( ( $undopt = $wgUser->getOption( 'underline' ) ) < 2 ) {
582 - $underline = $undopt ? 'underline' : 'none';
583 - $s .= "a { text-decoration: $underline; }\n";
584 - }
585 -
586 - if ( $wgUser->getOption( 'highlightbroken' ) ) {
587 - $s .= "a.new, #quickbar a.new { color: #CC2200; }\n";
588 - } else {
589 - $s .= <<<CSS
590 -a.new, #quickbar a.new,
591 -a.stub, #quickbar a.stub {
592 - color: inherit;
593 -}
594 -a.new:after, #quickbar a.new:after {
595 - content: "?";
596 - color: #CC2200;
597 -}
598 -a.stub:after, #quickbar a.stub:after {
599 - content: "!";
600 - color: #772233;
601 -}
602 -CSS;
603 - }
604 -
605 - if ( $wgUser->getOption( 'justify' ) ) {
606 - $s .= "#article, #bodyContent, #mw_content { text-align: justify; }\n";
607 - }
608 -
609 - if ( !$wgUser->getOption( 'showtoc' ) ) {
610 - $s .= "#toc { display: none; }\n";
611 - }
612 -
613 - if ( !$wgUser->getOption( 'editsection' ) ) {
614 - $s .= ".editsection { display: none; }\n";
615 - }
616 -
617 - $fontstyle = $wgUser->getOption( 'editfont' );
618 -
619 - if ( $fontstyle !== 'default' ) {
620 - $s .= "textarea { font-family: $fontstyle; }\n";
621 - }
622 -
623 - return $s;
 472+
 473+ // Stub - see ResourceLoaderUserModule, CologneBlue, Simple and Standard skins override this
 474+
 475+ return '';
624476 }
625477
626478 /**
@@ -627,7 +479,7 @@
628480 */
629481 function setupUserCss( OutputPage $out ) {
630482 global $wgRequest, $wgUser;
631 - global $wgAllowUserCss, $wgUseSiteCss, $wgSquidMaxage;
 483+ global $wgUseSiteCss, $wgAllowUserCss, $wgAllowUserCssPrefs, $wgSquidMaxage;
632484
633485 wfProfileIn( __METHOD__ );
634486
@@ -643,51 +495,26 @@
644496 $out->addStyle( $url );
645497 }
646498
647 - // If we use the site's dynamic CSS, throw that in, too
648499 // Per-site custom styles
649500 if ( $wgUseSiteCss ) {
650501 $out->addModuleStyles( 'site' );
651502 }
652503
653 - global $wgAllowUserCssPrefs;
654 -
655 - if ( $wgAllowUserCssPrefs ) {
656 - if ( $wgUser->isLoggedIn() ) {
657 - // Ensure that logged-in users' generated CSS isn't clobbered
658 - // by anons' publicly cacheable generated CSS.
659 - $siteargs['smaxage'] = '0';
660 - $siteargs['ts'] = $wgUser->mTouched;
661 - }
662 -
663 - // Per-user styles based on preferences
664 - $siteargs['gen'] = 'css';
665 -
666 - if ( ( $us = $wgRequest->getVal( 'useskin', '' ) ) !== '' ) {
667 - $siteargs['useskin'] = $us;
668 - }
669 -
670 - $out->addStyle( self::makeUrl( '-', wfArrayToCGI( $siteargs ) ) );
671 - }
672 -
673 - // Per-user custom style pages
674 - if ( $wgAllowUserCss && $wgUser->isLoggedIn() ) {
675 - $action = $wgRequest->getVal( 'action' );
676 -
677 - # If we're previewing the CSS page, use it
678 - if ( $this->mTitle->isCssSubpage() && $this->userCanPreview( $action ) ) {
 504+ // Per-user custom styles
 505+ if ( $wgAllowUserCss ) {
 506+ if ( $this->mTitle->isCssSubpage() && $this->userCanPreview( $wgRequest->getVal( 'action' ) ) ) {
679507 // @FIXME: properly escape the cdata!
680508 $out->addInlineStyle( $wgRequest->getText( 'wpTextbox1' ) );
681509 } else {
682 - $names = array( 'common', $this->getSkinName() );
683 - foreach ( $names as $name ) {
684 - $out->addStyle( self::makeUrl(
685 - $this->userpage . '/' . $name . '.css',
686 - 'action=raw&ctype=text/css' )
687 - );
688 - }
 510+ $out->addModuleStyles( 'user' );
689511 }
690512 }
691513
 514+ // Per-user preference styles
 515+ if ( $wgAllowUserCssPrefs ) {
 516+ $out->addModuleStyles( 'user.preferences' );
 517+ }
 518+
692519 wfProfileOut( __METHOD__ );
693520 }
694521
Index: trunk/phase3/includes/ResourceLoaderModule.php
@@ -81,8 +81,6 @@
8282 return $context->getDirection() === 'rtl';
8383 }
8484
85 - /* Abstract Methods */
86 -
8785 /**
8886 * Get all JS for this module for a given language and skin.
8987 * Includes all relevant JS except loader scripts.
@@ -90,7 +88,10 @@
9189 * @param $context ResourceLoaderContext object
9290 * @return String: JS
9391 */
94 - public abstract function getScript( ResourceLoaderContext $context );
 92+ public function getScript( ResourceLoaderContext $context ) {
 93+ // Stub, override expected
 94+ return '';
 95+ }
9596
9697 /**
9798 * Get all CSS for this module for a given skin.
@@ -98,7 +99,10 @@
99100 * @param $context ResourceLoaderContext object
100101 * @return array: strings of CSS keyed by media type
101102 */
102 - public abstract function getStyles( ResourceLoaderContext $context );
 103+ public function getStyles( ResourceLoaderContext $context ) {
 104+ // Stub, override expected
 105+ return '';
 106+ }
103107
104108 /**
105109 * Get the messages needed for this module.
@@ -107,14 +111,20 @@
108112 *
109113 * @return array of message keys. Keys may occur more than once
110114 */
111 - public abstract function getMessages();
 115+ public function getMessages() {
 116+ // Stub, override expected
 117+ return array();
 118+ }
112119
113120 /**
114121 * Get the loader JS for this module, if set.
115122 *
116123 * @return Mixed: loader JS (string) or false if no custom loader set
117124 */
118 - public abstract function getLoaderScript();
 125+ public function getLoaderScript() {
 126+ // Stub, override expected
 127+ return '';
 128+ }
119129
120130 /**
121131 * Get a list of modules this module depends on.
@@ -131,8 +141,13 @@
132142 * loader script, see getLoaderScript()
133143 * @return Array of module names (strings)
134144 */
135 - public abstract function getDependencies();
 145+ public function getDependencies() {
 146+ // Stub, override expected
 147+ return array();
 148+ }
136149
 150+ /* Abstract Methods */
 151+
137152 /**
138153 * Get this module's last modification timestamp for a given
139154 * combination of language, skin and debug mode flag. This is typically
@@ -682,58 +697,65 @@
683698 /* Protected Members */
684699
685700 // In-object cache for modified time
686 - protected $modifiedTime = null;
 701+ protected $modifiedTime = array();
687702
688703 /* Abstract Protected Methods */
689704
690705 abstract protected function getPages( ResourceLoaderContext $context );
691706
692 - /* Protected Methods */
693 -
694 - protected function getStyleCode( array $styles ) {
695 - foreach ( $styles as $media => $messages ) {
696 - foreach ( $messages as $i => $message ) {
697 - $style = wfMsgExt( $message, 'content' );
698 - if ( !wfEmptyMsg( $message, $style ) ) {
699 - $styles[$media][$i] = $style;
 707+ /* Methods */
 708+
 709+ public function getScript( ResourceLoaderContext $context ) {
 710+ $scripts = '';
 711+ foreach ( $this->getPages( $context ) as $page => $options ) {
 712+ if ( $options['type'] === 'script' ) {
 713+ $script = wfMsgExt( $page, 'content' );
 714+ $scripts .= "/* MediaWiki:$page */\n" . ( !wfEmptyMsg( $page, $script ) ? $script : '' ) . "\n";
 715+ }
 716+ }
 717+ return $scripts;
 718+ }
 719+
 720+ public function getStyles( ResourceLoaderContext $context ) {
 721+ $styles = array();
 722+ foreach ( $this->getPages( $context ) as $page => $options ) {
 723+ if ( $options['type'] === 'style' ) {
 724+ $media = isset( $options['media'] ) ? $options['media'] : 'all';
 725+ $style = wfMsgExt( $page, 'content' );
 726+ if ( !isset( $styles[$media] ) ) {
 727+ $styles[$media] = '';
700728 }
 729+ $styles[$media] .= "/* MediaWiki:$page */\n" . ( !wfEmptyMsg( $page, $style ) ? $style : '' ) . "\n";
701730 }
702731 }
703 - foreach ( $styles as $media => $messages ) {
704 - $styles[$media] = implode( "\n", $messages );
705 - }
706732 return $styles;
707733 }
708 -
709 - /* Methods */
710 -
 734+
711735 public function getModifiedTime( ResourceLoaderContext $context ) {
712 - if ( isset( $this->modifiedTime[$context->getHash()] ) ) {
713 - return $this->modifiedTime[$context->getHash()];
 736+ $hash = $context->getHash();
 737+ if ( isset( $this->modifiedTime[$hash] ) ) {
 738+ return $this->modifiedTime[$hash];
714739 }
715 - $pages = $this->getPages( $context );
716 - foreach ( $pages as $i => $page ) {
717 - $pages[$i] = Title::makeTitle( NS_MEDIAWIKI, $page );
 740+ $titles = array();
 741+ foreach ( $this->getPages( $context ) as $page => $options ) {
 742+ $titles[] = Title::makeTitle( NS_MEDIAWIKI, $page );
718743 }
719744 // Do batch existence check
720745 // TODO: This would work better if page_touched were loaded by this as well
721 - $lb = new LinkBatch( $pages );
 746+ $lb = new LinkBatch( $titles );
722747 $lb->execute();
723 - $this->modifiedTime = 1; // wfTimestamp() interprets 0 as "now"
724 - foreach ( $pages as $page ) {
725 - if ( $page->exists() ) {
726 - $this->modifiedTime = max( $this->modifiedTime, wfTimestamp( TS_UNIX, $page->getTouched() ) );
 748+ $modifiedTime = 1; // wfTimestamp() interprets 0 as "now"
 749+ foreach ( $titles as $title ) {
 750+ if ( $title->exists() ) {
 751+ $modifiedTime = max( $modifiedTime, wfTimestamp( TS_UNIX, $title->getTouched() ) );
727752 }
728753 }
729 - return $this->modifiedTime;
 754+ return $this->modifiedTime[$hash] = $modifiedTime;
730755 }
731 - public function getMessages() { return array(); }
732 - public function getLoaderScript() { return ''; }
733 - public function getDependencies() { return array(); }
734756 }
735757
736758 /**
737 - * Custom module for site customizations
 759+ * Module for site customizations
738760 */
739761 class ResourceLoaderSiteModule extends ResourceLoaderWikiModule {
740762
@@ -742,49 +764,172 @@
743765 protected function getPages( ResourceLoaderContext $context ) {
744766 global $wgHandheldStyle;
745767
746 - // HACK: We duplicate the message names from generateUserJs() and generateUserCss here and weird things (i.e.
747 - // mtime moving backwards) can happen when a MediaWiki:Something.js page is deleted
748768 $pages = array(
749 - 'Common.js',
750 - 'Common.css',
751 - ucfirst( $context->getSkin() ) . '.js',
752 - ucfirst( $context->getSkin() ) . '.css',
753 - 'Print.css',
 769+ 'Common.js' => array( 'type' => 'script' ),
 770+ 'Common.css' => array( 'type' => 'style' ),
 771+ ucfirst( $context->getSkin() ) . '.js' => array( 'type' => 'script' ),
 772+ ucfirst( $context->getSkin() ) . '.css' => array( 'type' => 'style' ),
 773+ 'Print.css' => array( 'type' => 'style', 'media' => 'print' ),
754774 );
755775 if ( $wgHandheldStyle ) {
756 - $pages[] = 'Handheld.css';
 776+ $pages['Handheld.css'] = array( 'type' => 'style', 'media' => 'handheld' );
757777 }
758778 return $pages;
759779 }
 780+}
760781
 782+/**
 783+ * Module for user customizations
 784+ */
 785+class ResourceLoaderUserModule extends ResourceLoaderWikiModule {
 786+
 787+ /* Protected Methods */
 788+
 789+ protected function getPages( ResourceLoaderContext $context ) {
 790+ global $wgAllowUserCss;
 791+
 792+ if ( $context->getUser() && $wgAllowUserCss ) {
 793+ $user = User::newFromName( $context->getUser() );
 794+ $userPage = $user->getUserPage()->getPrefixedText();
 795+ return array(
 796+ "$userPage/common.css" => array( 'type' => 'style' ),
 797+ "$userPage/" . $context->getSkin() . '.css' => array( 'type' => 'style' ),
 798+ );
 799+ }
 800+ return array();
 801+ }
 802+}
 803+
 804+/**
 805+ * Module for user preference customizations
 806+ */
 807+class ResourceLoaderUserPreferencesModule extends ResourceLoaderModule {
 808+
 809+ /* Protected Members */
 810+
 811+ protected $modifiedTime = array();
 812+
761813 /* Methods */
762814
763 - public function getScript( ResourceLoaderContext $context ) {
764 - return Skin::newFromKey( $context->getSkin() )->generateUserJs();
 815+ public function getModifiedTime( ResourceLoaderContext $context ) {
 816+ $hash = $context->getHash();
 817+ if ( isset( $this->modifiedTime[$hash] ) ) {
 818+ return $this->modifiedTime[$hash];
 819+ }
 820+ $user = User::newFromName( $context->getUser() );
 821+ return $this->modifiedTime[$hash] = $user->getTouched();
765822 }
766823
767824 public function getStyles( ResourceLoaderContext $context ) {
768 - global $wgHandheldStyle;
769 - $styles = array(
770 - 'all' => array( 'Common.css', $context->getSkin() . '.css' ),
771 - 'print' => array( 'Print.css' ),
772 - );
773 - if ( $wgHandheldStyle ) {
774 - $sources['handheld'] = array( 'Handheld.css' );
 825+ global $wgAllowUserCssPrefs;
 826+ if ( $wgAllowUserCssPrefs ) {
 827+ $user = User::newFromName( $context->getUser() );
 828+ $rules = array();
 829+ if ( ( $underline = $user->getOption( 'underline' ) ) < 2 ) {
 830+ $rules[] = "a { text-decoration: " . ( $underline ? 'underline' : 'none' ) . "; }";
 831+ }
 832+ if ( $user->getOption( 'highlightbroken' ) ) {
 833+ $rules[] = "a.new, #quickbar a.new { color: #CC2200; }\n";
 834+ } else {
 835+ $rules[] = "a.new, #quickbar a.new, a.stub, #quickbar a.stub { color: inherit; }";
 836+ $rules[] = "a.new:after, #quickbar a.new:after { content: '?'; color: #CC2200; }";
 837+ $rules[] = "a.stub:after, #quickbar a.stub:after { content: '!'; color: #772233; }";
 838+ }
 839+ if ( $user->getOption( 'justify' ) ) {
 840+ $rules[] = "#article, #bodyContent, #mw_content { text-align: justify; }\n";
 841+ }
 842+ if ( !$user->getOption( 'showtoc' ) ) {
 843+ $rules[] = "#toc { display: none; }\n";
 844+ }
 845+ if ( !$user->getOption( 'editsection' ) ) {
 846+ $rules[] = ".editsection { display: none; }\n";
 847+ }
 848+ if ( ( $fontstyle = $user->getOption( 'editfont' ) ) !== 'default' ) {
 849+ $rules[] = "textarea { font-family: $fontstyle; }\n";
 850+ }
 851+ return array( 'all' => implode( "\n", $rules ) );
775852 }
776 - return $this->getStyleCode( $styles );
 853+ return array();
777854 }
 855+
 856+ public function getFlip( $context ) {
 857+ global $wgContLang;
 858+
 859+ return $wgContLang->getDir() !== $context->getDirection();
 860+ }
778861 }
779862
780863 class ResourceLoaderStartUpModule extends ResourceLoaderModule {
781864 /* Protected Members */
782865
783 - protected $modifiedTime = null;
 866+ protected $modifiedTime = array();
784867
 868+ /* Protected Methods */
 869+
 870+ protected function getConfig( $context ) {
 871+ global $wgLoadScript, $wgScript, $wgStylePath, $wgScriptExtension, $wgArticlePath, $wgScriptPath, $wgServer,
 872+ $wgContLang, $wgBreakFrames, $wgVariantArticlePath, $wgActionPaths, $wgUseAjax, $wgAjaxWatch, $wgVersion,
 873+ $wgEnableAPI, $wgEnableWriteAPI, $wgDBname, $wgEnableMWSuggest, $wgSitename, $wgFileExtensions;
 874+
 875+ // Pre-process information
 876+ $separatorTransTable = $wgContLang->separatorTransformTable();
 877+ $separatorTransTable = $separatorTransTable ? $separatorTransTable : array();
 878+ $compactSeparatorTransTable = array(
 879+ implode( "\t", array_keys( $separatorTransTable ) ),
 880+ implode( "\t", $separatorTransTable ),
 881+ );
 882+ $digitTransTable = $wgContLang->digitTransformTable();
 883+ $digitTransTable = $digitTransTable ? $digitTransTable : array();
 884+ $compactDigitTransTable = array(
 885+ implode( "\t", array_keys( $digitTransTable ) ),
 886+ implode( "\t", $digitTransTable ),
 887+ );
 888+ $mainPage = Title::newMainPage();
 889+
 890+ // Build list of variables
 891+ $vars = array(
 892+ 'wgLoadScript' => $wgLoadScript,
 893+ 'debug' => $context->getDebug(),
 894+ 'skin' => $context->getSkin(),
 895+ 'stylepath' => $wgStylePath,
 896+ 'wgUrlProtocols' => wfUrlProtocols(),
 897+ 'wgArticlePath' => $wgArticlePath,
 898+ 'wgScriptPath' => $wgScriptPath,
 899+ 'wgScriptExtension' => $wgScriptExtension,
 900+ 'wgScript' => $wgScript,
 901+ 'wgVariantArticlePath' => $wgVariantArticlePath,
 902+ 'wgActionPaths' => $wgActionPaths,
 903+ 'wgServer' => $wgServer,
 904+ 'wgUserLanguage' => $context->getLanguage(),
 905+ 'wgContentLanguage' => $wgContLang->getCode(),
 906+ 'wgBreakFrames' => $wgBreakFrames,
 907+ 'wgVersion' => $wgVersion,
 908+ 'wgEnableAPI' => $wgEnableAPI,
 909+ 'wgEnableWriteAPI' => $wgEnableWriteAPI,
 910+ 'wgSeparatorTransformTable' => $compactSeparatorTransTable,
 911+ 'wgDigitTransformTable' => $compactDigitTransTable,
 912+ 'wgMainPageTitle' => $mainPage ? $mainPage->getPrefixedText() : null,
 913+ 'wgFormattedNamespaces' => $wgContLang->getFormattedNamespaces(),
 914+ 'wgNamespaceIds' => $wgContLang->getNamespaceIds(),
 915+ 'wgSiteName' => $wgSitename,
 916+ 'wgFileExtensions' => $wgFileExtensions,
 917+ );
 918+ if ( $wgContLang->hasVariants() ) {
 919+ $vars['wgUserVariant'] = $wgContLang->getPreferredVariant();
 920+ }
 921+ if ( $wgUseAjax && $wgEnableMWSuggest ) {
 922+ $vars['wgMWSuggestTemplate'] = SearchEngine::getMWSuggestTemplate();
 923+ $vars['wgDBname'] = $wgDBname;
 924+ $vars['wgSearchNamespaces'] = SearchEngine::userNamespaces( $wgUser );
 925+ }
 926+
 927+ return $vars;
 928+ }
 929+
785930 /* Methods */
786931
787932 public function getScript( ResourceLoaderContext $context ) {
788 - global $IP;
 933+ global $IP, $wgStylePath, $wgLoadScript;
789934
790935 $scripts = file_get_contents( "$IP/resources/startup.js" );
791936
@@ -792,9 +937,7 @@
793938 // Get all module registrations
794939 $registration = ResourceLoader::getModuleRegistrations( $context );
795940 // Build configuration
796 - $config = FormatJson::encode(
797 - array( 'server' => $context->getServer(), 'debug' => $context->getDebug() )
798 - );
 941+ $config = FormatJson::encode( $this->getConfig( $context ) );
799942 // Add a well-known start-up function
800943 $scripts .= "window.startUp = function() { $registration mediaWiki.config.set( $config ); };";
801944 // Build load query for jquery and mediawiki modules
@@ -814,7 +957,7 @@
815958 );
816959
817960 // Build HTML code for loading jquery and mediawiki modules
818 - $loadScript = Html::linkedScript( $context->getServer() . "?$query" );
 961+ $loadScript = Html::linkedScript( "$wgLoadScript?$query" );
819962 // Add code to add jquery and mediawiki loading code; only if the current client is compatible
820963 $scripts .= "if ( isCompatible() ) { document.write( '$loadScript' ); }";
821964 // Delete the compatible function - it's not needed anymore
@@ -827,14 +970,15 @@
828971 public function getModifiedTime( ResourceLoaderContext $context ) {
829972 global $IP;
830973
831 - if ( !is_null( $this->modifiedTime ) ) {
832 - return $this->modifiedTime;
 974+ $hash = $context->getHash();
 975+ if ( isset( $this->modifiedTime[$hash] ) ) {
 976+ return $this->modifiedTime[$hash];
833977 }
834 -
835 - // HACK getHighestModifiedTime() calls this function, so protect against infinite recursion
836 - $this->modifiedTime = filemtime( "$IP/resources/startup.js" );
837 - $this->modifiedTime = ResourceLoader::getHighestModifiedTime( $context );
838 - return $this->modifiedTime;
 978+ $this->modifiedTime[$hash] = filemtime( "$IP/resources/startup.js" );
 979+ // ATTENTION!: Because of the line above, this is not going to cause infinite recursion - think carefully
 980+ // before making changes to this code!
 981+ $this->modifiedTime[$hash] = ResourceLoader::getHighestModifiedTime( $context );
 982+ return $this->modifiedTime[$hash];
839983 }
840984
841985 public function getClientMaxage() {
@@ -845,14 +989,9 @@
846990 return 300; // 5 minutes
847991 }
848992
849 - public function getStyles( ResourceLoaderContext $context ) { return array(); }
850 -
851993 public function getFlip( $context ) {
852994 global $wgContLang;
853995
854996 return $wgContLang->getDir() !== $context->getDirection();
855997 }
856 - public function getMessages() { return array(); }
857 - public function getLoaderScript() { return ''; }
858 - public function getDependencies() { return array(); }
859998 }
Index: trunk/phase3/load.php
@@ -45,7 +45,7 @@
4646 }
4747
4848 // Respond to resource loading request
49 -ResourceLoader::respond( new ResourceLoaderContext( $wgRequest, $wgServer . $wgScriptPath . '/load.php' ) );
 49+ResourceLoader::respond( new ResourceLoaderContext( $wgRequest ) );
5050
5151 wfProfileOut( 'load.php' );
5252 wfLogProfilingData();
Index: trunk/phase3/resources/Resources.php
@@ -6,6 +6,8 @@
77
88 'site' => new ResourceLoaderSiteModule,
99 'startup' => new ResourceLoaderStartUpModule,
 10+ 'user' => new ResourceLoaderUserModule,
 11+ 'user.preferences' => new ResourceLoaderUserPreferencesModule,
1012
1113 /* Skins */
1214
@@ -356,6 +358,7 @@
357359 'mediawiki.legacy.mwsuggest' => new ResourceLoaderFileModule( array(
358360 'scripts' => 'skins/common/mwsuggest.js',
359361 'dependencies' => 'mediawiki.legacy.wikibits',
 362+ 'messages' => array( 'search-mwsuggest-enabled', 'search-mwsuggest-disabled' ),
360363 ) ),
361364 'mediawiki.legacy.password' => new ResourceLoaderFileModule( array(
362365 'scripts' => 'skins/common/password.js',
Index: trunk/phase3/resources/mediawiki/mediawiki.js
@@ -469,7 +469,7 @@
470470 var html = '';
471471 for ( var r = 0; r < requests.length; r++ ) {
472472 // Build out the HTML
473 - var src = mediaWiki.config.get( 'server' ) + '?' + $.param( requests[r] );
 473+ var src = mediaWiki.config.get( 'wgLoadScript' ) + '?' + $.param( requests[r] );
474474 html += '<script type="text/javascript" src="' + src + '"></script>';
475475 }
476476 return html;

Follow-up revisions

RevisionCommit summaryAuthorDate
r72776Fixed user scripts/styles and site scripts/styles - they were totally broken ...tparscal07:33, 11 September 2010

Past revisions this follows-up on

RevisionCommit summaryAuthorDate
r72763Applied patch for bug #25044 by Niklas Laxström -- THANKS!tparscal21:51, 10 September 2010

Comments

#Comment by Raymond (talk | contribs)   05:22, 11 September 2010

This or one of the previous revisions break user site CSS: seems not to be loaded, at least it is not working.

Compare HTHML heads section running r72743 http://dpaste.org/4UZN/

with

running r72772 http://dpaste.org/u9w8/

#Comment by Trevor Parscal (WMF) (talk | contribs)   07:34, 11 September 2010

Yes, I was coding in too much of a hurry (trying to get out of the office to go to dinner...) and I missed some glaring issues. Things are fixed in r72776.

#Comment by Catrope (talk | contribs)   16:17, 27 September 2010

Please don't mark a revision 'resolved' in this case, unless you have reviewed both the revision and the fixes (in this case, you authored both of them so you can't review them). If you believe all outstanding issues have been addressed but haven't actually reviewed the code, set the status back to 'new'.

#Comment by Trevor Parscal (WMF) (talk | contribs)   18:45, 27 September 2010

Fair enough - I think this is an area where code review is lacking. There should be a way to say I've addressed this but it needs additional oversight.

#Comment by Catrope (talk | contribs)   18:47, 27 September 2010

Currently that's the new -> fixme -> new cycle. The fact that you addressed the errors people got from running your code doesn't really mean it's 'more reviewed' than something else.

Status & tagging log