Index: branches/REL1_18/phase3/skins/common/shared.css |
— | — | @@ -181,12 +181,13 @@ |
182 | 182 | /** |
183 | 183 | * Categories |
184 | 184 | */ |
185 | | -#catlinks ul, #catlinks li { |
| 185 | +#catlinks ul { |
186 | 186 | display:inline; |
187 | 187 | margin: 0px; |
188 | 188 | list-style:none; |
189 | 189 | list-style-type:none; |
190 | 190 | list-style-image:none; |
| 191 | + vertical-align: middle !ie; |
191 | 192 | } |
192 | 193 | |
193 | 194 | #catlinks li { |
— | — | @@ -195,13 +196,14 @@ |
196 | 197 | padding: 0 .7em; |
197 | 198 | border-left: 1px solid #AAA; |
198 | 199 | margin: 0.3em 0; |
| 200 | + zoom: 1; |
| 201 | + display:inline !ie; |
199 | 202 | } |
200 | 203 | |
201 | 204 | #catlinks li:first-child { |
202 | 205 | padding-left: .4em; |
203 | 206 | border-left: none; |
204 | 207 | } |
205 | | - |
206 | 208 | /** |
207 | 209 | * Hidden categories |
208 | 210 | */ |
Index: branches/REL1_18/phase3/tests/phpunit/includes/ArticleTest.php |
— | — | @@ -50,14 +50,17 @@ |
51 | 51 | "Article get/set magic on update to new field" ); |
52 | 52 | } |
53 | 53 | |
| 54 | + /** |
| 55 | + * Checks for the existence of the backwards compatibility static functions (forwarders to WikiPage class) |
| 56 | + */ |
54 | 57 | function testStaticFunctions() { |
55 | 58 | $this->assertEquals( WikiPage::selectFields(), Article::selectFields(), |
56 | 59 | "Article static functions" ); |
57 | | - $this->assertEquals( null, Article::onArticleCreate( $this->title ), |
| 60 | + $this->assertEquals( true, is_callable( "Article::onArticleCreate" ), |
58 | 61 | "Article static functions" ); |
59 | | - $this->assertEquals( null, Article::onArticleDelete( $this->title ), |
| 62 | + $this->assertEquals( true, is_callable( "Article::onArticleDelete" ), |
60 | 63 | "Article static functions" ); |
61 | | - $this->assertEquals( null, ImagePage::onArticleEdit( $this->title ), |
| 64 | + $this->assertEquals( true, is_callable( "ImagePage::onArticleEdit" ), |
62 | 65 | "Article static functions" ); |
63 | 66 | $this->assertTrue( is_string( CategoryPage::getAutosummary( '', '', 0 ) ), |
64 | 67 | "Article static functions" ); |
Index: branches/REL1_18/phase3/tests/parser/parserTests.txt |
— | — | @@ -742,6 +742,15 @@ |
743 | 743 | !!end |
744 | 744 | |
745 | 745 | !! test |
| 746 | +External links: protocol-relative URL in the middle of a word is left alone (bug 30269) |
| 747 | +!! input |
| 748 | +foo//example.com/Foo |
| 749 | +!! result |
| 750 | +<p>foo//example.com/Foo |
| 751 | +</p> |
| 752 | +!! end |
| 753 | + |
| 754 | +!! test |
746 | 755 | External image |
747 | 756 | !! input |
748 | 757 | External image: http://meta.wikimedia.org/upload/f/f1/Ncwikicol.png |
Index: branches/REL1_18/phase3/includes/GlobalFunctions.php |
— | — | @@ -464,14 +464,18 @@ |
465 | 465 | /** |
466 | 466 | * Returns a regular expression of url protocols |
467 | 467 | * |
| 468 | + * @param $includeProtocolRelative bool If false, remove '//' from the returned protocol list. |
| 469 | + * DO NOT USE this directy, use wfUrlProtocolsWithoutProtRel() instead |
468 | 470 | * @return String |
469 | 471 | */ |
470 | | -function wfUrlProtocols() { |
| 472 | +function wfUrlProtocols( $includeProtocolRelative = true ) { |
471 | 473 | global $wgUrlProtocols; |
472 | 474 | |
473 | | - static $retval = null; |
474 | | - if ( !is_null( $retval ) ) { |
475 | | - return $retval; |
| 475 | + // Cache return values separately based on $includeProtocolRelative |
| 476 | + static $withProtRel = null, $withoutProtRel = null; |
| 477 | + $cachedValue = $includeProtocolRelative ? $withProtRel : $withoutProtRel; |
| 478 | + if ( !is_null( $cachedValue ) ) { |
| 479 | + return $cachedValue; |
476 | 480 | } |
477 | 481 | |
478 | 482 | // Support old-style $wgUrlProtocols strings, for backwards compatibility |
— | — | @@ -479,17 +483,40 @@ |
480 | 484 | if ( is_array( $wgUrlProtocols ) ) { |
481 | 485 | $protocols = array(); |
482 | 486 | foreach ( $wgUrlProtocols as $protocol ) { |
483 | | - $protocols[] = preg_quote( $protocol, '/' ); |
| 487 | + // Filter out '//' if !$includeProtocolRelative |
| 488 | + if ( $includeProtocolRelative || $protocol !== '//' ) { |
| 489 | + $protocols[] = preg_quote( $protocol, '/' ); |
| 490 | + } |
484 | 491 | } |
485 | 492 | |
486 | 493 | $retval = implode( '|', $protocols ); |
487 | 494 | } else { |
| 495 | + // Ignore $includeProtocolRelative in this case |
| 496 | + // This case exists for pre-1.6 compatibility, and we can safely assume |
| 497 | + // that '//' won't appear in a pre-1.6 config because protocol-relative |
| 498 | + // URLs weren't supported until 1.18 |
488 | 499 | $retval = $wgUrlProtocols; |
489 | 500 | } |
| 501 | + |
| 502 | + // Cache return value |
| 503 | + if ( $includeProtocolRelative ) { |
| 504 | + $withProtRel = $retval; |
| 505 | + } else { |
| 506 | + $withoutProtRel = $retval; |
| 507 | + } |
490 | 508 | return $retval; |
491 | 509 | } |
492 | 510 | |
493 | 511 | /** |
| 512 | + * Like wfUrlProtocols(), but excludes '//' from the protocol list. Use this if |
| 513 | + * you need a regex that matches all URL protocols but does not match protocol- |
| 514 | + * relative URLs |
| 515 | + */ |
| 516 | +function wfUrlProtocolsWithoutProtRel() { |
| 517 | + return wfUrlProtocols( false ); |
| 518 | +} |
| 519 | + |
| 520 | +/** |
494 | 521 | * parse_url() work-alike, but non-broken. Differences: |
495 | 522 | * |
496 | 523 | * 1) Does not raise warnings on bad URLs (just returns false) |
Property changes on: branches/REL1_18/phase3/includes/GlobalFunctions.php |
___________________________________________________________________ |
Modified: svn:mergeinfo |
497 | 524 | Merged /trunk/phase3/includes/GlobalFunctions.php:r92962,93062,93093,93385,93468,93473,94350,94502,94504,94511,94548 |
Index: branches/REL1_18/phase3/includes/parser/Parser.php |
— | — | @@ -1184,7 +1184,7 @@ |
1185 | 1185 | */ |
1186 | 1186 | function doMagicLinks( $text ) { |
1187 | 1187 | wfProfileIn( __METHOD__ ); |
1188 | | - $prots = $this->mUrlProtocols; |
| 1188 | + $prots = wfUrlProtocolsWithoutProtRel(); |
1189 | 1189 | $urlChar = self::EXT_LINK_URL_CLASS; |
1190 | 1190 | $text = preg_replace_callback( |
1191 | 1191 | '!(?: # Start cases |
Index: branches/REL1_18/phase3/includes/api/ApiFormatBase.php |
— | — | @@ -263,7 +263,7 @@ |
264 | 264 | // encode all comments or tags as safe blue strings |
265 | 265 | $text = preg_replace( '/\<(!--.*?--|.*?)\>/', '<span style="color:blue;"><\1></span>', $text ); |
266 | 266 | // identify URLs |
267 | | - $protos = wfUrlProtocols(); |
| 267 | + $protos = wfUrlProtocolsWithoutProtRel(); |
268 | 268 | // This regex hacks around bug 13218 (" included in the URL) |
269 | 269 | $text = preg_replace( "#(($protos).*?)(")?([ \\'\"<>\n]|<|>|")#", '<a href="\\1">\\1</a>\\3\\4', $text ); |
270 | 270 | // identify requests to api.php |
Index: branches/REL1_18/phase3/includes/api/ApiParamInfo.php |
— | — | @@ -123,6 +123,9 @@ |
124 | 124 | $result->setIndexedTagName( $retval['helpurls'], 'helpurl' ); |
125 | 125 | |
126 | 126 | $retval['allexamples'] = $examples; |
| 127 | + if ( isset( $retval['allexamples'][0] ) && $retval['allexamples'][0] === false ) { |
| 128 | + $retval['allexamples'] = array(); |
| 129 | + } |
127 | 130 | $result->setIndexedTagName( $retval['allexamples'], 'example' ); |
128 | 131 | |
129 | 132 | $retval['parameters'] = array(); |
Index: branches/REL1_18/phase3/includes/Title.php |
— | — | @@ -3259,6 +3259,7 @@ |
3260 | 3260 | if ( $u ) { |
3261 | 3261 | $u->doUpdate(); |
3262 | 3262 | } |
| 3263 | + |
3263 | 3264 | # Update message cache for interface messages |
3264 | 3265 | if ( $this->getNamespace() == NS_MEDIAWIKI ) { |
3265 | 3266 | # @bug 17860: old article can be deleted, if this the case, |
— | — | @@ -3348,10 +3349,11 @@ |
3349 | 3350 | } |
3350 | 3351 | $nullRevId = $nullRevision->insertOn( $dbw ); |
3351 | 3352 | |
| 3353 | + $now = wfTimestampNow(); |
3352 | 3354 | # Change the name of the target page: |
3353 | 3355 | $dbw->update( 'page', |
3354 | 3356 | /* SET */ array( |
3355 | | - 'page_touched' => $dbw->timestamp(), |
| 3357 | + 'page_touched' => $dbw->timestamp( $now ), |
3356 | 3358 | 'page_namespace' => $nt->getNamespace(), |
3357 | 3359 | 'page_title' => $nt->getDBkey(), |
3358 | 3360 | 'page_latest' => $nullRevId, |
— | — | @@ -3363,6 +3365,7 @@ |
3364 | 3366 | |
3365 | 3367 | $article = new Article( $nt ); |
3366 | 3368 | wfRunHooks( 'NewRevisionFromEditComplete', array( $article, $nullRevision, $latest, $wgUser ) ); |
| 3369 | + $article->setCachedLastEditTime( $now ); |
3367 | 3370 | |
3368 | 3371 | # Recreate the redirect, this time in the other direction. |
3369 | 3372 | if ( $createRedirect || !$wgUser->isAllowed( 'suppressredirect' ) ) { |
Property changes on: branches/REL1_18/phase3/includes/Title.php |
___________________________________________________________________ |
Modified: svn:mergeinfo |
3370 | 3373 | Merged /trunk/phase3/includes/Title.php:r92962,93062,93093,93385,93468,93473,94350,94502,94504,94511,94548 |
Index: branches/REL1_18/phase3/includes/WikiPage.php |
— | — | @@ -350,19 +350,28 @@ |
351 | 351 | * A DB query result object or... |
352 | 352 | * "fromdb" to get from a slave DB or... |
353 | 353 | * "fromdbmaster" to get from the master DB |
| 354 | + * @return void |
354 | 355 | */ |
355 | 356 | public function loadPageData( $data = 'fromdb' ) { |
356 | | - if ( $data === 'fromdb' || $data === 'fromdbmaster' ) { |
357 | | - $db = ( $data == 'fromdbmaster' ) |
358 | | - ? wfGetDB( DB_MASTER ) |
359 | | - : wfGetDB( DB_SLAVE ); |
360 | | - $data = $this->pageDataFromTitle( $db, $this->mTitle ); |
| 357 | + if ( $data === 'fromdbmaster' ) { |
| 358 | + $data = $this->pageDataFromTitle( wfGetDB( DB_MASTER ), $this->mTitle ); |
| 359 | + } elseif ( $data === 'fromdb' ) { // slave |
| 360 | + $data = $this->pageDataFromTitle( wfGetDB( DB_SLAVE ), $this->mTitle ); |
| 361 | + # Use a "last rev inserted" timestamp key to dimish the issue of slave lag. |
| 362 | + # Note that DB also stores the master position in the session and checks it. |
| 363 | + $touched = $this->getCachedLastEditTime(); |
| 364 | + if ( $touched ) { // key set |
| 365 | + if ( !$data || $touched > wfTimestamp( TS_MW, $data->page_touched ) ) { |
| 366 | + $data = $this->pageDataFromTitle( wfGetDB( DB_MASTER ), $this->mTitle ); |
| 367 | + } |
| 368 | + } |
361 | 369 | } |
362 | 370 | |
363 | 371 | $lc = LinkCache::singleton(); |
364 | 372 | |
365 | 373 | if ( $data ) { |
366 | | - $lc->addGoodLinkObj( $data->page_id, $this->mTitle, $data->page_len, $data->page_is_redirect, $data->page_latest ); |
| 374 | + $lc->addGoodLinkObj( $data->page_id, $this->mTitle, |
| 375 | + $data->page_len, $data->page_is_redirect, $data->page_latest ); |
367 | 376 | |
368 | 377 | $this->mTitle->loadFromRow( $data ); |
369 | 378 | |
— | — | @@ -814,10 +823,11 @@ |
815 | 824 | $conditions['page_latest'] = $lastRevision; |
816 | 825 | } |
817 | 826 | |
| 827 | + $now = wfTimestampNow(); |
818 | 828 | $dbw->update( 'page', |
819 | 829 | array( /* SET */ |
820 | 830 | 'page_latest' => $revision->getId(), |
821 | | - 'page_touched' => $dbw->timestamp(), |
| 831 | + 'page_touched' => $dbw->timestamp( $now ), |
822 | 832 | 'page_is_new' => ( $lastRevision === 0 ) ? 1 : 0, |
823 | 833 | 'page_is_redirect' => $rt !== null ? 1 : 0, |
824 | 834 | 'page_len' => strlen( $text ), |
— | — | @@ -828,6 +838,7 @@ |
829 | 839 | $result = $dbw->affectedRows() != 0; |
830 | 840 | if ( $result ) { |
831 | 841 | $this->updateRedirectOn( $dbw, $rt, $lastRevIsRedirect ); |
| 842 | + $this->setCachedLastEditTime( $now ); |
832 | 843 | } |
833 | 844 | |
834 | 845 | wfProfileOut( __METHOD__ ); |
— | — | @@ -835,6 +846,29 @@ |
836 | 847 | } |
837 | 848 | |
838 | 849 | /** |
| 850 | + * Get the cached timestamp for the last time the page changed. |
| 851 | + * This is only used to help handle slave lag by comparing to page_touched. |
| 852 | + * @return string MW timestamp |
| 853 | + */ |
| 854 | + protected function getCachedLastEditTime() { |
| 855 | + global $wgMemc; |
| 856 | + $key = wfMemcKey( 'page-lastedit', md5( $this->mTitle->getPrefixedDBkey() ) ); |
| 857 | + return $wgMemc->get( $key ); |
| 858 | + } |
| 859 | + |
| 860 | + /** |
| 861 | + * Set the cached timestamp for the last time the page changed. |
| 862 | + * This is only used to help handle slave lag by comparing to page_touched. |
| 863 | + * @param $timestamp string |
| 864 | + * @return void |
| 865 | + */ |
| 866 | + public function setCachedLastEditTime( $timestamp ) { |
| 867 | + global $wgMemc; |
| 868 | + $key = wfMemcKey( 'page-lastedit', md5( $this->mTitle->getPrefixedDBkey() ) ); |
| 869 | + $wgMemc->set( $key, wfTimestamp( TS_MW, $timestamp ), 60*15 ); |
| 870 | + } |
| 871 | + |
| 872 | + /** |
839 | 873 | * Add row to the redirect table if this is a redirect, remove otherwise. |
840 | 874 | * |
841 | 875 | * @param $dbw DatabaseBase |
Index: branches/REL1_18/phase3/includes/specials/SpecialEditWatchlist.php |
— | — | @@ -43,7 +43,7 @@ |
44 | 44 | array(), |
45 | 45 | array( 'returnto' => $this->getTitle()->getPrefixedText() ) |
46 | 46 | ); |
47 | | - $out->addHTML( wfMessage( 'watchlistanontext' )->rawParam( $llink )->parse() ); |
| 47 | + $out->addHTML( wfMessage( 'watchlistanontext' )->rawParams( $llink )->parse() ); |
48 | 48 | return; |
49 | 49 | } |
50 | 50 | |
Index: branches/REL1_18/phase3/includes/Block.php |
— | — | @@ -1057,6 +1057,19 @@ |
1058 | 1058 | return array( null, null ); |
1059 | 1059 | } |
1060 | 1060 | |
| 1061 | + if ( IP::isValid( $target ) ) { |
| 1062 | + # We can still create a User if it's an IP address, but we need to turn |
| 1063 | + # off validation checking (which would exclude IP addresses) |
| 1064 | + return array( |
| 1065 | + User::newFromName( IP::sanitizeIP( $target ), false ), |
| 1066 | + Block::TYPE_IP |
| 1067 | + ); |
| 1068 | + |
| 1069 | + } elseif ( IP::isValidBlock( $target ) ) { |
| 1070 | + # Can't create a User from an IP range |
| 1071 | + return array( IP::sanitizeRange( $target ), Block::TYPE_RANGE ); |
| 1072 | + } |
| 1073 | + |
1061 | 1074 | # Consider the possibility that this is not a username at all |
1062 | 1075 | # but actually an old subpage (bug #29797) |
1063 | 1076 | if( strpos( $target, '/' ) !== false ){ |
— | — | @@ -1072,18 +1085,6 @@ |
1073 | 1086 | # since hash characters are not valid in usernames or titles generally. |
1074 | 1087 | return array( $userObj, Block::TYPE_USER ); |
1075 | 1088 | |
1076 | | - } elseif ( IP::isValid( $target ) ) { |
1077 | | - # We can still create a User if it's an IP address, but we need to turn |
1078 | | - # off validation checking (which would exclude IP addresses) |
1079 | | - return array( |
1080 | | - User::newFromName( IP::sanitizeIP( $target ), false ), |
1081 | | - Block::TYPE_IP |
1082 | | - ); |
1083 | | - |
1084 | | - } elseif ( IP::isValidBlock( $target ) ) { |
1085 | | - # Can't create a User from an IP range |
1086 | | - return array( IP::sanitizeRange( $target ), Block::TYPE_RANGE ); |
1087 | | - |
1088 | 1089 | } elseif ( preg_match( '/^#\d+$/', $target ) ) { |
1089 | 1090 | # Autoblock reference in the form "#12345" |
1090 | 1091 | return array( substr( $target, 1 ), Block::TYPE_AUTO ); |
Index: branches/REL1_18/phase3/includes/SpecialPage.php |
— | — | @@ -545,7 +545,7 @@ |
546 | 546 | if ( $this->userCanExecute( $this->getUser() ) ) { |
547 | 547 | $func = $this->mFunction; |
548 | 548 | // only load file if the function does not exist |
549 | | - if(!is_callable($func) and $this->mFile) { |
| 549 | + if( !is_callable($func) && $this->mFile ) { |
550 | 550 | require_once( $this->mFile ); |
551 | 551 | } |
552 | 552 | $this->outputHeader(); |
Property changes on: branches/REL1_18/phase3/includes/SpecialPage.php |
___________________________________________________________________ |
Modified: svn:mergeinfo |
553 | 553 | Merged /trunk/phase3/includes/SpecialPage.php:r92962,93062,93093,93385,93468,93473,94350,94502,94504,94511,94548 |