X-Git-Url: http://git.heureux-cyclage.org/?a=blobdiff_plain;f=includes%2FLinker.php;h=a25013b06a7f7c1df6d41d66757639e30557ea01;hb=f052f6a0e82f41e71e693e9762c64a6e37c0ba14;hp=3161cbfeec5849b7a77244e6b5de29b270660cb3;hpb=9b923334c70f28a2925881259eda13292d06326d;p=lhc%2Fweb%2Fwiklou.git diff --git a/includes/Linker.php b/includes/Linker.php index 3161cbfeec..a25013b06a 100644 --- a/includes/Linker.php +++ b/includes/Linker.php @@ -21,13 +21,11 @@ class Linker { * Get the appropriate HTML attributes to add to the "a" element of an ex- * ternal link, as created by [wikisyntax]. * - * @param string $title The (unescaped) title text for the link - * @param string $unused Unused * @param string $class The contents of the class attribute; if an empty * string is passed, which is the default value, defaults to 'external'. */ - function getExternalLinkAttributes( $title, $unused = null, $class='' ) { - return $this->getLinkAttributesInternal( $title, $class, 'external' ); + function getExternalLinkAttributes( $class = 'external' ) { + return $this->getLinkAttributesInternal( '', $class ); } /** @@ -40,7 +38,7 @@ class Linker { * @param string $class The contents of the class attribute; if an empty * string is passed, which is the default value, defaults to 'external'. */ - function getInterwikiLinkAttributes( $title, $unused = null, $class='' ) { + function getInterwikiLinkAttributes( $title, $unused = null, $class = 'external' ) { global $wgContLang; # FIXME: We have a whole bunch of handling here that doesn't happen in @@ -49,7 +47,7 @@ class Linker { $title = $wgContLang->checkTitleEncoding( $title ); $title = preg_replace( '/[\\x00-\\x1f]/', ' ', $title ); - return $this->getLinkAttributesInternal( $title, $class, 'external' ); + return $this->getLinkAttributesInternal( $title, $class ); } /** @@ -87,20 +85,16 @@ class Linker { /** * Common code for getLinkAttributesX functions */ - private function getLinkAttributesInternal( $title, $class, $classDefault = false ) { + private function getLinkAttributesInternal( $title, $class ) { $title = htmlspecialchars( $title ); - if( $class === '' and $classDefault !== false ) { - # FIXME: Parameter defaults the hard way! We should just have - # $class = 'external' or whatever as the default in the externally- - # exposed functions, not $class = ''. - $class = $classDefault; - } $class = htmlspecialchars( $class ); $r = ''; - if( $class !== '' ) { + if ( $class != '' ) { $r .= " class=\"$class\""; } - $r .= " title=\"$title\""; + if ( $title != '') { + $r .= " title=\"$title\""; + } return $r; } @@ -212,7 +206,7 @@ class Linker { $ret = null; if( wfRunHooks( 'LinkEnd', array( $this, $target, $options, &$text, &$attribs, &$ret ) ) ) { - $ret = Xml::openElement( 'a', $attribs ) . $text . Xml::closeElement( 'a' ); + $ret = Html::rawElement( 'a', $attribs, $text ); } wfProfileOut( __METHOD__ ); @@ -222,7 +216,7 @@ class Linker { /** * Identical to link(), except $options defaults to 'known'. */ - public function linkKnown( $target, $text = null, $customAttribs = array(), $query = array(), $options = 'known' ) { + public function linkKnown( $target, $text = null, $customAttribs = array(), $query = array(), $options = array('known','noclasses') ) { return $this->link( $target, $text, $customAttribs, $query, $options ); } @@ -337,6 +331,7 @@ class Linker { global $wgUser; $threshold = intval( $wgUser->getOption( 'stubthreshold' ) ); $colour = ( $size < $threshold ) ? 'stub' : ''; + // FIXME: replace deprecated makeColouredLinkObj by link() return $this->makeColouredLinkObj( $nt, $colour, $text, $query, $trail, $prefix ); } @@ -387,7 +382,7 @@ class Linker { wfDebug("Hook LinkerMakeExternalImage changed the output of external image with url {$url} and alt text {$alt} to {$img}\n", true); return $img; } - return Xml::element( 'img', + return Html::element( 'img', array( 'src' => $url, 'alt' => $alt ) ); @@ -446,8 +441,7 @@ class Linker { $page = isset( $hp['page'] ) ? $hp['page'] : false; if ( !isset( $fp['align'] ) ) $fp['align'] = ''; if ( !isset( $fp['alt'] ) ) $fp['alt'] = ''; - # Backward compatibility, title used to always be equal to alt text - if ( !isset( $fp['title'] ) ) $fp['title'] = $fp['alt']; + if ( !isset( $fp['title'] ) ) $fp['title'] = ''; $prefix = $postfix = ''; @@ -490,7 +484,7 @@ class Linker { # If 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->isRTL() ? 'left' : 'right'; + $fp['align'] = $wgContLang->alignEnd(); } return $prefix.$this->makeThumbLink2( $title, $file, $fp, $hp, $time, $query ).$postfix; } @@ -565,8 +559,7 @@ class Linker { $page = isset( $hp['page'] ) ? $hp['page'] : false; if ( !isset( $fp['align'] ) ) $fp['align'] = 'right'; if ( !isset( $fp['alt'] ) ) $fp['alt'] = ''; - # Backward compatibility, title used to always be equal to alt text - if ( !isset( $fp['title'] ) ) $fp['title'] = $fp['alt']; + if ( !isset( $fp['title'] ) ) $fp['title'] = ''; if ( !isset( $fp['caption'] ) ) $fp['caption'] = ''; if ( empty( $hp['width'] ) ) { @@ -703,7 +696,7 @@ class Linker { ### HOTFIX. Instead of breaking, return empty string. return $text; } else { - $img = wfFindFile( $title, $time ); + $img = wfFindFile( $title, array( 'time' => $time ) ); if( $img ) { $url = $img->getURL(); $class = 'internal'; @@ -748,7 +741,7 @@ class Linker { * hook play with them, *then* expand it all at once. */ function makeExternalLink( $url, $text, $escape = true, $linktype = '', $attribs = array() ) { - $attribsText = $this->getExternalLinkAttributes( $url, $text, 'external ' . $linktype ); + $attribsText = $this->getExternalLinkAttributes( 'external ' . $linktype ); $url = htmlspecialchars( $url ); if( $escape ) { $text = htmlspecialchars( $text ); @@ -760,7 +753,7 @@ class Linker { return $link; } if ( $attribs ) { - $attribsText .= Xml::expandAttributes( $attribs ); + $attribsText .= Html::expandAttributes( $attribs ); } return ''.$text.''; } @@ -929,7 +922,7 @@ class Linker { # Render autocomments and make links: $comment = $this->formatAutoComments( $comment, $title, $local ); - $comment = $this->formatLinksInComment( $comment ); + $comment = $this->formatLinksInComment( $comment, $title, $local ); wfProfileOut( __METHOD__ ); return $comment; @@ -1016,11 +1009,16 @@ class Linker { * @param string $comment Text to format links in * @return string */ - public function formatLinksInComment( $comment ) { - return preg_replace_callback( + public function formatLinksInComment( $comment, $title = null, $local = false ) { + $this->commentContextTitle = $title; + $this->commentLocal = $local; + $html = preg_replace_callback( '/\[\[:?(.*?)(\|(.*?))*\]\]([^[]*)/', array( $this, 'formatLinksInCommentCallback' ), $comment ); + unset( $this->commentContextTitle ); + unset( $this->commentLocal ); + return $html; } protected function formatLinksInCommentCallback( $match ) { @@ -1043,10 +1041,12 @@ class Linker { $text = $match[1]; } $submatch = array(); + $thelink = null; if( preg_match( '/^' . $medians . '(.*)$/i', $match[1], $submatch ) ) { # Media link; trail not supported. $linkRegexp = '/\[\[(.*?)\]\]/'; - $thelink = $this->makeMediaLink( $submatch[1], "", $text ); + $title = Title::makeTitleSafe( NS_FILE, $submatch[1] ); + $thelink = $this->makeMediaLinkObj( $title, $text ); } else { # Other kind of link if( preg_match( $wgContLang->linkTrail(), $match[4], $submatch ) ) { @@ -1058,15 +1058,103 @@ class Linker { if (isset($match[1][0]) && $match[1][0] == ':') $match[1] = substr($match[1], 1); list( $inside, $trail ) = Linker::splitTrail( $trail ); - $thelink = $this->link( - Title::newFromText( $match[1] ), - $text . $inside - ) . $trail; + + $linkText = $text; + $linkTarget = Linker::normalizeSubpageLink( $this->commentContextTitle, + $match[1], $linkText ); + + $target = Title::newFromText( $linkTarget ); + if( $target ) { + if( $target->getText() == '' && !$this->commentLocal && $this->commentContextTitle ) { + $newTarget = clone( $this->commentContextTitle ); + $newTarget->setFragment( '#' . $target->getFragment() ); + $target = $newTarget; + } + $thelink = $this->link( + $target, + $linkText . $inside + ) . $trail; + } + } + if( $thelink ) { + // If the link is still valid, go ahead and replace it in! + $comment = preg_replace( $linkRegexp, StringUtils::escapeRegexReplacement( $thelink ), $comment, 1 ); } - $comment = preg_replace( $linkRegexp, StringUtils::escapeRegexReplacement( $thelink ), $comment, 1 ); return $comment; } + + static function normalizeSubpageLink( $contextTitle, $target, &$text ) { + # Valid link forms: + # Foobar -- normal + # :Foobar -- override special treatment of prefix (images, language links) + # /Foobar -- convert to CurrentPage/Foobar + # /Foobar/ -- convert to CurrentPage/Foobar, strip the initial / from text + # ../ -- convert to CurrentPage, from CurrentPage/CurrentSubPage + # ../Foobar -- convert to CurrentPage/Foobar, from CurrentPage/CurrentSubPage + + wfProfileIn( __METHOD__ ); + $ret = $target; # default return value is no change + + # Some namespaces don't allow subpages, + # so only perform processing if subpages are allowed + if( $contextTitle && MWNamespace::hasSubpages( $contextTitle->getNamespace() ) ) { + $hash = strpos( $target, '#' ); + if( $hash !== false ) { + $suffix = substr( $target, $hash ); + $target = substr( $target, 0, $hash ); + } else { + $suffix = ''; + } + # bug 7425 + $target = trim( $target ); + # Look at the first character + if( $target != '' && $target{0} === '/' ) { + # / at end means we don't want the slash to be shown + $m = array(); + $trailingSlashes = preg_match_all( '%(/+)$%', $target, $m ); + if( $trailingSlashes ) { + $noslash = $target = substr( $target, 1, -strlen($m[0][0]) ); + } else { + $noslash = substr( $target, 1 ); + } + + $ret = $contextTitle->getPrefixedText(). '/' . trim($noslash) . $suffix; + if( '' === $text ) { + $text = $target . $suffix; + } # this might be changed for ugliness reasons + } else { + # check for .. subpage backlinks + $dotdotcount = 0; + $nodotdot = $target; + while( strncmp( $nodotdot, "../", 3 ) == 0 ) { + ++$dotdotcount; + $nodotdot = substr( $nodotdot, 3 ); + } + if($dotdotcount > 0) { + $exploded = explode( '/', $contextTitle->GetPrefixedText() ); + if( count( $exploded ) > $dotdotcount ) { # not allowed to go below top level page + $ret = implode( '/', array_slice( $exploded, 0, -$dotdotcount ) ); + # / at the end means don't show full path + if( substr( $nodotdot, -1, 1 ) === '/' ) { + $nodotdot = substr( $nodotdot, 0, -1 ); + if( '' === $text ) { + $text = $nodotdot . $suffix; + } + } + $nodotdot = trim( $nodotdot ); + if( $nodotdot != '' ) { + $ret .= '/' . $nodotdot; + } + $ret .= $suffix; + } + } + } + } + + wfProfileOut( __METHOD__ ); + return $ret; + } /** * Wrap a comment in standard punctuation and formatting if @@ -1140,8 +1228,11 @@ class Linker { /** * parameter level defines if we are on an indentation level */ - function tocLine( $anchor, $tocline, $tocnumber, $level ) { - return "\n
  • ' . $tocnumber . ' ' . $tocline . ''; @@ -1154,22 +1245,47 @@ class Linker { /** @todo document */ function tocList($toc) { - global $wgJsMimeType; $title = wfMsgHtml('toc') ; return - '
    ' + '
    ' . '

    ' . $title . "

    \n" . $toc # no trailing newline, script should not be wrapped in a # paragraph . "\n
    " - . '\n"; + . Html::inlineScript( + 'if (window.showTocToggle) {' + . ' var tocShowText = "' . Xml::escapeJsString( wfMsg('showtoc') ) . '";' + . ' var tocHideText = "' . Xml::escapeJsString( wfMsg('hidetoc') ) . '";' + . ' showTocToggle();' + . ' } ' ) + . "\n"; + } + + /** + * Generate a table of contents from a section tree + * @param $tree Return value of ParserOutput::getSections() + * @return string HTML + */ + public function generateTOC( $tree ) { + $toc = ''; + $lastLevel = 0; + foreach ( $tree as $section ) { + if ( $section['toclevel'] > $lastLevel ) + $toc .= $this->tocIndent(); + else if ( $section['toclevel'] < $lastLevel ) + $toc .= $this->tocUnindent( + $lastLevel - $section['toclevel'] ); + else + $toc .= $this->tocLineEnd(); + + $toc .= $this->tocLine( $section['anchor'], + $section['line'], $section['number'], + $section['toclevel'], $section['index'] ); + $lastLevel = $section['toclevel']; + } + $toc .= $this->tocLineEnd(); + return $this->tocList( $toc ); } /** @@ -1237,13 +1353,12 @@ class Linker { * @return string HTML headline */ public function makeHeadline( $level, $attribs, $anchor, $text, $link, $legacyAnchor = false ) { - $ret = "" - . "$text" + . " $text" . ""; if ( $legacyAnchor !== false ) { - $ret = "$ret"; + $ret = "$ret"; } return $ret; } @@ -1740,6 +1855,7 @@ class Linker { } else $style = ''; return $this->makeKnownLinkObj( $nt, $text, $query, $trail, $prefix, '', $style ); } + /** Obsolete alias */ function makeImage( $url, $alt = '' ) { wfDeprecated( __METHOD__ ); @@ -1781,7 +1897,7 @@ class Linker { if ( $valign ) { $frameParams['valign'] = $valign; } - $file = wfFindFile( $title, $time ); + $file = wfFindFile( $title, array( 'time' => $time ) ); return $this->makeImageLink2( $title, $file, $frameParams, $handlerParams, $time ); } @@ -1795,6 +1911,7 @@ class Linker { * Used to generate section edit links that point to "other" pages * (sections that are really part of included pages). * + * @deprecated use Linker::doEditSectionLink() * @param $title Title string. * @param $section Integer: section number. */ @@ -1805,6 +1922,7 @@ class Linker { } /** + * @deprecated use Linker::doEditSectionLink() * @param $nt Title object. * @param $section Integer: section number. * @param $hint Link String: title, or default if omitted or empty @@ -1823,6 +1941,9 @@ class Linker { * @deprecated Returns raw bits of HTML, use titleAttrib() and accesskey() */ public function tooltipAndAccesskey( $name ) { + global $wgDisableTooltipsAndAccesskeys; + if ($wgDisableTooltipsAndAccesskeys) + return array(); # FIXME: If Sanitizer::expandAttributes() treated "false" as "output # no attribute" instead of "output '' as value for attribute", this # would be three lines. @@ -1841,6 +1962,9 @@ class Linker { /** @deprecated Returns raw bits of HTML, use titleAttrib() */ public function tooltip( $name, $options = null ) { + global $wgDisableTooltipsAndAccesskeys; + if ($wgDisableTooltipsAndAccesskeys) + return array(); # FIXME: If Sanitizer::expandAttributes() treated "false" as "output # no attribute" instead of "output '' as value for attribute", this # would be two lines.