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) { |