Bug 36785 Special:Shortpages lists only NS_MAIN pages. (pages from all $wgContentName...
[lhc/web/wiklou.git] / includes / ImagePage.php
index 956977e..fc3bdff 100644 (file)
@@ -1,4 +1,25 @@
 <?php
+/**
+ * Special handling for file description pages.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ * http://www.gnu.org/copyleft/gpl.html
+ *
+ * @file
+ */
+
 /**
  * Class for viewing MediaWiki file description pages
  *
@@ -18,6 +39,10 @@ class ImagePage extends Article {
 
        var $mExtraDescription = false;
 
+       /**
+        * @param $title Title
+        * @return WikiFilePage
+        */
        protected function newPage( Title $title ) {
                // Overload mPage with a file-specific page
                return new WikiFilePage( $title );
@@ -26,6 +51,7 @@ class ImagePage extends Article {
        /**
         * Constructor from a page id
         * @param $id Int article ID to load
+        * @return ImagePage|null
         */
        public static function newFromID( $id ) {
                $t = Title::newFromID( $id );
@@ -46,7 +72,7 @@ class ImagePage extends Article {
 
        protected function loadFile() {
                if ( $this->fileLoaded ) {
-                       return true;
+                       return;
                }
                $this->fileLoaded = true;
 
@@ -70,19 +96,21 @@ class ImagePage extends Article {
         * Include body text only; none of the image extras
         */
        public function render() {
-               global $wgOut;
-               $wgOut->setArticleBodyOnly( true );
+               $this->getContext()->setArticleBodyOnly( true );
                parent::view();
        }
 
        public function view() {
-               global $wgOut, $wgShowEXIF, $wgRequest, $wgUser;
+               global $wgShowEXIF;
 
-               $diff = $wgRequest->getVal( 'diff' );
-               $diffOnly = $wgRequest->getBool( 'diffonly', $wgUser->getOption( 'diffonly' ) );
+               $out = $this->getContext()->getOutput();
+               $request = $this->getContext()->getRequest();
+               $diff = $request->getVal( 'diff' );
+               $diffOnly = $request->getBool( 'diffonly', $this->getContext()->getUser()->getOption( 'diffonly' ) );
 
                if ( $this->getTitle()->getNamespace() != NS_FILE || ( isset( $diff ) && $diffOnly ) ) {
-                       return parent::view();
+                       parent::view();
+                       return;
                }
 
                $this->loadFile();
@@ -91,21 +119,20 @@ class ImagePage extends Article {
                        if ( $this->getTitle()->getDBkey() == $this->mPage->getFile()->getName() || isset( $diff ) ) {
                                // mTitle is the same as the redirect target so ask Article
                                // to perform the redirect for us.
-                               $wgRequest->setVal( 'diffonly', 'true' );
-                               return parent::view();
+                               $request->setVal( 'diffonly', 'true' );
+                               parent::view();
+                               return;
                        } else {
                                // mTitle is not the same as the redirect target so it is
                                // probably the redirect page itself. Fake the redirect symbol
-                               $wgOut->setPageTitle( $this->getTitle()->getPrefixedText() );
-                               $wgOut->addHTML( $this->viewRedirect( Title::makeTitle( NS_FILE, $this->mPage->getFile()->getName() ),
+                               $out->setPageTitle( $this->getTitle()->getPrefixedText() );
+                               $out->addHTML( $this->viewRedirect( Title::makeTitle( NS_FILE, $this->mPage->getFile()->getName() ),
                                        /* $appendSubtitle */ true, /* $forceKnown */ true ) );
-                               $this->mPage->viewUpdates();
+                               $this->mPage->doViewUpdates( $this->getContext()->getUser() );
                                return;
                        }
                }
 
-               $this->showRedirectedFromHeader();
-
                if ( $wgShowEXIF && $this->displayImg->exists() ) {
                        // @todo FIXME: Bad interface, see note on MediaHandler::formatMetadata().
                        $formattedMetadata = $this->displayImg->formatMetadata();
@@ -115,7 +142,7 @@ class ImagePage extends Article {
                }
 
                if ( !$diff && $this->displayImg->exists() ) {
-                       $wgOut->addHTML( $this->showTOC( $showmeta ) );
+                       $out->addHTML( $this->showTOC( $showmeta ) );
                }
 
                if ( !$diff ) {
@@ -127,32 +154,32 @@ class ImagePage extends Article {
                        # NS_FILE is in the user language, but this section (the actual wikitext)
                        # should be in page content language
                        $pageLang = $this->getTitle()->getPageLanguage();
-                       $wgOut->addHTML( Xml::openElement( 'div', array( 'id' => 'mw-imagepage-content',
+                       $out->addHTML( Xml::openElement( 'div', array( 'id' => 'mw-imagepage-content',
                                'lang' => $pageLang->getCode(), 'dir' => $pageLang->getDir(),
                                'class' => 'mw-content-'.$pageLang->getDir() ) ) );
                        parent::view();
-                       $wgOut->addHTML( Xml::closeElement( 'div' ) );
+                       $out->addHTML( Xml::closeElement( 'div' ) );
                } else {
                        # Just need to set the right headers
-                       $wgOut->setArticleFlag( true );
-                       $wgOut->setPageTitle( $this->getTitle()->getPrefixedText() );
-                       $this->mPage->viewUpdates();
+                       $out->setArticleFlag( true );
+                       $out->setPageTitle( $this->getTitle()->getPrefixedText() );
+                       $this->mPage->doViewUpdates( $this->getContext()->getUser() );
                }
 
                # Show shared description, if needed
                if ( $this->mExtraDescription ) {
                        $fol = wfMessage( 'shareddescriptionfollows' );
                        if ( !$fol->isDisabled() ) {
-                               $wgOut->addWikiText( $fol->plain() );
+                               $out->addWikiText( $fol->plain() );
                        }
-                       $wgOut->addHTML( '<div id="shared-image-desc">' . $this->mExtraDescription . "</div>\n" );
+                       $out->addHTML( '<div id="shared-image-desc">' . $this->mExtraDescription . "</div>\n" );
                }
 
                $this->closeShowImage();
                $this->imageHistory();
                // TODO: Cleanup the following
 
-               $wgOut->addHTML( Xml::element( 'h2',
+               $out->addHTML( Xml::element( 'h2',
                        array( 'id' => 'filelinks' ),
                        wfMsg( 'imagelinks' ) ) . "\n" );
                $this->imageDupes();
@@ -164,26 +191,29 @@ class ImagePage extends Article {
                $html = '';
                wfRunHooks( 'ImagePageAfterImageLinks', array( $this, &$html ) );
                if ( $html ) {
-                       $wgOut->addHTML( $html );
+                       $out->addHTML( $html );
                }
 
                if ( $showmeta ) {
-                       $wgOut->addHTML( Xml::element( 'h2', array( 'id' => 'metadata' ), wfMsg( 'metadata' ) ) . "\n" );
-                       $wgOut->addWikiText( $this->makeMetadataTable( $formattedMetadata ) );
-                       $wgOut->addModules( array( 'mediawiki.action.view.metadata' ) );
+                       $out->addHTML( Xml::element( 'h2', array( 'id' => 'metadata' ), wfMsg( 'metadata' ) ) . "\n" );
+                       $out->addWikiText( $this->makeMetadataTable( $formattedMetadata ) );
+                       $out->addModules( array( 'mediawiki.action.view.metadata' ) );
                }
 
                // Add remote Filepage.css
                if( !$this->repo->isLocal() ) {
                        $css = $this->repo->getDescriptionStylesheetUrl();
                        if ( $css ) {
-                               $wgOut->addStyle( $css );
+                               $out->addStyle( $css );
                        }
                }
                // always show the local local Filepage.css, bug 29277
-               $wgOut->addModuleStyles( 'filepage' );
+               $out->addModuleStyles( 'filepage' );
        }
 
+       /**
+        * @return File
+        */
        public function getDisplayedFile() {
                $this->loadFile();
                return $this->displayImg;
@@ -243,6 +273,7 @@ class ImagePage extends Article {
         *
         * Omit noarticletext if sharedupload; text will be fetched from the
         * shared upload server if possible.
+        * @return string
         */
        public function getContent() {
                $this->loadFile();
@@ -253,12 +284,16 @@ class ImagePage extends Article {
        }
 
        protected function openShowImage() {
-               global $wgOut, $wgUser, $wgImageLimits, $wgRequest,
-                       $wgLang, $wgEnableUploads;
+               global $wgImageLimits, $wgEnableUploads, $wgSend404Code;
 
                $this->loadFile();
+               $out = $this->getContext()->getOutput();
+               $user = $this->getContext()->getUser();
+               $lang = $this->getContext()->getLanguage();
+               $dirmark = $lang->getDirMarkEntity();
+               $request = $this->getContext()->getRequest();
 
-               $sizeSel = intval( $wgUser->getOption( 'imagesize' ) );
+               $sizeSel = intval( $user->getOption( 'imagesize' ) );
                if ( !isset( $wgImageLimits[$sizeSel] ) ) {
                        $sizeSel = User::getDefaultOption( 'imagesize' );
 
@@ -272,11 +307,10 @@ class ImagePage extends Article {
                $max = $wgImageLimits[$sizeSel];
                $maxWidth = $max[0];
                $maxHeight = $max[1];
-               $dirmark = $wgLang->getDirMark();
 
                if ( $this->displayImg->exists() ) {
                        # image
-                       $page = $wgRequest->getIntOrNull( 'page' );
+                       $page = $request->getIntOrNull( 'page' );
                        if ( is_null( $page ) ) {
                                $params = array();
                                $page = 1;
@@ -290,7 +324,7 @@ class ImagePage extends Article {
 
                        $longDesc = wfMsg( 'parentheses', $this->displayImg->getLongDesc() );
 
-                       wfRunHooks( 'ImageOpenShowImageInlineBefore', array( &$this, &$wgOut ) );
+                       wfRunHooks( 'ImageOpenShowImageInlineBefore', array( &$this, &$out ) );
 
                        if ( $this->displayImg->allowInlineDisplay() ) {
                                # image
@@ -322,12 +356,21 @@ class ImagePage extends Article {
                                        }
                                        $msgsmall = wfMessage( 'show-big-image-preview' )->
                                                rawParams( $this->makeSizeLink( $params, $width, $height ) )->
-                                               parse() . ' ' .
-                                               wfMessage( 'show-big-image-other' )->
-                                               rawParams( $wgLang->pipeList( $otherSizes ) )->parse();
+                                               parse();
+                                       if ( count( $otherSizes ) && $this->displayImg->getRepo()->canTransformVia404() ) {
+                                               $msgsmall .= ' ' .
+                                               Html::rawElement( 'span', array( 'class' => 'mw-filepage-other-resolutions' ),
+                                                       wfMessage( 'show-big-image-other' )->rawParams( $lang->pipeList( $otherSizes ) )->
+                                                       params( count( $otherSizes ) )->parse()
+                                               );
+                                       }
+                               } elseif ( $width == 0 && $height == 0 ){
+                                       # Some sort of audio file that doesn't have dimensions
+                                       # Don't output a no hi res message for such a file
+                                       $msgsmall = '';
                                } else {
                                        # Image is small enough to show full size on image page
-                                       $msgsmall = wfMsgExt( 'file-nohires', array( 'parseinline' ) );
+                                       $msgsmall = wfMessage( 'file-nohires' )->parse();
                                }
 
                                $params['width'] = $width;
@@ -335,11 +378,11 @@ class ImagePage extends Article {
                                $thumbnail = $this->displayImg->transform( $params );
 
                                $showLink = true;
-                               $anchorclose = '<br />' . $msgsmall;
+                               $anchorclose = Html::rawElement( 'div', array( 'class' => 'mw-filepage-resolutioninfo' ), $msgsmall );
 
                                $isMulti = $this->displayImg->isMultipage() && $this->displayImg->pageCount() > 1;
                                if ( $isMulti ) {
-                                       $wgOut->addHTML( '<table class="multipageimage"><tr><td>' );
+                                       $out->addHTML( '<table class="multipageimage"><tr><td>' );
                                }
 
                                if ( $thumbnail ) {
@@ -347,7 +390,7 @@ class ImagePage extends Article {
                                                'alt' => $this->displayImg->getTitle()->getPrefixedText(),
                                                'file-link' => true,
                                        );
-                                       $wgOut->addHTML( '<div class="fullImageLink" id="file">' .
+                                       $out->addHTML( '<div class="fullImageLink" id="file">' .
                                                $thumbnail->toHtml( $options ) .
                                                $anchorclose . "</div>\n" );
                                }
@@ -356,7 +399,7 @@ class ImagePage extends Article {
                                        $count = $this->displayImg->pageCount();
 
                                        if ( $page > 1 ) {
-                                               $label = $wgOut->parse( wfMsg( 'imgmultipageprev' ), false );
+                                               $label = $out->parse( wfMsg( 'imgmultipageprev' ), false );
                                                $link = Linker::link(
                                                        $this->getTitle(),
                                                        $label,
@@ -392,22 +435,22 @@ class ImagePage extends Article {
                                                'action' => $wgScript,
                                                'onchange' => 'document.pageselector.submit();',
                                        );
-
+                                       $options = array();
                                        for ( $i = 1; $i <= $count; $i++ ) {
-                                               $options[] = Xml::option( $wgLang->formatNum( $i ), $i, $i == $page );
+                                               $options[] = Xml::option( $lang->formatNum( $i ), $i, $i == $page );
                                        }
                                        $select = Xml::tags( 'select',
                                                array( 'id' => 'pageselector', 'name' => 'page' ),
                                                implode( "\n", $options ) );
 
-                                       $wgOut->addHTML(
+                                       $out->addHTML(
                                                '</td><td><div class="multipageimagenavbox">' .
                                                Xml::openElement( 'form', $formParams ) .
                                                Html::hidden( 'title', $this->getTitle()->getPrefixedDBkey() ) .
                                                wfMsgExt( 'imgmultigoto', array( 'parseinline', 'replaceafter' ), $select ) .
                                                Xml::submitButton( wfMsg( 'imgmultigo' ) ) .
                                                Xml::closeElement( 'form' ) .
-                                               "<hr />$thumb1\n$thumb2<br clear=\"all\" /></div></td></tr></table>"
+                                               "<hr />$thumb1\n$thumb2<br style=\"clear: both\" /></div></td></tr></table>"
                                        );
                                }
                        } else {
@@ -415,7 +458,7 @@ class ImagePage extends Article {
                                if ( $this->displayImg->isSafeFile() ) {
                                        $icon = $this->displayImg->iconThumb();
 
-                                       $wgOut->addHTML( '<div class="fullImageLink" id="file">' .
+                                       $out->addHTML( '<div class="fullImageLink" id="file">' .
                                                $icon->toHtml( array( 'file-link' => true ) ) .
                                                "</div>\n" );
                                }
@@ -433,14 +476,21 @@ class ImagePage extends Article {
 
                                if ( !$this->displayImg->isSafeFile() ) {
                                        $warning = wfMsgNoTrans( 'mediawarning' );
-                                       $wgOut->addWikiText( <<<EOT
-<div class="fullMedia"><span class="dangerousLink">{$medialink}</span>$dirmark <span class="fileInfo">$longDesc</span></div>
+                                       // dirmark is needed here to separate the file name, which
+                                       // most likely ends in Latin characters, from the description,
+                                       // which may begin with the file type. In RTL environment
+                                       // this will get messy.
+                                       // The dirmark, however, must not be immediately adjacent
+                                       // to the filename, because it can get copied with it.
+                                       // See bug 25277.
+                                       $out->addWikiText( <<<EOT
+<div class="fullMedia"><span class="dangerousLink">{$medialink}</span> $dirmark<span class="fileInfo">$longDesc</span></div>
 <div class="mediaWarning">$warning</div>
 EOT
                                                );
                                } else {
-                                       $wgOut->addWikiText( <<<EOT
-<div class="fullMedia">{$medialink}{$dirmark} <span class="fileInfo">$longDesc</span>
+                                       $out->addWikiText( <<<EOT
+<div class="fullMedia">{$medialink} {$dirmark}<span class="fileInfo">$longDesc</span>
 </div>
 EOT
                                        );
@@ -452,7 +502,23 @@ EOT
                        }
                } else {
                        # Image does not exist
-                       if ( $wgEnableUploads && $wgUser->isAllowed( 'upload' ) ) {
+                       if ( !$this->getID() ) {
+                               # No article exists either
+                               # Show deletion log to be consistent with normal articles
+                               LogEventsList::showLogExtract(
+                                       $out,
+                                       array( 'delete', 'move' ),
+                                       $this->getTitle()->getPrefixedText(),
+                                       '',
+                                       array(  'lim' => 10,
+                                               'conds' => array( "log_action != 'revision'" ),
+                                               'showIfEmpty' => false,
+                                               'msgKey' => array( 'moveddeleted-notice' )
+                                       )
+                               );
+                       }
+
+                       if ( $wgEnableUploads && $user->isAllowed( 'upload' ) ) {
                                // Only show an upload link if the user can upload
                                $uploadTitle = SpecialPage::getTitleFor( 'Upload' );
                                $nofile = array(
@@ -465,22 +531,23 @@ EOT
                        // Note, if there is an image description page, but
                        // no image, then this setRobotPolicy is overriden
                        // by Article::View().
-                       $wgOut->setRobotPolicy( 'noindex,nofollow' );
-                       $wgOut->wrapWikiMsg( "<div id='mw-imagepage-nofile' class='plainlinks'>\n$1\n</div>", $nofile );
-                       if ( !$this->getID() ) {
+                       $out->setRobotPolicy( 'noindex,nofollow' );
+                       $out->wrapWikiMsg( "<div id='mw-imagepage-nofile' class='plainlinks'>\n$1\n</div>", $nofile );
+                       if ( !$this->getID() && $wgSend404Code ) {
                                // If there is no image, no shared image, and no description page,
                                // output a 404, to be consistent with articles.
-                               $wgRequest->response()->header( 'HTTP/1.1 404 Not Found' );
+                               $request->response()->header( 'HTTP/1.1 404 Not Found' );
                        }
                }
-               $wgOut->setFileVersion( $this->displayImg );
+               $out->setFileVersion( $this->displayImg );
        }
 
        /**
         * Creates an thumbnail of specified size and returns an HTML link to it
-        * @param array $params Scaler parameters
-        * @param int $width
-        * @param int $height
+        * @param $params array Scaler parameters
+        * @param $width int
+        * @param $height int
+        * @return string
         */
        private function makeSizeLink( $params, $width, $height ) {
                $params['width'] = $width;
@@ -502,8 +569,7 @@ EOT
         * Show a notice that the file is from a shared repository
         */
        protected function printSharedImageText() {
-               global $wgOut;
-
+               $out = $this->getContext()->getOutput();
                $this->loadFile();
 
                $descUrl = $this->mPage->getFile()->getDescriptionUrl();
@@ -511,18 +577,18 @@ EOT
 
                /* Add canonical to head if there is no local page for this shared file */
                if( $descUrl && $this->mPage->getID() == 0 ) {
-                       $wgOut->addLink( array( 'rel' => 'canonical', 'href' => $descUrl ) );
+                       $out->addLink( array( 'rel' => 'canonical', 'href' => $descUrl ) );
                }
 
                $wrap = "<div class=\"sharedUploadNotice\">\n$1\n</div>\n";
                $repo = $this->mPage->getFile()->getRepo()->getDisplayName();
 
                if ( $descUrl && $descText && wfMsgNoTrans( 'sharedupload-desc-here' ) !== '-'  ) {
-                       $wgOut->wrapWikiMsg( $wrap, array( 'sharedupload-desc-here', $repo, $descUrl ) );
+                       $out->wrapWikiMsg( $wrap, array( 'sharedupload-desc-here', $repo, $descUrl ) );
                } elseif ( $descUrl && wfMsgNoTrans( 'sharedupload-desc-there' ) !== '-' ) {
-                       $wgOut->wrapWikiMsg( $wrap, array( 'sharedupload-desc-there', $repo, $descUrl ) );
+                       $out->wrapWikiMsg( $wrap, array( 'sharedupload-desc-there', $repo, $descUrl ) );
                } else {
-                       $wgOut->wrapWikiMsg( $wrap, array( 'sharedupload', $repo ), ''/*BACKCOMPAT*/ );
+                       $out->wrapWikiMsg( $wrap, array( 'sharedupload', $repo ), ''/*BACKCOMPAT*/ );
                }
 
                if ( $descText ) {
@@ -544,7 +610,7 @@ EOT
         * external editing (and instructions link) etc.
         */
        protected function uploadLinksBox() {
-               global $wgUser, $wgOut, $wgEnableUploads, $wgUseExternalEditor;
+               global $wgEnableUploads, $wgUseExternalEditor;
 
                if ( !$wgEnableUploads ) {
                        return;
@@ -555,12 +621,13 @@ EOT
                        return;
                }
 
-               $wgOut->addHTML( "<br /><ul>\n" );
+               $out = $this->getContext()->getOutput();
+               $out->addHTML( "<br /><ul>\n" );
 
                # "Upload a new version of this file" link
-               if ( UploadBase::userCanReUpload( $wgUser, $this->mPage->getFile()->name ) ) {
+               if ( UploadBase::userCanReUpload( $this->getContext()->getUser(), $this->mPage->getFile()->name ) ) {
                        $ulink = Linker::makeExternalLink( $this->getUploadUrl(), wfMsg( 'uploadnewversion-linktext' ) );
-                       $wgOut->addHTML( "<li id=\"mw-imagepage-reupload-link\"><div class=\"plainlinks\">{$ulink}</div></li>\n" );
+                       $out->addHTML( "<li id=\"mw-imagepage-reupload-link\"><div class=\"plainlinks\">{$ulink}</div></li>\n" );
                }
 
                # External editing link
@@ -576,14 +643,14 @@ EOT
                                ),
                                array( 'known', 'noclasses' )
                        );
-                       $wgOut->addHTML(
+                       $out->addHTML(
                                '<li id="mw-imagepage-edit-external">' . $elink . ' <small>' .
                                wfMsgExt( 'edit-externally-help', array( 'parseinline' ) ) .
                                "</small></li>\n"
                        );
                }
 
-               $wgOut->addHTML( "</ul>\n" );
+               $out->addHTML( "</ul>\n" );
        }
 
        protected function closeShowImage() { } # For overloading
@@ -593,12 +660,11 @@ EOT
         * we follow it with an upload history of the image and its usage.
         */
        protected function imageHistory() {
-               global $wgOut;
-
                $this->loadFile();
+               $out = $this->getContext()->getOutput();
                $pager = new ImageHistoryPseudoPager( $this );
-               $wgOut->addHTML( $pager->getBody() );
-               $wgOut->preventClickjacking( $pager->getPreventClickjacking() );
+               $out->addHTML( $pager->getBody() );
+               $out->preventClickjacking( $pager->getPreventClickjacking() );
 
                $this->mPage->getFile()->resetHistory(); // free db resources
 
@@ -609,6 +675,11 @@ EOT
                }
        }
 
+       /**
+        * @param $target
+        * @param $limit
+        * @return ResultWrapper
+        */
        protected function queryImageLinks( $target, $limit ) {
                $dbr = wfGetDB( DB_SLAVE );
 
@@ -622,10 +693,9 @@ EOT
        }
 
        protected function imageLinks() {
-               global $wgOut, $wgLang;
-
                $limit = 100;
 
+               $out = $this->getContext()->getOutput();
                $res = $this->queryImageLinks( $this->getTitle()->getDbKey(), $limit + 1);
                $rows = array();
                $redirects = array();
@@ -649,7 +719,7 @@ EOT
                }
 
                if ( $count == 0 ) {
-                       $wgOut->wrapWikiMsg(
+                       $out->wrapWikiMsg(
                                Html::rawElement( 'div',
                                        array( 'id' => 'mw-imagepage-nolinkstoimage' ), "\n$1\n" ),
                                'nolinkstoimage'
@@ -657,18 +727,18 @@ EOT
                        return;
                }
 
-               $wgOut->addHTML( "<div id='mw-imagepage-section-linkstoimage'>\n" );
+               $out->addHTML( "<div id='mw-imagepage-section-linkstoimage'>\n" );
                if ( !$hasMore ) {
-                       $wgOut->addWikiMsg( 'linkstoimage', $count );
+                       $out->addWikiMsg( 'linkstoimage', $count );
                } else {
                        // More links than the limit. Add a link to [[Special:Whatlinkshere]]
-                       $wgOut->addWikiMsg( 'linkstoimage-more',
-                               $wgLang->formatNum( $limit ),
+                       $out->addWikiMsg( 'linkstoimage-more',
+                               $this->getContext()->getLanguage()->formatNum( $limit ),
                                $this->getTitle()->getPrefixedDBkey()
                        );
                }
 
-               $wgOut->addHTML(
+               $out->addHTML(
                        Html::openElement( 'ul',
                                array( 'class' => 'mw-imagepage-linkstoimage' ) ) . "\n"
                );
@@ -707,7 +777,7 @@ EOT
                                $liContents = wfMessage( 'linkstoimage-redirect' )->rawParams(
                                        $link, $ul )->parse();
                        }
-                       $wgOut->addHTML( Html::rawElement(
+                       $out->addHTML( Html::rawElement(
                                        'li',
                                        array( 'id' => 'mw-imagepage-linkstoimage-ns' . $element->page_namespace ),
                                        $liContents
@@ -715,32 +785,34 @@ EOT
                        );
 
                };
-               $wgOut->addHTML( Html::closeElement( 'ul' ) . "\n" );
+               $out->addHTML( Html::closeElement( 'ul' ) . "\n" );
                $res->free();
 
                // Add a links to [[Special:Whatlinkshere]]
                if ( $count > $limit ) {
-                       $wgOut->addWikiMsg( 'morelinkstoimage', $this->getTitle()->getPrefixedDBkey() );
+                       $out->addWikiMsg( 'morelinkstoimage', $this->getTitle()->getPrefixedDBkey() );
                }
-               $wgOut->addHTML( Html::closeElement( 'div' ) . "\n" );
+               $out->addHTML( Html::closeElement( 'div' ) . "\n" );
        }
 
        protected function imageDupes() {
-               global $wgOut, $wgLang;
-
                $this->loadFile();
+               $out = $this->getContext()->getOutput();
 
                $dupes = $this->mPage->getDuplicates();
                if ( count( $dupes ) == 0 ) {
                        return;
                }
 
-               $wgOut->addHTML( "<div id='mw-imagepage-section-duplicates'>\n" );
-               $wgOut->addWikiMsg( 'duplicatesoffile',
-                       $wgLang->formatNum( count( $dupes ) ), $this->getTitle()->getDBkey()
+               $out->addHTML( "<div id='mw-imagepage-section-duplicates'>\n" );
+               $out->addWikiMsg( 'duplicatesoffile',
+                       $this->getContext()->getLanguage()->formatNum( count( $dupes ) ), $this->getTitle()->getDBkey()
                );
-               $wgOut->addHTML( "<ul class='mw-imagepage-duplicates'>\n" );
+               $out->addHTML( "<ul class='mw-imagepage-duplicates'>\n" );
 
+               /**
+                * @var $file File
+                */
                foreach ( $dupes as $file ) {
                        $fromSrc = '';
                        if ( $file->isLocal() ) {
@@ -756,42 +828,38 @@ EOT
                                        $file->getTitle()->getPrefixedText() );
                                $fromSrc = wfMsg( 'shared-repo-from', $file->getRepo()->getDisplayName() );
                        }
-                       $wgOut->addHTML( "<li>{$link} {$fromSrc}</li>\n" );
+                       $out->addHTML( "<li>{$link} {$fromSrc}</li>\n" );
                }
-               $wgOut->addHTML( "</ul></div>\n" );
+               $out->addHTML( "</ul></div>\n" );
        }
 
        /**
         * Delete the file, or an earlier version of it
         */
        public function delete() {
-               global $wgUploadMaintenance;
-               if ( $wgUploadMaintenance && $this->getTitle() && $this->getTitle()->getNamespace() == NS_FILE ) {
-                       global $wgOut;
-                       $wgOut->wrapWikiMsg( "<div class='error'>\n$1\n</div>\n", array( 'filedelete-maintenance' ) );
-                       return;
-               }
-
-               $this->loadFile();
-               if ( !$this->mPage->getFile()->exists() || !$this->mPage->getFile()->isLocal() || $this->mPage->getFile()->getRedirected() ) {
+               $file = $this->mPage->getFile();
+               if ( !$file->exists() || !$file->isLocal() || $file->getRedirected() ) {
                        // Standard article deletion
                        parent::delete();
                        return;
                }
-               $deleter = new FileDeleteForm( $this->mPage->getFile() );
+
+               $deleter = new FileDeleteForm( $file );
                $deleter->execute();
        }
 
        /**
         * Display an error with a wikitext description
+        *
+        * @param $description String
         */
        function showError( $description ) {
-               global $wgOut;
-               $wgOut->setPageTitle( wfMsg( 'internalerror' ) );
-               $wgOut->setRobotPolicy( 'noindex,nofollow' );
-               $wgOut->setArticleRelated( false );
-               $wgOut->enableClientCache( false );
-               $wgOut->addWikiText( $description );
+               $out = $this->getContext()->getOutput();
+               $out->setPageTitle( wfMessage( 'internalerror' ) );
+               $out->setRobotPolicy( 'noindex,nofollow' );
+               $out->setArticleRelated( false );
+               $out->enableClientCache( false );
+               $out->addWikiText( $description );
        }
 
        /**
@@ -816,7 +884,7 @@ EOT
  *
  * @ingroup Media
  */
-class ImageHistoryList {
+class ImageHistoryList extends ContextSource {
 
        /**
         * @var Title
@@ -833,6 +901,11 @@ class ImageHistoryList {
         */
        protected $imagePage;
 
+       /**
+        * @var File
+        */
+       protected $current;
+
        protected $repo, $showThumb;
        protected $preventClickjacking = false;
 
@@ -846,25 +919,35 @@ class ImageHistoryList {
                $this->title = $imagePage->getTitle();
                $this->imagePage = $imagePage;
                $this->showThumb = $wgShowArchiveThumbnails && $this->img->canRender();
+               $this->setContext( $imagePage->getContext() );
        }
 
+       /**
+        * @return ImagePage
+        */
        public function getImagePage() {
                return $this->imagePage;
        }
 
+       /**
+        * @return File
+        */
        public function getFile() {
                return $this->img;
        }
 
+       /**
+        * @param $navLinks string
+        * @return string
+        */
        public function beginImageHistoryList( $navLinks = '' ) {
-               global $wgOut, $wgUser;
                return Xml::element( 'h2', array( 'id' => 'filehistory' ), wfMsg( 'filehist' ) ) . "\n"
                        . "<div id=\"mw-imagepage-section-filehistory\">\n"
-                       . $wgOut->parse( wfMsgNoTrans( 'filehist-help' ) )
+                       . $this->getOutput()->parse( wfMsgNoTrans( 'filehist-help' ) )
                        . $navLinks . "\n"
                        . Xml::openElement( 'table', array( 'class' => 'wikitable filehistory' ) ) . "\n"
                        . '<tr><td></td>'
-                       . ( $this->current->isLocal() && ( $wgUser->isAllowedAny( 'delete', 'deletedhistory' ) ) ? '<td></td>' : '' )
+                       . ( $this->current->isLocal() && ( $this->getUser()->isAllowedAny( 'delete', 'deletedhistory' ) ) ? '<td></td>' : '' )
                        . '<th>' . wfMsgHtml( 'filehist-datetime' ) . '</th>'
                        . ( $this->showThumb ? '<th>' . wfMsgHtml( 'filehist-thumb' ) . '</th>' : '' )
                        . '<th>' . wfMsgHtml( 'filehist-dimensions' ) . '</th>'
@@ -873,6 +956,10 @@ class ImageHistoryList {
                        . "</tr>\n";
        }
 
+       /**
+        * @param $navLinks string
+        * @return string
+        */
        public function endImageHistoryList( $navLinks = '' ) {
                return "</table>\n$navLinks\n</div>\n";
        }
@@ -883,22 +970,24 @@ class ImageHistoryList {
         * @return string
         */
        public function imageHistoryLine( $iscur, $file ) {
-               global $wgUser, $wgLang, $wgContLang;
+               global $wgContLang;
 
+               $user = $this->getUser();
+               $lang = $this->getLanguage();
                $timestamp = wfTimestamp( TS_MW, $file->getTimestamp() );
                $img = $iscur ? $file->getName() : $file->getArchiveName();
-               $user = $file->getUser( 'id' );
-               $usertext = $file->getUser( 'text' );
+               $userId = $file->getUser( 'id' );
+               $userText = $file->getUser( 'text' );
                $description = $file->getDescription();
 
                $local = $this->current->isLocal();
                $row = $selected = '';
 
                // Deletion link
-               if ( $local && ( $wgUser->isAllowedAny( 'delete', 'deletedhistory' ) ) ) {
+               if ( $local && ( $user->isAllowedAny( 'delete', 'deletedhistory' ) ) ) {
                        $row .= '<td>';
                        # Link to remove from history
-                       if ( $wgUser->isAllowed( 'delete' ) ) {
+                       if ( $user->isAllowed( 'delete' ) ) {
                                $q = array( 'action' => 'delete' );
                                if ( !$iscur ) {
                                        $q['oldimage'] = $img;
@@ -910,16 +999,16 @@ class ImageHistoryList {
                                );
                        }
                        # Link to hide content. Don't show useless link to people who cannot hide revisions.
-                       $canHide = $wgUser->isAllowed( 'deleterevision' );
-                       if ( $canHide || ( $wgUser->isAllowed( 'deletedhistory' ) && $file->getVisibility() ) ) {
-                               if ( $wgUser->isAllowed( 'delete' ) ) {
+                       $canHide = $user->isAllowed( 'deleterevision' );
+                       if ( $canHide || ( $user->isAllowed( 'deletedhistory' ) && $file->getVisibility() ) ) {
+                               if ( $user->isAllowed( 'delete' ) ) {
                                        $row .= '<br />';
                                }
                                // If file is top revision or locked from this user, don't link
                                if ( $iscur || !$file->userCan( File::DELETED_RESTRICTED ) ) {
                                        $del = Linker::revDeleteLinkDisabled( $canHide );
                                } else {
-                                       list( $ts, $name ) = explode( '!', $img, 2 );
+                                       list( $ts, ) = explode( '!', $img, 2 );
                                        $query = array(
                                                'type'   => 'oldimage',
                                                'target' => $this->title->getPrefixedText(),
@@ -937,7 +1026,7 @@ class ImageHistoryList {
                $row .= '<td>';
                if ( $iscur ) {
                        $row .= wfMsgHtml( 'filehist-current' );
-               } elseif ( $local && $wgUser->isLoggedIn() && $this->title->userCan( 'edit' ) ) {
+               } elseif ( $local && $user->isLoggedIn() && $this->title->userCan( 'edit' ) ) {
                        if ( $file->isDeleted( File::DELETED_FILE ) ) {
                                $row .= wfMsgHtml( 'filehist-revert' );
                        } else {
@@ -948,7 +1037,7 @@ class ImageHistoryList {
                                        array(
                                                'action' => 'revert',
                                                'oldimage' => $img,
-                                               'wpEditToken' => $wgUser->editToken( $img )
+                                               'wpEditToken' => $user->getEditToken( $img )
                                        ),
                                        array( 'known', 'noclasses' )
                                );
@@ -963,7 +1052,7 @@ class ImageHistoryList {
                $row .= "<td $selected style='white-space: nowrap;'>";
                if ( !$file->userCan( File::DELETED_FILE ) ) {
                        # Don't link to unviewable files
-                       $row .= '<span class="history-deleted">' . $wgLang->timeAndDate( $timestamp, true ) . '</span>';
+                       $row .= '<span class="history-deleted">' . $lang->timeanddate( $timestamp, true ) . '</span>';
                } elseif ( $file->isDeleted( File::DELETED_FILE ) ) {
                        if ( $local ) {
                                $this->preventClickjacking();
@@ -971,22 +1060,22 @@ class ImageHistoryList {
                                # Make a link to review the image
                                $url = Linker::link(
                                        $revdel,
-                                       $wgLang->timeAndDate( $timestamp, true ),
+                                       $lang->timeanddate( $timestamp, true ),
                                        array(),
                                        array(
                                                'target' => $this->title->getPrefixedText(),
                                                'file' => $img,
-                                               'token' => $wgUser->editToken( $img )
+                                               'token' => $user->getEditToken( $img )
                                        ),
                                        array( 'known', 'noclasses' )
                                );
                        } else {
-                               $url = $wgLang->timeAndDate( $timestamp, true );
+                               $url = $lang->timeanddate( $timestamp, true );
                        }
                        $row .= '<span class="history-deleted">' . $url . '</span>';
                } else {
                        $url = $iscur ? $this->current->getUrl() : $this->current->getArchiveUrl( $img );
-                       $row .= Xml::element( 'a', array( 'href' => $url ), $wgLang->timeAndDate( $timestamp, true ) );
+                       $row .= Xml::element( 'a', array( 'href' => $url ), $lang->timeanddate( $timestamp, true ) );
                }
                $row .= "</td>";
 
@@ -1008,10 +1097,10 @@ class ImageHistoryList {
                        $row .= '<span class="history-deleted">' . wfMsgHtml( 'rev-deleted-user' ) . '</span>';
                } else {
                        if ( $local ) {
-                               $row .= Linker::userLink( $user, $usertext ) . ' <span style="white-space: nowrap;">' .
-                               Linker::userToolLinks( $user, $usertext ) . '</span>';
+                               $row .= Linker::userLink( $userId, $userText ) . ' <span style="white-space: nowrap;">' .
+                               Linker::userToolLinks( $userId, $userText ) . '</span>';
                        } else {
-                               $row .= htmlspecialchars( $usertext );
+                               $row .= htmlspecialchars( $userText );
                        }
                }
                $row .= '</td>';
@@ -1020,7 +1109,7 @@ class ImageHistoryList {
                if ( $file->isDeleted( File::DELETED_COMMENT ) ) {
                        $row .= '<td><span class="history-deleted">' . wfMsgHtml( 'rev-deleted-comment' ) . '</span></td>';
                } else {
-                       $row .= '<td dir="' . $wgContLang->getDir() . '">' . Linker::commentBlock( $description, $this->title ) . '</td>';
+                       $row .= '<td dir="' . $wgContLang->getDir() . '">' . Linker::formatComment( $description, $this->title ) . '</td>';
                }
 
                $rowClass = null;
@@ -1035,8 +1124,7 @@ class ImageHistoryList {
         * @return string
         */
        protected function getThumbForLine( $file ) {
-               global $wgLang;
-
+               $lang = $this->getLanguage();
                if ( $file->allowInlineDisplay() && $file->userCan( File::DELETED_FILE ) && !$file->isDeleted( File::DELETED_FILE ) ) {
                        $params = array(
                                'width' => '120',
@@ -1047,9 +1135,9 @@ class ImageHistoryList {
                        $thumbnail = $file->transform( $params );
                        $options = array(
                                'alt' => wfMsg( 'filehist-thumbtext',
-                                       $wgLang->timeAndDate( $timestamp, true ),
-                                       $wgLang->date( $timestamp, true ),
-                                       $wgLang->time( $timestamp, true ) ),
+                                       $lang->timeanddate( $timestamp, true ),
+                                       $lang->date( $timestamp, true ),
+                                       $lang->time( $timestamp, true ) ),
                                'file-link' => true,
                        );
 
@@ -1063,10 +1151,16 @@ class ImageHistoryList {
                }
        }
 
+       /**
+        * @param $enable bool
+        */
        protected function preventClickjacking( $enable = true ) {
                $this->preventClickjacking = $enable;
        }
 
+       /**
+        * @return bool
+        */
        public function getPreventClickjacking() {
                return $this->preventClickjacking;
        }
@@ -1098,6 +1192,9 @@ class ImageHistoryPseudoPager extends ReverseChronologicalPager {
                $this->mRange = array( 0, 0 ); // display range
        }
 
+       /**
+        * @return Title
+        */
        function getTitle() {
                return $this->mTitle;
        }
@@ -1106,14 +1203,24 @@ class ImageHistoryPseudoPager extends ReverseChronologicalPager {
                return false;
        }
 
+       /**
+        * @return string
+        */
        function getIndexField() {
                return '';
        }
 
+       /**
+        * @param $row object
+        * @return string
+        */
        function formatRow( $row ) {
                return '';
        }
 
+       /**
+        * @return string
+        */
        function getBody() {
                $s = '';
                $this->doQuery();
@@ -1217,10 +1324,16 @@ class ImageHistoryPseudoPager extends ReverseChronologicalPager {
                $this->mQueryDone = true;
        }
 
+       /**
+        * @param $enable bool
+        */
        protected function preventClickjacking( $enable = true ) {
                $this->preventClickjacking = $enable;
        }
 
+       /**
+        * @return bool
+        */
        public function getPreventClickjacking() {
                return $this->preventClickjacking;
        }