Merge "prop=duplicatefiles does not show duplicates under same name"
[lhc/web/wiklou.git] / includes / Linker.php
index 083845d..632cf43 100644 (file)
@@ -198,6 +198,12 @@ class Linker {
                        wfProfileOut( __METHOD__ );
                        return "<!-- ERROR -->$html";
                }
+
+               if( is_string( $query ) ) {
+                       // some functions withing core using this still hand over query strings
+                       wfDeprecated( __METHOD__ . ' with parameter $query as string (should be array)', '1.20' );
+                       $query = wfCgiToArray( $query );
+               }
                $options = (array)$options;
 
                $dummy = new DummyLinker; // dummy linker instance for bc on the hooks
@@ -339,7 +345,7 @@ class Linker {
                } elseif ( in_array( 'known', $options ) ) {
                        $defaults['title'] = $target->getPrefixedText();
                } else {
-                       $defaults['title'] = wfMsg( 'red-link-title', $target->getPrefixedText() );
+                       $defaults['title'] = wfMessage( 'red-link-title', $target->getPrefixedText() )->text();
                }
 
                # Finally, merge the custom attribs with the default ones, and iterate
@@ -513,7 +519,8 @@ class Linker {
         * Given parameters derived from [[Image:Foo|options...]], generate the
         * HTML that that syntax inserts in the page.
         *
-        * @param $title Title object
+        * @param $parser Parser object
+        * @param $title Title object of the file (not the currently viewed page)
         * @param $file File object, or false if it doesn't exist
         * @param $frameParams Array: associative array of parameters external to the media handler.
         *     Boolean parameters are indicated by presence or absence, the value is arbitrary and
@@ -529,6 +536,7 @@ class Linker {
         *          valign          Vertical alignment (baseline, sub, super, top, text-top, middle,
         *                          bottom, text-bottom)
         *          alt             Alternate text for image (i.e. alt attribute). Plain text.
+        *          class           HTML for image classes. Plain text.
         *          caption         HTML for image caption.
         *          link-url        URL to link to
         *          link-title      Title object to link to
@@ -540,9 +548,10 @@ class Linker {
         * @param $time String: timestamp of the file, set as false for current
         * @param $query String: query params for desc url
         * @param $widthOption: Used by the parser to remember the user preference thumbnailsize
+        * @since 1.20
         * @return String: HTML for an image, with links, wrappers, etc.
         */
-       public static function makeImageLink2( Title $title, $file, $frameParams = array(),
+       public static function makeImageLink( /*Parser*/ $parser, Title $title, $file, $frameParams = array(),
                $handlerParams = array(), $time = false, $query = "", $widthOption = null )
        {
                $res = null;
@@ -572,6 +581,9 @@ class Linker {
                if ( !isset( $fp['title'] ) ) {
                        $fp['title'] = '';
                }
+               if ( !isset( $fp['class'] ) ) {
+                       $fp['class'] = '';
+               }
 
                $prefix = $postfix = '';
 
@@ -615,16 +627,20 @@ class Linker {
                }
 
                if ( isset( $fp['thumbnail'] ) || isset( $fp['manualthumb'] ) || isset( $fp['framed'] ) ) {
-                       global $wgContLang;
-                       # Create a thumbnail. Alignment depends on language
-                       # writing direction, # right aligned for left-to-right-
-                       # languages ("Western languages"), left-aligned
-                       # for right-to-left-languages ("Semitic languages")
+                       # Create a thumbnail. Alignment depends on the writing direction of
+                       # the page content language (right-aligned for LTR languages,
+                       # left-aligned for RTL languages)
                        #
-                       # If  thumbnail width has not been provided, it is set
+                       # If a thumbnail width has not been provided, it is set
                        # to the default user option as specified in Language*.php
                        if ( $fp['align'] == '' ) {
-                               $fp['align'] = $wgContLang->alignEnd();
+                               if( $parser instanceof Parser ) {
+                                       $fp['align'] = $parser->getTargetLanguage()->alignEnd();
+                               } else {
+                                       # backwards compatibility, remove with makeImageLink2()
+                                       global $wgContLang;
+                                       $fp['align'] = $wgContLang->alignEnd();
+                               }
                        }
                        return $prefix . self::makeThumbLink2( $title, $file, $fp, $hp, $time, $query ) . $postfix;
                }
@@ -651,9 +667,12 @@ class Linker {
                        $params = array(
                                'alt' => $fp['alt'],
                                'title' => $fp['title'],
-                               'valign' => isset( $fp['valign'] ) ? $fp['valign'] : false ,
-                               'img-class' => isset( $fp['border'] ) ? 'thumbborder' : false );
-                       $params = self::getImageLinkMTOParams( $fp, $query ) + $params;
+                               'valign' => isset( $fp['valign'] ) ? $fp['valign'] : false,
+                               'img-class' => $fp['class'] );
+                       if ( isset( $fp['border'] ) ) {
+                               $params['img-class'] .= ( $params['img-class'] !== '' ) ? ' thumbborder' : 'thumbborder';
+                       }
+                       $params = self::getImageLinkMTOParams( $fp, $query, $parser ) + $params;
 
                        $s = $thumb->toHtml( $params );
                }
@@ -663,6 +682,17 @@ class Linker {
                return str_replace( "\n", ' ', $prefix . $s . $postfix );
        }
 
+       /**
+        * See makeImageLink()
+        * When this function is removed, remove if( $parser instanceof Parser ) check there too
+        * @deprecated since 1.20
+        */
+       public static function makeImageLink2( Title $title, $file, $frameParams = array(),
+               $handlerParams = array(), $time = false, $query = "", $widthOption = null ) {
+               return self::makeImageLink( null, $title, $file, $frameParams,
+                       $handlerParams, $time, $query, $widthOption );
+       }
+
        /**
         * Get the link parameters for MediaTransformOutput::toHtml() from given
         * frame parameters supplied by the Parser.
@@ -670,13 +700,20 @@ class Linker {
         * @param $query string An optional query string to add to description page links
         * @return array
         */
-       private static function getImageLinkMTOParams( $frameParams, $query = '' ) {
+       private static function getImageLinkMTOParams( $frameParams, $query = '', $parser = null ) {
                $mtoParams = array();
                if ( isset( $frameParams['link-url'] ) && $frameParams['link-url'] !== '' ) {
                        $mtoParams['custom-url-link'] = $frameParams['link-url'];
                        if ( isset( $frameParams['link-target'] ) ) {
                                $mtoParams['custom-target-link'] = $frameParams['link-target'];
                        }
+                       if ( $parser ) {
+                               $extLinkAttrs = $parser->getExternalLinkAttribs( $frameParams['link-url'] );
+                               foreach ( $extLinkAttrs as $name => $val ) {
+                                       // Currently could include 'rel' and 'target'
+                                       $mtoParams['parser-extlink-'.$name] = $val;
+                               }
+                       }
                } elseif ( isset( $frameParams['link-title'] ) && $frameParams['link-title'] !== '' ) {
                        $mtoParams['custom-title-link'] = self::normaliseSpecialPage( $frameParams['link-title'] );
                } elseif ( !empty( $frameParams['no-link'] ) ) {
@@ -795,13 +832,14 @@ class Linker {
                        $s .= self::makeBrokenImageLinkObj( $title, $fp['title'], '', '', '', $time == true );
                        $zoomIcon = '';
                } elseif ( !$thumb ) {
-                       $s .= htmlspecialchars( wfMsg( 'thumbnail_error', '' ) );
+                       $s .= wfMessage( 'thumbnail_error', '' )->escaped();
                        $zoomIcon = '';
                } else {
                        $params = array(
                                'alt' => $fp['alt'],
                                'title' => $fp['title'],
-                               'img-class' => 'thumbimage' );
+                               'img-class' => ( isset( $fp['class'] ) && $fp['class'] !== '' ) ? $fp['class'] . ' thumbimage' : 'thumbimage'
+                       );
                        $params = self::getImageLinkMTOParams( $fp, $query ) + $params;
                        $s .= $thumb->toHtml( $params );
                        if ( isset( $fp['framed'] ) ) {
@@ -811,7 +849,7 @@ class Linker {
                                        Html::rawElement( 'a', array(
                                                'href' => $url,
                                                'class' => 'internal',
-                                               'title' => wfMsg( 'thumbnail-more' ) ),
+                                               'title' => wfMessage( 'thumbnail-more' )->text() ),
                                                Html::element( 'img', array(
                                                        'src' => $wgStylePath . '/common/images/magnify-clip' . ( $wgContLang->isRTL() ? '-rtl' : '' ) . '.png',
                                                        'width' => 15,
@@ -851,7 +889,7 @@ class Linker {
 
                        if ( $redir ) {
                                wfProfileOut( __METHOD__ );
-                               return self::linkKnown( $title, "$prefix$html$inside", array(), $query ) . $trail;
+                               return self::linkKnown( $title, "$prefix$html$inside", array(), wfCgiToArray( $query ) ) . $trail;
                        }
 
                        $href = self::getUploadUrl( $title, $query );
@@ -862,7 +900,7 @@ class Linker {
                                "$prefix$html$inside</a>$trail";
                } else {
                        wfProfileOut( __METHOD__ );
-                       return self::linkKnown( $title, "$prefix$html$inside", array(), $query ) . $trail;
+                       return self::linkKnown( $title, "$prefix$html$inside", array(), wfCgiToArray( $query ) ) . $trail;
                }
        }
 
@@ -941,7 +979,7 @@ class Linker {
                        $key = strtolower( $name );
                }
 
-               return self::linkKnown( SpecialPage::getTitleFor( $name ) , wfMsg( $key ) );
+               return self::linkKnown( SpecialPage::getTitleFor( $name ) , wfMessage( $key )->text() );
        }
 
        /**
@@ -1033,7 +1071,7 @@ class Linker {
                        }
                        $contribsPage = SpecialPage::getTitleFor( 'Contributions', $userText );
 
-                       $items[] = self::link( $contribsPage, wfMsgHtml( 'contribslink' ), $attribs );
+                       $items[] = self::link( $contribsPage, wfMessage( 'contribslink' )->escaped(), $attribs );
                }
                if ( $blockable && $wgUser->isAllowed( 'block' ) ) {
                        $items[] = self::blockLink( $userId, $userText );
@@ -1074,7 +1112,7 @@ class Linker {
         */
        public static function userTalkLink( $userId, $userText ) {
                $userTalkPage = Title::makeTitle( NS_USER_TALK, $userText );
-               $userTalkLink = self::link( $userTalkPage, wfMsgHtml( 'talkpagelinktext' ) );
+               $userTalkLink = self::link( $userTalkPage, wfMessage( 'talkpagelinktext' )->escaped() );
                return $userTalkLink;
        }
 
@@ -1085,7 +1123,7 @@ class Linker {
         */
        public static function blockLink( $userId, $userText ) {
                $blockPage = SpecialPage::getTitleFor( 'Block', $userText );
-               $blockLink = self::link( $blockPage, wfMsgHtml( 'blocklink' ) );
+               $blockLink = self::link( $blockPage, wfMessage( 'blocklink' )->escaped() );
                return $blockLink;
        }
 
@@ -1096,7 +1134,7 @@ class Linker {
         */
        public static function emailLink( $userId, $userText ) {
                $emailPage = SpecialPage::getTitleFor( 'Emailuser', $userText );
-               $emailLink = self::link( $emailPage, wfMsgHtml( 'emaillink' ) );
+               $emailLink = self::link( $emailPage, wfMessage( 'emaillink' )->escaped() );
                return $emailLink;
        }
 
@@ -1108,12 +1146,12 @@ class Linker {
         */
        public static function revUserLink( $rev, $isPublic = false ) {
                if ( $rev->isDeleted( Revision::DELETED_USER ) && $isPublic ) {
-                       $link = wfMsgHtml( 'rev-deleted-user' );
+                       $link = wfMessage( 'rev-deleted-user' )->escaped();
                } elseif ( $rev->userCan( Revision::DELETED_USER ) ) {
                        $link = self::userLink( $rev->getUser( Revision::FOR_THIS_USER ),
                                $rev->getUserText( Revision::FOR_THIS_USER ) );
                } else {
-                       $link = wfMsgHtml( 'rev-deleted-user' );
+                       $link = wfMessage( 'rev-deleted-user' )->escaped();
                }
                if ( $rev->isDeleted( Revision::DELETED_USER ) ) {
                        return '<span class="history-deleted">' . $link . '</span>';
@@ -1129,7 +1167,7 @@ class Linker {
         */
        public static function revUserTools( $rev, $isPublic = false ) {
                if ( $rev->isDeleted( Revision::DELETED_USER ) && $isPublic ) {
-                       $link = wfMsgHtml( 'rev-deleted-user' );
+                       $link = wfMessage( 'rev-deleted-user' )->escaped();
                } elseif ( $rev->userCan( Revision::DELETED_USER ) ) {
                        $userId = $rev->getUser( Revision::FOR_THIS_USER );
                        $userText = $rev->getUserText( Revision::FOR_THIS_USER );
@@ -1137,7 +1175,7 @@ class Linker {
                                . wfMessage( 'word-separator' )->plain()
                                . self::userToolLinks( $userId, $userText );
                } else {
-                       $link = wfMsgHtml( 'rev-deleted-user' );
+                       $link = wfMessage( 'rev-deleted-user' )->escaped();
                }
                if ( $rev->isDeleted( Revision::DELETED_USER ) ) {
                        return ' <span class="history-deleted">' . $link . '</span>';
@@ -1251,11 +1289,11 @@ class Linker {
                        }
                        if ( $pre ) {
                                # written summary $presep autocomment (summary /* section */)
-                               $pre .= wfMsgExt( 'autocomment-prefix', array( 'escapenoentities', 'content' ) );
+                               $pre .= wfMessage( 'autocomment-prefix' )->inContentLanguage()->escaped();
                        }
                        if ( $post ) {
                                # autocomment $postsep written summary (/* section */ summary)
-                               $auto .= wfMsgExt( 'colon-separator', array( 'escapenoentities', 'content' ) );
+                               $auto .= wfMessage( 'colon-separator' )->inContentLanguage()->escaped();
                        }
                        $auto = '<span class="autocomment">' . $auto . '</span>';
                        $comment = $pre . $link . $wgLang->getDirMark() . '<span dir="auto">' . $auto . $post . '</span>';
@@ -1477,12 +1515,12 @@ class Linker {
                        return "";
                }
                if ( $rev->isDeleted( Revision::DELETED_COMMENT ) && $isPublic ) {
-                       $block = " <span class=\"comment\">" . wfMsgHtml( 'rev-deleted-comment' ) . "</span>";
+                       $block = " <span class=\"comment\">" . wfMessage( 'rev-deleted-comment' )->escaped() . "</span>";
                } elseif ( $rev->userCan( Revision::DELETED_COMMENT ) ) {
                        $block = self::commentBlock( $rev->getComment( Revision::FOR_THIS_USER ),
                                $rev->getTitle(), $local );
                } else {
-                       $block = " <span class=\"comment\">" . wfMsgHtml( 'rev-deleted-comment' ) . "</span>";
+                       $block = " <span class=\"comment\">" . wfMessage( 'rev-deleted-comment' )->escaped() . "</span>";
                }
                if ( $rev->isDeleted( Revision::DELETED_COMMENT ) ) {
                        return " <span class=\"history-deleted\">$block</span>";
@@ -1496,13 +1534,11 @@ class Linker {
         */
        public static function formatRevisionSize( $size ) {
                if ( $size == 0 ) {
-                       $stxt = wfMsgExt( 'historyempty', 'parsemag' );
+                       $stxt = wfMessage( 'historyempty' )->escaped();
                } else {
-                       global $wgLang;
-                       $stxt = wfMsgExt( 'nbytes', 'parsemag', $wgLang->formatNum( $size ) );
+                       $stxt = wfMessage( 'nbytes' )->numParams( $size )->escaped();
                        $stxt = wfMessage( 'parentheses' )->rawParams( $stxt )->escaped();
                }
-               $stxt = htmlspecialchars( $stxt );
                return "<span class=\"history-size\">$stxt</span>";
        }
 
@@ -1558,7 +1594,7 @@ class Linker {
         * @return String: full html of the TOC
         */
        public static function tocList( $toc, $lang = false ) {
-               $title = wfMsgExt( 'toc', array( 'language' => $lang, 'escape' ) );
+               $title = wfMessage( 'toc' )->inLanguage( $lang )->escaped();
                return
                   '<table id="toc" class="toc"><tr><td>'
                 . '<div id="toctitle"><h2>' . $title . "</h2></div>\n"
@@ -1673,6 +1709,11 @@ class Linker {
         * @return String: HTML fragment
         */
        public static function buildRollbackLink( $rev, IContextSource $context = null ) {
+               global $wgShowRollbackEditCount, $wgMiserMode;
+               
+               // To config which pages are effected by miser mode
+               $disableRollbackEditCountSpecialPage = array( 'Recentchanges', 'Watchlist' );
+
                if ( $context === null ) {
                        $context = RequestContext::getMain();
                }
@@ -1687,13 +1728,61 @@ class Linker {
                        $query['bot'] = '1';
                        $query['hidediff'] = '1'; // bug 15999
                }
-               return self::link(
-                       $title,
-                       $context->msg( 'rollbacklink' )->escaped(),
-                       array( 'title' => $context->msg( 'tooltip-rollback' )->text() ),
-                       $query,
-                       array( 'known', 'noclasses' )
-               );
+
+               $disableRollbackEditCount = false;
+               if( $wgMiserMode ) {
+                       foreach( $disableRollbackEditCountSpecialPage as $specialPage ) {
+                               if( $context->getTitle()->isSpecial( $specialPage ) ) {
+                                       $disableRollbackEditCount = true;
+                                       break;
+                               }
+                       }
+               }
+
+               if( !$disableRollbackEditCount && is_int( $wgShowRollbackEditCount ) && $wgShowRollbackEditCount > 0 ) {
+                       $dbr = wfGetDB( DB_SLAVE );
+
+                       // Up to the value of $wgShowRollbackEditCount revisions are counted
+                       $res = $dbr->select( 'revision',
+                               array( 'rev_id', 'rev_user_text' ),
+                               // $rev->getPage() returns null sometimes
+                               array( 'rev_page' => $rev->getTitle()->getArticleID() ),
+                               __METHOD__,
+                               array(  'USE INDEX' => 'page_timestamp',
+                                       'ORDER BY' => 'rev_timestamp DESC',
+                                       'LIMIT' => $wgShowRollbackEditCount + 1 )
+                       );
+
+                       $editCount = 0;
+                       while( $row = $dbr->fetchObject( $res ) ) {
+                               if( $rev->getUserText() != $row->rev_user_text ) {
+                                       break;
+                               }
+                               $editCount++;
+                       }
+
+                       if( $editCount > $wgShowRollbackEditCount ) {
+                               $editCount_output = $context->msg( 'rollbacklinkcount-morethan' )->numParams( $wgShowRollbackEditCount )->parse();
+                       } else {
+                               $editCount_output = $context->msg( 'rollbacklinkcount' )->numParams( $editCount )->parse();
+                       }
+
+                       return self::link(
+                               $title,
+                               $editCount_output,
+                               array( 'title' => $context->msg( 'tooltip-rollback' )->text() ),
+                               $query,
+                               array( 'known', 'noclasses' )
+                       );
+               } else {
+                       return self::link(
+                               $title,
+                               $context->msg( 'rollbacklink' )->escaped(),
+                               array( 'title' => $context->msg( 'tooltip-rollback' )->text() ),
+                               $query,
+                               array( 'known', 'noclasses' )
+                       );
+               }
        }
 
        /**
@@ -1720,11 +1809,14 @@ class Linker {
                        # Construct the HTML
                        $outText = '<div class="mw-templatesUsedExplanation">';
                        if ( $preview ) {
-                               $outText .= wfMsgExt( 'templatesusedpreview', array( 'parse' ), count( $templates ) );
+                               $outText .= wfMessage( 'templatesusedpreview' )->numParams( count( $templates ) )
+                                       ->parseAsBlock();
                        } elseif ( $section ) {
-                               $outText .= wfMsgExt( 'templatesusedsection', array( 'parse' ), count( $templates ) );
+                               $outText .= wfMessage( 'templatesusedsection' )->numParams( count( $templates ) )
+                                       ->parseAsBlock();
                        } else {
-                               $outText .= wfMsgExt( 'templatesused', array( 'parse' ), count( $templates ) );
+                               $outText .= wfMessage( 'templatesused' )->numParams( count( $templates ) )
+                                       ->parseAsBlock();
                        }
                        $outText .= "</div><ul>\n";
 
@@ -1732,23 +1824,23 @@ class Linker {
                        foreach ( $templates as $titleObj ) {
                                $r = $titleObj->getRestrictions( 'edit' );
                                if ( in_array( 'sysop', $r ) ) {
-                                       $protected = wfMsgExt( 'template-protected', array( 'parseinline' ) );
+                                       $protected = wfMessage( 'template-protected' )->parse();
                                } elseif ( in_array( 'autoconfirmed', $r ) ) {
-                                       $protected = wfMsgExt( 'template-semiprotected', array( 'parseinline' ) );
+                                       $protected = wfMessage( 'template-semiprotected' )->parse();
                                } else {
                                        $protected = '';
                                }
                                if ( $titleObj->quickUserCan( 'edit' ) ) {
                                        $editLink = self::link(
                                                $titleObj,
-                                               wfMsg( 'editlink' ),
+                                               wfMessage( 'editlink' )->text(),
                                                array(),
                                                array( 'action' => 'edit' )
                                        );
                                } else {
                                        $editLink = self::link(
                                                $titleObj,
-                                               wfMsg( 'viewsourcelink' ),
+                                               wfMessage( 'viewsourcelink' )->text(),
                                                array(),
                                                array( 'action' => 'edit' )
                                        );
@@ -1776,7 +1868,7 @@ class Linker {
                if ( count( $hiddencats ) > 0 ) {
                        # Construct the HTML
                        $outText = '<div class="mw-hiddenCategoriesExplanation">';
-                       $outText .= wfMsgExt( 'hiddencategories', array( 'parse' ), $wgLang->formatnum( count( $hiddencats ) ) );
+                       $outText .= wfMessage( 'hiddencategories' )->numParams( count( $hiddencats ) )->parseAsBlock();
                        $outText .= "</div><ul>\n";
 
                        foreach ( $hiddencats as $titleObj ) {
@@ -1936,7 +2028,8 @@ class Linker {
         */
        public static function revDeleteLink( $query = array(), $restricted = false, $delete = true ) {
                $sp = SpecialPage::getTitleFor( 'Revisiondelete' );
-               $html = $delete ? wfMsgHtml( 'rev-delundel' ) : wfMsgHtml( 'rev-showdeleted' );
+               $msgKey = $delete ? 'rev-delundel' : 'rev-showdeleted';
+               $html = wfMessage( $msgKey )->escaped();
                $tag = $restricted ? 'strong' : 'span';
                $link = self::link( $sp, $html, array(), $query, array( 'known', 'noclasses' ) );
                return Xml::tags( $tag, array( 'class' => 'mw-revdelundel-link' ), wfMessage( 'parentheses' )->rawParams( $link )->escaped() );
@@ -1951,8 +2044,10 @@ class Linker {
         * of appearance with CSS
         */
        public static function revDeleteLinkDisabled( $delete = true ) {
-               $html = $delete ? wfMsgHtml( 'rev-delundel' ) : wfMsgHtml( 'rev-showdeleted' );
-               return Xml::tags( 'span', array( 'class' => 'mw-revdelundel-link' ), wfMessage( 'parentheses' )->rawParams( $html )->escaped() );
+               $msgKey = $delete ? 'rev-delundel' : 'rev-showdeleted';
+               $html = wfMessage( $msgKey )->escaped();
+               $htmlParentheses = wfMessage( 'parentheses' )->rawParams( $html )->escaped();
+               return Xml::tags( 'span', array( 'class' => 'mw-revdelundel-link' ), $htmlParentheses );
        }
 
        /* Deprecated methods */