Fix bug 9246 by watching a page when the upload\reupload "Watch this page" checkbox...
[lhc/web/wiklou.git] / includes / OutputPage.php
index deb126b..a2e1198 100644 (file)
@@ -23,12 +23,14 @@ class OutputPage {
        var $mIsArticleRelated;
        protected $mParserOptions; // lazy initialised, use parserOptions()
        var $mShowFeedLinks = false;
+       var $mFeedLinksAppendQuery = false;
        var $mEnableClientCache = true;
        var $mArticleBodyOnly = false;
        
        var $mNewSectionLink = false;
        var $mNoGallery = false;
        var $mPageTitleActionText = '';
+       var $mParseWarnings = array();
 
        /**
         * Constructor
@@ -63,6 +65,7 @@ class OutputPage {
                $this->mRedirect = str_replace( "\n", '', $url );
                $this->mRedirectCode = $responsecode;
        }
+       
        public function getRedirect() {
                return $this->mRedirect;
        }
@@ -231,6 +234,8 @@ class OutputPage {
        public function isPrintable() { return $this->mPrintable; }
        public function setSyndicated( $show = true ) { $this->mShowFeedLinks = $show; }
        public function isSyndicated() { return $this->mShowFeedLinks; }
+       public function setFeedAppendQuery( $val ) { $this->mFeedLinksAppendQuery = $val; }
+       public function getFeedAppendQuery() { return $this->mFeedLinksAppendQuery; }
        public function setOnloadHandler( $js ) { $this->mOnloadHandler = $js; }
        public function getOnloadHandler() { return $this->mOnloadHandler; }
        public function disable() { $this->mDoNothing = true; }
@@ -375,6 +380,7 @@ class OutputPage {
                $this->addCategoryLinks( $parserOutput->getCategories() );
                $this->mNewSectionLink = $parserOutput->getNewSection();
                $this->addKeywords( $parserOutput );
+               $this->mParseWarnings = $parserOutput->getWarnings();
                if ( $parserOutput->getCacheTime() == -1 ) {
                        $this->enableClientCache( false );
                }
@@ -586,22 +592,6 @@ class OutputPage {
                }
                $fname = 'OutputPage::output';
                wfProfileIn( $fname );
-               $sk = $wgUser->getSkin();
-
-               if ( $wgUseAjax ) {
-                       $this->addScript( "<script type=\"{$wgJsMimeType}\" src=\"{$wgStylePath}/common/ajax.js?$wgStyleVersion\"></script>\n" );
-
-                       wfRunHooks( 'AjaxAddScript', array( &$this ) );
-
-                       if( $wgAjaxSearch ) {
-                               $this->addScript( "<script type=\"{$wgJsMimeType}\" src=\"{$wgStylePath}/common/ajaxsearch.js?$wgStyleVersion\"></script>\n" );
-                               $this->addScript( "<script type=\"{$wgJsMimeType}\">hookEvent(\"load\", sajax_onload);</script>\n" );
-                       }
-
-                       if( $wgAjaxWatch && $wgUser->isLoggedIn() ) {
-                               $this->addScript( "<script type=\"{$wgJsMimeType}\" src=\"{$wgStylePath}/common/ajaxwatch.js?$wgStyleVersion\"></script>\n" );
-                       }
-               }
 
                if ( '' != $this->mRedirect ) {
                        if( substr( $this->mRedirect, 0, 4 ) != 'http' ) {
@@ -685,6 +675,25 @@ class OutputPage {
                                $wgRequest->response()->header( 'HTTP/1.1 ' . $this->mStatusCode . ' ' . $statusMessage[$this->mStatusCode] );
                }
 
+               $sk = $wgUser->getSkin();
+
+               if ( $wgUseAjax ) {
+                       $this->addScript( "<script type=\"{$wgJsMimeType}\" src=\"{$wgStylePath}/common/ajax.js?$wgStyleVersion\"></script>\n" );
+
+                       wfRunHooks( 'AjaxAddScript', array( &$this ) );
+
+                       if( $wgAjaxSearch && $wgUser->getBoolOption( 'ajaxsearch' ) ) {
+                               $this->addScript( "<script type=\"{$wgJsMimeType}\" src=\"{$wgStylePath}/common/ajaxsearch.js?$wgStyleVersion\"></script>\n" );
+                               $this->addScript( "<script type=\"{$wgJsMimeType}\">hookEvent(\"load\", sajax_onload);</script>\n" );
+                       }
+
+                       if( $wgAjaxWatch && $wgUser->isLoggedIn() ) {
+                               $this->addScript( "<script type=\"{$wgJsMimeType}\" src=\"{$wgStylePath}/common/ajaxwatch.js?$wgStyleVersion\"></script>\n" );
+                       }
+               }
+
+
+
                # Buffer output; final headers may depend on later processing
                ob_start();
 
@@ -763,6 +772,9 @@ class OutputPage {
 
                $name = User::whoIs( $wgUser->blockedBy() );
                $reason = $wgUser->blockedFor();
+               if( $reason == '' ) {
+                       $reason = wfMsg( 'blockednoreason' );
+               }
                $blockTimestamp = $wgLang->timeanddate( wfTimestamp( TS_MW, $wgUser->mBlock->mTimestamp ), true );
                $ip = wfGetIP();
 
@@ -816,9 +828,9 @@ class OutputPage {
         */
        public function showErrorPage( $title, $msg, $params = array() ) {
                global $wgTitle;
-
-               $this->mDebugtext .= 'Original title: ' .
-                 $wgTitle->getPrefixedText() . "\n";
+               if ( isset($wgTitle) ) {
+                       $this->mDebugtext .= 'Original title: ' . $wgTitle->getPrefixedText() . "\n";
+               }
                $this->setPageTitle( wfMsg( $title ) );
                $this->setHTMLTitle( wfMsg( 'errorpagetitle' ) );
                $this->setRobotpolicy( 'noindex,nofollow' );
@@ -844,7 +856,7 @@ class OutputPage {
                global $wgTitle;
 
                $this->mDebugtext .= 'Original title: ' .
-                        $wgTitle->getPrefixedText() . "\n";
+               $wgTitle->getPrefixedText() . "\n";
                $this->setPageTitle( wfMsg( 'permissionserrors' ) );
                $this->setHTMLTitle( wfMsg( 'permissionserrors' ) );
                $this->setRobotpolicy( 'noindex,nofollow' );
@@ -972,14 +984,12 @@ class OutputPage {
 
        /**
         * @param array $errors An array of arrays returned by Title::getUserPermissionsErrors
-        * @return string The error-messages, formatted into a list.
+        * @return string The wikitext error-messages, formatted into a list.
         */
        public function formatPermissionsErrorMessage( $errors ) {
-               $text = '';
+               $text = wfMsgExt( 'permissionserrorstext', array( 'parsemag' ), count( $errors ) ) . "\n\n";
 
-               if (sizeof( $errors ) > 1) {
-
-                       $text .= wfMsgExt( 'permissionserrorstext', array( 'parse' ), count( $errors ) ) . "\n";
+               if (count( $errors ) > 1) {
                        $text .= '<ul class="permissions-errors">' . "\n";
 
                        foreach( $errors as $error )
@@ -990,18 +1000,30 @@ class OutputPage {
                        }
                        $text .= '</ul>';
                } else {
-                       $text .= call_user_func_array( 'wfMsg', $errors[0]);
+                       $text .= '<div class="permissions-errors">' . call_user_func_array( 'wfMsg', $errors[0]) . '</div>';
                }
 
                return $text;
        }
 
        /**
-        * @todo document
-        * @param bool  $protected Is the reason the page can't be reached because it's protected?
-        * @param mixed $source
-        * @param bool $protected, page is protected?
-        * @param array $reason, array of arrays( msg, args )
+        * Display a page stating that the Wiki is in read-only mode,
+        * and optionally show the source of the page that the user
+        * was trying to edit.  Should only be called (for this
+        * purpose) after wfReadOnly() has returned true.
+        *
+        * For historical reasons, this function is _also_ used to
+        * show the error message when a user tries to edit a page
+        * they are not allowed to edit.  (Unless it's because they're
+        * blocked, then we show blockedPage() instead.)  In this
+        * case, the second parameter should be set to true and a list
+        * of reasons supplied as the third parameter.
+        *
+        * @todo Needs to be split into multiple functions.
+        *
+        * @param string $source    Source code to show (or null).
+        * @param bool   $protected Is this a permissions error?
+        * @param array  $reasons   List of reasons for this error, as returned by Title::getUserPermissionsErrors().
         */
        public function readOnlyPage( $source = null, $protected = false, $reasons = array() ) {
                global $wgUser, $wgReadOnlyFile, $wgReadOnly, $wgTitle;
@@ -1009,61 +1031,59 @@ class OutputPage {
 
                $this->setRobotpolicy( 'noindex,nofollow' );
                $this->setArticleRelated( false );
-               
-               if ( !empty($reasons) ) {
-                       $this->setPageTitle( wfMsg( 'viewsource' ) );
-                       $this->setSubtitle( wfMsg( 'viewsourcefor', $skin->makeKnownLinkObj( $wgTitle ) ) );
 
-                       $this->addWikiText( $this->formatPermissionsErrorMessage( $reasons ) );
-               } else if( $protected ) {
-                       $this->setPageTitle( wfMsg( 'viewsource' ) );
-                       $this->setSubtitle( wfMsg( 'viewsourcefor', $skin->makeKnownLinkObj( $wgTitle ) ) );
-                       list( $cascadeSources, /* $restrictions */ ) = $wgTitle->getCascadeProtectionSources();
-
-                       // Show an appropriate explanation depending upon the reason
-                       // for the protection...all of these should be moved to the
-                       // callers
-                       if( $wgTitle->getNamespace() == NS_MEDIAWIKI ) {
-                               // User isn't allowed to edit the interface
-                               $this->addWikiText( wfMsg( 'protectedinterface' ) );
-                       } elseif( $cascadeSources && ( $count = count( $cascadeSources ) ) > 0 ) {
-                               // Cascading protection
-                                       $titles = '';
-                                       foreach( $cascadeSources as $title )
-                                               $titles .= "* [[:" . $title->getPrefixedText()  . "]]\n";
-                                       $this->addWikiText( wfMsgExt( 'cascadeprotected', 'parsemag', $count ) . "\n{$titles}" );
-                       } elseif( !$wgTitle->isProtected( 'edit' ) && $wgTitle->isNamespaceProtected() ) {
-                               // Namespace protection
-                               $ns = $wgTitle->getNamespace() == NS_MAIN
-                                       ? wfMsg( 'nstab-main' )
-                                       : $wgTitle->getNsText();
-                               $this->addWikiText( wfMsg( 'namespaceprotected', $ns ) );
+               // If no reason is given, just supply a default "I can't let you do
+               // that, Dave" message.  Should only occur if called by legacy code.
+               if ( $protected && empty($reasons) ) {
+                       $reasons[] = array( 'badaccess-group0' );
+               }
+
+               if ( !empty($reasons) ) {
+                       // Permissions error
+                       if( $source ) {
+                               $this->setPageTitle( wfMsg( 'viewsource' ) );
+                               $this->setSubtitle( wfMsg( 'viewsourcefor', $skin->makeKnownLinkObj( $wgTitle ) ) );
                        } else {
-                               // Standard protection
-                               $this->addWikiText( wfMsg( 'protectedpagetext' ) );
+                               $this->setPageTitle( wfMsg( 'badaccess' ) );
                        }
+                       $this->addWikiText( $this->formatPermissionsErrorMessage( $reasons ) );
                } else {
+                       // Wiki is read only
                        $this->setPageTitle( wfMsg( 'readonly' ) );
                        if ( $wgReadOnly ) {
                                $reason = $wgReadOnly;
                        } else {
+                               // Should not happen, user should have called wfReadOnly() first
                                $reason = file_get_contents( $wgReadOnlyFile );
                        }
                        $this->addWikiText( wfMsg( 'readonlytext', $reason ) );
                }
 
+               // Show source, if supplied
                if( is_string( $source ) ) {
                        $this->addWikiText( wfMsg( 'viewsourcetext' ) );
-                       $rows = $wgUser->getIntOption( 'rows' );
-                       $cols = $wgUser->getIntOption( 'cols' );
-                       $text = "\n<textarea name='wpTextbox1' id='wpTextbox1' cols='$cols' rows='$rows' readonly='readonly'>" .
-                               htmlspecialchars( $source ) . "\n</textarea>";
+                       $text = wfOpenElement( 'textarea',
+                                               array( 'id'   => 'wpTextbox1',
+                                                      'name' => 'wpTextbox1',
+                                                      'cols' => $wgUser->getOption( 'cols' ),
+                                                      'rows' => $wgUser->getOption( 'rows' ),
+                                                      'readonly' => 'readonly' ) );
+                       $text .= htmlspecialchars( $source );
+                       $text .= wfCloseElement( 'textarea' );
                        $this->addHTML( $text );
+
+                       // Show templates used by this article
+                       $skin = $wgUser->getSkin();
+                       $article = new Article( $wgTitle );
+                       $this->addHTML( $skin->formatTemplates( $article->getUsedTemplates() ) );
                }
-               $article = new Article( $wgTitle );
-               $this->addHTML( $skin->formatTemplates( $article->getUsedTemplates() ) );
 
-               $this->returnToMain( false, $wgTitle );
+               # If the title doesn't exist, it's fairly pointless to print a return
+               # link to it.  After all, you just tried editing it and couldn't, so
+               # what's there to do there?
+               if( $wgTitle->exists() ) {
+                       $this->returnToMain( false, $wgTitle );
+               }
        }
 
        /** @deprecated */
@@ -1281,21 +1301,17 @@ class OutputPage {
                        $ret .= " />\n";
                }
                
-               if( $this->isSyndicated() ) {
-                       # FIXME: centralize the mime-type and name information in Feed.php
+               foreach( $this->getSyndicationLinks() as $format => $link ) {
                        # Use the page name for the title (accessed through $wgTitle since
                        # there's no other way).  In principle, this could lead to issues
                        # with having the same name for different feeds corresponding to
                        # the same page, but we can't avoid that at this low a level.
                        global $wgTitle;
+
                        $ret .= $this->feedLink(
-                               'rss',
-                               $wgRequest->appendQuery( 'feed=rss' ),
-                               wfMsg( 'page-rss-feed', $wgTitle->getPrefixedText() ) );
-                       $ret .= $this->feedLink(
-                               'atom',
-                               $wgRequest->appendQuery( 'feed=atom' ),
-                               wfMsg( 'page-atom-feed', $wgTitle->getPrefixedText() ) );
+                               $format,
+                               $link,
+                               wfMsg( "page-{$format}-feed", $wgTitle->getPrefixedText() ) ); # Used messages: 'page-rss-feed' and 'page-atom-feed' (for an easier grep)
                }
 
                # Recent changes feed should appear on every page
@@ -1315,6 +1331,28 @@ class OutputPage {
                return $ret;
        }
        
+       /**
+        * Return URLs for each supported syndication format for this page.
+        * @return array associating format keys with URLs
+        */
+       public function getSyndicationLinks() {
+               global $wgTitle, $wgFeedClasses;
+               $links = array();
+               
+               if( $this->isSyndicated() ) {
+                       if( is_string( $this->getFeedAppendQuery() ) ) {
+                               $appendQuery = "&" . $this->getFeedAppendQuery();
+                       } else {
+                               $appendQuery = "";
+                       }
+
+                       foreach( $wgFeedClasses as $format => $class ) {
+                               $links[$format] = $wgTitle->getLocalUrl( "feed=$format{$appendQuery}" );
+                       }
+               }
+               return $links;
+       }
+       
        /**
         * Generate a <link rel/> for an RSS feed.
         */
@@ -1329,14 +1367,20 @@ class OutputPage {
        /**
         * Turn off regular page output and return an error reponse
         * for when rate limiting has triggered.
-        * @todo i18n
         */
        public function rateLimited() {
-               global $wgOut;
-               $wgOut->disable();
-               wfHttpError( 500, 'Internal Server Error',
-                       'Sorry, the server has encountered an internal error. ' .
-                       'Please wait a moment and hit "refresh" to submit the request again.' );
+               global $wgOut, $wgTitle;
+
+               $this->setPageTitle(wfMsg('actionthrottled'));
+               $this->setRobotPolicy( 'noindex,follow' );
+               $this->setArticleRelated( false );
+               $this->enableClientCache( false );
+               $this->mRedirect = '';
+               $this->clearHTML();
+               $this->setStatusCode(503);
+               $this->addWikiText( wfMsg('actionthrottledtext') );
+
+               $this->returnToMain( false, $wgTitle );
        }
        
        /**
@@ -1367,5 +1411,5 @@ class OutputPage {
                        $this->addHtml( "<div class=\"mw-{$message}\">\n{$warning}\n</div>\n" );
                }
        }
-       
+
 }