From a8825b9e3e7932e30dc4c8279130a7e52c9c9265 Mon Sep 17 00:00:00 2001 From: Tim Starling Date: Wed, 27 Apr 2005 07:48:14 +0000 Subject: [PATCH] * Deglobalised link placeholder handling by moving the relevant functionality from Linker::makeLinkObj() to Parser::makeLinkHolder() * Did a similar trick for the handling of image options, in order to fix a bug reported by the parser unit test. * Updated parser tests to match current output where appropriate. --- includes/Linker.php | 239 +++++++++------------------------- includes/Parser.php | 250 ++++++++++++++++++++++++++---------- includes/ParserXML.php | 4 +- includes/Skin.php | 11 -- includes/Title.php | 13 ++ maintenance/parserTests.php | 1 + maintenance/parserTests.txt | 2 +- 7 files changed, 256 insertions(+), 264 deletions(-) diff --git a/includes/Linker.php b/includes/Linker.php index 37642c57cf..dcd9cc0df0 100644 --- a/includes/Linker.php +++ b/includes/Linker.php @@ -16,20 +16,14 @@ * @package MediaWiki */ class Linker { - var $linktrail ; # linktrail regexp - var $postParseLinkColour = false; - /** @todo document */ - function Linker() { - global $wgContLang; - $this->linktrail = $wgContLang->linkTrail(); - } - + function Linker() {} + /** - * Get/set accessor for delayed link colouring + * OBSOLETE */ - function postParseLinkColour( $setting = NULL ) { - return wfSetVar( $this->postParseLinkColour, $setting ); + function postParseLinkColour( $s = NULL ) { + return NULL; } /** @todo document */ @@ -137,12 +131,12 @@ class Linker { * Pass a title object, not a title string */ function makeLinkObj( &$nt, $text= '', $query = '', $trail = '', $prefix = '' ) { - global $wgOut, $wgUser, $wgLinkHolders, $wgInputEncoding; + global $wgOut, $wgUser, $wgInputEncoding; $fname = 'Skin::makeLinkObj'; wfProfileIn( $fname ); # Fail gracefully - if ( ! isset($nt) ) { + if ( ! is_object($nt) ) { # wfDebugDieBacktrace(); wfProfileOut( $fname ); return "{$prefix}{$text}{$trail}"; @@ -183,45 +177,10 @@ class Linker { $t = "{$text}{$inside}"; - if( $this->postParseLinkColour ) { - # There's no existence check, but this will prevent - # interwiki links from being parsed as external links. - global $wgInterwikiLinkHolders; - $nr = array_push($wgInterwikiLinkHolders, $t); - $retVal = '{$trail}"; - } else { - return $t; - } - } elseif ( 0 == $ns && "" == $dbkey ) { - # A self-link with a fragment; skip existence check. - $retVal = $this->makeKnownLinkObj( $nt, $text, $query, $trail, $prefix ); - } elseif ( ( NS_SPECIAL == $ns ) || ( NS_IMAGE == $ns ) ) { - # These are always shown as existing, currently. - # Special pages don't exist in the database; images may - # occasionally be present when there is no description - # page per se, so we always shown them. + return $t; + } elseif ( $nt->isAlwaysKnown() ) { + # Image links, special page links and self-links with fragements are always known. $retVal = $this->makeKnownLinkObj( $nt, $text, $query, $trail, $prefix ); - } elseif ( $this->postParseLinkColour ) { - wfProfileIn( $fname.'-postparse' ); - # Insert a placeholder, and we'll work out the existence checks - # in a big lump later. - $inside = ''; - if ( '' != $trail ) { - if ( preg_match( $this->linktrail, $trail, $m ) ) { - $inside = $m[1]; - $trail = $m[2]; - } - } - - # These get picked up by Parser::replaceLinkHolders() - $nr = array_push( $wgLinkHolders['namespaces'], $nt->getNamespace() ); - $wgLinkHolders['dbkeys'][] = $dbkey; - $wgLinkHolders['queries'][] = $query; - $wgLinkHolders['texts'][] = $prefix.$text.$inside; - $wgLinkHolders['titles'][] =& $nt; - - $retVal = '{$trail}"; - wfProfileOut( $fname.'-postparse' ); } else { wfProfileIn( $fname.'-immediate' ); # Work out link colour immediately @@ -294,14 +253,8 @@ class Linker { $text = htmlspecialchars( $nt->getPrefixedText() ); } $style = $this->getInternalLinkAttributesObj( $nt, $text ); - - $inside = ''; - if ( '' != $trail ) { - if ( preg_match( $this->linktrail, $trail, $m ) ) { - $inside = $m[1]; - $trail = $m[2]; - } - } + + list( $inside, $trail ) = Linker::splitTrail( $trail ); $r = "{$prefix}{$text}{$inside}{$trail}"; wfProfileOut( $fname ); return $r; @@ -331,14 +284,8 @@ class Linker { $text = htmlspecialchars( $nt->getPrefixedText() ); } $style = $this->getInternalLinkAttributesObj( $nt, $text, "yes" ); - - $inside = ''; - if ( '' != $trail ) { - if ( preg_match( $this->linktrail, $trail, $m ) ) { - $inside = $m[1]; - $trail = $m[2]; - } - } + + list( $inside, $trail ) = Linker::splitTrail( $trail ); $s = "{$prefix}{$text}{$inside}{$trail}"; wfProfileOut( $fname ); @@ -358,13 +305,7 @@ class Linker { } $style = $this->getInternalLinkAttributesObj( $nt, $text, 'stub' ); - $inside = ''; - if ( '' != $trail ) { - if ( preg_match( $this->linktrail, $trail, $m ) ) { - $inside = $m[1]; - $trail = $m[2]; - } - } + list( $inside, $trail ) = Linker::splitTrail( $trail ); $s = "{$prefix}{$text}{$inside}{$trail}"; return $s; } @@ -375,13 +316,7 @@ class Linker { if ( '' == $text ) { $text = htmlspecialchars( $nt->getPrefixedText() ); } - $inside = ''; - if ( '' != $trail ) { - if ( preg_match( $this->linktrail, $trail, $m ) ) { - $inside = $m[1]; - $trail = $m[2]; - } - } + list( $inside, $trail ) = Linker::splitTrail( $trail ); return "{$prefix}{$text}{$inside}{$trail}"; } @@ -396,8 +331,13 @@ class Linker { return htmlspecialchars( $basename ); } - /** @todo document */ + /** Obsolete alias */ function makeImage( $url, $alt = '' ) { + return $this->makeExternalImage( $url, $alt ); + } + + /** @todo document */ + function makeExternalImage( $url, $alt = '' ) { global $wgOut; if ( '' == $alt ) { $alt = $this->fnamePart( $url ); @@ -407,81 +347,15 @@ class Linker { } /** @todo document */ - function makeImageLink( $name, $url, $alt = '' ) { - $nt = Title::makeTitleSafe( NS_IMAGE, $name ); - return $this->makeImageLinkObj( $nt, $alt ); - } - - /** @todo document */ - function makeImageLinkObj( $nt, $alt = '' ) { - global $wgContLang, $wgUseImageResize; - global $wgUser, $wgThumbLimits; + function makeImageLinkObj( &$nt, $label, $alt, $align = '', $width = false, $height = false, $framed = false, + $thumb = false, $manual_thumb = '' ) + { + global $wgContLang, $wgUser, $wgThumbLimits; $img = new Image( $nt ); $url = $img->getViewURL(); - - $align = ''; $prefix = $postfix = ''; - - # Check if the alt text is of the form "options|alt text" - # Options are: - # * thumbnail make a thumbnail with enlarge-icon and caption, alignment depends on lang - # * left no resizing, just left align. label is used for alt= only - # * right same, but right aligned - # * none same, but not aligned - # * ___px scale to ___ pixels width, no aligning. e.g. use in taxobox - # * center center the image - # * framed Keep original image size, no magnify-button. - - $part = explode( '|', $alt); - - $mwThumb =& MagicWord::get( MAG_IMG_THUMBNAIL ); - $mwLeft =& MagicWord::get( MAG_IMG_LEFT ); - $mwRight =& MagicWord::get( MAG_IMG_RIGHT ); - $mwNone =& MagicWord::get( MAG_IMG_NONE ); - $mwWidth =& MagicWord::get( MAG_IMG_WIDTH ); - $mwCenter =& MagicWord::get( MAG_IMG_CENTER ); - $mwFramed =& MagicWord::get( MAG_IMG_FRAMED ); - $alt = ''; - - $height = $framed = $thumb = false; - $manual_thumb = "" ; - - foreach( $part as $key => $val ) { - $val_parts = explode ( "=" , $val , 2 ) ; - $left_part = array_shift ( $val_parts ) ; - if ( $wgUseImageResize && ! is_null( $mwThumb->matchVariableStartToEnd($val) ) ) { - $thumb=true; - } elseif ( $wgUseImageResize && count ( $val_parts ) == 1 && ! is_null( $mwThumb->matchVariableStartToEnd($left_part) ) ) { - # use manually specified thumbnail - $thumb=true; - $manual_thumb = array_shift ( $val_parts ) ; - } elseif ( ! is_null( $mwRight->matchVariableStartToEnd($val) ) ) { - # remember to set an alignment, don't render immediately - $align = 'right'; - } elseif ( ! is_null( $mwLeft->matchVariableStartToEnd($val) ) ) { - # remember to set an alignment, don't render immediately - $align = 'left'; - } elseif ( ! is_null( $mwCenter->matchVariableStartToEnd($val) ) ) { - # remember to set an alignment, don't render immediately - $align = 'center'; - } elseif ( ! is_null( $mwNone->matchVariableStartToEnd($val) ) ) { - # remember to set an alignment, don't render immediately - $align = 'none'; - } elseif ( $wgUseImageResize && ! is_null( $match = $mwWidth->matchVariableStartToEnd($val) ) ) { - # $match is the image width in pixels - if ( preg_match( '/^([0-9]*)x([0-9]*)$/', $match, $m ) ) { - $width = intval( $m[1] ); - $height = intval( $m[2] ); - } else { - $width = intval($match); - } - } elseif ( ! is_null( $mwFramed->matchVariableStartToEnd($val) ) ) { - $framed=true; - } else { - $alt = $val; - } - } + if ( 'center' == $align ) { $prefix = '
'; @@ -503,7 +377,7 @@ class Linker { } - if ( ! isset($width) ) { + if ( $width === false ) { $wopt = $wgUser->getOption( 'thumbsize' ); if( !isset( $wgThumbLimits[$wopt] ) ) { @@ -513,28 +387,21 @@ class Linker { $width = $wgThumbLimits[$wopt]; } - return $prefix.$this->makeThumbLinkObj( $img, $alt, $align, $width, $height, $framed, $manual_thumb ).$postfix; + return $prefix.$this->makeThumbLinkObj( $img, $label, $alt, $align, $width, $height, $framed, $manual_thumb ).$postfix; - } elseif ( isset($width) ) { + } elseif ( $width ) { # Create a resized image, without the additional thumbnail # features - if ( ( ! $height === false ) - && ( $img->getHeight() * $width / $img->getWidth() > $height ) ) { + if ( $height !== false && ( $img->getHeight() * $width / $img->getWidth() > $height ) ) { $width = $img->getWidth() * $height / $img->getHeight(); } - if ( '' == $manual_thumb ) $url = $img->createThumb( $width ); + if ( '' == $manual_thumb ) { + $url = $img->createThumb( $width ); + } } - # FIXME: This is a gross hack using a global. - # Replace link color holders in the caption text so the - # text portion can be placed int the alt/title attributes. - global $wgParser; - $wgParser->replaceLinkHolders( $alt ); - - $alt = Sanitizer::stripAllTags( $alt ); - $u = $nt->escapeLocalURL(); if ( $url == '' ) { $s = $this->makeBrokenImageLinkObj( $img->getTitle() ); @@ -553,14 +420,10 @@ class Linker { * Make HTML for a thumbnail including image, border and caption * $img is an Image object */ - function makeThumbLinkObj( $img, $label = '', $align = 'right', $boxwidth = 180, $boxheight=false, $framed=false , $manual_thumb = "" ) { + function makeThumbLinkObj( $img, $label = '', $alt, $align = 'right', $boxwidth = 180, $boxheight=false, $framed=false , $manual_thumb = "" ) { global $wgStylePath, $wgContLang; - # $image = Title::makeTitleSafe( NS_IMAGE, $name ); $url = $img->getViewURL(); - #$label = htmlspecialchars( $label ); - $alt = Sanitizer::stripAllTags( $label ); - $width = $height = 0; if ( $img->exists() ) { @@ -661,14 +524,7 @@ class Linker { $text = htmlspecialchars( $nt->getPrefixedText() ); } $style = $this->getInternalLinkAttributesObj( $nt, $text, "yes" ); - - $inside = ''; - if ( '' != $trail ) { - if ( preg_match( $this->linktrail, $trail, $m ) ) { - $inside = $m[1]; - $trail = $m[2]; - } - } + list( $inside, $trail ) = Linker::splitTrail( $trail ); $s = "{$prefix}{$text}{$inside}{$trail}"; wfProfileOut( $fname ); @@ -920,5 +776,28 @@ class Linker { } return "
[".$url."]
"; } + + /** + * Split a link trail, return the "inside" portion and the remainder of the trail + * as a two-element array + * + * @static + */ + function splitTrail( $trail ) { + static $regex = false; + if ( $regex === false ) { + global $wgContLang; + $regex = $wgContLang->linkTrail(); + } + $inside = ''; + if ( '' != $trail ) { + if ( preg_match( $regex, $trail, $m ) ) { + $inside = $m[1]; + $trail = $m[2]; + } + } + return array( $inside, $trail ); + } + } ?> diff --git a/includes/Parser.php b/includes/Parser.php index 306b86006a..75810d59bb 100644 --- a/includes/Parser.php +++ b/includes/Parser.php @@ -101,6 +101,7 @@ class Parser # Cleared with clearState(): var $mOutput, $mAutonumber, $mDTopen, $mStripState = array(); var $mVariables, $mIncludeCount, $mArgStack, $mLastSection, $mInPre; + var $mInterwikiLinkHolders, $mLinkHolders; # Temporary: var $mOptions, $mTitle, $mOutputType, @@ -117,6 +118,7 @@ class Parser * @access public */ function Parser() { + global $wgContLang; $this->mTemplates = array(); $this->mTemplatePath = array(); $this->mTagHooks = array(); @@ -138,6 +140,14 @@ class Parser $this->mStripState = array(); $this->mArgStack = array(); $this->mInPre = false; + $this->mInterwikiLinkHolders = array(); + $this->mLinkHolders = array( + 'namespaces' => array(), + 'dbkeys' => array(), + 'queries' => array(), + 'texts' => array(), + 'titles' => array() + ); } /** @@ -166,7 +176,7 @@ class Parser $this->mOutputType = OT_HTML; $this->mStripState = NULL; - global $fnord; $fnord = 1; + //$text = $this->strip( $text, $this->mStripState ); // VOODOO MAGIC FIX! Sometimes the above segfaults in PHP5. $x =& $this->mStripState; @@ -965,8 +975,6 @@ class Parser wfProfileIn( $fname ); $sk =& $this->mOptions->getSkin(); - global $wgContLang; - $linktrail = $wgContLang->linkTrail(); $bits = preg_split( EXT_LINK_BRACKETED, $text, -1, PREG_SPLIT_DELIM_CAPTURE ); @@ -989,7 +997,7 @@ class Parser # If the link text is an image URL, replace it with an tag # This happened by accident in the original parser, but some people used it extensively - $img = $this->maybeMakeImageLink( $text ); + $img = $this->maybeMakeExternalImage( $text ); if ( $img !== false ) { $text = $img; } @@ -1013,17 +1021,14 @@ class Parser } else { # Have link text, e.g. [http://domain.tld/some.link text]s # Check for trail - if ( preg_match( $linktrail, $trail, $m2 ) ) { - $dtrail = $m2[1]; - $trail = $m2[2]; - } + list( $dtrail, $trail ) = Linker::splitTrail( $trail ); } $text = $wgContLang->markNoConversion($text); # Replace & from obsolete syntax with &. # All HTML entities will be escaped by makeExternalLink() - # or maybeMakeImageLink() + # or maybeMakeExternalImage() $url = str_replace( '&', '&', $url ); # Process the trail (i.e. everything after this link up until start of the next link), @@ -1089,11 +1094,11 @@ class Parser # Replace & from obsolete syntax with &. # All HTML entities will be escaped by makeExternalLink() - # or maybeMakeImageLink() + # or maybeMakeExternalImage() $url = str_replace( '&', '&', $url ); # Is this an external image? - $text = $this->maybeMakeImageLink( $url ); + $text = $this->maybeMakeExternalImage( $url ); if ( $text === false ) { # Not an image, make a link $text = $sk->makeExternalLink( $url, $wgContLang->markNoConversion($url), true, 'free' ); @@ -1111,13 +1116,13 @@ class Parser * make an image if it's allowed * @access private */ - function maybeMakeImageLink( $url ) { + function maybeMakeExternalImage( $url ) { $sk =& $this->mOptions->getSkin(); $text = false; if ( $this->mOptions->getAllowExternalImages() ) { if ( preg_match( EXT_IMAGE_REGEX, $url ) ) { # Image found - $text = $sk->makeImage( htmlspecialchars( $url ) ); + $text = $sk->makeExternalImage( htmlspecialchars( $url ) ); } } return $text; @@ -1140,10 +1145,6 @@ class Parser if ( !$tc ) { $tc = Title::legalChars() . '#%'; } $sk =& $this->mOptions->getSkin(); - global $wgUseOldExistenceCheck; - # "Post-parse link colour check" works only on wiki text since it's now - # in Parser. Enable it, then disable it when we're done. - $saveParseColour = $sk->postParseLinkColour( !$wgUseOldExistenceCheck ); #split the entire text string on occurences of [[ $a = explode( '[[', ' ' . $s ); @@ -1327,7 +1328,7 @@ class Parser $text = $this->replaceInternalLinks($text); # cloak any absolute URLs inside the image markup, so replaceExternalLinks() won't touch them - $s .= $prefix . str_replace('http://', 'http-noparse://', $sk->makeImageLinkObj( $nt, $text ) ) . $trail; + $s .= $prefix . str_replace('http://', 'http-noparse://', $this->makeImage( $nt, $text ) ) . $trail; $wgLinkCache->addImageLinkObj( $nt ); wfProfileOut( "$fname-image" ); @@ -1343,10 +1344,7 @@ class Parser $s = rtrim($s . "\n"); # bug 87 $wgLinkCache->suspend(); # Don't save in links/brokenlinks - $pPLC=$sk->postParseLinkColour(); - $sk->postParseLinkColour( false ); $t = $sk->makeLinkObj( $nt, $t, '', '' , $prefix ); - $sk->postParseLinkColour( $pPLC ); $wgLinkCache->resume(); if ( $wasblank ) { @@ -1388,13 +1386,53 @@ class Parser $s .= $prefix . $sk->makeKnownLinkObj( $nt, $text, '', $trail ); continue; } - $s .= $sk->makeLinkObj( $nt, $text, '', $trail, $prefix ); + if ( $nt->isAlwaysKnown() ) { + $s .= $sk->makeKnownLinkObj( $nt, $text, '', $trail, $prefix ); + } else { + /** + * Add a link placeholder + * Later, this will be replaced by a real link, after the existence or + * non-existence of all the links is known + */ + $s .= $this->makeLinkHolder( $nt, $text, '', $trail, $prefix ); + } } - $sk->postParseLinkColour( $saveParseColour ); wfProfileOut( $fname ); return $s; } + /** + * Make a link placeholder. The text returned can be later resolved to a real link with + * replaceLinkHolders(). This is done for two reasons: firstly to avoid further + * parsing of interwiki links, and secondly to allow all extistence checks and + * article length checks (for stub links) to be bundled into a single query. + * + */ + function makeLinkHolder( &$nt, $text = '', $query = '', $trail = '', $prefix = '' ) { + if ( ! is_object($nt) ) { + # Fail gracefully + $retVal = "{$prefix}{$text}{$trail}"; + } else { + # Separate the link trail from the rest of the link + list( $inside, $trail ) = Linker::splitTrail( $trail ); + + if ( $nt->isExternal() ) { + $iwRecord = array( $nt->getPrefixedDBkey(), $prefix.$text.$inside ); + $nr = array_push($this->mInterwikiLinkHolders, $iwRecord); + $retVal = '{$trail}"; + } else { + $nr = array_push( $this->mLinkHolders['namespaces'], $nt->getNamespace() ); + $this->mLinkHolders['dbkeys'][] = $nt->getDBkey(); + $this->mLinkHolders['queries'][] = $query; + $this->mLinkHolders['texts'][] = $prefix.$text.$inside; + $this->mLinkHolders['titles'][] =& $nt; + + $retVal = '{$trail}"; + } + } + return $retVal; + } + /** * Return true if subpage links should be expanded on this page. * @return bool @@ -2409,10 +2447,10 @@ class Parser # turns into # link text with suffix $canonized_headline = preg_replace( '//e', - "\$wgLinkHolders['texts'][\$1]", + "\$this->mLinkHolders['texts'][\$1]", $canonized_headline ); $canonized_headline = preg_replace( '//e', - "\$wgInterwikiLinkHolders[\$1]", + "\$this->mInterwikiLinkHolders[\$1][1]", $canonized_headline ); # strip out HTML @@ -2791,36 +2829,30 @@ class Parser * $options is a bit field, RLH_FOR_UPDATE to select for update */ function replaceLinkHolders( &$text, $options = 0 ) { - global $wgUser, $wgLinkCache, $wgUseOldExistenceCheck, $wgLinkHolders; - global $wgInterwikiLinkHolders; - global $outputReplace; - - if ( $wgUseOldExistenceCheck ) { - return array(); - } + global $wgUser, $wgLinkCache; + global $wgOutputReplace; $fname = 'Parser::replaceLinkHolders'; wfProfileIn( $fname ); $pdbks = array(); $colours = array(); + $sk = $this->mOptions->getSkin(); - #if ( !empty( $tmpLinks[0] ) ) { #TODO - if ( !empty( $wgLinkHolders['namespaces'] ) ) { + if ( !empty( $this->mLinkHolders['namespaces'] ) ) { wfProfileIn( $fname.'-check' ); $dbr =& wfGetDB( DB_SLAVE ); $page = $dbr->tableName( 'page' ); - $sk = $wgUser->getSkin(); $threshold = $wgUser->getOption('stubthreshold'); # Sort by namespace - asort( $wgLinkHolders['namespaces'] ); + asort( $this->mLinkHolders['namespaces'] ); # Generate query $query = false; - foreach ( $wgLinkHolders['namespaces'] as $key => $val ) { + foreach ( $this->mLinkHolders['namespaces'] as $key => $val ) { # Make title object - $title = $wgLinkHolders['titles'][$key]; + $title = $this->mLinkHolders['titles'][$key]; # Skip invalid entries. # Result will be ugly, but prevents crash. @@ -2850,7 +2882,7 @@ class Parser $query .= ', '; } - $query .= $dbr->addQuotes( $wgLinkHolders['dbkeys'][$key] ); + $query .= $dbr->addQuotes( $this->mLinkHolders['dbkeys'][$key] ); } } if ( $query ) { @@ -2886,25 +2918,25 @@ class Parser # Construct search and replace arrays wfProfileIn( $fname.'-construct' ); - $outputReplace = array(); - foreach ( $wgLinkHolders['namespaces'] as $key => $ns ) { + $wgOutputReplace = array(); + foreach ( $this->mLinkHolders['namespaces'] as $key => $ns ) { $pdbk = $pdbks[$key]; - $searchkey = ''; - $title = $wgLinkHolders['titles'][$key]; + $searchkey = ""; + $title = $this->mLinkHolders['titles'][$key]; if ( empty( $colours[$pdbk] ) ) { $wgLinkCache->addBadLink( $pdbk ); $colours[$pdbk] = 0; - $outputReplace[$searchkey] = $sk->makeBrokenLinkObj( $title, - $wgLinkHolders['texts'][$key], - $wgLinkHolders['queries'][$key] ); + $wgOutputReplace[$searchkey] = $sk->makeBrokenLinkObj( $title, + $this->mLinkHolders['texts'][$key], + $this->mLinkHolders['queries'][$key] ); } elseif ( $colours[$pdbk] == 1 ) { - $outputReplace[$searchkey] = $sk->makeKnownLinkObj( $title, - $wgLinkHolders['texts'][$key], - $wgLinkHolders['queries'][$key] ); + $wgOutputReplace[$searchkey] = $sk->makeKnownLinkObj( $title, + $this->mLinkHolders['texts'][$key], + $this->mLinkHolders['queries'][$key] ); } elseif ( $colours[$pdbk] == 2 ) { - $outputReplace[$searchkey] = $sk->makeStubLinkObj( $title, - $wgLinkHolders['texts'][$key], - $wgLinkHolders['queries'][$key] ); + $wgOutputReplace[$searchkey] = $sk->makeStubLinkObj( $title, + $this->mLinkHolders['texts'][$key], + $this->mLinkHolders['queries'][$key] ); } } wfProfileOut( $fname.'-construct' ); @@ -2914,32 +2946,30 @@ class Parser $text = preg_replace_callback( '/()/', - "outputReplaceMatches", + "wfOutputReplaceMatches", $text); + wfProfileOut( $fname.'-replace' ); } - if ( !empty( $wgInterwikiLinkHolders ) ) { + # Now process interwiki link holders + # This is quite a bit simpler than internal links + if ( !empty( $this->mInterwikiLinkHolders ) ) { wfProfileIn( $fname.'-interwiki' ); - $outputReplace = $wgInterwikiLinkHolders; + # Make interwiki link HTML + $wgOutputReplace = array(); + foreach( $this->mInterwikiLinkHolders as $i => $lh ) { + $s = $sk->makeLink( $lh[0], $lh[1] ); + $wgOutputReplace[] = $s; + } + $text = preg_replace_callback( '//', - "outputReplaceMatches", + "wfOutputReplaceMatches", $text ); wfProfileOut( $fname.'-interwiki' ); } - # Clear link holders, no need to fetch these ones again in a subsequent invocation - $wgLinkHolders = array( - 'namespaces' => array(), - 'dbkeys' => array(), - 'queries' => array(), - 'texts' => array(), - 'titles' => array() - ); - $wgInterwikiLinkHolders = array(); - - wfProfileOut( $fname ); return $colours; } @@ -2952,6 +2982,8 @@ class Parser * given as text will return the HTML of a gallery with two images, * labeled 'The number "1"' and * 'A tree'. + * + * @static */ function renderImageGallery( $text ) { # Setup the parser @@ -2991,6 +3023,84 @@ class Parser } return $ig->toHTML(); } + + /** + * Parse image options text and use it to make an image + */ + function makeImage( &$nt, $options ) { + global $wgContLang, $wgUseImageResize; + global $wgUser, $wgThumbLimits; + + $align = ''; + + # Check if the options text is of the form "options|alt text" + # Options are: + # * thumbnail make a thumbnail with enlarge-icon and caption, alignment depends on lang + # * left no resizing, just left align. label is used for alt= only + # * right same, but right aligned + # * none same, but not aligned + # * ___px scale to ___ pixels width, no aligning. e.g. use in taxobox + # * center center the image + # * framed Keep original image size, no magnify-button. + + $part = explode( '|', $options); + + $mwThumb =& MagicWord::get( MAG_IMG_THUMBNAIL ); + $mwLeft =& MagicWord::get( MAG_IMG_LEFT ); + $mwRight =& MagicWord::get( MAG_IMG_RIGHT ); + $mwNone =& MagicWord::get( MAG_IMG_NONE ); + $mwWidth =& MagicWord::get( MAG_IMG_WIDTH ); + $mwCenter =& MagicWord::get( MAG_IMG_CENTER ); + $mwFramed =& MagicWord::get( MAG_IMG_FRAMED ); + $caption = ''; + + $width = $height = $framed = $thumb = false; + $manual_thumb = "" ; + + foreach( $part as $key => $val ) { + $val_parts = explode ( "=" , $val , 2 ) ; + $left_part = array_shift ( $val_parts ) ; + if ( $wgUseImageResize && ! is_null( $mwThumb->matchVariableStartToEnd($val) ) ) { + $thumb=true; + } elseif ( $wgUseImageResize && count ( $val_parts ) == 1 && ! is_null( $mwThumb->matchVariableStartToEnd($left_part) ) ) { + # use manually specified thumbnail + $thumb=true; + $manual_thumb = array_shift ( $val_parts ) ; + } elseif ( ! is_null( $mwRight->matchVariableStartToEnd($val) ) ) { + # remember to set an alignment, don't render immediately + $align = 'right'; + } elseif ( ! is_null( $mwLeft->matchVariableStartToEnd($val) ) ) { + # remember to set an alignment, don't render immediately + $align = 'left'; + } elseif ( ! is_null( $mwCenter->matchVariableStartToEnd($val) ) ) { + # remember to set an alignment, don't render immediately + $align = 'center'; + } elseif ( ! is_null( $mwNone->matchVariableStartToEnd($val) ) ) { + # remember to set an alignment, don't render immediately + $align = 'none'; + } elseif ( $wgUseImageResize && ! is_null( $match = $mwWidth->matchVariableStartToEnd($val) ) ) { + # $match is the image width in pixels + if ( preg_match( '/^([0-9]*)x([0-9]*)$/', $match, $m ) ) { + $width = intval( $m[1] ); + $height = intval( $m[2] ); + } else { + $width = intval($match); + } + } elseif ( ! is_null( $mwFramed->matchVariableStartToEnd($val) ) ) { + $framed=true; + } else { + $caption = $val; + } + } + # Strip bad stuff out of the alt text + $alt = $caption; + $this->replaceLinkHolders( $alt ); + $alt = Sanitizer::stripAllTags( $alt ); + + # Linker does the rest + $sk =& $this->mOptions->getSkin(); + return $sk->makeImageLinkObj( $nt, $caption, $alt, $align, $width, $height, $framed, $thumb, $manual_thumb ); + } } /** @@ -3131,9 +3241,9 @@ class ParserOptions * Callback function used by Parser::replaceLinkHolders() * to substitute link placeholders. */ -function &outputReplaceMatches( $matches ) { - global $outputReplace; - return $outputReplace[$matches[1]]; +function &wfOutputReplaceMatches( $matches ) { + global $wgOutputReplace; + return $wgOutputReplace[$matches[1]]; } /** diff --git a/includes/ParserXML.php b/includes/ParserXML.php index 39984796b3..4b97a5beb8 100644 --- a/includes/ParserXML.php +++ b/includes/ParserXML.php @@ -144,7 +144,7 @@ class element { # There's stuff missing here... if ($nt->getNamespace() == NS_IMAGE) { $options[] = $display_title; - return $skin->makeImageLinkObj($nt, implode('|', $options)); + return $parser->makeImage($nt, implode('|', $options)); } else { # Default $title = $target; @@ -639,4 +639,4 @@ class ParserXML extends Parser { } } -?> \ No newline at end of file +?> diff --git a/includes/Skin.php b/includes/Skin.php index be60733968..2f79d90f08 100644 --- a/includes/Skin.php +++ b/includes/Skin.php @@ -34,17 +34,6 @@ unset($matches); require_once( 'RecentChange.php' ); -global $wgLinkHolders; -$wgLinkHolders = array( - 'namespaces' => array(), - 'dbkeys' => array(), - 'queries' => array(), - 'texts' => array(), - 'titles' => array() -); -global $wgInterwikiLinkHolders; -$wgInterwikiLinkHolders = array(); - /** * @todo document * @package MediaWiki diff --git a/includes/Title.php b/includes/Title.php index 29fe5579ea..89312beee7 100644 --- a/includes/Title.php +++ b/includes/Title.php @@ -1989,5 +1989,18 @@ class Title { return $this->getArticleId() != 0; } + /** + * Should a link should be displayed as a known link, just based on its title? + * + * Currently, a self-link with a fragment, special pages and image pages are in + * this category. Special pages never exist in the database. Some images do not + * have description pages in the database, but the description page contains + * useful history information that the user may want to link to. + * + */ + function isAlwaysKnown() { + return ( 0 == $this->mNamespace && "" == $this->mDbkeyform ) + || NS_SPECIAL == $this->mNamespace || NS_IMAGE == $this->mNamespace; + } } ?> diff --git a/maintenance/parserTests.php b/maintenance/parserTests.php index 85a2be8c41..919925250d 100644 --- a/maintenance/parserTests.php +++ b/maintenance/parserTests.php @@ -302,6 +302,7 @@ class ParserTest { 'wgCapitalLinks' => true, 'wgDefaultUserOptions' => array(), 'wgNoFollowLinks' => true, + 'wgThumbnailScriptPath' => false, ); $this->savedGlobals = array(); foreach( $settings as $var => $val ) { diff --git a/maintenance/parserTests.txt b/maintenance/parserTests.txt index 2f2567b4cd..c0c9787e61 100644 --- a/maintenance/parserTests.txt +++ b/maintenance/parserTests.txt @@ -1658,7 +1658,7 @@ Image caption containing another image !! input [[Image:Foobar.jpg|thumb|This is a caption with another [[Image:icon.png|image]] inside it!]] !! result -
Missing image
Foobar.jpg
This is a caption with another image inside it!
+
This is a caption with another Image:Icon.png inside it!
Enlarge
This is a caption with another Image:Icon.png inside it!
!! end -- 2.20.1