Start on some cleanup of how CSS stylesheets are loaded. Initially addressing only...
authorBrion Vibber <brion@users.mediawiki.org>
Mon, 28 Jul 2008 05:09:08 +0000 (05:09 +0000)
committerBrion Vibber <brion@users.mediawiki.org>
Mon, 28 Jul 2008 05:09:08 +0000 (05:09 +0000)
* A skin can make calls to $this->addScript to much more cleanly list which style sheets it wants to load, for which media variants and which IE conditional versions. This replaces the 'cssfiles' array hack and giant pile of ugly conditionals in MonoBook's template.

* 'printable=yes' and 'handheld=yes' URL options are handled transparently -- 'screen' stylesheets are hidden, while those with no media specifier are left.

MediaWiki:Common.css is now listed without media -- so infoboxes are still formatted -- while the skin-specific eg MediaWiki:Monobook.css are listed for screen, as they're specific to the on-screen skin.

Note it should be a matter of one line of code to add a MediaWiki:Print.css and have it correctly handled now.

* All sheets are now loaded via <link rel="stylesheet"> instead of a mix of those and @import decls.

IIRC we had used @import originally to hide styles from Netscape 4, which tends to utterly break on MonoBook, but these days that's pretty much a non-issue.
@import also breaks some browsers' ability to save stylesheets with a file to disk, which sucks.

Confirmed that Firefox 3 can now save pages with their styles.

* 'screen, projection' media specifier has been changed to just 'screen' -- projection is something totally different.

* Added experimental options for specifying handheld stylesheets:

/**
 * Optionally, we can specify a stylesheet to use for media="handheld".
 * This is recognized by some, but not all, handheld/mobile/PDA browsers.
 * If left empty, compliant handheld browsers won't pick up the skin
 * stylesheet, which is specified for 'screen' media.
 *
 * Can be a complete URL, base-relative path, or $wgStylePath-relative path.
 * Try 'chick/main.css' to apply the Chick styles to the MonoBook HTML.
 *
 * Will also be switched in when 'handheld=yes' is added to the URL, like
 * the 'printable=yes' mode for print media.
 */
$wgHandheldStyle = false;

/**
 * If set, 'screen' and 'handheld' media specifiers for stylesheets are
 * transformed such that they apply to the iPhone/iPod Touch Mobile Safari,
 * which doesn't recognize 'handheld' but does support media queries on its
 * screen size.
 *
 * Consider only using this if you have a *really good* handheld stylesheet,
 * as iPhone users won't have any way to disable it and use the "grown-up"
 * styles instead.
 */
$wgHandheldForIPhone = false;

includes/DefaultSettings.php
includes/SkinTemplate.php
skins/Chick.php
skins/MonoBook.php
skins/chick/main.css

index 36690a8..4f77d53 100644 (file)
@@ -2136,6 +2136,32 @@ $wgValidateAllHtml = false;
 /** See list of skins and their symbolic names in languages/Language.php */
 $wgDefaultSkin = 'monobook';
 
+/**
+ * Optionally, we can specify a stylesheet to use for media="handheld".
+ * This is recognized by some, but not all, handheld/mobile/PDA browsers.
+ * If left empty, compliant handheld browsers won't pick up the skin
+ * stylesheet, which is specified for 'screen' media.
+ *
+ * Can be a complete URL, base-relative path, or $wgStylePath-relative path.
+ * Try 'chick/main.css' to apply the Chick styles to the MonoBook HTML.
+ *
+ * Will also be switched in when 'handheld=yes' is added to the URL, like
+ * the 'printable=yes' mode for print media.
+ */
+$wgHandheldStyle = false;
+
+/**
+ * If set, 'screen' and 'handheld' media specifiers for stylesheets are
+ * transformed such that they apply to the iPhone/iPod Touch Mobile Safari,
+ * which doesn't recognize 'handheld' but does support media queries on its
+ * screen size.
+ *
+ * Consider only using this if you have a *really good* handheld stylesheet,
+ * as iPhone users won't have any way to disable it and use the "grown-up"
+ * styles instead.
+ */
+$wgHandheldForIPhone = false;
+
 /**
  * Settings added to this array will override the default globals for the user
  * preferences used by anonymous visitors and newly created accounts.
index c60cfb4..ac56d0f 100644 (file)
@@ -86,12 +86,13 @@ class SkinTemplate extends Skin {
         * will actually fill the template.
         */
        var $template;
-
+       
        /**
-        * An array of strings representing extra CSS files to load.  May include:
-        * 'IE', 'IE50', 'IE55', 'IE60', 'IE70', 'rtl'.
+        * An array of stylesheet filenames (relative from skins path), with options
+        * for CSS media, IE conditions, and RTL/LTR direction.
+        * For internal use; add settings in the skin via $this->addStyle()
         */
-       var $cssfiles;
+       var $styles = array();
 
        /**#@-*/
 
@@ -107,7 +108,9 @@ class SkinTemplate extends Skin {
                $this->skinname  = 'monobook';
                $this->stylename = 'monobook';
                $this->template  = 'QuickTemplate';
-               $this->cssfiles = array();
+               
+               $this->addStyle( 'common/shared.css', 'screen' );
+               $this->addStyle( 'common/commonPrint.css', 'print' );
        }
 
        /**
@@ -247,6 +250,8 @@ class SkinTemplate extends Skin {
                $tpl->set( 'skinclass', get_class( $this ) );
                $tpl->setRef( 'stylename', $this->stylename );
                $tpl->set( 'printable', $wgRequest->getBool( 'printable' ) );
+               $tpl->set( 'handheld', $wgRequest->getBool( 'handheld' ) );
+               $tpl->set( 'csslinks', $this->buildCssLinks() );
                $tpl->setRef( 'loggedin', $this->loggedin );
                $tpl->set('nsclass', 'ns-'.$this->mTitle->getNamespace());
                $tpl->set('notspecialpage', $this->mTitle->getNamespace() != NS_SPECIAL);
@@ -274,7 +279,6 @@ class SkinTemplate extends Skin {
                $tpl->setRef( 'userpageurl', $this->userpageUrlDetails['href']);
                $tpl->set( 'userlang', $wgLang->getCode() );
                $tpl->set( 'pagecss', $this->setupPageCss() );
-               $tpl->set( 'printcss', $this->getPrintCss() );
                $tpl->setRef( 'usercss', $this->usercss);
                $tpl->setRef( 'userjs', $this->userjs);
                $tpl->setRef( 'userjsprev', $this->userjsprev);
@@ -964,54 +968,49 @@ class SkinTemplate extends Skin {
 
                global $wgRequest, $wgAllowUserCss, $wgUseSiteCss, $wgContLang, $wgSquidMaxage, $wgStylePath, $wgUser;
 
-               $sitecss = '';
                $usercss = '';
                $siteargs = '&maxage=' . $wgSquidMaxage;
                if( $this->loggedin ) {
                        // Ensure that logged-in users' generated CSS isn't clobbered
                        // by anons' publicly cacheable generated CSS.
                        $siteargs .= '&smaxage=0';
-               }
-
-               # Add user-specific code if this is a user and we allow that kind of thing
-
-               if ( $wgAllowUserCss && $this->loggedin ) {
-                       $action = $wgRequest->getText('action');
-
-                       # if we're previewing the CSS page, use it
-                       if( $this->mTitle->isCssSubpage() and $this->userCanPreview( $action ) ) {
-                               $siteargs = "&smaxage=0&maxage=0";
-                               $usercss = $wgRequest->getText('wpTextbox1');
-                       } else {
-                               $usercss = '@import "' .
-                                 self::makeUrl($this->userpage . '/'.$this->skinname.'.css',
-                                                                'action=raw&ctype=text/css') . '";' ."\n";
-                       }
-
                        $siteargs .= '&ts=' . $wgUser->mTouched;
                }
 
-               if( $wgContLang->isRTL() && in_array( 'rtl', $this->cssfiles ) ) {
-                       global $wgStyleVersion;
-                       $sitecss .= "@import \"$wgStylePath/$this->stylename/rtl.css?$wgStyleVersion\";\n";
-               }
-
                # If we use the site's dynamic CSS, throw that in, too
+               // Per-site custom styles
                if ( $wgUseSiteCss ) {
                        $query = "usemsgcache=yes&action=raw&ctype=text/css&smaxage=$wgSquidMaxage";
                        $skinquery = '';
                        if (($us = $wgRequest->getVal('useskin', '')) !== '')
                                $skinquery = "&useskin=$us";
-                       $sitecss .= '@import "' . self::makeNSUrl( 'Common.css', $query, NS_MEDIAWIKI) . '";' . "\n";
-                       $sitecss .= '@import "' . self::makeNSUrl( ucfirst( $this->skinname ) . '.css', $query, NS_MEDIAWIKI ) . '";' . "\n";
-                       $sitecss .= '@import "' . self::makeUrl( '-', "action=raw&gen=css$siteargs$skinquery" ) . '";' . "\n";
+                       
+                       $this->addStyle( self::makeNSUrl( 'Common.css', $query, NS_MEDIAWIKI) );
+                       $this->addStyle( self::makeNSUrl( ucfirst( $this->skinname ) . '.css', $query, NS_MEDIAWIKI ),
+                               'screen' );
                }
 
-               # If we use any dynamic CSS, make a little CDATA block out of it.
+               // Per-user styles based on preferences
+               $this->addStyle( self::makeUrl( '-', "action=raw&gen=css$siteargs$skinquery" ), 'screen' );
+
+               // Per-user custom style pages
+               if ( $wgAllowUserCss && $this->loggedin ) {
+                       $action = $wgRequest->getVal('action');
 
-               if ( !empty($sitecss) || !empty($usercss) ) {
-                       $this->usercss = "/*<![CDATA[*/\n" . $sitecss . $usercss . '/*]]>*/';
+                       # if we're previewing the CSS page, use it
+                       if( $this->mTitle->isCssSubpage() and $this->userCanPreview( $action ) ) {
+                               $previewCss = $wgRequest->getText('wpTextbox1');
+                               
+                               /// @fixme properly escape the cdata!
+                               $this->usercss = "/*<![CDATA[*/\n" .
+                                       $previewCss .
+                                       "/*]]>*/";
+                       } else {
+                               $this->addStyle( self::makeUrl($this->userpage . '/'.$this->skinname.'.css',
+                                                                'action=raw&ctype=text/css'), 'screen' );
+                       }
                }
+               
                wfProfileOut( __METHOD__ );
        }
 
@@ -1062,17 +1061,6 @@ class SkinTemplate extends Skin {
                return $s;
        }
 
-       /**
-        * Returns the print stylesheet for this skin.  In all default skins this
-        * is just commonPrint.css, but third-party skins may want to modify it.
-        *
-        * @return string
-        */
-       protected function getPrintCss() {
-               global $wgStylePath;
-               return $wgStylePath . "/common/commonPrint.css";
-       }
-
        /**
         * This returns MediaWiki:Common.js and MediaWiki:[Skinname].js concate-
         * nated together.  For some bizarre reason, it does *not* return any
@@ -1102,6 +1090,118 @@ class SkinTemplate extends Skin {
                wfProfileOut( __METHOD__ );
                return $s;
        }
+       
+       /**
+        * Add a local or specified stylesheet, with the given media options.
+        * Meant primarily for internal use...
+        *
+        * @param $media -- to specify a media type, 'screen', 'printable', 'handheld' or any.
+        * @param $conditional -- for IE conditional comments, specifying an IE version
+        * @param $dir -- set to 'rtl' or 'ltr' for direction-specific sheets
+        */
+       public function addStyle( $style, $media='', $condition='', $dir='' ) {
+               $options = array();
+               if( $media )
+                       $options['media'] = $media;
+               if( $condition )
+                       $options['condition'] = $condition;
+               if( $dir )
+                       $options['dir'] = $dir;
+               $this->styles[$style] = $options;
+       }
+
+       /**
+        * Build a set of <link>s for the stylesheets specified in the $this->styles array.
+        * These will be applied to various media & IE conditionals.
+        */
+       protected function buildCssLinks() {
+               global $wgContLang;
+               
+               foreach( $this->styles as $file => $options ) {
+                       $links[] = $this->styleLink( $file, $options );
+               }
+               
+               return implode( "\n", $links );
+       }
+       
+       protected function styleLink( $style, $options ) {
+               global $wgRequest;
+               
+               if( isset( $options['dir'] ) ) {
+                       global $wgContLang;
+                       $siteDir = $wgContLang->isRTL() ? 'rtl' : 'ltr';
+                       if( $siteDir != $options['dir'] )
+                               return '';
+               }
+               
+               if( isset( $options['media'] ) ) {
+                       $media = $this->transformCssMedia( $options['media'] );
+                       if( is_null( $media ) ) {
+                               return '';
+                       }
+               } else {
+                       $media = '';
+               }
+               
+               if( substr( $style, 0, 1 ) == '/' ||
+                       substr( $style, 0, 5 ) == 'http:' ||
+                       substr( $style, 0, 6 ) == 'https:' ) {
+                       $url = $style;
+               } else {
+                       global $wgStylePath, $wgStyleVersion;
+                       $url = $wgStylePath . '/' . $style . '?' . $wgStyleVersion;
+               }
+               
+               $attribs = array(
+                       'rel' => 'stylesheet',
+                       'href' => $url,
+                       'type' => 'text/css' );
+               if( $media ) {
+                       $attribs['media'] = $media;
+               }
+
+               $link = Xml::element( 'link', $attribs );
+
+               if( isset( $options['condition'] ) ) {
+                       $condition = htmlspecialchars( $options['condition'] );
+                       $link = "<!--[if $condition]>$link<![endif]-->";
+               }
+               return $link;
+       }
+       
+       function transformCssMedia( $media ) {
+               global $wgRequest, $wgHandheldForIPhone;
+               
+               // Switch in on-screen display for media testing
+               $switches = array(
+                       'printable' => 'print',
+                       'handheld' => 'handheld',
+               );
+               foreach( $switches as $switch => $targetMedia ) {
+                       if( $wgRequest->getBool( $switch ) ) {
+                               if( $media == $targetMedia ) {
+                                       $media = '';
+                               } elseif( $media == 'screen' ) {
+                                       return null;
+                               }
+                       }
+               }
+               
+               // Expand longer media queries as iPhone doesn't grok 'handheld'
+               if( $wgHandheldForIPhone ) {
+                       $mediaAliases = array(
+                               'screen' => 'screen and (min-device-width: 481px)',
+                               'handheld' => 'handheld, only screen and (max-device-width: 480px)',
+                       );
+               
+                       if( isset( $mediaAliases[$media] ) ) {
+                               $media = $mediaAliases[$media];
+                       }
+               }
+               
+               return $media;
+       }
+
 }
 
 /**
index cfbdbc7..1ad6c7e 100644 (file)
@@ -23,7 +23,12 @@ class SkinChick extends SkinTemplate {
                $this->skinname  = 'chick';
                $this->stylename = 'chick';
                $this->template  = 'MonoBookTemplate';
-               $this->fixfiles  = array( 'IE50', 'IE55', 'IE60' );
+
+               // Append to the default screen common & print styles...
+               $this->addStyle( 'chick/main.css', 'screen,handheld' );
+               $this->addStyle( 'chick/IE50Fixes.css', 'screen,handheld', 'lt IE 5.5000' );
+               $this->addStyle( 'chick/IE55Fixes.css', 'screen,handheld', 'IE 5.5000' );
+               $this->addStyle( 'chick/IE60Fixes.css', 'screen,handheld', 'IE 6' );
        }
 }
 
index a0b3157..edf85ac 100644 (file)
@@ -21,13 +21,26 @@ if( !defined( 'MEDIAWIKI' ) )
 class SkinMonoBook extends SkinTemplate {
        /** Using monobook. */
        function initPage( &$out ) {
+               global $wgHandheldStyle;
+               
                SkinTemplate::initPage( $out );
                $this->skinname  = 'monobook';
                $this->stylename = 'monobook';
                $this->template  = 'MonoBookTemplate';
-               # Bug 14520: skins that just include this file shouldn't load nonexis-
-               # tent CSS fix files.
-               $this->cssfiles = array( 'IE', 'IE50', 'IE55', 'IE60', 'IE70', 'rtl' );
+               
+               // Append to the default screen common & print styles...
+               $this->addStyle( 'monobook/main.css', 'screen' );
+               if( $wgHandheldStyle ) {
+                       // Currently in testing... try 'chick/main.css'
+                       $this->addStyle( $wgHandheldStyle, 'handheld' );
+               }
+               
+               $this->addStyle( 'monobook/IE50Fixes.css', 'screen', 'lt IE 5.5000' );
+               $this->addStyle( 'monobook/IE55Fixes.css', 'screen', 'IE 5.5000' );
+               $this->addStyle( 'monobook/IE60Fixes.css', 'screen', 'IE 6' );
+               $this->addStyle( 'monobook/IE70Fixes.css', 'screen', 'IE 7' );
+               
+               $this->addStyle( 'monobook/rtl.css', 'screen', '', 'rtl' );
        }
 }
 
@@ -62,17 +75,10 @@ class MonoBookTemplate extends QuickTemplate {
                <meta http-equiv="Content-Type" content="<?php $this->text('mimetype') ?>; charset=<?php $this->text('charset') ?>" />
                <?php $this->html('headlinks') ?>
                <title><?php $this->text('pagetitle') ?></title>
-               <style type="text/css" media="screen, projection">/*<![CDATA[*/
-                       @import "<?php $this->text('stylepath') ?>/common/shared.css?<?php echo $GLOBALS['wgStyleVersion'] ?>";
-                       @import "<?php $this->text('stylepath') ?>/<?php $this->text('stylename') ?>/main.css?<?php echo $GLOBALS['wgStyleVersion'] ?>";
-               /*]]>*/</style>
-               <link rel="stylesheet" type="text/css" <?php if(empty($this->data['printable']) ) { ?>media="print"<?php } ?> href="<?php $this->text('printcss') ?>?<?php echo $GLOBALS['wgStyleVersion'] ?>" />
-               <?php if( in_array( 'IE50', $skin->cssfiles ) ) { ?><!--[if lt IE 5.5000]><style type="text/css">@import "<?php $this->text('stylepath') ?>/<?php $this->text('stylename') ?>/IE50Fixes.css?<?php echo $GLOBALS['wgStyleVersion'] ?>";</style><![endif]-->
-               <?php } if( in_array( 'IE55', $skin->cssfiles ) ) { ?><!--[if IE 5.5000]><style type="text/css">@import "<?php $this->text('stylepath') ?>/<?php $this->text('stylename') ?>/IE55Fixes.css?<?php echo $GLOBALS['wgStyleVersion'] ?>";</style><![endif]-->
-               <?php } if( in_array( 'IE60', $skin->cssfiles ) ) { ?><!--[if IE 6]><style type="text/css">@import "<?php $this->text('stylepath') ?>/<?php $this->text('stylename') ?>/IE60Fixes.css?<?php echo $GLOBALS['wgStyleVersion'] ?>";</style><![endif]-->
-               <?php } if( in_array( 'IE70', $skin->cssfiles ) ) { ?><!--[if IE 7]><style type="text/css">@import "<?php $this->text('stylepath') ?>/<?php $this->text('stylename') ?>/IE70Fixes.css?<?php echo $GLOBALS['wgStyleVersion'] ?>";</style><![endif]-->
-               <?php } ?><!--[if lt IE 7]><?php if( in_array( 'IE', $skin->cssfiles ) ) { ?><script type="<?php $this->text('jsmimetype') ?>" src="<?php $this->text('stylepath') ?>/common/IEFixes.js?<?php echo $GLOBALS['wgStyleVersion'] ?>"></script>
-               <?php } ?><meta http-equiv="imagetoolbar" content="no" /><![endif]-->
+<?php $this->html('csslinks') ?>
+
+               <!--[if lt IE 7]><script type="<?php $this->text('jsmimetype') ?>" src="<?php $this->text('stylepath') ?>/common/IEFixes.js?<?php echo $GLOBALS['wgStyleVersion'] ?>"></script>
+               <meta http-equiv="imagetoolbar" content="no" /><![endif]-->
                
                <?php print Skin::makeGlobalVariablesScript( $this->data ); ?>
                 
index 9ba9792..ed11bc2 100644 (file)
@@ -419,7 +419,7 @@ div.gallerytext {
         padding: 2px 4px;
 }       
 
-#jump-to-nav {
+#xjump-to-nav {
   display: none;
 }
 
@@ -430,3 +430,21 @@ div#mw-upload-deleted-warn ul li,
 div#mw-recreate-deleted-warn ul li {
        font-size: 95%;
 }
+
+
+.printfooter {
+       display: none;
+}
+
+#footer {
+       background-color: white;
+       border-top: 1px solid #fabd23;
+       border-bottom: 1px solid #fabd23;
+       margin: .6em 0 1em 0;
+       padding: .4em 0 1.2em 0;
+       text-align: center;
+       font-size: 90%;
+}
+#f-poweredbyico, #f-copyrightico {
+       display: inline;
+}
\ No newline at end of file