From 81d611bcac8d291ce98c49f89bbb14b746576d72 Mon Sep 17 00:00:00 2001 From: Aryeh Gregor Date: Tue, 5 Aug 2008 17:05:59 +0000 Subject: [PATCH] Re-commit turning makeKnownLinkObj(), makeBrokenLinkObj(), makeLinkObj() into link() wrappers. This should mean that all link processing now goes through link(). Per Brion's advice, remove the BrokenLink hook and replace it with LinkBegin and LinkEnd hooks. All parser tests pass except the usual suspects. --- docs/hooks.txt | 41 ++++++--- includes/GlobalFunctions.php | 28 ++++++ includes/Linker.php | 166 +++++++++++++++-------------------- includes/Sanitizer.php | 2 +- includes/Xml.php | 2 +- maintenance/parserTests.txt | 6 +- 6 files changed, 133 insertions(+), 112 deletions(-) diff --git a/docs/hooks.txt b/docs/hooks.txt index df13a6650a..69ab7723c8 100644 --- a/docs/hooks.txt +++ b/docs/hooks.txt @@ -479,18 +479,6 @@ $user: the user who did the block (not the one being blocked) $isbn: ISBN to show information for $output: OutputPage object in use -'BrokenLink': Before the HTML is created for a broken (i.e. red) link -&$linker: Linker instance -$nt: the page title -$query: the URL query string passed in -&$u: the URL of this link -&$style: the inline CSS style -&$prefix: a prefix prepended to the linked text -&$text: the text placed by the user in the wiki-link -&$inside: any additional alphanumeric characters placed after the wiki-link, -that are made part of the link text -&$trail: text placed immediately after the HTML link - 'CategoryPageView': before viewing a categorypage in CategoryPage::view $catpage: CategoryPage instance @@ -754,6 +742,35 @@ $lang: laguage code (string) $specialPageAliases: associative array of magic words synonyms $lang: laguage code (string) +'LinkBegin': Used when generating internal and interwiki links in +Linker::link(), before processing starts. Return false to skip default proces- +sing and return $ret. See documentation for Linker::link() for details on the +expected meanings of parameters. +$skin: the Skin object +$target: the Title that the link is pointing to +&$text: the contents that the tag should have (raw HTML); null means "de- + fault" +&$customAttribs: the HTML attributes that the tag should have, in associa- + tive array form, with keys and values unescaped. Should be merged with de- + fault values, with a value of false meaning to suppress the attribute. +&$query: the query string to add to the generated URL (the bit after the "?"), + in associative array form, with keys and values unescaped. +&$options: the options. Can include 'known', 'broken', 'noclasses'. +&$ret: the value to return if your hook returns false. + +'LinkEnd': Used when generating internal and interwiki links in Linker::link(), +just before the function returns a value. If you return true, an element +with HTML attributes $attribs and contents $text will be returned. If you re- +turn false, $ret will be returned. +$skin: the Skin object +$target: the Title object that the link is pointing to +$options: the options. Will always include either 'known' or 'broken', and may + include 'noclasses'. +&$text: the final (raw HTML) contents of the tag, after processing. +&$attribs: the final HTML attributes of the tag, after processing, in asso- + ciative array form. +&$ret: the value to return if your hook returns false. + 'LinkerMakeExternalImage': At the end of Linker::makeExternalImage() just before the return &$url: the image url &$alt: the image's alt text diff --git a/includes/GlobalFunctions.php b/includes/GlobalFunctions.php index c0d7fe9398..c5d5f1f567 100644 --- a/includes/GlobalFunctions.php +++ b/includes/GlobalFunctions.php @@ -1055,6 +1055,34 @@ function wfArrayToCGI( $array1, $array2 = NULL ) return $cgi; } +/** + * This is the logical opposite of wfArrayToCGI(): it accepts a query string as + * its argument and returns the same string in array form. This allows compa- + * tibility with legacy functions that accept raw query strings instead of nice + * arrays. Of course, keys and values are urldecode()d. Don't try passing in- + * valid query strings, or it will explode. + * + * @param $query string Query string + * @return array Array version of input + */ +function wfCgiToArray( $query ) { + if( isset( $query[0] ) and $query[0] == '?' ) { + $query = substr( $query, 1 ); + } + $bits = explode( '&', $query ); + $ret = array(); + foreach( $bits as $bit ) { + if( $bit === '' ) { + continue; + } + list( $key, $value ) = explode( '=', $bit ); + $key = urldecode( $key ); + $value = urldecode( $value ); + $ret[$key] = $value; + } + return $ret; +} + /** * Append a query string to an existing URL, which may or may not already * have query string parameters already. If so, they will be combined. diff --git a/includes/Linker.php b/includes/Linker.php index b913ebf10c..9cee79f2b3 100644 --- a/includes/Linker.php +++ b/includes/Linker.php @@ -168,6 +168,13 @@ class Linker { */ public function link( $target, $text = null, $customAttribs = array(), $query = array(), $options = array() ) { wfProfileIn( __METHOD__ ); + $ret = null; + if( !wfRunHooks( 'LinkBegin', array( $this, $target, &$text, + &$customAttribs, &$query, &$options, &$ret ) ) ) { + wfProfileOut( __METHOD__ ); + return $ret; + } + if( !$target instanceof Title ) { throw new MWException( 'Linker::link passed invalid target' ); } @@ -205,9 +212,13 @@ class Linker { $text = $this->linkText( $target ); } - $ret = Xml::openElement( 'a', $attribs ) - . $text - . Xml::closeElement( 'a' ); + $ret = null; + if( wfRunHooks( 'LinkEnd', array( $this, $target, $options, &$text, + &$attribs, &$ret ) ) ) { + $ret = Xml::openElement( 'a', $attribs ) + . $text + . Xml::closeElement( 'a' ); + } wfProfileOut( __METHOD__ ); return $ret; @@ -215,6 +226,13 @@ class Linker { private function linkUrl( $target, $query, $options ) { wfProfileIn( __METHOD__ ); + # We don't want to include fragments for broken links, because they + # generally make no sense. + if( in_array( 'broken', $options ) and $target->mFragment !== '' ) { + $target = clone $target; + $target->mFragment = ''; + } + # If it's a broken link, add the appropriate query pieces, unless # there's already an action specified, or unless 'edit' makes no sense # (i.e., for a nonexistent special page). @@ -235,7 +253,7 @@ class Linker { if( !in_array( 'noclasses', $options ) ) { wfProfileIn( __METHOD__ . '-getClasses' ); - # Build the classes. + # Now build the classes. $classes = array(); if( in_array( 'broken', $options ) ) { @@ -294,6 +312,8 @@ class Linker { } /** + * @deprecated Use link() + * * This function is a shortcut to makeLinkObj(Title::newFromText($title),...). Do not call * it if you already have a title object handy. See makeLinkObj for further documentation. * @@ -305,6 +325,7 @@ class Linker { * the end of the link. */ function makeLink( $title, $text = '', $query = '', $trail = '' ) { + wfDeprecated( __METHOD__ ); wfProfileIn( __METHOD__ ); $nt = Title::newFromText( $title ); if ( $nt instanceof Title ) { @@ -319,6 +340,8 @@ class Linker { } /** + * @deprecated Use link() + * * This function is a shortcut to makeKnownLinkObj(Title::newFromText($title),...). Do not call * it if you already have a title object handy. See makeKnownLinkObj for further documentation. * @@ -330,6 +353,7 @@ class Linker { * the end of the link. */ function makeKnownLink( $title, $text = '', $query = '', $trail = '', $prefix = '',$aprops = '') { + wfDeprecated( __METHOD__ ); $nt = Title::newFromText( $title ); if ( $nt instanceof Title ) { return $this->makeKnownLinkObj( $nt, $text, $query, $trail, $prefix , $aprops ); @@ -340,6 +364,8 @@ class Linker { } /** + * @deprecated Use link() + * * This function is a shortcut to makeBrokenLinkObj(Title::newFromText($title),...). Do not call * it if you already have a title object handy. See makeBrokenLinkObj for further documentation. * @@ -351,6 +377,7 @@ class Linker { * the end of the link. */ function makeBrokenLink( $title, $text = '', $query = '', $trail = '' ) { + wfDeprecated( __METHOD__ ); $nt = Title::newFromText( $title ); if ( $nt instanceof Title ) { return $this->makeBrokenLinkObj( $nt, $text, $query, $trail ); @@ -361,7 +388,7 @@ class Linker { } /** - * @deprecated use makeColouredLinkObj + * @deprecated Use link() * * This function is a shortcut to makeStubLinkObj(Title::newFromText($title),...). Do not call * it if you already have a title object handy. See makeStubLinkObj for further documentation. @@ -374,6 +401,7 @@ class Linker { * the end of the link. */ function makeStubLink( $title, $text = '', $query = '', $trail = '' ) { + wfDeprecated( __METHOD__ ); $nt = Title::newFromText( $title ); if ( $nt instanceof Title ) { return $this->makeStubLinkObj( $nt, $text, $query, $trail ); @@ -384,6 +412,8 @@ class Linker { } /** + * @deprecated Use link() + * * Make a link for a title which may or may not be in the database. If you need to * call this lots of times, pre-fill the link cache with a LinkBatch, otherwise each * call to this will result in a DB query. @@ -398,64 +428,26 @@ class Linker { * @param $prefix String: optional prefix. As trail, only before instead of after. */ function makeLinkObj( Title $nt, $text= '', $query = '', $trail = '', $prefix = '' ) { + wfDeprecated( __METHOD__ ); global $wgUser; wfProfileIn( __METHOD__ ); - if ( $nt->isExternal() ) { - $u = $nt->getFullURL(); - $link = $nt->getPrefixedURL(); - if ( '' == $text ) { $text = $nt->getPrefixedText(); } - $style = $this->getInterwikiLinkAttributes( $link, $text, 'extiw' ); - - $inside = ''; - if ( '' != $trail ) { - $m = array(); - if ( preg_match( '/^([a-z]+)(.*)$$/sD', $trail, $m ) ) { - $inside = $m[1]; - $trail = $m[2]; - } - } - $t = "{$text}{$inside}"; + $query = wfCgiToArray( $query ); + list( $inside, $trail ) = Linker::splitTrail( $trail ); + if( $text === '' ) { + $text = $this->linkText( $nt ); + } - wfProfileOut( __METHOD__ ); - return $t; - } elseif ( $nt->isAlwaysKnown() ) { - # Image links, special page links and self-links with fragments are always known. - $retVal = $this->makeKnownLinkObj( $nt, $text, $query, $trail, $prefix ); - } else { - wfProfileIn( __METHOD__.'-immediate' ); + $ret = $this->link( $nt, "$prefix$text$inside", array(), $query, + 'noclasses' ) . $trail; - # Handles links to special pages which do not exist in the database: - if( $nt->getNamespace() == NS_SPECIAL ) { - if( SpecialPage::exists( $nt->getDBkey() ) ) { - $retVal = $this->makeKnownLinkObj( $nt, $text, $query, $trail, $prefix ); - } else { - $retVal = $this->makeBrokenLinkObj( $nt, $text, $query, $trail, $prefix ); - } - wfProfileOut( __METHOD__.'-immediate' ); - wfProfileOut( __METHOD__ ); - return $retVal; - } - - # Work out link colour immediately - $aid = $nt->getArticleID() ; - if ( 0 == $aid ) { - $retVal = $this->makeBrokenLinkObj( $nt, $text, $query, $trail, $prefix ); - } else { - $colour = ''; - if ( $nt->isContentPage() ) { - $threshold = $wgUser->getOption('stubthreshold'); - $colour = $this->getLinkColour( $nt, $threshold ); - } - $retVal = $this->makeColouredLinkObj( $nt, $colour, $text, $query, $trail, $prefix ); - } - wfProfileOut( __METHOD__.'-immediate' ); - } wfProfileOut( __METHOD__ ); - return $retVal; + return $ret; } /** + * @deprecated Use link() + * * Make a link for a title which definitely exists. This is faster than makeLinkObj because * it doesn't have to do a database query. It's also valid for interwiki titles and special * pages. @@ -470,36 +462,29 @@ class Linker { * @return the a-element */ function makeKnownLinkObj( Title $title, $text = '', $query = '', $trail = '', $prefix = '' , $aprops = '', $style = '' ) { + wfDeprecated( __METHOD__ ); wfProfileIn( __METHOD__ ); - $nt = $this->normaliseSpecialPage( $title ); - - $u = $nt->escapeLocalURL( $query ); - if ( $nt->getFragment() != '' ) { - if( $nt->getPrefixedDbkey() == '' ) { - $u = ''; - if ( '' == $text ) { - $text = htmlspecialchars( $nt->getFragment() ); - } - } - $u .= $nt->getFragmentForURL(); - } if ( $text == '' ) { - $text = htmlspecialchars( $nt->getPrefixedText() ); - } - if ( $style == '' ) { - $style = $this->getInternalLinkAttributesObj( $nt, $text ); + $text = $this->linkText( $title ); } + $attribs = Sanitizer::mergeAttributes( + Sanitizer::decodeTagAttributes( $aprops ), + Sanitizer::decodeTagAttributes( $style ) + ); + $query = wfCgiToArray( $query ); + list( $inside, $trail ) = Linker::splitTrail( $trail ); - if ( $aprops !== '' ) $aprops = " $aprops"; + $ret = $this->link( $title, "$prefix$text$inside", $attribs, $query, + array( 'known', 'noclasses' ) ) . $trail; - list( $inside, $trail ) = Linker::splitTrail( $trail ); - $r = "{$prefix}{$text}{$inside}{$trail}"; wfProfileOut( __METHOD__ ); - return $r; + return $ret; } /** + * @deprecated Use link() + * * Make a red link to the edit page of a given title. * * @param $nt Title object of the target page @@ -510,36 +495,24 @@ class Linker { * the end of the link. */ function makeBrokenLinkObj( Title $title, $text = '', $query = '', $trail = '', $prefix = '' ) { + wfDeprecated( __METHOD__ ); wfProfileIn( __METHOD__ ); - $nt = $this->normaliseSpecialPage( $title ); - - if( $nt->getNamespace() == NS_SPECIAL ) { - $q = $query; - } else if ( '' == $query ) { - $q = 'action=edit&redlink=1'; - } else { - $q = 'action=edit&redlink=1&'.$query; - } - $u = $nt->escapeLocalURL( $q ); - - $titleText = $nt->getPrefixedText(); - if ( '' == $text ) { - $text = htmlspecialchars( $titleText ); - } - $titleAttr = wfMsg( 'red-link-title', $titleText ); - $style = $this->getInternalLinkAttributesObj( $nt, $text, 'new', $titleAttr ); list( $inside, $trail ) = Linker::splitTrail( $trail ); + if( $text === '' ) { + $text = $this->linkText( $title ); + } + $nt = $this->normaliseSpecialPage( $title ); - wfRunHooks( 'BrokenLink', array( &$this, $nt, $query, &$u, &$style, &$prefix, &$text, &$inside, &$trail ) ); - $s = "{$prefix}{$text}{$inside}{$trail}"; + $ret = $this->link( $title, "$prefix$text$inside", array(), + wfCgiToArray( $query ), 'broken' ) . $trail; wfProfileOut( __METHOD__ ); - return $s; + return $ret; } /** - * @deprecated use makeColouredLinkObj + * @deprecated Use link() * * Make a brown link to a short article. * @@ -556,6 +529,8 @@ class Linker { } /** + * @deprecated Use link() + * * Make a coloured link. * * @param $nt Title object of the target page @@ -567,6 +542,7 @@ class Linker { * the end of the link. */ function makeColouredLinkObj( $nt, $colour, $text = '', $query = '', $trail = '', $prefix = '' ) { + wfDeprecated( __METHOD__ ); if($colour != ''){ $style = $this->getInternalLinkAttributesObj( $nt, $text, $colour ); } else $style = ''; diff --git a/includes/Sanitizer.php b/includes/Sanitizer.php index 5f01e99c49..b01912b6c1 100644 --- a/includes/Sanitizer.php +++ b/includes/Sanitizer.php @@ -839,7 +839,7 @@ class Sanitizer { * @param string * @return array */ - static function decodeTagAttributes( $text ) { + public static function decodeTagAttributes( $text ) { $attribs = array(); if( trim( $text ) == '' ) { diff --git a/includes/Xml.php b/includes/Xml.php index 7db9ee8cca..a36e2819ec 100644 --- a/includes/Xml.php +++ b/includes/Xml.php @@ -682,4 +682,4 @@ class XmlSelect { return Xml::tags( 'select', $this->attributes, implode( "\n", $this->options ) ); } -} \ No newline at end of file +} diff --git a/maintenance/parserTests.txt b/maintenance/parserTests.txt index 46f12f469b..ad8093ef13 100644 --- a/maintenance/parserTests.txt +++ b/maintenance/parserTests.txt @@ -3339,7 +3339,7 @@ Link to category !! input [[:Category:MediaWiki User's Guide]] !! result -

Category:MediaWiki User's Guide +

Category:MediaWiki User's Guide

!! end @@ -3350,7 +3350,7 @@ cat !! input [[Category:MediaWiki User's Guide]] !! result -MediaWiki User's Guide +MediaWiki User's Guide !! end !! test @@ -6625,7 +6625,7 @@ language=sr cat !! input [[:Category:МедиаWики Усер'с Гуиде]] !! result -MediaWiki User's Guide +MediaWiki User's Guide !! end -- 2.20.1