Revert r104659 and its followup r104665: break the unit tests with a fatal error...
[lhc/web/wiklou.git] / includes / OutputPage.php
index 0a81ecd..feae2c1 100644 (file)
@@ -67,7 +67,7 @@ class OutputPage extends ContextSource {
         * Contains the page subtitle. Special pages usually have some links here.
         * Don't confuse with site subtitle added by skins.
         */
-       var $mSubtitle = '';
+       private $mSubtitle = array();
 
        var $mRedirect = '';
        var $mStatusCode;
@@ -222,6 +222,14 @@ class OutputPage extends ContextSource {
                'Cookie' => null
        );
 
+       /**
+        * If the current page was reached through a redirect, $mRedirectedFrom contains the Title
+        * of the redirect.
+        *
+        * @var Title
+        */
+       private $mRedirectedFrom = null;
+
        /**
         * Constructor for OutputPage. This should not be called directly.
         * Instead a new RequestContext should be created and it will implicitly create
@@ -776,6 +784,15 @@ class OutputPage extends ContextSource {
                return $this->mHTMLtitle;
        }
 
+       /**
+        * Set $mRedirectedFrom, the Title of the page which redirected us to the current page.
+        *
+        * param @t Title
+        */
+       public function setRedirectedFrom( $t ) {
+               $this->mRedirectedFrom = $t;
+       }
+
        /**
         * "Page title" means the contents of \<h1\>. It is stored as a valid HTML fragment.
         * This function allows good tags like \<sup\> in the \<h1\> tag, but not bad tags like \<script\>.
@@ -820,19 +837,54 @@ class OutputPage extends ContextSource {
        /**
         * Replace the subtile with $str
         *
-        * @param $str String: new value of the subtitle
+        * @param $str String|Message: new value of the subtitle
         */
        public function setSubtitle( $str ) {
-               $this->mSubtitle = /*$this->parse(*/ $str /*)*/; // @bug 2514
+               $this->clearSubtitle();
+               $this->addSubtitle( $str );
        }
 
        /**
         * Add $str to the subtitle
         *
-        * @param $str String to add to the subtitle
+        * @deprecated in 1.19; use addSubtitle() instead
+        * @param $str String|Message to add to the subtitle
         */
        public function appendSubtitle( $str ) {
-               $this->mSubtitle .= /*$this->parse(*/ $str /*)*/; // @bug 2514
+               $this->addSubtitle( $str );
+       }
+
+       /**
+        * Add $str to the subtitle
+        *
+        * @param $str String|Message to add to the subtitle
+        */
+       public function addSubtitle( $str ) {
+               if ( $str instanceof Message ) {
+                       $this->mSubtitle[] = $str->setContext( $this->getContext() )->parse();
+               } else {
+                       $this->mSubtitle[] = $str;
+               }
+       }
+
+       /**
+        * Add a subtitle containing a backlink to a page
+        *
+        * @param $title Title to link to
+        */
+       public function addBacklinkSubtitle( Title $title ) {
+               $query = array();
+               if ( $title->isRedirect() ) {
+                       $query['redirect'] = 'no';
+               }
+               $this->addSubtitle( $this->msg( 'backlinksubtitle' )->rawParams( Linker::link( $title, null, array(), $query ) ) );
+       }
+
+       /**
+        * Clear the subtitles
+        */
+       public function clearSubtitle() {
+               $this->mSubtitle = array();
        }
 
        /**
@@ -841,7 +893,7 @@ class OutputPage extends ContextSource {
         * @return String
         */
        public function getSubtitle() {
-               return $this->mSubtitle;
+               return implode( "<br />\n\t\t\t\t", $this->mSubtitle );
        }
 
        /**
@@ -1947,6 +1999,7 @@ class OutputPage extends ContextSource {
                $this->setArticleRelated( false );
                $this->enableClientCache( false );
                $this->mRedirect = '';
+               $this->clearSubtitle();
                $this->clearHTML();
        }
 
@@ -1993,7 +2046,13 @@ class OutputPage extends ContextSource {
                        || ( isset( $wgGroupPermissions['autoconfirmed'][$action] ) && $wgGroupPermissions['autoconfirmed'][$action] ) )
                ) {
                        $displayReturnto = null;
-                       $returnto = $this->getTitle();
+
+                       # Due to bug 32276, if a user does not have read permissions,
+                       # $this->getTitle() will just give Special:Badtitle, which is
+                       # not especially useful as a returnto parameter. Use the title
+                       # from the request instead, if there was one.
+                       $request = $this->getRequest();
+                       $returnto = Title::newFromURL( $request->getVal( 'title', '' ) );
                        if ( $action == 'edit' ) {
                                $msg = 'whitelistedittext';
                                $displayReturnto = $returnto;
@@ -2007,9 +2066,10 @@ class OutputPage extends ContextSource {
                        }
 
                        $query = array();
+
                        if ( $returnto ) {
                                $query['returnto'] = $returnto->getPrefixedText();
-                               $request = $this->getRequest();
+
                                if ( !$request->wasPosted() ) {
                                        $returntoquery = $request->getValues();
                                        unset( $returntoquery['title'] );
@@ -2140,10 +2200,8 @@ class OutputPage extends ContextSource {
                if ( !empty( $reasons ) ) {
                        // Permissions error
                        if( $source ) {
-                               $this->setPageTitle( $this->msg( 'viewsource' ) );
-                               $this->setSubtitle(
-                                       $this->msg( 'viewsourcefor', Linker::linkKnown( $this->getTitle() ) )->text()
-                               );
+                               $this->setPageTitle( $this->msg( 'viewsource-title', $this->getTitle()->getPrefixedText() ) );
+                               $this->addBacklinkSubtitle( $this->getTitle() );
                        } else {
                                $this->setPageTitle( $this->msg( 'badaccess' ) );
                        }
@@ -2170,8 +2228,8 @@ class OutputPage extends ContextSource {
                        $this->addHTML( Html::element( 'textarea', $params, $source ) );
 
                        // Show templates used by this article
-                       $article = new Article( $this->getTitle() );
-                       $templates = Linker::formatTemplates( $article->getUsedTemplates() );
+                       $page = WikiPage::factory( $this->getTitle() );
+                       $templates = Linker::formatTemplates( $page->getUsedTemplates() );
                        $this->addHTML( "<div class='templatesUsed'>
 $templates
 </div>
@@ -2210,7 +2268,7 @@ $templates
                                ? 'lag-warn-normal'
                                : 'lag-warn-high';
                        $wrap = Html::rawElement( 'div', array( 'class' => "mw-{$message}" ), "\n$1\n" );
-                       $this->wrapWikiMsg( "$wrap\n", array( $message, $this->getLang()->formatNum( $lag ) ) );
+                       $this->wrapWikiMsg( "$wrap\n", array( $message, $this->getLanguage()->formatNum( $lag ) ) );
                }
        }
 
@@ -2293,15 +2351,15 @@ $templates
         * @return String: The doctype, opening <html>, and head element.
         */
        public function headElement( Skin $sk, $includeStyle = true ) {
-               global $wgContLang, $wgUseTrackbacks;
-               $userdir = $this->getLang()->getDir();
+               global $wgContLang;
+               $userdir = $this->getLanguage()->getDir();
                $sitedir = $wgContLang->getDir();
 
                if ( $sk->commonPrintStylesheet() ) {
                        $this->addModuleStyles( 'mediawiki.legacy.wikiprintable' );
                }
 
-               $ret = Html::htmlHeader( array( 'lang' => $this->getLang()->getCode(), 'dir' => $userdir, 'class' => 'client-nojs' ) );
+               $ret = Html::htmlHeader( array( 'lang' => $this->getLanguage()->getCode(), 'dir' => $userdir, 'class' => 'client-nojs' ) );
 
                if ( $this->getHTMLTitle() == '' ) {
                        $this->setHTMLTitle( $this->msg( 'pagetitle', $this->getPageTitle() ) );
@@ -2322,10 +2380,6 @@ $templates
                        $this->getHeadItems()
                ) );
 
-               if ( $wgUseTrackbacks && $this->isArticleRelated() ) {
-                       $ret .= $this->getTitle()->trackbackRDF();
-               }
-
                $closeHead = Html::closeElement( 'head' );
                if ( $closeHead ) {
                        $ret .= "$closeHead\n";
@@ -2336,7 +2390,7 @@ $templates
                # Classes for LTR/RTL directionality support
                $bodyAttrs['class'] = "mediawiki $userdir sitedir-$sitedir";
 
-               if ( $this->getLang()->capitalizeAllNouns() ) {
+               if ( $this->getLanguage()->capitalizeAllNouns() ) {
                        # A <body> class is probably not the best way to do this . . .
                        $bodyAttrs['class'] .= ' capitalize-all-nouns';
                }
@@ -2442,7 +2496,8 @@ $templates
                foreach ( (array) $modules as $name ) {
                        $module = $resourceLoader->getModule( $name );
                        # Check that we're allowed to include this module on this page
-                       if ( ( $module->getOrigin() > $this->getAllowedModules( ResourceLoaderModule::TYPE_SCRIPTS )
+                       if ( !$module
+                               || ( $module->getOrigin() > $this->getAllowedModules( ResourceLoaderModule::TYPE_SCRIPTS )
                                        && $only == ResourceLoaderModule::TYPE_SCRIPTS )
                                || ( $module->getOrigin() > $this->getAllowedModules( ResourceLoaderModule::TYPE_STYLES )
                                        && $only == ResourceLoaderModule::TYPE_STYLES )
@@ -2470,7 +2525,7 @@ $templates
                        // correct timestamp and emptiness data
                        $query = ResourceLoader::makeLoaderQuery(
                                array(), // modules; not determined yet
-                               $this->getLang()->getCode(),
+                               $this->getLanguage()->getCode(),
                                $this->getSkin()->getSkinName(),
                                $user,
                                null, // version; not determined yet
@@ -2526,7 +2581,7 @@ $templates
 
                        $url = ResourceLoader::makeLoaderURL(
                                array_keys( $modules ),
-                               $this->getLang()->getCode(),
+                               $this->getLanguage()->getCode(),
                                $this->getSkin()->getSkinName(),
                                $user,
                                $version,
@@ -2683,6 +2738,7 @@ $templates
         * - in other words, page-independent/site-wide variables (without state).
         * You will only be adding bloat to the html page and causing page caches to
         * have to be purged on configuration changes.
+        * @return array
         */
        protected function getJSVars() {
                global $wgUseAjax, $wgEnableMWSuggest;
@@ -2696,6 +2752,22 @@ $templates
                        $canonicalName = false; # bug 21115
                }
 
+               $lang = $title->getPageLanguage();
+
+               // Pre-process information
+               $separatorTransTable = $lang->separatorTransformTable();
+               $separatorTransTable = $separatorTransTable ? $separatorTransTable : array();
+               $compactSeparatorTransTable = array(
+                       implode( "\t", array_keys( $separatorTransTable ) ),
+                       implode( "\t", $separatorTransTable ),
+               );
+               $digitTransTable = $lang->digitTransformTable();
+               $digitTransTable = $digitTransTable ? $digitTransTable : array();
+               $compactDigitTransTable = array(
+                       implode( "\t", array_keys( $digitTransTable ) ),
+                       implode( "\t", $digitTransTable ),
+               );
+
                $vars = array(
                        'wgCanonicalNamespace' => $nsname,
                        'wgCanonicalSpecialPageName' => $canonicalName,
@@ -2710,8 +2782,10 @@ $templates
                        'wgUserGroups' => $this->getUser()->getEffectiveGroups(),
                        'wgCategories' => $this->getCategories(),
                        'wgBreakFrames' => $this->getFrameOptions() == 'DENY',
+                       'wgPageContentLanguage' => $lang->getCode(),
+                       'wgSeparatorTransformTable' => $compactSeparatorTransTable,
+                       'wgDigitTransformTable' => $compactDigitTransTable,
                );
-               $lang = $this->getTitle()->getPageLanguage();
                if ( $lang->hasVariants() ) {
                        $vars['wgUserVariant'] = $lang->getPreferredVariant();
                }
@@ -2724,6 +2798,9 @@ $templates
                if ( $title->isMainPage() ) {
                        $vars['wgIsMainPage'] = true;
                }
+               if ( $this->mRedirectedFrom ) {
+                       $vars['wgRedirectedFrom'] = $this->mRedirectedFrom->getPrefixedDBKey();
+               }
 
                // Allow extensions to add their custom variables to the mw.config map.
                // Use the 'ResourceLoaderGetConfigVars' hook if the variable is not
@@ -2841,9 +2918,10 @@ $templates
                }
 
                # Universal edit button
-               if ( $wgUniversalEditButton ) {
-                       if ( $this->isArticleRelated() && $this->getTitle() && $this->getTitle()->quickUserCan( 'edit' )
-                               && ( $this->getTitle()->exists() || $this->getTitle()->quickUserCan( 'create' ) ) ) {
+               if ( $wgUniversalEditButton && $this->isArticleRelated() ) {
+                       $user = $this->getUser();
+                       if ( $this->getTitle()->quickUserCan( 'edit', $user )
+                               && ( $this->getTitle()->exists() || $this->getTitle()->quickUserCan( 'create', $user ) ) ) {
                                // Original UniversalEditButton
                                $msg = $this->msg( 'edit' )->text();
                                $tags[] = Html::element( 'link', array(
@@ -3035,7 +3113,7 @@ $templates
         * @param $flip String: Set to 'flip' to flip the CSS if needed
         */
        public function addInlineStyle( $style_css, $flip = 'noflip' ) {
-               if( $flip === 'flip' && $this->getLang()->isRTL() ) {
+               if( $flip === 'flip' && $this->getLanguage()->isRTL() ) {
                        # If wanted, and the interface is right-to-left, flip the CSS
                        $style_css = CSSJanus::transform( $style_css, true, false );
                }
@@ -3092,7 +3170,11 @@ $templates
                }
 
                foreach ( $moduleStyles as $name ) {
-                       $group = $resourceLoader->getModule( $name )->getGroup();
+                       $module = $resourceLoader->getModule( $name );
+                       if ( !$module ) {
+                               continue;
+                       }
+                       $group = $module->getGroup();
                        // Modules in groups named "other" or anything different than "user", "site" or "private"
                        // will be placed in the "other" group
                        $styles[isset( $styles[$group] ) ? $group : 'other'][] = $name;
@@ -3154,7 +3236,7 @@ $templates
         */
        protected function styleLink( $style, $options ) {
                if( isset( $options['dir'] ) ) {
-                       if( $this->getLang()->getDir() != $options['dir'] ) {
+                       if( $this->getLanguage()->getDir() != $options['dir'] ) {
                                return '';
                        }
                }