| Index: trunk/phase3/includes/MagicWord.php |
| — | — | @@ -69,6 +69,7 @@ |
| 70 | 70 | 'MAG_UC', |
| 71 | 71 | 'MAG_FULLPAGENAME', |
| 72 | 72 | 'MAG_FULLPAGENAMEE', |
| | 73 | + 'MAG_RAW', |
| 73 | 74 | ); |
| 74 | 75 | if ( ! defined( 'MEDIAWIKI_INSTALL' ) ) |
| 75 | 76 | wfRunHooks( 'MagicWordMagicWords', array( &$magicWords ) ); |
| Index: trunk/phase3/includes/Title.php |
| — | — | @@ -494,7 +494,7 @@ |
| 495 | 495 | function isTrans() { |
| 496 | 496 | global $wgTitleInterwikiCache, $wgDBname; |
| 497 | 497 | |
| 498 | | - if ($this->mInterwiki == '' || !$this->isLocal()) |
| | 498 | + if ($this->mInterwiki == '') |
| 499 | 499 | return false; |
| 500 | 500 | # Make sure key is loaded into cache |
| 501 | 501 | $this->getInterwikiLink( $this->mInterwiki ); |
| — | — | @@ -752,6 +752,13 @@ |
| 753 | 753 | |
| 754 | 754 | if ( $this->isExternal() ) { |
| 755 | 755 | $url = $this->getFullURL(); |
| | 756 | + if ( $query ) { |
| | 757 | + // This is currently only used for edit section links in the |
| | 758 | + // context of interwiki transclusion. In theory we should |
| | 759 | + // append the query to the end of any existing query string, |
| | 760 | + // but interwiki transclusion is already broken in that case. |
| | 761 | + $url .= "?$query"; |
| | 762 | + } |
| 756 | 763 | } else { |
| 757 | 764 | $dbkey = wfUrlencode( $this->getPrefixedDBkey() ); |
| 758 | 765 | if ( $query == '' ) { |
| — | — | @@ -1344,6 +1351,13 @@ |
| 1345 | 1352 | # Do another namespace split... |
| 1346 | 1353 | continue; |
| 1347 | 1354 | } |
| | 1355 | + |
| | 1356 | + # If there's an initial colon after the interwiki, that also |
| | 1357 | + # resets the default namespace |
| | 1358 | + if ( $t !== '' && $t[0] == ':' ) { |
| | 1359 | + $this->mNamespace = NS_MAIN; |
| | 1360 | + $t = substr( $t, 1 ); |
| | 1361 | + } |
| 1348 | 1362 | } |
| 1349 | 1363 | # If there's no recognized interwiki or namespace, |
| 1350 | 1364 | # then let the colon expression be part of the title. |
| Index: trunk/phase3/includes/HttpFunctions.php |
| — | — | @@ -9,7 +9,7 @@ |
| 10 | 10 | * if $timeout is 'default', $wgHTTPTimeout is used |
| 11 | 11 | */ |
| 12 | 12 | function wfGetHTTP( $url, $timeout = 'default' ) { |
| 13 | | - global $wgHTTPTimeout, $wgHTTPProxy, $wgVersion; |
| | 13 | + global $wgHTTPTimeout, $wgHTTPProxy, $wgVersion, $wgTitle, $wgCommandLineMode; |
| 14 | 14 | |
| 15 | 15 | # Use curl if available |
| 16 | 16 | if ( function_exists( 'curl_init' ) ) { |
| — | — | @@ -25,6 +25,16 @@ |
| 26 | 26 | } |
| 27 | 27 | curl_setopt( $c, CURLOPT_TIMEOUT, $timeout ); |
| 28 | 28 | curl_setopt( $c, CURLOPT_USERAGENT, "MediaWiki/$wgVersion" ); |
| | 29 | + |
| | 30 | + # Set the referer to $wgTitle, even in command-line mode |
| | 31 | + # This is useful for interwiki transclusion, where the foreign |
| | 32 | + # server wants to know what the referring page is. |
| | 33 | + # $_SERVER['REQUEST_URI'] gives a less reliable indication of the |
| | 34 | + # referring page. |
| | 35 | + if ( is_object( $wgTitle ) ) { |
| | 36 | + curl_setopt( $c, CURLOPT_REFERER, $wgTitle->getFullURL() ); |
| | 37 | + } |
| | 38 | + |
| 29 | 39 | ob_start(); |
| 30 | 40 | curl_exec( $c ); |
| 31 | 41 | $text = ob_get_contents(); |
| Index: trunk/phase3/includes/Parser.php |
| — | — | @@ -2253,9 +2253,10 @@ |
| 2254 | 2254 | * |
| 2255 | 2255 | * @param string $tex The text to transform |
| 2256 | 2256 | * @param array $args Key-value pairs representing template parameters to substitute |
| | 2257 | + * @param bool $argsOnly Only do argument (triple-brace) expansion, not double-brace expansion |
| 2257 | 2258 | * @access private |
| 2258 | 2259 | */ |
| 2259 | | - function replaceVariables( $text, $args = array() ) { |
| | 2260 | + function replaceVariables( $text, $args = array(), $argsOnly = false ) { |
| 2260 | 2261 | # Prevent too big inclusions |
| 2261 | 2262 | if( strlen( $text ) > MAX_INCLUDE_SIZE ) { |
| 2262 | 2263 | return $text; |
| — | — | @@ -2268,7 +2269,9 @@ |
| 2269 | 2270 | array_push( $this->mArgStack, $args ); |
| 2270 | 2271 | |
| 2271 | 2272 | $braceCallbacks = array(); |
| 2272 | | - $braceCallbacks[2] = array( &$this, 'braceSubstitution' ); |
| | 2273 | + if ( !$argsOnly ) { |
| | 2274 | + $braceCallbacks[2] = array( &$this, 'braceSubstitution' ); |
| | 2275 | + } |
| 2273 | 2276 | if ( $this->mOutputType == OT_HTML || $this->mOutputType == OT_WIKI ) { |
| 2274 | 2277 | $braceCallbacks[3] = array( &$this, 'argSubstitution' ); |
| 2275 | 2278 | } |
| — | — | @@ -2356,12 +2359,16 @@ |
| 2357 | 2360 | $fname = 'Parser::braceSubstitution'; |
| 2358 | 2361 | wfProfileIn( $fname ); |
| 2359 | 2362 | |
| 2360 | | - $found = false; |
| 2361 | | - $nowiki = false; |
| 2362 | | - $noparse = false; |
| 2363 | | - $replaceHeadings = false; |
| 2364 | | - $isHTML = false; |
| | 2363 | + # Flags |
| | 2364 | + $found = false; # $text has been filled |
| | 2365 | + $nowiki = false; # wiki markup in $text should be escaped |
| | 2366 | + $noparse = false; # Unsafe HTML tags should not be stripped, etc. |
| | 2367 | + $noargs = false; # Don't replace triple-brace arguments in $text |
| | 2368 | + $replaceHeadings = false; # Make the edit section links go to the template not the article |
| | 2369 | + $isHTML = false; # $text is HTML, armour it against wikitext transformation |
| | 2370 | + $forceRawInterwiki = false; # Force interwiki transclusion to be done in raw mode not rendered |
| 2365 | 2371 | |
| | 2372 | + # Title object, where $text came from |
| 2366 | 2373 | $title = NULL; |
| 2367 | 2374 | |
| 2368 | 2375 | $linestart = ''; |
| — | — | @@ -2378,6 +2385,7 @@ |
| 2379 | 2386 | $text = $replaceWith; |
| 2380 | 2387 | $found = true; |
| 2381 | 2388 | $noparse = true; |
| | 2389 | + $noargs = true; |
| 2382 | 2390 | } |
| 2383 | 2391 | } |
| 2384 | 2392 | |
| — | — | @@ -2395,10 +2403,11 @@ |
| 2396 | 2404 | $text = $piece['text']; |
| 2397 | 2405 | $found = true; |
| 2398 | 2406 | $noparse = true; |
| | 2407 | + $noargs = true; |
| 2399 | 2408 | } |
| 2400 | 2409 | } |
| 2401 | 2410 | |
| 2402 | | - # MSG, MSGNW and INT |
| | 2411 | + # MSG, MSGNW, INT and RAW |
| 2403 | 2412 | if ( !$found ) { |
| 2404 | 2413 | # Check for MSGNW: |
| 2405 | 2414 | $mwMsgnw =& MagicWord::get( MAG_MSGNW ); |
| — | — | @@ -2409,7 +2418,13 @@ |
| 2410 | 2419 | $mwMsg =& MagicWord::get( MAG_MSG ); |
| 2411 | 2420 | $mwMsg->matchStartAndRemove( $part1 ); |
| 2412 | 2421 | } |
| 2413 | | - |
| | 2422 | + |
| | 2423 | + # Check for RAW: |
| | 2424 | + $mwRaw =& MagicWord::get( MAG_RAW ); |
| | 2425 | + if ( $mwRaw->matchStartAndRemove( $part1 ) ) { |
| | 2426 | + $forceRawInterwiki = true; |
| | 2427 | + } |
| | 2428 | + |
| 2414 | 2429 | # Check if it is an internal message |
| 2415 | 2430 | $mwInt =& MagicWord::get( MAG_INT ); |
| 2416 | 2431 | if ( $mwInt->matchStartAndRemove( $part1 ) ) { |
| — | — | @@ -2515,12 +2530,13 @@ |
| 2516 | 2531 | |
| 2517 | 2532 | # Did we encounter this template already? If yes, it is in the cache |
| 2518 | 2533 | # and we need to check for loops. |
| 2519 | | - if ( !$found && isset( $this->mTemplates[$part1] ) ) { |
| | 2534 | + if ( !$found && isset( $this->mTemplates[$piece['title']] ) ) { |
| 2520 | 2535 | $found = true; |
| 2521 | 2536 | |
| 2522 | 2537 | # Infinite loop test |
| 2523 | 2538 | if ( isset( $this->mTemplatePath[$part1] ) ) { |
| 2524 | 2539 | $noparse = true; |
| | 2540 | + $noargs = true; |
| 2525 | 2541 | $found = true; |
| 2526 | 2542 | $text = $linestart . |
| 2527 | 2543 | '{{' . $part1 . '}}' . |
| — | — | @@ -2528,7 +2544,7 @@ |
| 2529 | 2545 | wfDebug( "$fname: template loop broken at '$part1'\n" ); |
| 2530 | 2546 | } else { |
| 2531 | 2547 | # set $text to cached message. |
| 2532 | | - $text = $linestart . $this->mTemplates[$part1]; |
| | 2548 | + $text = $linestart . $this->mTemplates[$piece['title']]; |
| 2533 | 2549 | } |
| 2534 | 2550 | } |
| 2535 | 2551 | |
| — | — | @@ -2553,6 +2569,7 @@ |
| 2554 | 2570 | if ( is_string( $text ) ) { |
| 2555 | 2571 | $found = true; |
| 2556 | 2572 | $noparse = true; |
| | 2573 | + $noargs = true; |
| 2557 | 2574 | $isHTML = true; |
| 2558 | 2575 | $this->disableCache(); |
| 2559 | 2576 | } |
| — | — | @@ -2571,23 +2588,26 @@ |
| 2572 | 2589 | $text = '[['.$title->getPrefixedText().']]'; |
| 2573 | 2590 | $found = true; |
| 2574 | 2591 | } |
| 2575 | | - |
| 2576 | | - # Template cache array insertion |
| 2577 | | - if( $found ) { |
| 2578 | | - $this->mTemplates[$part1] = $text; |
| 2579 | | - $text = $linestart . $text; |
| 2580 | | - } |
| 2581 | 2592 | } elseif ( $title->isTrans() ) { |
| 2582 | 2593 | // Interwiki transclusion |
| 2583 | | - if ( $this->mOutputType == OT_HTML ) { |
| | 2594 | + if ( $this->mOutputType == OT_HTML && !$forceRawInterwiki ) { |
| 2584 | 2595 | $text = $this->interwikiTransclude( $title, 'render' ); |
| 2585 | 2596 | $isHTML = true; |
| 2586 | 2597 | $noparse = true; |
| 2587 | 2598 | } else { |
| 2588 | 2599 | $text = $this->interwikiTransclude( $title, 'raw' ); |
| | 2600 | + $replaceHeadings = true; |
| 2589 | 2601 | } |
| 2590 | 2602 | $found = true; |
| 2591 | 2603 | } |
| | 2604 | + |
| | 2605 | + # Template cache array insertion |
| | 2606 | + # Use the original $piece['title'] not the mangled $part1, so that |
| | 2607 | + # modifiers such as RAW: produce separate cache entries |
| | 2608 | + if( $found ) { |
| | 2609 | + $this->mTemplates[$piece['title']] = $text; |
| | 2610 | + $text = $linestart . $text; |
| | 2611 | + } |
| 2592 | 2612 | } |
| 2593 | 2613 | } |
| 2594 | 2614 | |
| — | — | @@ -2595,52 +2615,61 @@ |
| 2596 | 2616 | # Only for HTML output |
| 2597 | 2617 | if ( $nowiki && $found && $this->mOutputType == OT_HTML ) { |
| 2598 | 2618 | $text = wfEscapeWikiText( $text ); |
| 2599 | | - } elseif ( ($this->mOutputType == OT_HTML || $this->mOutputType == OT_WIKI) && $found && !$noparse) { |
| 2600 | | - # Clean up argument array |
| 2601 | | - $assocArgs = array(); |
| 2602 | | - $index = 1; |
| 2603 | | - foreach( $args as $arg ) { |
| 2604 | | - $eqpos = strpos( $arg, '=' ); |
| 2605 | | - if ( $eqpos === false ) { |
| 2606 | | - $assocArgs[$index++] = $arg; |
| 2607 | | - } else { |
| 2608 | | - $name = trim( substr( $arg, 0, $eqpos ) ); |
| 2609 | | - $value = trim( substr( $arg, $eqpos+1 ) ); |
| 2610 | | - if ( $value === false ) { |
| 2611 | | - $value = ''; |
| | 2619 | + } elseif ( ($this->mOutputType == OT_HTML || $this->mOutputType == OT_WIKI) && $found ) { |
| | 2620 | + if ( !$noargs ) { |
| | 2621 | + # Clean up argument array |
| | 2622 | + $assocArgs = array(); |
| | 2623 | + $index = 1; |
| | 2624 | + foreach( $args as $arg ) { |
| | 2625 | + $eqpos = strpos( $arg, '=' ); |
| | 2626 | + if ( $eqpos === false ) { |
| | 2627 | + $assocArgs[$index++] = $arg; |
| | 2628 | + } else { |
| | 2629 | + $name = trim( substr( $arg, 0, $eqpos ) ); |
| | 2630 | + $value = trim( substr( $arg, $eqpos+1 ) ); |
| | 2631 | + if ( $value === false ) { |
| | 2632 | + $value = ''; |
| | 2633 | + } |
| | 2634 | + if ( $name !== false ) { |
| | 2635 | + $assocArgs[$name] = $value; |
| | 2636 | + } |
| 2612 | 2637 | } |
| 2613 | | - if ( $name !== false ) { |
| 2614 | | - $assocArgs[$name] = $value; |
| 2615 | | - } |
| 2616 | 2638 | } |
| | 2639 | + |
| | 2640 | + # Add a new element to the templace recursion path |
| | 2641 | + $this->mTemplatePath[$part1] = 1; |
| 2617 | 2642 | } |
| 2618 | 2643 | |
| 2619 | | - # Add a new element to the templace recursion path |
| 2620 | | - $this->mTemplatePath[$part1] = 1; |
| | 2644 | + if ( !$noparse ) { |
| | 2645 | + # If there are any <onlyinclude> tags, only include them |
| | 2646 | + if ( in_string( '<onlyinclude>', $text ) && in_string( '</onlyinclude>', $text ) ) { |
| | 2647 | + preg_match_all( '/<onlyinclude>(.*?)\n?<\/onlyinclude>/s', $text, $m ); |
| | 2648 | + $text = ''; |
| | 2649 | + foreach ($m[1] as $piece) |
| | 2650 | + $text .= $piece; |
| | 2651 | + } |
| | 2652 | + # Remove <noinclude> sections and <includeonly> tags |
| | 2653 | + $text = preg_replace( '/<noinclude>.*?<\/noinclude>/s', '', $text ); |
| | 2654 | + $text = strtr( $text, array( '<includeonly>' => '' , '</includeonly>' => '' ) ); |
| 2621 | 2655 | |
| 2622 | | - # If there are any <onlyinclude> tags, only include them |
| 2623 | | - if ( in_string( '<onlyinclude>', $text ) && in_string( '</onlyinclude>', $text ) ) { |
| 2624 | | - preg_match_all( '/<onlyinclude>(.*?)\n?<\/onlyinclude>/s', $text, $m ); |
| 2625 | | - $text = ''; |
| 2626 | | - foreach ($m[1] as $piece) |
| 2627 | | - $text .= $piece; |
| 2628 | | - } |
| 2629 | | - # Remove <noinclude> sections and <includeonly> tags |
| 2630 | | - $text = preg_replace( '/<noinclude>.*?<\/noinclude>/s', '', $text ); |
| 2631 | | - $text = strtr( $text, array( '<includeonly>' => '' , '</includeonly>' => '' ) ); |
| | 2656 | + if( $this->mOutputType == OT_HTML ) { |
| | 2657 | + # Strip <nowiki>, <pre>, etc. |
| | 2658 | + $text = $this->strip( $text, $this->mStripState ); |
| | 2659 | + $text = Sanitizer::removeHTMLtags( $text, array( &$this, 'replaceVariables' ), $assocArgs ); |
| | 2660 | + } |
| | 2661 | + $text = $this->replaceVariables( $text, $assocArgs ); |
| 2632 | 2662 | |
| 2633 | | - if( $this->mOutputType == OT_HTML ) { |
| 2634 | | - # Strip <nowiki>, <pre>, etc. |
| 2635 | | - $text = $this->strip( $text, $this->mStripState ); |
| 2636 | | - $text = Sanitizer::removeHTMLtags( $text, array( &$this, 'replaceVariables' ), $assocArgs ); |
| | 2663 | + # If the template begins with a table or block-level |
| | 2664 | + # element, it should be treated as beginning a new line. |
| | 2665 | + if (!$piece['lineStart'] && preg_match('/^({\\||:|;|#|\*)/', $text)) { |
| | 2666 | + $text = "\n" . $text; |
| | 2667 | + } |
| | 2668 | + } elseif ( !$noargs ) { |
| | 2669 | + # $noparse and !$noargs |
| | 2670 | + # Just replace the arguments, not any double-brace items |
| | 2671 | + # This is used for rendered interwiki transclusion |
| | 2672 | + $text = $this->replaceVariables( $text, $assocArgs, true ); |
| 2637 | 2673 | } |
| 2638 | | - $text = $this->replaceVariables( $text, $assocArgs ); |
| 2639 | | - |
| 2640 | | - # If the template begins with a table or block-level |
| 2641 | | - # element, it should be treated as beginning a new line. |
| 2642 | | - if (!$piece['lineStart'] && preg_match('/^({\\||:|;|#|\*)/', $text)) { |
| 2643 | | - $text = "\n" . $text; |
| 2644 | | - } |
| 2645 | 2674 | } |
| 2646 | 2675 | # Prune lower levels off the recursion check path |
| 2647 | 2676 | $this->mTemplatePath = $lastPathLevel; |
| Index: trunk/phase3/RELEASE-NOTES |
| — | — | @@ -258,6 +258,7 @@ |
| 259 | 259 | character before doing anything with them. This prevents certain kinds of |
| 260 | 260 | spam filter evasion. |
| 261 | 261 | * (bug 4783) : Fix for "{{ns:0}} does not render" |
| | 262 | +* Improved support for interwiki transclusion |
| 262 | 263 | |
| 263 | 264 | Upload: |
| 264 | 265 | * (bug 2527) Always set destination filename when new file is selected |
| Index: trunk/phase3/languages/Language.php |
| — | — | @@ -253,10 +253,11 @@ |
| 254 | 254 | MAG_PLURAL => array( 0, 'PLURAL:' ), |
| 255 | 255 | MAG_FULLURL => array( 0, 'FULLURL:' ), |
| 256 | 256 | MAG_FULLURLE => array( 0, 'FULLURLE:' ), |
| 257 | | - MAG_LCFIRST => array( 0, 'LCFIRST:' ), |
| 258 | | - MAG_UCFIRST => array( 0, 'UCFIRST:' ), |
| 259 | | - MAG_LC => array( 0, 'LC:' ), |
| 260 | | - MAG_UC => array( 0, 'UC:' ), |
| | 257 | + MAG_LCFIRST => array( 0, 'LCFIRST:' ), |
| | 258 | + MAG_UCFIRST => array( 0, 'UCFIRST:' ), |
| | 259 | + MAG_LC => array( 0, 'LC:' ), |
| | 260 | + MAG_UC => array( 0, 'UC:' ), |
| | 261 | + MAG_RAW => array( 0, 'RAW:' ), |
| 261 | 262 | ); |
| 262 | 263 | |
| 263 | 264 | if (!$wgCachedMessageArrays) { |