From 8f416baead93a48e5799e44b8bd2e2c4859f4e04 Mon Sep 17 00:00:00 2001 From: Pierre Schmitz Date: Fri, 14 Sep 2007 13:18:58 +0200 Subject: auf Version 1.11 aktualisiert; Login-Bug behoben --- includes/Parser.php | 420 +++++++++++++++++++++++++++++++++++----------------- 1 file changed, 287 insertions(+), 133 deletions(-) (limited to 'includes/Parser.php') diff --git a/includes/Parser.php b/includes/Parser.php index 8e36e170..32e7f2a8 100644 --- a/includes/Parser.php +++ b/includes/Parser.php @@ -1,5 +1,7 @@ mTagHooks = array(); + $this->mTransparentTagHooks = array(); $this->mFunctionHooks = array(); $this->mFunctionSynonyms = array( 0 => array(), 1 => array() ); $this->mFirstCall = true; } - + /** * Do various kinds of initialisation on the first call of the parser */ @@ -138,12 +142,12 @@ class Parser if ( !$this->mFirstCall ) { return; } - + wfProfileIn( __METHOD__ ); global $wgAllowDisplayTitle, $wgAllowSlowParserFunctions; - + $this->setHook( 'pre', array( $this, 'renderPreTag' ) ); - + $this->setFunctionHook( 'int', array( 'CoreParserFunctions', 'intFunction' ), SFH_NO_HASH ); $this->setFunctionHook( 'ns', array( 'CoreParserFunctions', 'ns' ), SFH_NO_HASH ); $this->setFunctionHook( 'urlencode', array( 'CoreParserFunctions', 'urlencode' ), SFH_NO_HASH ); @@ -306,7 +310,7 @@ class Parser $fixtags = array( # french spaces, last one Guillemet-left # only if there is something before the space - '/(.) (?=\\?|:|;|!|\\302\\273)/' => '\\1 \\2', + '/(.) (?=\\?|:|;|!|%|\\302\\273)/' => '\\1 \\2', # french spaces, Guillemet-right '/(\\302\\253) /' => '\\1 ', ); @@ -327,6 +331,26 @@ class Parser wfRunHooks( 'ParserBeforeTidy', array( &$this, &$text ) ); +//!JF Move to its own function + + $uniq_prefix = $this->mUniqPrefix; + $matches = array(); + $elements = array_keys( $this->mTransparentTagHooks ); + $text = Parser::extractTagsAndParams( $elements, $text, $matches, $uniq_prefix ); + + foreach( $matches as $marker => $data ) { + list( $element, $content, $params, $tag ) = $data; + $tagName = strtolower( $element ); + if( isset( $this->mTransparentTagHooks[$tagName] ) ) { + $output = call_user_func_array( $this->mTransparentTagHooks[$tagName], + array( $content, $params, $this ) ); + } else { + $output = $tag; + } + $this->mStripState->general->setPair( $marker, $output ); + } + $text = $this->mStripState->unstripGeneral( $text ); + $text = Sanitizer::normalizeCharReferences( $text ); if (($wgUseTidy and $this->mOptions->mTidy) or $wgAlwaysUseTidy) { @@ -398,12 +422,15 @@ class Parser * Expand templates and variables in the text, producing valid, static wikitext. * Also removes comments. */ - function preprocess( $text, $title, $options ) { + function preprocess( $text, $title, $options, $revid = null ) { wfProfileIn( __METHOD__ ); $this->clearState(); $this->setOutputType( OT_PREPROCESS ); $this->mOptions = $options; $this->mTitle = $title; + if( $revid !== null ) { + $this->mRevisionId = $revid; + } wfRunHooks( 'ParserBeforeStrip', array( &$this, &$text, &$this->mStripState ) ); $text = $this->strip( $text, $this->mStripState ); wfRunHooks( 'ParserAfterStrip', array( &$this, &$text, &$this->mStripState ) ); @@ -449,7 +476,7 @@ class Parser * @param $text Source text string. * @param $uniq_prefix * - * @private + * @public * @static */ function extractTagsAndParams($elements, $text, &$matches, $uniq_prefix = ''){ @@ -480,7 +507,7 @@ class Parser $inside = $p[4]; } - $marker = "$uniq_prefix-$element-" . sprintf('%08X', $n++) . '-QINU'; + $marker = "$uniq_prefix-$element-" . sprintf('%08X', $n++) . "-QINU\x07"; $stripped .= $marker; if ( $close === '/>' ) { @@ -587,7 +614,8 @@ class Parser $output = Xml::escapeTagsOnly( $content ); break; case 'math': - $output = $wgContLang->armourMath( MathRenderer::renderMath( $content ) ); + $output = $wgContLang->armourMath( + MathRenderer::renderMath( $content, $params ) ); break; case 'gallery': $output = $this->renderImageGallery( $content, $params ); @@ -725,7 +753,7 @@ class Parser $descriptorspec = array( 0 => array('pipe', 'r'), 1 => array('pipe', 'w'), - 2 => array('file', '/dev/null', 'a') // FIXME: this line in UNIX-specific, it generates a warning on Windows, because /dev/null is not a valid Windows file. + 2 => array('file', wfGetNull(), 'a') ); $pipes = array(); $process = proc_open("$wgTidyBin -config $wgTidyConf $wgTidyOpts$opts", $descriptorspec, $pipes); @@ -1000,7 +1028,7 @@ class Parser $text = strtr( $text, array( '' => '', '' => '') ); $text = StringUtils::delimiterReplace( '', '', '', $text ); - $text = Sanitizer::removeHTMLtags( $text, array( &$this, 'attributeStripCallback' ) ); + $text = Sanitizer::removeHTMLtags( $text, array( &$this, 'attributeStripCallback' ), array(), array_keys( $this->mTransparentTagHooks ) ); $text = $this->replaceVariables( $text, $args ); wfRunHooks( 'InternalParseBeforeLinks', array( &$this, &$text, &$this->mStripState ) ); @@ -1797,11 +1825,15 @@ class Parser $this->mOutput->addImage( $nt->getDBkey() ); continue; } elseif( $ns == NS_SPECIAL ) { - $s .= $this->makeKnownLinkHolder( $nt, $text, '', $trail, $prefix ); + if( SpecialPage::exists( $nt->getDBkey() ) ) { + $s .= $this->makeKnownLinkHolder( $nt, $text, '', $trail, $prefix ); + } else { + $s .= $this->makeLinkHolder( $nt, $text, '', $trail, $prefix ); + } continue; } elseif( $ns == NS_IMAGE ) { - $img = new Image( $nt ); - if( $img->exists() ) { + $img = wfFindFile( $nt ); + if( $img ) { // Force a blue link if the file exists; may be a remote // upload on the shared repository, and we want to see its // auto-generated page. @@ -1918,15 +1950,22 @@ class Parser wfProfileIn( $fname ); $ret = $target; # default return value is no change - # bug 7425 - $target = trim( $target ); - # Some namespaces don't allow subpages, # so only perform processing if subpages are allowed if( $this->areSubpagesAllowed() ) { + $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]) ); @@ -1934,9 +1973,9 @@ class Parser $noslash = substr( $target, 1 ); } - $ret = $this->mTitle->getPrefixedText(). '/' . trim($noslash); + $ret = $this->mTitle->getPrefixedText(). '/' . trim($noslash) . $suffix; if( '' === $text ) { - $text = $target; + $text = $target . $suffix; } # this might be changed for ugliness reasons } else { # check for .. subpage backlinks @@ -1954,13 +1993,14 @@ class Parser if( substr( $nodotdot, -1, 1 ) == '/' ) { $nodotdot = substr( $nodotdot, 0, -1 ); if( '' === $text ) { - $text = $nodotdot; + $text = $nodotdot . $suffix; } } $nodotdot = trim( $nodotdot ); if( $nodotdot != '' ) { $ret .= '/' . $nodotdot; } + $ret .= $suffix; } } } @@ -2406,6 +2446,8 @@ class Parser $oldtz = getenv( 'TZ' ); putenv( 'TZ='.$wgLocaltimezone ); } + + wfSuppressWarnings(); // E_STRICT system time bitching $localTimestamp = date( 'YmdHis', $ts ); $localMonth = date( 'm', $ts ); $localMonthName = date( 'n', $ts ); @@ -2418,20 +2460,21 @@ class Parser if ( isset( $wgLocaltimezone ) ) { putenv( 'TZ='.$oldtz ); } + wfRestoreWarnings(); switch ( $index ) { case 'currentmonth': - return $varCache[$index] = $wgContLang->formatNum( date( 'm', $ts ) ); + return $varCache[$index] = $wgContLang->formatNum( gmdate( 'm', $ts ) ); case 'currentmonthname': - return $varCache[$index] = $wgContLang->getMonthName( date( 'n', $ts ) ); + return $varCache[$index] = $wgContLang->getMonthName( gmdate( 'n', $ts ) ); case 'currentmonthnamegen': - return $varCache[$index] = $wgContLang->getMonthNameGen( date( 'n', $ts ) ); + return $varCache[$index] = $wgContLang->getMonthNameGen( gmdate( 'n', $ts ) ); case 'currentmonthabbrev': - return $varCache[$index] = $wgContLang->getMonthAbbreviation( date( 'n', $ts ) ); + return $varCache[$index] = $wgContLang->getMonthAbbreviation( gmdate( 'n', $ts ) ); case 'currentday': - return $varCache[$index] = $wgContLang->formatNum( date( 'j', $ts ) ); + return $varCache[$index] = $wgContLang->formatNum( gmdate( 'j', $ts ) ); case 'currentday2': - return $varCache[$index] = $wgContLang->formatNum( date( 'd', $ts ) ); + return $varCache[$index] = $wgContLang->formatNum( gmdate( 'd', $ts ) ); case 'localmonth': return $varCache[$index] = $wgContLang->formatNum( $localMonth ); case 'localmonthname': @@ -2445,25 +2488,25 @@ class Parser case 'localday2': return $varCache[$index] = $wgContLang->formatNum( $localDay2 ); case 'pagename': - return $this->mTitle->getText(); + return wfEscapeWikiText( $this->mTitle->getText() ); case 'pagenamee': return $this->mTitle->getPartialURL(); case 'fullpagename': - return $this->mTitle->getPrefixedText(); + return wfEscapeWikiText( $this->mTitle->getPrefixedText() ); case 'fullpagenamee': return $this->mTitle->getPrefixedURL(); case 'subpagename': - return $this->mTitle->getSubpageText(); + return wfEscapeWikiText( $this->mTitle->getSubpageText() ); case 'subpagenamee': return $this->mTitle->getSubpageUrlForm(); case 'basepagename': - return $this->mTitle->getBaseText(); + return wfEscapeWikiText( $this->mTitle->getBaseText() ); case 'basepagenamee': return wfUrlEncode( str_replace( ' ', '_', $this->mTitle->getBaseText() ) ); case 'talkpagename': if( $this->mTitle->canTalk() ) { $talkPage = $this->mTitle->getTalkPage(); - return $talkPage->getPrefixedText(); + return wfEscapeWikiText( $talkPage->getPrefixedText() ); } else { return ''; } @@ -2476,7 +2519,7 @@ class Parser } case 'subjectpagename': $subjPage = $this->mTitle->getSubjectPage(); - return $subjPage->getPrefixedText(); + return wfEscapeWikiText( $subjPage->getPrefixedText() ); case 'subjectpagenamee': $subjPage = $this->mTitle->getSubjectPage(); return $subjPage->getPrefixedUrl(); @@ -2505,19 +2548,19 @@ class Parser case 'subjectspacee': return( wfUrlencode( $this->mTitle->getSubjectNsText() ) ); case 'currentdayname': - return $varCache[$index] = $wgContLang->getWeekdayName( date( 'w', $ts ) + 1 ); + return $varCache[$index] = $wgContLang->getWeekdayName( gmdate( 'w', $ts ) + 1 ); case 'currentyear': - return $varCache[$index] = $wgContLang->formatNum( date( 'Y', $ts ), true ); + return $varCache[$index] = $wgContLang->formatNum( gmdate( 'Y', $ts ), true ); case 'currenttime': return $varCache[$index] = $wgContLang->time( wfTimestamp( TS_MW, $ts ), false, false ); case 'currenthour': - return $varCache[$index] = $wgContLang->formatNum( date( 'H', $ts ), true ); + return $varCache[$index] = $wgContLang->formatNum( gmdate( 'H', $ts ), true ); case 'currentweek': // @bug 4594 PHP5 has it zero padded, PHP4 does not, cast to // int to remove the padding - return $varCache[$index] = $wgContLang->formatNum( (int)date( 'W', $ts ) ); + return $varCache[$index] = $wgContLang->formatNum( (int)gmdate( 'W', $ts ) ); case 'currentdow': - return $varCache[$index] = $wgContLang->formatNum( date( 'w', $ts ) ); + return $varCache[$index] = $wgContLang->formatNum( gmdate( 'w', $ts ) ); case 'localdayname': return $varCache[$index] = $wgContLang->getWeekdayName( $localDayOfWeek + 1 ); case 'localyear': @@ -3089,7 +3132,7 @@ class Parser $found = false; //access denied wfDebug( "$fname: template inclusion denied for " . $title->getPrefixedDBkey() ); } else { - $articleContent = $this->fetchTemplate( $title ); + list($articleContent,$title) = $this->fetchTemplateAndtitle( $title ); if ( $articleContent !== false ) { $found = true; $text = $articleContent; @@ -3220,6 +3263,7 @@ class Parser PREG_SPLIT_DELIM_CAPTURE); $text = ''; $nsec = $headingOffset; + for( $i = 0; $i < count($m); $i += 2 ) { $text .= $m[$i]; if (!isset($m[$i + 1]) || $m[$i + 1] == "") continue; @@ -3255,13 +3299,26 @@ class Parser /** * Fetch the unparsed text of a template and register a reference to it. */ - function fetchTemplate( $title ) { - $text = false; + function fetchTemplateAndtitle( $title ) { + $text = $skip = false; + $finalTitle = $title; // Loop to fetch the article, with up to 1 redirect for ( $i = 0; $i < 2 && is_object( $title ); $i++ ) { - $rev = Revision::newFromTitle( $title ); - $this->mOutput->addTemplate( $title, $title->getArticleID() ); - if ( $rev ) { + # Give extensions a chance to select the revision instead + $id = false; // Assume current + wfRunHooks( 'BeforeParserFetchTemplateAndtitle', array( &$this, &$title, &$skip, &$id ) ); + + if( $skip ) { + $text = false; + $this->mOutput->addTemplate( $title, $title->getArticleID(), null ); + break; + } + $rev = $id ? Revision::newFromId( $id ) : Revision::newFromTitle( $title ); + $rev_id = $rev ? $rev->getId() : 0; + + $this->mOutput->addTemplate( $title, $title->getArticleID(), $rev_id ); + + if( $rev ) { $text = $rev->getText(); } elseif( $title->getNamespace() == NS_MEDIAWIKI ) { global $wgLang; @@ -3278,9 +3335,15 @@ class Parser break; } // Redirect? + $finalTitle = $title; $title = Title::newFromRedirect( $text ); } - return $text; + return array($text,$finalTitle); + } + + function fetchTemplate( $title ) { + $rv = $this->fetchTemplateAndtitle($title); + return $rv[0]; } /** @@ -3375,7 +3438,13 @@ class Parser } /** - * Detect __TOC__ magic word and set a placeholder + * Find the first __TOC__ magic word and set a + * placeholder that will then be replaced by the real TOC in + * ->formatHeadings, this works because at this points real + * comments will have already been discarded by the sanitizer. + * + * Any additional __TOC__ magic words left over will be discarded + * as there can only be one TOC on the page. */ function stripToc( $text ) { # if the string __NOTOC__ (not case-sensitive) occurs in the HTML, @@ -3453,17 +3522,13 @@ class Parser $enoughToc = true; } - # Never ever show TOC if no headers - if( $numMatches < 1 ) { - $enoughToc = false; - } - # We need this to perform operations on the HTML $sk = $this->mOptions->getSkin(); # headline counter $headlineCount = 0; $sectionCount = 0; # headlineCount excluding template sections + $numVisible = 0; # Ugh .. the TOC should have neat indentation levels which can be # passed to the skin functions. These are determined here @@ -3504,7 +3569,9 @@ class Parser $toclevel++; $sublevelCount[$toclevel] = 0; if( $toclevel<$wgMaxTocLevel ) { + $prevtoclevel = $toclevel; $toc .= $sk->tocIndent(); + $numVisible++; } } elseif ( $level < $prevlevel && $toclevel > 1 ) { @@ -3528,7 +3595,12 @@ class Parser } } if( $toclevel<$wgMaxTocLevel ) { - $toc .= $sk->tocUnindent( $prevtoclevel - $toclevel ); + if($prevtoclevel < $wgMaxTocLevel) { + # Unindent only if the previous toc level was shown :p + $toc .= $sk->tocUnindent( $prevtoclevel - $toclevel ); + } else { + $toc .= $sk->tocLineEnd(); + } } } else { @@ -3569,12 +3641,21 @@ class Parser "\$this->mInterwikiLinkHolders['texts'][\$1]", $canonized_headline ); - # strip out HTML - $canonized_headline = preg_replace( '/<.*?' . '>/','',$canonized_headline ); - $tocline = trim( $canonized_headline ); + # Strip out HTML (other than plain and : bug 8393) + $tocline = preg_replace( + array( '#<(?!/?(sup|sub)).*?'.'>#', '#<(/?(sup|sub)).*?'.'>#' ), + array( '', '<$1>'), + $canonized_headline + ); + $tocline = trim( $tocline ); + + # For the anchor, strip out HTML-y stuff period + $canonized_headline = preg_replace( '/<.*?'.'>/', '', $canonized_headline ); + $canonized_headline = trim( $canonized_headline ); + # Save headline for section edit hint before it's escaped - $headline_hint = trim( $canonized_headline ); - $canonized_headline = Sanitizer::escapeId( $tocline ); + $headline_hint = $canonized_headline; + $canonized_headline = Sanitizer::escapeId( $canonized_headline ); $refers[$headlineCount] = $canonized_headline; # count how many in assoc. array so we can track dupes in anchors @@ -3611,9 +3692,14 @@ class Parser $sectionCount++; } + # Never ever show TOC if no headers + if( $numVisible < 1 ) { + $enoughToc = false; + } + if( $enoughToc ) { - if( $toclevel<$wgMaxTocLevel ) { - $toc .= $sk->tocUnindent( $toclevel - 1 ); + if( $prevtoclevel > 0 && $prevtoclevel < $wgMaxTocLevel ) { + $toc .= $sk->tocUnindent( $prevtoclevel - 1 ); } $toc = $sk->tocList( $toc ); } @@ -3759,11 +3845,16 @@ class Parser * @private */ function getUserSig( &$user ) { + global $wgMaxSigChars; + $username = $user->getName(); $nickname = $user->getOption( 'nickname' ); $nickname = $nickname === '' ? $username : $nickname; - - if( $user->getBoolOption( 'fancysig' ) !== false ) { + + if( mb_strlen( $nickname ) > $wgMaxSigChars ) { + $nickname = $username; + wfDebug( __METHOD__ . ": $username has overlong signature.\n" ); + } elseif( $user->getBoolOption( 'fancysig' ) !== false ) { # Sig. might contain markup; validate this if( $this->validateSig( $nickname ) !== false ) { # Validated; clean up (if needed) and return it @@ -3903,6 +3994,14 @@ class Parser return $oldVal; } + function setTransparentTagHook( $tag, $callback ) { + $tag = strtolower( $tag ); + $oldVal = isset( $this->mTransparentTagHooks[$tag] ) ? $this->mTransparentTagHooks[$tag] : null; + $this->mTransparentTagHooks[$tag] = $callback; + + return $oldVal; + } + /** * Create a function, e.g. {{sum:1|2|3}} * The callback function should have the form: @@ -4018,6 +4117,8 @@ class Parser $this->mOutput->addLink( $title, $id ); } elseif ( $linkCache->isBadLink( $pdbk ) ) { $colours[$pdbk] = 0; + } elseif ( $title->getNamespace() == NS_SPECIAL && !SpecialPage::exists( $pdbk ) ) { + $colours[$pdbk] = 0; } else { # Not in the link cache, add it to the query if ( !isset( $current ) ) { @@ -4055,16 +4156,11 @@ class Parser $linkCache->addGoodLinkObj( $s->page_id, $title ); $this->mOutput->addLink( $title, $s->page_id ); - if ( $threshold > 0 ) { - $size = $s->page_len; - if ( $s->page_is_redirect || $s->page_namespace != 0 || $size >= $threshold ) { - $colours[$pdbk] = 1; - } else { - $colours[$pdbk] = 2; - } - } else { - $colours[$pdbk] = 1; - } + $colours[$pdbk] = ( $threshold == 0 || ( + $s->page_len >= $threshold || # always true if $threshold <= 0 + $s->page_is_redirect || + !Namespace::isContent( $s->page_namespace ) ) + ? 1 : 2 ); } } wfProfileOut( $fname.'-check' ); @@ -4104,7 +4200,7 @@ class Parser } // process categories, check if a category exists in some variant - foreach( $categories as $category){ + foreach( $categories as $category ){ $variants = $wgContLang->convertLinkToAllVariants($category); foreach($variants as $variant){ if($variant != $category){ @@ -4324,8 +4420,11 @@ class Parser $ig->setContextTitle( $this->mTitle ); $ig->setShowBytes( false ); $ig->setShowFilename( false ); - $ig->setParsing(); + $ig->setParser( $this ); + $ig->setHideBadImages(); + $ig->setAttributes( Sanitizer::validateTagAttributes( $params, 'table' ) ); $ig->useSkin( $this->mOptions->getSkin() ); + $ig->mRevisionId = $this->mRevisionId; if( isset( $params['caption'] ) ) { $caption = $params['caption']; @@ -4342,6 +4441,8 @@ class Parser if( isset( $params['heights'] ) ) { $ig->setHeights( $params['heights'] ); } + + wfRunHooks( 'BeforeParserrenderImageGallery', array( &$this, &$ig ) ); $lines = explode( "\n", $text ); foreach ( $lines as $line ) { @@ -4373,7 +4474,7 @@ class Parser ); $html = $pout->getText(); - $ig->add( new Image( $nt ), $html ); + $ig->add( $nt, $html ); # Only add real images (bug #5586) if ( $nt->getNamespace() == NS_IMAGE ) { @@ -4383,10 +4484,50 @@ class Parser return $ig->toHTML(); } + function getImageParams( $handler ) { + if ( $handler ) { + $handlerClass = get_class( $handler ); + } else { + $handlerClass = ''; + } + if ( !isset( $this->mImageParams[$handlerClass] ) ) { + // Initialise static lists + static $internalParamNames = array( + 'horizAlign' => array( 'left', 'right', 'center', 'none' ), + 'vertAlign' => array( 'baseline', 'sub', 'super', 'top', 'text-top', 'middle', + 'bottom', 'text-bottom' ), + 'frame' => array( 'thumbnail', 'manualthumb', 'framed', 'frameless', + 'upright', 'border' ), + ); + static $internalParamMap; + if ( !$internalParamMap ) { + $internalParamMap = array(); + foreach ( $internalParamNames as $type => $names ) { + foreach ( $names as $name ) { + $magicName = str_replace( '-', '_', "img_$name" ); + $internalParamMap[$magicName] = array( $type, $name ); + } + } + } + + // Add handler params + $paramMap = $internalParamMap; + if ( $handler ) { + $handlerParamMap = $handler->getParamMap(); + foreach ( $handlerParamMap as $magic => $paramName ) { + $paramMap[$magic] = array( 'handler', $paramName ); + } + } + $this->mImageParams[$handlerClass] = $paramMap; + $this->mImageParamsMagicArray[$handlerClass] = new MagicWordArray( array_keys( $paramMap ) ); + } + return array( $this->mImageParams[$handlerClass], $this->mImageParamsMagicArray[$handlerClass] ); + } + /** * Parse image options text and use it to make an image */ - function makeImage( $nt, $options ) { + function makeImage( $title, $options ) { # @TODO: let the MediaHandler specify its transform parameters # # Check if the options text is of the form "options|alt text" @@ -4398,6 +4539,9 @@ class Parser # * ___px scale to ___ pixels width, no aligning. e.g. use in taxobox # * center center the image # * framed Keep original image size, no magnify-button. + # * frameless like 'thumb' but without a frame. Keeps user preferences for width + # * upright reduce width for upright images, rounded to full __0 px + # * border draw a 1px border around the image # vertical-align values (no % or length right now): # * baseline # * sub @@ -4407,67 +4551,66 @@ class Parser # * middle # * bottom # * text-bottom + + $parts = array_map( 'trim', explode( '|', $options) ); + $sk = $this->mOptions->getSkin(); + # Give extensions a chance to select the file revision for us + $skip = $time = false; + wfRunHooks( 'BeforeParserMakeImageLinkObj', array( &$this, &$title, &$skip, &$time ) ); - $part = array_map( 'trim', explode( '|', $options) ); - - $mwAlign = array(); - $alignments = array( 'left', 'right', 'center', 'none', 'baseline', 'sub', 'super', 'top', 'text-top', 'middle', 'bottom', 'text-bottom' ); - foreach ( $alignments as $alignment ) { - $mwAlign[$alignment] =& MagicWord::get( 'img_'.$alignment ); + if ( $skip ) { + return $sk->makeLinkObj( $title ); } - $mwThumb =& MagicWord::get( 'img_thumbnail' ); - $mwManualThumb =& MagicWord::get( 'img_manualthumb' ); - $mwWidth =& MagicWord::get( 'img_width' ); - $mwFramed =& MagicWord::get( 'img_framed' ); - $mwPage =& MagicWord::get( 'img_page' ); - $caption = ''; - $params = array(); - $framed = $thumb = false; - $manual_thumb = '' ; - $align = $valign = ''; - $sk = $this->mOptions->getSkin(); + # Get parameter map + $file = wfFindFile( $title, $time ); + $handler = $file ? $file->getHandler() : false; - foreach( $part as $val ) { - if ( !is_null( $mwThumb->matchVariableStartToEnd($val) ) ) { - $thumb=true; - } elseif ( ! is_null( $match = $mwManualThumb->matchVariableStartToEnd($val) ) ) { - # use manually specified thumbnail - $thumb=true; - $manual_thumb = $match; - } else { - foreach( $alignments as $alignment ) { - if ( ! is_null( $mwAlign[$alignment]->matchVariableStartToEnd($val) ) ) { - switch ( $alignment ) { - case 'left': case 'right': case 'center': case 'none': - $align = $alignment; break; - default: - $valign = $alignment; - } - continue 2; - } - } - if ( ! is_null( $match = $mwPage->matchVariableStartToEnd($val) ) ) { - # Select a page in a multipage document - $params['page'] = $match; - } elseif ( !isset( $params['width'] ) && ! is_null( $match = $mwWidth->matchVariableStartToEnd($val) ) ) { - wfDebug( "img_width match: $match\n" ); - # $match is the image width in pixels + list( $paramMap, $mwArray ) = $this->getImageParams( $handler ); + + # Process the input parameters + $caption = ''; + $params = array( 'frame' => array(), 'handler' => array(), + 'horizAlign' => array(), 'vertAlign' => array() ); + foreach( $parts as $part ) { + list( $magicName, $value ) = $mwArray->matchVariableStartToEnd( $part ); + if ( isset( $paramMap[$magicName] ) ) { + list( $type, $paramName ) = $paramMap[$magicName]; + $params[$type][$paramName] = $value; + + // Special case; width and height come in one variable together + if( $type == 'handler' && $paramName == 'width' ) { $m = array(); - if ( preg_match( '/^([0-9]*)x([0-9]*)$/', $match, $m ) ) { - $params['width'] = intval( $m[1] ); - $params['height'] = intval( $m[2] ); + if ( preg_match( '/^([0-9]*)x([0-9]*)$/', $value, $m ) ) { + $params[$type]['width'] = intval( $m[1] ); + $params[$type]['height'] = intval( $m[2] ); } else { - $params['width'] = intval($match); + $params[$type]['width'] = intval( $value ); } - } elseif ( ! is_null( $mwFramed->matchVariableStartToEnd($val) ) ) { - $framed=true; - } else { - $caption = $val; + } + } else { + $caption = $part; + } + } + + # Process alignment parameters + if ( $params['horizAlign'] ) { + $params['frame']['align'] = key( $params['horizAlign'] ); + } + if ( $params['vertAlign'] ) { + $params['frame']['valign'] = key( $params['vertAlign'] ); + } + + # Validate the handler parameters + if ( $handler ) { + foreach ( $params['handler'] as $name => $value ) { + if ( !$handler->validateParam( $name, $value ) ) { + unset( $params['handler'][$name] ); } } } + # Strip bad stuff out of the alt text $alt = $this->replaceLinkHoldersText( $caption ); @@ -4477,8 +4620,18 @@ class Parser $alt = $this->mStripState->unstripBoth( $alt ); $alt = Sanitizer::stripAllTags( $alt ); + $params['frame']['alt'] = $alt; + $params['frame']['caption'] = $caption; + # Linker does the rest - return $sk->makeImageLinkObj( $nt, $caption, $alt, $align, $params, $framed, $thumb, $manual_thumb, $valign ); + $ret = $sk->makeImageLink2( $title, $file, $params['frame'], $params['handler'] ); + + # Give the handler a chance to modify the parser object + if ( $handler ) { + $handler->parserTransformHook( $this, $file ); + } + + return $ret; } /** @@ -4517,7 +4670,7 @@ class Parser /**#@+ * Accessor */ - function getTags() { return array_keys( $this->mTagHooks ); } + function getTags() { return array_merge( array_keys($this->mTransparentTagHooks), array_keys( $this->mTagHooks ) ); } /**#@-*/ @@ -4537,6 +4690,10 @@ class Parser * for "replace", the whole page with the section replaced. */ private function extractSections( $text, $section, $mode, $newtext='' ) { + # I.... _hope_ this is right. + # Otherwise, sometimes we don't have things initialized properly. + $this->clearState(); + # strip NOWIKI etc. to avoid confusion (true-parameter causes HTML # comments to be stripped as well) $stripState = new StripState; @@ -4554,7 +4711,7 @@ class Parser # now that we can be sure that no pseudo-sections are in the source, # split it up by section $uniq = preg_quote( $this->uniqPrefix(), '/' ); - $comment = "(?:$uniq-!--.*?QINU)"; + $comment = "(?:$uniq-!--.*?QINU\x07)"; $secs = preg_split( "/ ( @@ -4717,7 +4874,6 @@ class Parser : $this->mTitle->getPrefixedText(); } } - } /** @@ -4770,5 +4926,3 @@ class StripState { return $text; } } - -?> -- cgit v1.2.2