Index: trunk/phase3/maintenance/archives/patch-filejournal.sql |
— | — | @@ -1,24 +0,0 @@ |
2 | | -CREATE TABLE /*_*/filejournal ( |
3 | | - -- Unique ID for each file operation |
4 | | - fj_id bigint unsigned NOT NULL PRIMARY KEY auto_increment, |
5 | | - -- UUID of the batch this operation belongs to |
6 | | - fj_batch_uuid varbinary(32) NOT NULL, |
7 | | - -- The registered file backend name |
8 | | - fj_backend varchar(255) NOT NULL, |
9 | | - -- The storage path that was affected (may be internal paths) |
10 | | - fj_path blob NOT NULL, |
11 | | - -- SHA-1 file path hash in base-36 |
12 | | - fj_path_sha1 varbinary(32) NOT NULL default '', |
13 | | - -- Primitive operation description (create/update/delete) |
14 | | - fj_op varchar(16) NOT NULL default '', |
15 | | - -- SHA-1 file content hash in base-36 |
16 | | - fj_new_sha1 varbinary(32) NOT NULL default '', |
17 | | - -- Timestamp of the batch operation |
18 | | - fj_timestamp varbinary(14) NOT NULL default '' |
19 | | -); |
20 | | - |
21 | | -CREATE INDEX /*i*/fj_batch_id ON /*_*/filejournal (fj_batch_uuid,fj_id); |
22 | | -CREATE INDEX /*i*/fj_path_id ON /*_*/filejournal (fj_path_sha1,fj_id); |
23 | | -CREATE INDEX /*i*/fj_new_sha1 ON /*_*/filejournal (fj_new_sha1,fj_id); |
24 | | -CREATE INDEX /*i*/fj_timestamp ON /*_*/filejournal (fj_timestamp); |
Index: trunk/phase3/maintenance/language/messages.inc |
— | — | @@ -408,7 +408,6 @@ |
409 | 409 | 'customjsprotected', |
410 | 410 | 'ns-specialprotected', |
411 | 411 | 'titleprotected', |
412 | | - 'filereadonlyerror' |
413 | 412 | ), |
414 | 413 | 'virus' => array( |
415 | 414 | 'virus-badscanner', |
— | — | @@ -1378,11 +1377,6 @@ |
1379 | 1378 | 'backend-fail-batchsize' |
1380 | 1379 | ), |
1381 | 1380 | |
1382 | | - 'filejournal-errors' => array( |
1383 | | - 'filejournal-fail-dbconnect', |
1384 | | - 'filejournal-fail-dbquery' |
1385 | | - ), |
1386 | | - |
1387 | 1381 | 'lockmanager-errors' => array( |
1388 | 1382 | 'lockmanager-notlocked', |
1389 | 1383 | 'lockmanager-fail-closelock', |
Index: trunk/phase3/maintenance/dumpTextPass.php |
— | — | @@ -41,7 +41,9 @@ |
42 | 42 | var $prefetchCountLast = 0; |
43 | 43 | var $fetchCountLast = 0; |
44 | 44 | |
| 45 | + var $failures = 0; |
45 | 46 | var $maxFailures = 5; |
| 47 | + var $failedTextRetrievals = 0; |
46 | 48 | var $maxConsecutiveFailedTextRetrievals = 200; |
47 | 49 | var $failureTimeout = 5; // Seconds to sleep after db failure |
48 | 50 | |
— | — | @@ -69,54 +71,6 @@ |
70 | 72 | */ |
71 | 73 | protected $db; |
72 | 74 | |
73 | | - |
74 | | - /** |
75 | | - * Drop the database connection $this->db and try to get a new one. |
76 | | - * |
77 | | - * This function tries to get a /different/ connection if this is |
78 | | - * possible. Hence, (if this is possible) it switches to a different |
79 | | - * failover upon each call. |
80 | | - * |
81 | | - * This function resets $this->lb and closes all connections on it. |
82 | | - * |
83 | | - * @throws MWException |
84 | | - */ |
85 | | - function rotateDb() { |
86 | | - // Cleaning up old connections |
87 | | - if ( isset( $this->lb ) ) { |
88 | | - $this->lb->closeAll(); |
89 | | - unset( $this->lb ); |
90 | | - } |
91 | | - |
92 | | - if ( isset( $this->db ) && $this->db->isOpen() ) |
93 | | - { |
94 | | - throw new MWException( 'DB is set and has not been closed by the Load Balancer' ); |
95 | | - } |
96 | | - |
97 | | - |
98 | | - unset( $this->db ); |
99 | | - |
100 | | - // Trying to set up new connection. |
101 | | - // We do /not/ retry upon failure, but delegate to encapsulating logic, to avoid |
102 | | - // individually retrying at different layers of code. |
103 | | - |
104 | | - // 1. The LoadBalancer. |
105 | | - try { |
106 | | - $this->lb = wfGetLBFactory()->newMainLB(); |
107 | | - } catch (Exception $e) { |
108 | | - throw new MWException( __METHOD__ . " rotating DB failed to obtain new load balancer (" . $e->getMessage() . ")" ); |
109 | | - } |
110 | | - |
111 | | - |
112 | | - // 2. The Connection, through the load balancer. |
113 | | - try { |
114 | | - $this->db = $this->lb->getConnection( DB_SLAVE, 'backup' ); |
115 | | - } catch (Exception $e) { |
116 | | - throw new MWException( __METHOD__ . " rotating DB failed to obtain new database (" . $e->getMessage() . ")" ); |
117 | | - } |
118 | | - } |
119 | | - |
120 | | - |
121 | 75 | function initProgress( $history ) { |
122 | 76 | parent::initProgress(); |
123 | 77 | $this->timeOfCheckpoint = $this->startTime; |
— | — | @@ -133,19 +87,7 @@ |
134 | 88 | |
135 | 89 | $this->initProgress( $this->history ); |
136 | 90 | |
137 | | - // We are trying to get an initial database connection to avoid that the |
138 | | - // first try of this request's first call to getText fails. However, if |
139 | | - // obtaining a good DB connection fails it's not a serious issue, as |
140 | | - // getText does retry upon failure and can start without having a working |
141 | | - // DB connection. |
142 | | - try { |
143 | | - $this->rotateDb(); |
144 | | - } catch (Exception $e) { |
145 | | - // We do not even count this as failure. Just let eventual |
146 | | - // watchdogs know. |
147 | | - $this->progress( "Getting initial DB connection failed (" . |
148 | | - $e->getMessage() . ")" ); |
149 | | - } |
| 91 | + $this->db = $this->backupDb(); |
150 | 92 | |
151 | 93 | $this->egress = new ExportProgressFilter( $this->sink, $this ); |
152 | 94 | |
— | — | @@ -374,142 +316,98 @@ |
375 | 317 | return true; |
376 | 318 | } |
377 | 319 | |
378 | | - /** |
379 | | - * Tries to get the revision text for a revision id. |
380 | | - * |
381 | | - * Upon errors, retries (Up to $this->maxFailures tries each call). |
382 | | - * If still no good revision get could be found even after this retrying, "" is returned. |
383 | | - * If no good revision text could be returned for |
384 | | - * $this->maxConsecutiveFailedTextRetrievals consecutive calls to getText, MWException |
385 | | - * is thrown. |
386 | | - * |
387 | | - * @param $id string The revision id to get the text for |
388 | | - * |
389 | | - * @return string The revision text for $id, or "" |
390 | | - * @throws MWException |
391 | | - */ |
392 | 320 | function getText( $id ) { |
393 | | - $prefetchNotTried = true; // Whether or not we already tried to get the text via prefetch. |
394 | | - $text = false; // The candidate for a good text. false if no proper value. |
395 | | - $failures = 0; // The number of times, this invocation of getText already failed. |
396 | | - |
397 | | - static $consecutiveFailedTextRetrievals = 0; // The number of times getText failed without |
398 | | - // yielding a good text in between. |
399 | | - |
400 | 321 | $this->fetchCount++; |
401 | | - |
402 | | - // To allow to simply return on success and do not have to worry about book keeping, |
403 | | - // we assume, this fetch works (possible after some retries). Nevertheless, we koop |
404 | | - // the old value, so we can restore it, if problems occur (See after the while loop). |
405 | | - $oldConsecutiveFailedTextRetrievals = $consecutiveFailedTextRetrievals; |
406 | | - $consecutiveFailedTextRetrievals = 0; |
407 | | - |
408 | | - while ( $failures < $this->maxFailures ) { |
409 | | - |
410 | | - // As soon as we found a good text for the $id, we will return immediately. |
411 | | - // Hence, if we make it past the try catch block, we know that we did not |
412 | | - // find a good text. |
413 | | - |
414 | | - try { |
415 | | - // Step 1: Get some text (or reuse from previous iteratuon if checking |
416 | | - // for plausibility failed) |
417 | | - |
418 | | - // Trying to get prefetch, if it has not been tried before |
419 | | - if ( $text === false && isset( $this->prefetch ) && $prefetchNotTried ) { |
420 | | - $prefetchNotTried = false; |
421 | | - $tryIsPrefetch = true; |
422 | | - $text = $this->prefetch->prefetch( $this->thisPage, $this->thisRev ); |
423 | | - if ( $text === null ) { |
424 | | - $text = false; |
425 | | - } |
426 | | - } |
427 | | - |
428 | | - if ( $text === false ) { |
429 | | - // Fallback to asking the database |
430 | | - $tryIsPrefetch = false; |
431 | | - if ( $this->spawn ) { |
432 | | - $text = $this->getTextSpawned( $id ); |
433 | | - } else { |
434 | | - $text = $this->getTextDb( $id ); |
435 | | - } |
436 | | - } |
437 | | - |
438 | | - if ( $text === false ) { |
439 | | - throw new MWException( "Generic error while obtaining text for id " . $id ); |
440 | | - } |
441 | | - |
442 | | - // We received a good candidate for the text of $id via some method |
443 | | - |
444 | | - // Step 2: Checking for plausibility and return the text if it is |
445 | | - // plausible |
| 322 | + if ( isset( $this->prefetch ) ) { |
| 323 | + $text = $this->prefetch->prefetch( $this->thisPage, $this->thisRev ); |
| 324 | + if ( $text !== null ) { // Entry missing from prefetch dump |
| 325 | + $dbr = wfGetDB( DB_SLAVE ); |
446 | 326 | $revID = intval( $this->thisRev ); |
447 | | - if ( ! isset( $this->db ) ) { |
448 | | - throw new MWException( "No database available" ); |
449 | | - } |
450 | | - $revLength = $this->db->selectField( 'revision', 'rev_len', array( 'rev_id' => $revID ) ); |
| 327 | + $revLength = $dbr->selectField( 'revision', 'rev_len', array( 'rev_id' => $revID ) ); |
| 328 | + // if length of rev text in file doesn't match length in db, we reload |
| 329 | + // this avoids carrying forward broken data from previous xml dumps |
451 | 330 | if( strlen( $text ) == $revLength ) { |
452 | | - if ( $tryIsPrefetch ) { |
453 | | - $this->prefetchCount++; |
454 | | - } |
| 331 | + $this->prefetchCount++; |
455 | 332 | return $text; |
456 | 333 | } |
457 | | - |
458 | | - $text = false; |
459 | | - throw new MWException( "Received text is unplausible for id " . $id ); |
460 | | - |
461 | | - } catch (Exception $e) { |
462 | | - $msg = "getting/checking text " . $id . " failed (".$e->getMessage().")"; |
463 | | - if ( $failures + 1 < $this->maxFailures ) { |
464 | | - $msg .= " (Will retry " . ( $this->maxFailures - $failures - 1) . " more times)"; |
465 | | - } |
466 | | - $this->progress( $msg ); |
467 | 334 | } |
468 | | - |
469 | | - // Something went wrong; we did not a text that was plausible :( |
470 | | - $failures++; |
| 335 | + } |
| 336 | + return $this->doGetText( $id ); |
| 337 | + } |
471 | 338 | |
472 | | - |
473 | | - // After backing off for some time, we try to reboot the whole process as |
474 | | - // much as possible to not carry over failures from one part to the other |
475 | | - // parts |
476 | | - sleep( $this->failureTimeout ); |
477 | | - try { |
478 | | - $this->rotateDb(); |
479 | | - if ( $this->spawn ) { |
| 339 | + private function doGetText( $id ) { |
| 340 | + $id = intval( $id ); |
| 341 | + $this->failures = 0; |
| 342 | + $ex = new MWException( "Graceful storage failure" ); |
| 343 | + while (true) { |
| 344 | + if ( $this->spawn ) { |
| 345 | + if ($this->failures) { |
| 346 | + // we don't know why it failed, could be the child process |
| 347 | + // borked, could be db entry busted, could be db server out to lunch, |
| 348 | + // so cover all bases |
480 | 349 | $this->closeSpawn(); |
481 | 350 | $this->openSpawn(); |
482 | 351 | } |
483 | | - } catch (Exception $e) { |
484 | | - $this->progress( "Rebooting getText infrastructure failed (".$e->getMessage().")" . |
485 | | - " Trying to continue anyways" ); |
| 352 | + $text = $this->getTextSpawned( $id ); |
| 353 | + } else { |
| 354 | + $text = $this->getTextDbSafe( $id ); |
486 | 355 | } |
| 356 | + if ( $text === false ) { |
| 357 | + $this->failures++; |
| 358 | + if ( $this->failures > $this->maxFailures) { |
| 359 | + $this->progress( "Failed to retrieve revision text for text id ". |
| 360 | + "$id after $this->maxFailures tries, giving up" ); |
| 361 | + // were there so many bad retrievals in a row we want to bail? |
| 362 | + // at some point we have to declare the dump irretrievably broken |
| 363 | + $this->failedTextRetrievals++; |
| 364 | + if ($this->failedTextRetrievals > $this->maxConsecutiveFailedTextRetrievals) { |
| 365 | + throw $ex; |
| 366 | + } else { |
| 367 | + // would be nice to return something better to the caller someday, |
| 368 | + // log what we know about the failure and about the revision |
| 369 | + return ""; |
| 370 | + } |
| 371 | + } else { |
| 372 | + $this->progress( "Error $this->failures " . |
| 373 | + "of allowed $this->maxFailures retrieving revision text for text id $id! " . |
| 374 | + "Pausing $this->failureTimeout seconds before retry..." ); |
| 375 | + sleep( $this->failureTimeout ); |
| 376 | + } |
| 377 | + } else { |
| 378 | + $this->failedTextRetrievals= 0; |
| 379 | + return $text; |
| 380 | + } |
487 | 381 | } |
| 382 | + return ''; |
| 383 | + } |
488 | 384 | |
489 | | - // Retirieving a good text for $id failed (at least) maxFailures times. |
490 | | - // We abort for this $id. |
491 | | - |
492 | | - // Restoring the consecutive failures, and maybe aborting, if the dump |
493 | | - // is too broken. |
494 | | - $consecutiveFailedTextRetrievals = $oldConsecutiveFailedTextRetrievals + 1; |
495 | | - if ( $consecutiveFailedTextRetrievals > $this->maxConsecutiveFailedTextRetrievals ) { |
496 | | - throw new MWException( "Graceful storage failure" ); |
| 385 | + /** |
| 386 | + * Fetch a text revision from the database, retrying in case of failure. |
| 387 | + * This may survive some transitory errors by reconnecting, but |
| 388 | + * may not survive a long-term server outage. |
| 389 | + * |
| 390 | + * FIXME: WTF? Why is it using a loop and then returning unconditionally? |
| 391 | + * @param $id int |
| 392 | + * @return bool|string |
| 393 | + */ |
| 394 | + private function getTextDbSafe( $id ) { |
| 395 | + while ( true ) { |
| 396 | + try { |
| 397 | + $text = $this->getTextDb( $id ); |
| 398 | + } catch ( DBQueryError $ex ) { |
| 399 | + $text = false; |
| 400 | + } |
| 401 | + return $text; |
497 | 402 | } |
498 | | - |
499 | | - return ""; |
500 | 403 | } |
501 | 404 | |
502 | | - |
503 | 405 | /** |
504 | 406 | * May throw a database error if, say, the server dies during query. |
505 | 407 | * @param $id |
506 | 408 | * @return bool|string |
507 | | - * @throws MWException |
508 | 409 | */ |
509 | 410 | private function getTextDb( $id ) { |
510 | 411 | global $wgContLang; |
511 | | - if ( ! isset( $this->db ) ) { |
512 | | - throw new MWException( __METHOD__ . "No database available" ); |
513 | | - } |
514 | 412 | $row = $this->db->selectRow( 'text', |
515 | 413 | array( 'old_text', 'old_flags' ), |
516 | 414 | array( 'old_id' => $id ), |
Index: trunk/phase3/includes/db/DatabasePostgres.php |
— | — | @@ -708,19 +708,14 @@ |
709 | 709 | # Replace reserved words with better ones |
710 | 710 | switch( $name ) { |
711 | 711 | case 'user': |
712 | | - return $this->realTableName( 'mwuser', $format ); |
| 712 | + return 'mwuser'; |
713 | 713 | case 'text': |
714 | | - return $this->realTableName( 'pagecontent', $format ); |
| 714 | + return 'pagecontent'; |
715 | 715 | default: |
716 | | - return $this->realTableName( $name, $format ); |
| 716 | + return parent::tableName( $name, $format ); |
717 | 717 | } |
718 | 718 | } |
719 | 719 | |
720 | | - /* Don't cheat on installer */ |
721 | | - function realTableName( $name, $format = 'quoted' ) { |
722 | | - return parent::tableName( $name, $format ); |
723 | | - } |
724 | | - |
725 | 720 | /** |
726 | 721 | * Return the next in a sequence, save the value for retrieval via insertId() |
727 | 722 | * @return null |
— | — | @@ -995,7 +990,7 @@ |
996 | 991 | if ( !$schema ) { |
997 | 992 | $schema = $this->getCoreSchema(); |
998 | 993 | } |
999 | | - $table = $this->realTableName( $table, 'raw' ); |
| 994 | + $table = $this->tableName( $table, 'raw' ); |
1000 | 995 | $etable = $this->addQuotes( $table ); |
1001 | 996 | $eschema = $this->addQuotes( $schema ); |
1002 | 997 | $SQL = "SELECT 1 FROM pg_catalog.pg_class c, pg_catalog.pg_namespace n " |
Index: trunk/phase3/includes/db/Database.php |
— | — | @@ -680,7 +680,7 @@ |
681 | 681 | $dbType = strtolower( $dbType ); |
682 | 682 | $class = 'Database' . ucfirst( $dbType ); |
683 | 683 | |
684 | | - if( in_array( $dbType, $canonicalDBTypes ) || ( class_exists( $class ) && is_subclass_of( $class, 'DatabaseBase' ) ) ) { |
| 684 | + if( in_array( $dbType, $canonicalDBTypes ) ) { |
685 | 685 | return new $class( |
686 | 686 | isset( $p['host'] ) ? $p['host'] : false, |
687 | 687 | isset( $p['user'] ) ? $p['user'] : false, |
— | — | @@ -689,6 +689,8 @@ |
690 | 690 | isset( $p['flags'] ) ? $p['flags'] : 0, |
691 | 691 | isset( $p['tablePrefix'] ) ? $p['tablePrefix'] : 'get from global' |
692 | 692 | ); |
| 693 | + } elseif ( class_exists( $class ) && is_subclass_of( $class, 'DatabaseBase' ) ) { |
| 694 | + return new $class( $p ); |
693 | 695 | } else { |
694 | 696 | return null; |
695 | 697 | } |
Index: trunk/phase3/includes/filerepo/file/LocalFile.php |
— | — | @@ -908,13 +908,9 @@ |
909 | 909 | */ |
910 | 910 | function upload( $srcPath, $comment, $pageText, $flags = 0, $props = false, $timestamp = false, $user = null ) { |
911 | 911 | global $wgContLang; |
912 | | - |
913 | | - if ( $this->getRepo()->getReadOnlyReason() !== false ) { |
914 | | - return $this->readOnlyFatalStatus(); |
915 | | - } |
916 | | - |
917 | 912 | // truncate nicely or the DB will do it for us |
918 | | - // non-nicely (dangling multi-byte chars, non-truncated version in cache). |
| 913 | + // non-nicely (dangling multi-byte chars, non-truncated |
| 914 | + // version in cache). |
919 | 915 | $comment = $wgContLang->truncate( $comment, 255 ); |
920 | 916 | $this->lock(); // begin |
921 | 917 | $status = $this->publish( $srcPath, $flags ); |
— | — | @@ -1179,10 +1175,6 @@ |
1180 | 1176 | * archive name, or an empty string if it was a new file. |
1181 | 1177 | */ |
1182 | 1178 | function publishTo( $srcPath, $dstRel, $flags = 0 ) { |
1183 | | - if ( $this->getRepo()->getReadOnlyReason() !== false ) { |
1184 | | - return $this->readOnlyFatalStatus(); |
1185 | | - } |
1186 | | - |
1187 | 1179 | $this->lock(); // begin |
1188 | 1180 | |
1189 | 1181 | $archiveName = wfTimestamp( TS_MW ) . '!'. $this->getName(); |
— | — | @@ -1219,10 +1211,6 @@ |
1220 | 1212 | * @return FileRepoStatus object. |
1221 | 1213 | */ |
1222 | 1214 | function move( $target ) { |
1223 | | - if ( $this->getRepo()->getReadOnlyReason() !== false ) { |
1224 | | - return $this->readOnlyFatalStatus(); |
1225 | | - } |
1226 | | - |
1227 | 1215 | wfDebugLog( 'imagemove', "Got request to move {$this->name} to " . $target->getText() ); |
1228 | 1216 | $this->lock(); // begin |
1229 | 1217 | |
— | — | @@ -1262,10 +1250,6 @@ |
1263 | 1251 | * @return FileRepoStatus object. |
1264 | 1252 | */ |
1265 | 1253 | function delete( $reason, $suppress = false ) { |
1266 | | - if ( $this->getRepo()->getReadOnlyReason() !== false ) { |
1267 | | - return $this->readOnlyFatalStatus(); |
1268 | | - } |
1269 | | - |
1270 | 1254 | $this->lock(); // begin |
1271 | 1255 | |
1272 | 1256 | $batch = new LocalFileDeleteBatch( $this, $reason, $suppress ); |
— | — | @@ -1282,7 +1266,7 @@ |
1283 | 1267 | } |
1284 | 1268 | $status = $batch->execute(); |
1285 | 1269 | |
1286 | | - if ( $status->isOK() ) { |
| 1270 | + if ( $status->ok ) { |
1287 | 1271 | // Update site_stats |
1288 | 1272 | $site_stats = $dbw->tableName( 'site_stats' ); |
1289 | 1273 | $dbw->query( "UPDATE $site_stats SET ss_images=ss_images-1", __METHOD__ ); |
— | — | @@ -1309,10 +1293,6 @@ |
1310 | 1294 | * @return FileRepoStatus object. |
1311 | 1295 | */ |
1312 | 1296 | function deleteOld( $archiveName, $reason, $suppress = false ) { |
1313 | | - if ( $this->getRepo()->getReadOnlyReason() !== false ) { |
1314 | | - return $this->readOnlyFatalStatus(); |
1315 | | - } |
1316 | | - |
1317 | 1297 | $this->lock(); // begin |
1318 | 1298 | |
1319 | 1299 | $batch = new LocalFileDeleteBatch( $this, $reason, $suppress ); |
— | — | @@ -1322,7 +1302,7 @@ |
1323 | 1303 | |
1324 | 1304 | $this->unlock(); // done |
1325 | 1305 | |
1326 | | - if ( $status->isOK() ) { |
| 1306 | + if ( $status->ok ) { |
1327 | 1307 | $this->purgeDescription(); |
1328 | 1308 | $this->purgeHistory(); |
1329 | 1309 | } |
— | — | @@ -1342,12 +1322,6 @@ |
1343 | 1323 | * @return FileRepoStatus |
1344 | 1324 | */ |
1345 | 1325 | function restore( $versions = array(), $unsuppress = false ) { |
1346 | | - if ( $this->getRepo()->getReadOnlyReason() !== false ) { |
1347 | | - return $this->readOnlyFatalStatus(); |
1348 | | - } |
1349 | | - |
1350 | | - $this->lock(); // begin |
1351 | | - |
1352 | 1326 | $batch = new LocalFileRestoreBatch( $this, $unsuppress ); |
1353 | 1327 | |
1354 | 1328 | if ( !$versions ) { |
— | — | @@ -1358,14 +1332,14 @@ |
1359 | 1333 | |
1360 | 1334 | $status = $batch->execute(); |
1361 | 1335 | |
1362 | | - if ( $status->isGood() ) { |
1363 | | - $cleanupStatus = $batch->cleanup(); |
1364 | | - $cleanupStatus->successCount = 0; |
1365 | | - $cleanupStatus->failCount = 0; |
1366 | | - $status->merge( $cleanupStatus ); |
| 1336 | + if ( !$status->isGood() ) { |
| 1337 | + return $status; |
1367 | 1338 | } |
1368 | 1339 | |
1369 | | - $this->unlock(); // done |
| 1340 | + $cleanupStatus = $batch->cleanup(); |
| 1341 | + $cleanupStatus->successCount = 0; |
| 1342 | + $cleanupStatus->failCount = 0; |
| 1343 | + $status->merge( $cleanupStatus ); |
1370 | 1344 | |
1371 | 1345 | return $status; |
1372 | 1346 | } |
— | — | @@ -1470,14 +1444,6 @@ |
1471 | 1445 | $dbw = $this->repo->getMasterDB(); |
1472 | 1446 | $dbw->rollback( __METHOD__ ); |
1473 | 1447 | } |
1474 | | - |
1475 | | - /** |
1476 | | - * @return Status |
1477 | | - */ |
1478 | | - protected function readOnlyFatalStatus() { |
1479 | | - return $this->getRepo()->newFatal( 'filereadonlyerror', $this->getName(), |
1480 | | - $this->getRepo()->getName(), $this->getRepo()->getReadOnlyReason() ); |
1481 | | - } |
1482 | 1448 | } // LocalFile class |
1483 | 1449 | |
1484 | 1450 | # ------------------------------------------------------------------------------ |
— | — | @@ -1745,7 +1711,7 @@ |
1746 | 1712 | $this->status->merge( $status ); |
1747 | 1713 | } |
1748 | 1714 | |
1749 | | - if ( !$this->status->isOK() ) { |
| 1715 | + if ( !$this->status->ok ) { |
1750 | 1716 | // Critical file deletion error |
1751 | 1717 | // Roll back inserts, release lock and abort |
1752 | 1718 | // TODO: delete the defunct filearchive rows if we are using a non-transactional DB |
Index: trunk/phase3/includes/filerepo/file/File.php |
— | — | @@ -760,27 +760,16 @@ |
761 | 761 | * @param $thumbUrl string Thumbnail URL |
762 | 762 | * @param $params Array |
763 | 763 | * @param $flags integer |
764 | | - * @param $status Status Optional status object to use for errors |
765 | 764 | * @return MediaTransformOutput |
766 | 765 | */ |
767 | | - protected function transformErrorOutput( |
768 | | - $thumbPath, $thumbUrl, $params, $flags, Status $status = null |
769 | | - ) { |
| 766 | + protected function transformErrorOutput( $thumbPath, $thumbUrl, $params, $flags ) { |
770 | 767 | global $wgIgnoreImageErrors; |
771 | 768 | |
772 | 769 | if ( $wgIgnoreImageErrors && !( $flags & self::RENDER_NOW ) ) { |
773 | 770 | return $this->handler->getTransform( $this, $thumbPath, $thumbUrl, $params ); |
774 | 771 | } else { |
775 | | - $badStatus = Status::newFatal( 'thumbnail-dest-create' ); |
776 | | - if ( $status ) { // additional, more detailed errors |
777 | | - $badStatus->merge( $status ); |
778 | | - } |
779 | | - $err = array(); |
780 | | - foreach ( $badStatus->getErrorsArray() as $item ) { |
781 | | - $err[] = wfMsg( $item[0], array_slice( $item, 1 ) ); |
782 | | - } |
783 | 772 | return new MediaTransformError( 'thumbnail_error', |
784 | | - $params['width'], 0, implode( "\n", $err ) ); // MTO does "\n" => "<br/>" |
| 773 | + $params['width'], 0, wfMsg( 'thumbnail-dest-create' ) ); |
785 | 774 | } |
786 | 775 | } |
787 | 776 | |
— | — | @@ -886,8 +875,7 @@ |
887 | 876 | if ( $status->isOK() ) { |
888 | 877 | $thumb->setStoragePath( $thumbPath ); |
889 | 878 | } else { |
890 | | - $thumb = $this->transformErrorOutput( |
891 | | - $thumbPath, $thumbUrl, $params, $flags, $status ); |
| 879 | + $thumb = $this->transformErrorOutput( $thumbPath, $thumbUrl, $params, $flags ); |
892 | 880 | } |
893 | 881 | } |
894 | 882 | |
Index: trunk/phase3/includes/filerepo/backend/FileBackendMultiWrite.php |
— | — | @@ -133,7 +133,7 @@ |
134 | 134 | } |
135 | 135 | |
136 | 136 | // Actually attempt the operation batch... |
137 | | - $subStatus = FileOp::attemptBatch( $performOps, $opts, $this->fileJournal ); |
| 137 | + $subStatus = FileOp::attemptBatch( $performOps, $opts ); |
138 | 138 | |
139 | 139 | $success = array(); |
140 | 140 | $failCount = 0; |
Index: trunk/phase3/includes/filerepo/backend/FileOp.php |
— | — | @@ -24,7 +24,6 @@ |
25 | 25 | protected $state = self::STATE_NEW; // integer |
26 | 26 | protected $failed = false; // boolean |
27 | 27 | protected $useLatest = true; // boolean |
28 | | - protected $batchId; // string |
29 | 28 | |
30 | 29 | protected $sourceSha1; // string |
31 | 30 | protected $destSameAsSource; // boolean |
— | — | @@ -64,16 +63,6 @@ |
65 | 64 | } |
66 | 65 | |
67 | 66 | /** |
68 | | - * Set the batch UUID this operation belongs to |
69 | | - * |
70 | | - * @param $batchId string |
71 | | - * @return void |
72 | | - */ |
73 | | - final protected function setBatchId( $batchId ) { |
74 | | - $this->batchId = $batchId; |
75 | | - } |
76 | | - |
77 | | - /** |
78 | 67 | * Whether to allow stale data for file reads and stat checks |
79 | 68 | * |
80 | 69 | * @param $allowStale bool |
— | — | @@ -84,57 +73,43 @@ |
85 | 74 | } |
86 | 75 | |
87 | 76 | /** |
88 | | - * Attempt to perform a series of file operations. |
| 77 | + * Attempt a series of file operations. |
89 | 78 | * Callers are responsible for handling file locking. |
90 | 79 | * |
91 | 80 | * $opts is an array of options, including: |
92 | | - * 'force' : Errors that would normally cause a rollback do not. |
93 | | - * The remaining operations are still attempted if any fail. |
94 | | - * 'allowStale' : Don't require the latest available data. |
95 | | - * This can increase performance for non-critical writes. |
96 | | - * This has no effect unless the 'force' flag is set. |
97 | | - * 'nonJournaled' : Don't log this operation batch in the file journal. |
98 | | - * |
| 81 | + * 'force' : Errors that would normally cause a rollback do not. |
| 82 | + * The remaining operations are still attempted if any fail. |
| 83 | + * 'allowStale' : Don't require the latest available data. |
| 84 | + * This can increase performance for non-critical writes. |
| 85 | + * This has no effect unless the 'force' flag is set. |
| 86 | + * |
99 | 87 | * The resulting Status will be "OK" unless: |
100 | 88 | * a) unexpected operation errors occurred (network partitions, disk full...) |
101 | 89 | * b) significant operation errors occured and 'force' was not set |
102 | 90 | * |
103 | 91 | * @param $performOps Array List of FileOp operations |
104 | 92 | * @param $opts Array Batch operation options |
105 | | - * @param $journal FileJournal Journal to log operations to |
106 | 93 | * @return Status |
107 | 94 | */ |
108 | | - final public static function attemptBatch( |
109 | | - array $performOps, array $opts, FileJournal $journal |
110 | | - ) { |
| 95 | + final public static function attemptBatch( array $performOps, array $opts ) { |
111 | 96 | $status = Status::newGood(); |
112 | 97 | |
| 98 | + $allowStale = !empty( $opts['allowStale'] ); |
| 99 | + $ignoreErrors = !empty( $opts['force'] ); |
| 100 | + |
113 | 101 | $n = count( $performOps ); |
114 | 102 | if ( $n > self::MAX_BATCH_SIZE ) { |
115 | 103 | $status->fatal( 'backend-fail-batchsize', $n, self::MAX_BATCH_SIZE ); |
116 | 104 | return $status; |
117 | 105 | } |
118 | 106 | |
119 | | - $batchId = $journal->getTimestampedUUID(); |
120 | | - $allowStale = !empty( $opts['allowStale'] ); |
121 | | - $ignoreErrors = !empty( $opts['force'] ); |
122 | | - $journaled = empty( $opts['nonJournaled'] ); |
123 | | - |
124 | | - $entries = array(); // file journal entries |
125 | 107 | $predicates = FileOp::newPredicates(); // account for previous op in prechecks |
126 | 108 | // Do pre-checks for each operation; abort on failure... |
127 | 109 | foreach ( $performOps as $index => $fileOp ) { |
128 | | - $fileOp->setBatchId( $batchId ); |
129 | 110 | $fileOp->allowStaleReads( $allowStale ); |
130 | | - $oldPredicates = $predicates; |
131 | | - $subStatus = $fileOp->precheck( $predicates ); // updates $predicates |
| 111 | + $subStatus = $fileOp->precheck( $predicates ); |
132 | 112 | $status->merge( $subStatus ); |
133 | | - if ( $subStatus->isOK() ) { |
134 | | - if ( $journaled ) { // journal log entry |
135 | | - $entries = array_merge( $entries, |
136 | | - self::getJournalEntries( $fileOp, $oldPredicates, $predicates ) ); |
137 | | - } |
138 | | - } else { // operation failed? |
| 113 | + if ( !$subStatus->isOK() ) { // operation failed? |
139 | 114 | $status->success[$index] = false; |
140 | 115 | ++$status->failCount; |
141 | 116 | if ( !$ignoreErrors ) { |
— | — | @@ -143,15 +118,8 @@ |
144 | 119 | } |
145 | 120 | } |
146 | 121 | |
147 | | - // Log the operations in file journal... |
148 | | - if ( count( $entries ) ) { |
149 | | - $subStatus = $journal->logChangeBatch( $entries, $batchId ); |
150 | | - if ( !$subStatus->isOK() ) { |
151 | | - return $subStatus; // abort |
152 | | - } |
153 | | - } |
154 | | - |
155 | | - if ( $ignoreErrors ) { // treat precheck() fatals as mere warnings |
| 122 | + if ( $ignoreErrors ) { |
| 123 | + # Treat all precheck() fatals as merely warnings |
156 | 124 | $status->setResult( true, $status->value ); |
157 | 125 | } |
158 | 126 | |
— | — | @@ -187,46 +155,6 @@ |
188 | 156 | } |
189 | 157 | |
190 | 158 | /** |
191 | | - * Get the file journal entries for a single file operation |
192 | | - * |
193 | | - * @param $fileOp FileOp |
194 | | - * @param $oPredicates Array Pre-op information about files |
195 | | - * @param $nPredicates Array Post-op information about files |
196 | | - * @return Array |
197 | | - */ |
198 | | - final protected static function getJournalEntries( |
199 | | - FileOp $fileOp, array $oPredicates, array $nPredicates |
200 | | - ) { |
201 | | - $nullEntries = array(); |
202 | | - $updateEntries = array(); |
203 | | - $deleteEntries = array(); |
204 | | - $pathsUsed = array_merge( $fileOp->storagePathsRead(), $fileOp->storagePathsChanged() ); |
205 | | - foreach ( $pathsUsed as $path ) { |
206 | | - $nullEntries[] = array( // assertion for recovery |
207 | | - 'op' => 'null', |
208 | | - 'path' => $path, |
209 | | - 'newSha1' => $fileOp->fileSha1( $path, $oPredicates ) |
210 | | - ); |
211 | | - } |
212 | | - foreach ( $fileOp->storagePathsChanged() as $path ) { |
213 | | - if ( $nPredicates['sha1'][$path] === false ) { // deleted |
214 | | - $deleteEntries[] = array( |
215 | | - 'op' => 'delete', |
216 | | - 'path' => $path, |
217 | | - 'newSha1' => '' |
218 | | - ); |
219 | | - } else { // created/updated |
220 | | - $updateEntries[] = array( |
221 | | - 'op' => $fileOp->fileExists( $path, $oPredicates ) ? 'update' : 'create', |
222 | | - 'path' => $path, |
223 | | - 'newSha1' => $nPredicates['sha1'][$path] |
224 | | - ); |
225 | | - } |
226 | | - } |
227 | | - return array_merge( $nullEntries, $updateEntries, $deleteEntries ); |
228 | | - } |
229 | | - |
230 | | - /** |
231 | 159 | * Get the value of the parameter with the given name |
232 | 160 | * |
233 | 161 | * @param $name string |
— | — | @@ -424,8 +352,8 @@ |
425 | 353 | $params = $this->params; |
426 | 354 | $params['failedAction'] = $action; |
427 | 355 | try { |
428 | | - wfDebugLog( 'FileOperation', get_class( $this ) . |
429 | | - " failed (batch #{$this->batchId}): " . FormatJson::encode( $params ) ); |
| 356 | + wfDebugLog( 'FileOperation', |
| 357 | + get_class( $this ) . ' failed: ' . FormatJson::encode( $params ) ); |
430 | 358 | } catch ( Exception $e ) { |
431 | 359 | // bad config? debug log error? |
432 | 360 | } |
Index: trunk/phase3/includes/filerepo/backend/FileBackendStore.php |
— | — | @@ -708,7 +708,7 @@ |
709 | 709 | $this->clearCache(); |
710 | 710 | |
711 | 711 | // Actually attempt the operation batch... |
712 | | - $subStatus = FileOp::attemptBatch( $performOps, $opts, $this->fileJournal ); |
| 712 | + $subStatus = FileOp::attemptBatch( $performOps, $opts ); |
713 | 713 | |
714 | 714 | // Merge errors into status fields |
715 | 715 | $status->merge( $subStatus ); |
Index: trunk/phase3/includes/filerepo/backend/FileBackend.php |
— | — | @@ -45,8 +45,6 @@ |
46 | 46 | protected $readOnly; // string; read-only explanation message |
47 | 47 | /** @var LockManager */ |
48 | 48 | protected $lockManager; |
49 | | - /** @var FileJournal */ |
50 | | - protected $fileJournal; |
51 | 49 | |
52 | 50 | /** |
53 | 51 | * Create a new backend instance from configuration. |
— | — | @@ -57,10 +55,8 @@ |
58 | 56 | * This should consist of alphanumberic, '-', and '_' characters. |
59 | 57 | * This name should not be changed after use. |
60 | 58 | * 'wikiId' : Prefix to container names that is unique to this wiki. |
61 | | - * It should only consist of alphanumberic, '-', and '_' characters. |
| 59 | + * This should consist of alphanumberic, '-', and '_' characters. |
62 | 60 | * 'lockManager' : Registered name of a file lock manager to use. |
63 | | - * 'fileJournal' : File journal configuration; see FileJournal::factory(). |
64 | | - * Journals simply log changes to files stored in the backend. |
65 | 61 | * 'readOnly' : Write operations are disallowed if this is a non-empty string. |
66 | 62 | * It should be an explanation for the backend being read-only. |
67 | 63 | * |
— | — | @@ -77,9 +73,6 @@ |
78 | 74 | $this->lockManager = ( $config['lockManager'] instanceof LockManager ) |
79 | 75 | ? $config['lockManager'] |
80 | 76 | : LockManagerGroup::singleton()->get( $config['lockManager'] ); |
81 | | - $this->fileJournal = isset( $config['fileJournal'] ) |
82 | | - ? FileJournal::factory( $config['fileJournal'], $this->name ) |
83 | | - : FileJournal::factory( array( 'class' => 'NullFileJournal' ), $this->name ); |
84 | 77 | $this->readOnly = isset( $config['readOnly'] ) |
85 | 78 | ? (string)$config['readOnly'] |
86 | 79 | : ''; |
— | — | @@ -184,8 +177,6 @@ |
185 | 178 | * 'allowStale' : Don't require the latest available data. |
186 | 179 | * This can increase performance for non-critical writes. |
187 | 180 | * This has no effect unless the 'force' flag is set. |
188 | | - * 'nonJournaled' : Don't log this operation batch in the file journal. |
189 | | - * This limits the ability of recovery scripts. |
190 | 181 | * |
191 | 182 | * Remarks on locking: |
192 | 183 | * File system paths given to operations should refer to files that are |
Index: trunk/phase3/includes/filerepo/FileRepo.php |
— | — | @@ -120,15 +120,6 @@ |
121 | 121 | } |
122 | 122 | |
123 | 123 | /** |
124 | | - * Get an explanatory message if this repo is read-only |
125 | | - * |
126 | | - * @return string|bool Returns false if the repo is not read-only |
127 | | - */ |
128 | | - public function getReadOnlyReason() { |
129 | | - return $this->backend->getReadOnlyReason(); |
130 | | - } |
131 | | - |
132 | | - /** |
133 | 124 | * Prepare a single zone or list of zones for usage. |
134 | 125 | * See initDeletedDir() for additional setup needed for the 'deleted' zone. |
135 | 126 | * |
Index: trunk/phase3/includes/installer/PostgresUpdater.php |
— | — | @@ -27,11 +27,6 @@ |
28 | 28 | */ |
29 | 29 | protected function getCoreUpdateList() { |
30 | 30 | return array( |
31 | | - # rename tables 1.7.3 |
32 | | - # r15791 Change reserved word table names "user" and "text" |
33 | | - array( 'renameTable', 'user', 'mwuser'), |
34 | | - array( 'renameTable', 'text', 'pagecontent'), |
35 | | - |
36 | 31 | # new sequences |
37 | 32 | array( 'addSequence', 'logging_log_id_seq' ), |
38 | 33 | array( 'addSequence', 'page_restrictions_pr_id_seq' ), |
— | — | @@ -411,8 +406,7 @@ |
412 | 407 | protected function renameTable( $old, $new ) { |
413 | 408 | if ( $this->db->tableExists( $old ) ) { |
414 | 409 | $this->output( "Renaming table $old to $new\n" ); |
415 | | - $old = $this->db->realTableName( $old, "quoted" ); |
416 | | - $new = $this->db->realTableName( $new, "quoted" ); |
| 410 | + $old = $this->db->addQuotes( $old ); |
417 | 411 | $this->db->query( "ALTER TABLE $old RENAME TO $new" ); |
418 | 412 | } |
419 | 413 | } |
Index: trunk/phase3/includes/installer/DatabaseInstaller.php |
— | — | @@ -158,7 +158,7 @@ |
159 | 159 | } |
160 | 160 | $this->db->selectDB( $this->getVar( 'wgDBname' ) ); |
161 | 161 | |
162 | | - if( $this->db->tableExists( 'archive', __METHOD__ ) ) { |
| 162 | + if( $this->db->tableExists( 'user', __METHOD__ ) ) { |
163 | 163 | $status->warning( 'config-install-tables-exist' ); |
164 | 164 | $this->enableLB(); |
165 | 165 | return $status; |
Index: trunk/phase3/includes/api/ApiFeedContributions.php |
— | — | @@ -43,80 +43,56 @@ |
44 | 44 | } |
45 | 45 | |
46 | 46 | public function execute() { |
| 47 | + $params = $this->extractRequestParams(); |
47 | 48 | |
48 | 49 | global $wgFeed, $wgFeedClasses, $wgSitename, $wgLanguageCode; |
49 | 50 | |
50 | | - try { |
51 | | - $params = $this->extractRequestParams(); |
52 | | - |
53 | | - if( !$wgFeed ) { |
54 | | - $this->dieUsage( 'Syndication feeds are not available', 'feed-unavailable' ); |
55 | | - } |
56 | | - |
57 | | - if( !isset( $wgFeedClasses[ $params['feedformat'] ] ) ) { |
58 | | - $this->dieUsage( 'Invalid subscription feed type', 'feed-invalid' ); |
59 | | - } |
| 51 | + if( !$wgFeed ) { |
| 52 | + $this->dieUsage( 'Syndication feeds are not available', 'feed-unavailable' ); |
| 53 | + } |
60 | 54 | |
61 | | - global $wgMiserMode; |
62 | | - if ( $params['showsizediff'] && $wgMiserMode ) { |
63 | | - $this->dieUsage( 'Size difference is disabled in Miser Mode', 'sizediffdisabled' ); |
64 | | - } |
65 | | - |
66 | | - $msg = wfMsgForContent( 'Contributions' ); |
67 | | - $feedTitle = $wgSitename . ' - ' . $msg . ' [' . $wgLanguageCode . ']'; |
68 | | - $feedUrl = SpecialPage::getTitleFor( 'Contributions', $params['user'] )->getFullURL(); |
69 | | - |
70 | | - $target = $params['user'] == 'newbies' |
71 | | - ? 'newbies' |
72 | | - : Title::makeTitleSafe( NS_USER, $params['user'] )->getText(); |
73 | | - |
74 | | - $feed = new $wgFeedClasses[$params['feedformat']] ( |
75 | | - $feedTitle, |
76 | | - htmlspecialchars( $msg ), |
77 | | - $feedUrl |
78 | | - ); |
79 | | - |
80 | | - $pager = new ContribsPager( $this->getContext(), array( |
81 | | - 'target' => $target, |
82 | | - 'namespace' => $params['namespace'], |
83 | | - 'year' => $params['year'], |
84 | | - 'month' => $params['month'], |
85 | | - 'tagFilter' => $params['tagfilter'], |
86 | | - 'deletedOnly' => $params['deletedonly'], |
87 | | - 'topOnly' => $params['toponly'], |
88 | | - 'showSizeDiff' => $params['showsizediff'], |
89 | | - ) ); |
90 | | - |
91 | | - $feedItems = array(); |
92 | | - if( $pager->getNumRows() > 0 ) { |
93 | | - foreach ( $pager->mResult as $row ) { |
94 | | - $feedItems[] = $this->feedItem( $row ); |
95 | | - } |
96 | | - } |
97 | | - |
98 | | - ApiFormatFeedWrapper::setResult( $this->getResult(), $feed, $feedItems ); |
99 | | - |
100 | | - } catch ( Exception $e ) { |
101 | | - // Error results should not be cached |
102 | | - $this->getMain()->setCacheMaxAge( 0 ); |
| 55 | + if( !isset( $wgFeedClasses[ $params['feedformat'] ] ) ) { |
| 56 | + $this->dieUsage( 'Invalid subscription feed type', 'feed-invalid' ); |
| 57 | + } |
103 | 58 | |
104 | | - $feedTitle = $wgSitename . ' - Error - ' . wfMsgForContent( 'contributions' ) . ' [' . $wgLanguageCode . ']'; |
105 | | - $feedUrl = SpecialPage::getTitleFor( 'Contributions', $params['user'] )->getFullURL(); |
| 59 | + global $wgMiserMode; |
| 60 | + if ( $params['showsizediff'] && $wgMiserMode ) { |
| 61 | + $this->dieUsage( 'Size difference is disabled in Miser Mode', 'sizediffdisabled' ); |
| 62 | + } |
106 | 63 | |
107 | | - $feedFormat = isset( $params['feedformat'] ) ? $params['feedformat'] : 'rss'; |
108 | | - $feed = new $wgFeedClasses[$feedFormat] ( $feedTitle, htmlspecialchars( wfMsgForContent( 'contributions' ) ), $feedUrl ); |
| 64 | + $msg = wfMsgForContent( 'Contributions' ); |
| 65 | + $feedTitle = $wgSitename . ' - ' . $msg . ' [' . $wgLanguageCode . ']'; |
| 66 | + $feedUrl = SpecialPage::getTitleFor( 'Contributions', $params['user'] )->getFullURL(); |
109 | 67 | |
110 | | - if ( $e instanceof UsageException ) { |
111 | | - $errorCode = $e->getCodeString(); |
112 | | - } else { |
113 | | - // Something is seriously wrong |
114 | | - $errorCode = 'internal_api_error'; |
115 | | - } |
| 68 | + $target = $params['user'] == 'newbies' |
| 69 | + ? 'newbies' |
| 70 | + : Title::makeTitleSafe( NS_USER, $params['user'] )->getText(); |
116 | 71 | |
117 | | - $errorText = $e->getMessage(); |
118 | | - $feedItems[] = new FeedItem( "Error ($errorCode)", $errorText, '', '', '' ); |
119 | | - ApiFormatFeedWrapper::setResult( $this->getResult(), $feed, $feedItems ); |
| 72 | + $feed = new $wgFeedClasses[$params['feedformat']] ( |
| 73 | + $feedTitle, |
| 74 | + htmlspecialchars( $msg ), |
| 75 | + $feedUrl |
| 76 | + ); |
| 77 | + |
| 78 | + $pager = new ContribsPager( $this->getContext(), array( |
| 79 | + 'target' => $target, |
| 80 | + 'namespace' => $params['namespace'], |
| 81 | + 'year' => $params['year'], |
| 82 | + 'month' => $params['month'], |
| 83 | + 'tagFilter' => $params['tagfilter'], |
| 84 | + 'deletedOnly' => $params['deletedonly'], |
| 85 | + 'topOnly' => $params['toponly'], |
| 86 | + 'showSizeDiff' => $params['showsizediff'], |
| 87 | + ) ); |
| 88 | + |
| 89 | + $feedItems = array(); |
| 90 | + if( $pager->getNumRows() > 0 ) { |
| 91 | + foreach ( $pager->mResult as $row ) { |
| 92 | + $feedItems[] = $this->feedItem( $row ); |
| 93 | + } |
120 | 94 | } |
| 95 | + |
| 96 | + ApiFormatFeedWrapper::setResult( $this->getResult(), $feed, $feedItems ); |
121 | 97 | } |
122 | 98 | |
123 | 99 | protected function feedItem( $row ) { |
Index: trunk/phase3/includes/AutoLoader.php |
— | — | @@ -508,9 +508,6 @@ |
509 | 509 | 'FSFileBackendFileList' => 'includes/filerepo/backend/FSFileBackend.php', |
510 | 510 | 'SwiftFileBackend' => 'includes/filerepo/backend/SwiftFileBackend.php', |
511 | 511 | 'SwiftFileBackendFileList' => 'includes/filerepo/backend/SwiftFileBackend.php', |
512 | | - 'FileJournal' => 'includes/filerepo/backend/filejournal/FileJournal.php', |
513 | | - 'DBFileJournal' => 'includes/filerepo/backend/filejournal/DBFileJournal.php', |
514 | | - 'NullFileJournal' => 'includes/filerepo/backend/filejournal/FileJournal.php', |
515 | 512 | 'LockManagerGroup' => 'includes/filerepo/backend/lockmanager/LockManagerGroup.php', |
516 | 513 | 'LockManager' => 'includes/filerepo/backend/lockmanager/LockManager.php', |
517 | 514 | 'ScopedLock' => 'includes/filerepo/backend/lockmanager/LockManager.php', |
Index: trunk/phase3/includes/specials/SpecialBlock.php |
— | — | @@ -381,19 +381,19 @@ |
382 | 382 | $this->getLanguage()->pipeList( $links ) |
383 | 383 | ); |
384 | 384 | |
385 | | - $userTitle = self::getTargetUserTitle( $this->target ); |
386 | | - if( $userTitle ){ |
| 385 | + if( $this->target instanceof User ){ |
387 | 386 | # Get relevant extracts from the block and suppression logs, if possible |
| 387 | + $userpage = $this->target->getUserPage(); |
388 | 388 | $out = ''; |
389 | 389 | |
390 | 390 | LogEventsList::showLogExtract( |
391 | 391 | $out, |
392 | 392 | 'block', |
393 | | - $userTitle, |
| 393 | + $userpage, |
394 | 394 | '', |
395 | 395 | array( |
396 | 396 | 'lim' => 10, |
397 | | - 'msgKey' => array( 'blocklog-showlog', $userTitle->getText() ), |
| 397 | + 'msgKey' => array( 'blocklog-showlog', $userpage->getText() ), |
398 | 398 | 'showIfEmpty' => false |
399 | 399 | ) |
400 | 400 | ); |
— | — | @@ -404,12 +404,12 @@ |
405 | 405 | LogEventsList::showLogExtract( |
406 | 406 | $out, |
407 | 407 | 'suppress', |
408 | | - $userTitle, |
| 408 | + $userpage, |
409 | 409 | '', |
410 | 410 | array( |
411 | 411 | 'lim' => 10, |
412 | 412 | 'conds' => array( 'log_action' => array( 'block', 'reblock', 'unblock' ) ), |
413 | | - 'msgKey' => array( 'blocklog-showsuppresslog', $userTitle->getText() ), |
| 413 | + 'msgKey' => array( 'blocklog-showsuppresslog', $userpage->getText() ), |
414 | 414 | 'showIfEmpty' => false |
415 | 415 | ) |
416 | 416 | ); |
— | — | @@ -422,21 +422,6 @@ |
423 | 423 | } |
424 | 424 | |
425 | 425 | /** |
426 | | - * Get a user page target for things like logs. |
427 | | - * This handles account and IP range targets. |
428 | | - * @param $target User|string |
429 | | - * @return Title|null |
430 | | - */ |
431 | | - protected static function getTargetUserTitle( $target ) { |
432 | | - if( $target instanceof User ) { |
433 | | - return $target->getUserPage(); |
434 | | - } elseif ( IP::isIPAddress( $target ) ) { |
435 | | - return Title::makeTitleSafe( NS_USER, $target ); |
436 | | - } |
437 | | - return null; |
438 | | - } |
439 | | - |
440 | | - /** |
441 | 426 | * Determine the target of the block, and the type of target |
442 | 427 | * TODO: should be in Block.php? |
443 | 428 | * @param $par String subpage parameter passed to setup, or data value from |
Index: trunk/phase3/languages/messages/MessagesFrp.php |
— | — | @@ -26,8 +26,8 @@ |
27 | 27 | NS_MEDIA => 'Mèdia', |
28 | 28 | NS_SPECIAL => 'Spèciâl', |
29 | 29 | NS_TALK => 'Discussion', |
30 | | - NS_USER => 'Usanciér', |
31 | | - NS_USER_TALK => 'Discussion_usanciér', |
| 30 | + NS_USER => 'Utilisator', |
| 31 | + NS_USER_TALK => 'Discussion_utilisator', |
32 | 32 | NS_PROJECT_TALK => 'Discussion_$1', |
33 | 33 | NS_FILE => 'Fichiér', |
34 | 34 | NS_FILE_TALK => 'Discussion_fichiér', |
— | — | @@ -42,14 +42,13 @@ |
43 | 43 | ); |
44 | 44 | |
45 | 45 | $namespaceAliases = array( |
46 | | - 'Discutar' => NS_TALK, |
47 | | - 'Utilisator' => NS_USER, |
| 46 | + 'Discutar' => NS_TALK, |
48 | 47 | 'Discussion_Utilisator' => NS_USER_TALK, |
49 | | - 'Émâge' => NS_FILE, |
50 | | - 'Discussion_Émâge' => NS_FILE_TALK, |
51 | | - 'Discussion_Modèlo' => NS_TEMPLATE_TALK, |
52 | | - 'Discussion_Éde' => NS_HELP_TALK, |
53 | | - 'Discussion_Catègorie' => NS_CATEGORY_TALK |
| 48 | + 'Émâge' => NS_FILE, |
| 49 | + 'Discussion_Émâge' => NS_FILE_TALK, |
| 50 | + 'Discussion_Modèlo' => NS_TEMPLATE_TALK, |
| 51 | + 'Discussion_Éde' => NS_HELP_TALK, |
| 52 | + 'Discussion_Catègorie' => NS_CATEGORY_TALK |
54 | 53 | ); |
55 | 54 | |
56 | 55 | $specialPageAliases = array( |
Index: trunk/phase3/languages/messages/MessagesMk.php |
— | — | @@ -23,7 +23,7 @@ |
24 | 24 | */ |
25 | 25 | |
26 | 26 | $namespaceNames = array( |
27 | | - NS_MEDIA => 'Медиум', |
| 27 | + NS_MEDIA => 'Медија', |
28 | 28 | NS_SPECIAL => 'Специјална', |
29 | 29 | NS_TALK => 'Разговор', |
30 | 30 | NS_USER => 'Корисник', |
— | — | @@ -42,9 +42,8 @@ |
43 | 43 | ); |
44 | 44 | |
45 | 45 | $namespaceAliases = array( |
46 | | - 'Медија' => NS_MEDIA, |
47 | | - 'Специјални' => NS_SPECIAL, |
48 | | - 'Слика' => NS_FILE, |
| 46 | + 'Специјални' => NS_SPECIAL, |
| 47 | + 'Слика' => NS_FILE, |
49 | 48 | 'Разговор_за_слика' => NS_FILE_TALK, |
50 | 49 | ); |
51 | 50 | |
Index: trunk/phase3/languages/messages/MessagesYue.php |
— | — | @@ -22,11 +22,11 @@ |
23 | 23 | NS_TALK => '傾偈', |
24 | 24 | NS_USER => '用戶', |
25 | 25 | NS_USER_TALK => '用戶傾偈', |
26 | | - NS_PROJECT_TALK => '$1傾偈', |
| 26 | + NS_PROJECT_TALK => '$1_傾偈', |
27 | 27 | NS_FILE => '文件', |
28 | 28 | NS_FILE_TALK => '文件傾偈', |
29 | 29 | NS_MEDIAWIKI => 'MediaWiki', |
30 | | - NS_MEDIAWIKI_TALK => 'MediaWiki傾偈', |
| 30 | + NS_MEDIAWIKI_TALK => 'MediaWiki_傾偈', |
31 | 31 | NS_TEMPLATE => '模', |
32 | 32 | NS_TEMPLATE_TALK => '模傾偈', |
33 | 33 | NS_HELP => '幫手', |
— | — | @@ -47,7 +47,9 @@ |
48 | 48 | "用户 对话" => NS_USER_TALK, |
49 | 49 | "用戶 討論" => NS_USER_TALK, |
50 | 50 | "用户 讨论" => NS_USER_TALK, |
51 | | - '$1_傾偈' => NS_PROJECT_TALK, |
| 51 | + # This has never worked so it's unlikely to annoy anyone if I disable it -- TS |
| 52 | + # "{$wgMetaNamespace} 討論" => NS_PROJECT_TALK, |
| 53 | + # "{$wgMetaNamespace} 讨论" => NS_PROJECT_TALK, |
52 | 54 | "檔" => NS_FILE, |
53 | 55 | "檔案" => NS_FILE, |
54 | 56 | "档" => NS_FILE, |
— | — | @@ -66,7 +68,6 @@ |
67 | 69 | "图 讨论" => NS_FILE_TALK, |
68 | 70 | "圖像 討論" => NS_FILE_TALK, |
69 | 71 | "图像 讨论" => NS_FILE_TALK, |
70 | | - 'MediaWiki_傾偈' => NS_FILE_TALK, |
71 | 72 | "模 討論" => NS_TEMPLATE_TALK, |
72 | 73 | "模 讨论" => NS_TEMPLATE_TALK, |
73 | 74 | "幫助" => NS_HELP, |
Index: trunk/phase3/languages/messages/MessagesNds_nl.php |
— | — | @@ -23,35 +23,30 @@ |
24 | 24 | |
25 | 25 | $namespaceNames = array( |
26 | 26 | NS_MEDIA => 'Media', |
27 | | - NS_SPECIAL => 'Spesiaal', |
| 27 | + NS_SPECIAL => 'Speciaal', |
28 | 28 | NS_TALK => 'Overleg', |
29 | 29 | NS_USER => 'Gebruker', |
30 | 30 | NS_USER_TALK => 'Overleg_gebruker', |
31 | 31 | NS_PROJECT_TALK => 'Overleg_$1', |
32 | | - NS_FILE => 'Bestaand', |
33 | | - NS_FILE_TALK => 'Overleg_bestaand', |
| 32 | + NS_FILE => 'Ofbeelding', |
| 33 | + NS_FILE_TALK => 'Overleg_ofbeelding', |
34 | 34 | NS_MEDIAWIKI => 'MediaWiki', |
35 | 35 | NS_MEDIAWIKI_TALK => 'Overleg_MediaWiki', |
36 | 36 | NS_TEMPLATE => 'Mal', |
37 | 37 | NS_TEMPLATE_TALK => 'Overleg_mal', |
38 | 38 | NS_HELP => 'Hulpe', |
39 | 39 | NS_HELP_TALK => 'Overleg_hulpe', |
40 | | - NS_CATEGORY => 'Kategorie', |
41 | | - NS_CATEGORY_TALK => 'Overleg_kategorie', |
| 40 | + NS_CATEGORY => 'Kattegerie', |
| 41 | + NS_CATEGORY_TALK => 'Overleg_kattegerie', |
42 | 42 | ); |
43 | 43 | |
44 | 44 | $namespaceAliases = array( |
45 | | - 'Speciaol' => NS_SPECIAL, |
46 | | - 'Speciaal' => NS_SPECIAL, |
47 | | - 'Sjabloon' => NS_TEMPLATE, |
48 | | - 'Overleg_sjabloon' => NS_TEMPLATE_TALK, |
49 | | - 'Ofbeelding' => NS_FILE, |
50 | | - 'Overleg_ofbeelding' => NS_FILE_TALK, |
51 | | - 'Categorie' => NS_CATEGORY, |
52 | | - 'Overleg_categorie' => NS_CATEGORY_TALK, |
53 | | - 'Kattegerie' => NS_CATEGORY, |
54 | | - 'Overleg_categorie' => NS_CATEGORY_TALK, |
55 | | - 'Overleg_kattegerie' => NS_HELP_TALK, |
| 45 | + 'Speciaol' => NS_SPECIAL, |
| 46 | + 'Sjabloon' => NS_TEMPLATE, |
| 47 | + 'Overleg_sjabloon' => NS_TEMPLATE_TALK, |
| 48 | + 'Categorie' => NS_CATEGORY, |
| 49 | + 'Overleg_categorie' => NS_CATEGORY_TALK, |
| 50 | + 'Overleg_help' => NS_HELP_TALK, |
56 | 51 | ); |
57 | 52 | |
58 | 53 | $dateFormats = array( |
Index: trunk/phase3/languages/messages/MessagesEn.php |
— | — | @@ -2277,9 +2277,6 @@ |
2278 | 2278 | 'backend-fail-contenttype' => 'Could not determine the content type of the file to store at "$1".', |
2279 | 2279 | 'backend-fail-batchsize' => 'Storage backend given a batch of $1 file {{PLURAL:$1|operation|operations}}; the limit is $2 {{PLURAL:$2|operation|operations}}.', |
2280 | 2280 | |
2281 | | -'filejournal-fail-dbconnect' => 'Could not connect to the journal database for storage backend "$1".', |
2282 | | -'filejournal-fail-dbquery' => 'Could not update the journal database for storage backend "$1".', |
2283 | | - |
2284 | 2281 | # Lock manager |
2285 | 2282 | 'lockmanager-notlocked' => 'Could not unlock "$1"; it is not locked.', |
2286 | 2283 | 'lockmanager-fail-closelock' => 'Could not close lock file for "$1".', |
Index: trunk/phase3/languages/messages/MessagesWar.php |
— | — | @@ -14,25 +14,6 @@ |
15 | 15 | * @author לערי ריינהארט |
16 | 16 | */ |
17 | 17 | |
18 | | -$namespaceNames = array( |
19 | | - NS_MEDIA => 'Medya', |
20 | | - NS_SPECIAL => 'Pinaurog', |
21 | | - NS_TALK => 'Hiruhimangraw', |
22 | | - NS_USER => 'Gumaramit', |
23 | | - NS_USER_TALK => 'Hiruhimangaw_hiton_gumaramit', |
24 | | - NS_PROJECT_TALK => 'Hiruhimangraw_hiton_$1', |
25 | | - NS_FILE => 'Fayl', |
26 | | - NS_FILE_TALK => 'Hiruhimangraw_hiton_fayl', |
27 | | - NS_MEDIAWIKI => 'MediaWiki', |
28 | | - NS_MEDIAWIKI_TALK => 'Hiruhimangraw_hiton_MediaWiki', |
29 | | - NS_TEMPLATE => 'Batakan', |
30 | | - NS_TEMPLATE_TALK => 'Hiruhimangraw_hiton_batakan', |
31 | | - NS_HELP => 'Bulig', |
32 | | - NS_HELP_TALK => 'Hiruhimangaw_hiton_bulig', |
33 | | - NS_CATEGORY => 'Kaarangay', |
34 | | - NS_CATEGORY_TALK => 'Hiruhimangraw_hiton_kaarangay', |
35 | | -); |
36 | | - |
37 | 18 | $specialPageAliases = array( |
38 | 19 | 'Allpages' => array( 'NgatananngaPakli' ), |
39 | 20 | 'Categories' => array( 'Mga_kaarangay' ), |
Index: trunk/phase3/languages/messages/MessagesSa.php |
— | — | @@ -44,7 +44,7 @@ |
45 | 45 | |
46 | 46 | $namespaceNames = array( |
47 | 47 | NS_MEDIA => 'माध्यमम्', |
48 | | - NS_SPECIAL => 'विशेषम्', |
| 48 | + NS_SPECIAL => 'विशेष', |
49 | 49 | NS_TALK => 'सम्भाषणम्', |
50 | 50 | NS_USER => 'योजकः', |
51 | 51 | NS_USER_TALK => 'योजकसम्भाषणम्', |
— | — | @@ -63,7 +63,6 @@ |
64 | 64 | |
65 | 65 | $namespaceAliases = array( |
66 | 66 | 'माध्यम' => NS_MEDIA, |
67 | | - 'विशेष' => NS_SPECIAL, |
68 | 67 | 'संभाषणं' => NS_TALK, |
69 | 68 | 'योजकसंभाषणं' => NS_USER_TALK, |
70 | 69 | '$1संभाषणं' => NS_PROJECT_TALK, |
Index: trunk/phase3/languages/messages/MessagesOr.php |
— | — | @@ -40,17 +40,17 @@ |
41 | 41 | NS_MEDIA => 'ମାଧ୍ୟମ', |
42 | 42 | NS_SPECIAL => 'ବିଶେଷ', |
43 | 43 | NS_TALK => 'ଆଲୋଚନା', |
44 | | - NS_USER => 'ବ୍ୟବହାରକାରୀ', |
45 | | - NS_USER_TALK => 'ବ୍ୟବହାରକାରୀଙ୍କ_ଆଲୋଚନା', |
46 | | - NS_PROJECT_TALK => '$1_ଆଲୋଚନା', |
| 44 | + NS_USER => 'ବ୍ୟବାହାରକାରୀ', |
| 45 | + NS_USER_TALK => 'ବ୍ୟବାହାରକାରୀଙ୍କ_ଆଲୋଚନା', |
| 46 | + NS_PROJECT_TALK => 'ଉଇକିପିଡ଼ିଆ_ଆଲୋଚନା', |
47 | 47 | NS_FILE => 'ଫାଇଲ', |
48 | 48 | NS_FILE_TALK => 'ଫାଇଲ_ଆଲୋଚନା', |
49 | 49 | NS_MEDIAWIKI => 'ମିଡ଼ିଆଉଇକି', |
50 | 50 | NS_MEDIAWIKI_TALK => 'ମିଡ଼ିଆଉଇକି_ଆଲୋଚନା', |
51 | | - NS_TEMPLATE => 'ଛାଞ୍ଚ', |
52 | | - NS_TEMPLATE_TALK => 'ଛାଞ୍ଚ_ଆଲୋଚନା', |
53 | | - NS_HELP => 'ସହଯୋଗ', |
54 | | - NS_HELP_TALK => 'ସହଯୋଗ_ଆଲୋଚନା', |
| 51 | + NS_TEMPLATE => 'ଟେମ୍ପଲେଟ', |
| 52 | + NS_TEMPLATE_TALK => 'ଟେମ୍ପଲେଟ_ଆଲୋଚନା', |
| 53 | + NS_HELP => 'ସାହାଯ୍ୟ', |
| 54 | + NS_HELP_TALK => 'ସାହାଯ୍ୟ_ଆଲୋଚନା', |
55 | 55 | NS_CATEGORY => 'ଶ୍ରେଣୀ', |
56 | 56 | NS_CATEGORY_TALK => 'ଶ୍ରେଣୀ_ଆଲୋଚନା', |
57 | 57 | ); |
— | — | @@ -58,17 +58,10 @@ |
59 | 59 | $namespaceAliases = array( |
60 | 60 | 'ବ୍ୟବହାରକାରି' => NS_USER, |
61 | 61 | 'ବ୍ୟବହାରକାରିଁକ_ଆଲୋଚନା' => NS_USER_TALK, |
62 | | - 'ବ୍ୟବାହାରକାରୀ' => NS_USER, |
63 | | - 'ବ୍ୟବାହାରକାରୀଙ୍କ_ଆଲୋଚନା' => NS_USER_TALK, |
64 | | - 'ଉଇକିପିଡ଼ିଆ_ଆଲୋଚନା' => NS_PROJECT_TALK, |
65 | 62 | 'ଟେଁପଲେଟ' => NS_TEMPLATE, |
66 | 63 | 'ଟେଁପଲେଟ_ଆଲୋଚନା' => NS_TEMPLATE_TALK, |
67 | | - 'ଟେମ୍ପଲେଟ' => NS_TEMPLATE, |
68 | | - 'ଟେମ୍ପଲେଟ_ଆଲୋଚନା' => NS_TEMPLATE_TALK, |
69 | 64 | 'ବିଭାଗ' => NS_CATEGORY, |
70 | 65 | 'ବିଭାଗିୟ_ଆଲୋଚନା' => NS_CATEGORY_TALK, |
71 | | - 'ସାହାଯ୍ୟ' => NS_HELP, |
72 | | - 'ସାହାଯ୍ୟ_ଆଲୋଚନା' => NS_HELP_TALK, |
73 | 66 | ); |
74 | 67 | |
75 | 68 | $specialPageAliases = array( |
Index: trunk/phase3/languages/messages/MessagesMzn.php |
— | — | @@ -24,52 +24,46 @@ |
25 | 25 | $rtl = true; |
26 | 26 | |
27 | 27 | $namespaceNames = array( |
28 | | - NS_MEDIA => 'مدیا', |
| 28 | + NS_MEDIA => 'مهدیا', |
29 | 29 | NS_SPECIAL => 'شا', |
30 | | - NS_MAIN => '', |
31 | 30 | NS_TALK => 'گپ', |
32 | 31 | NS_USER => 'کارور', |
33 | 32 | NS_USER_TALK => 'کارور_گپ', |
34 | 33 | NS_PROJECT_TALK => '$1_گپ', |
35 | 34 | NS_FILE => 'پرونده', |
36 | 35 | NS_FILE_TALK => 'پرونده_گپ', |
37 | | - NS_MEDIAWIKI => 'مدیاویکی', |
38 | | - NS_MEDIAWIKI_TALK => 'مدیاویکی_گپ', |
| 36 | + NS_MEDIAWIKI => 'مهدیاویکی', |
| 37 | + NS_MEDIAWIKI_TALK => 'مهدیاویکی_گپ', |
39 | 38 | NS_TEMPLATE => 'شابلون', |
40 | 39 | NS_TEMPLATE_TALK => 'شابلون_گپ', |
41 | | - NS_HELP => 'رانما', |
42 | | - NS_HELP_TALK => 'رانما_گپ', |
| 40 | + NS_HELP => 'رانهما', |
| 41 | + NS_HELP_TALK => 'رانهمائه_گپ', |
43 | 42 | NS_CATEGORY => 'رج', |
44 | 43 | NS_CATEGORY_TALK => 'رج_گپ', |
45 | 44 | ); |
46 | 45 | |
47 | 46 | $namespaceAliases = array( |
48 | | - 'مهدیا' => NS_MEDIA, |
49 | 47 | 'مدیا' => NS_MEDIA, |
50 | 48 | 'ویژه' => NS_SPECIAL, |
51 | | - 'بحث' => NS_TALK, |
| 49 | + 'بحث' => NS_TALK, |
52 | 50 | 'کاربر' => NS_USER, |
53 | | - 'بحث_کاربر' => NS_USER_TALK, |
54 | | - 'بحث_$1' => NS_PROJECT_TALK, |
| 51 | + 'بحث_کاربر' => NS_USER_TALK, |
| 52 | + 'بحث_$1' => NS_PROJECT_TALK, |
55 | 53 | 'تصویر' => NS_FILE, |
56 | 54 | 'پرونده' => NS_FILE, |
57 | | - 'بحث_تصویر' => NS_FILE_TALK, |
58 | | - 'بحث_پرونده' => NS_FILE_TALK, |
| 55 | + 'بحث_تصویر' => NS_FILE_TALK, |
| 56 | + 'بحث_پرونده' => NS_FILE_TALK, |
59 | 57 | 'مدیاویکی' => NS_MEDIAWIKI, |
60 | 58 | 'مهدیا ویکی' => NS_MEDIAWIKI, |
61 | | - 'مهدیاویکی' => NS_MEDIAWIKI, |
62 | | - 'مهدیاویکی_گپ' => NS_MEDIAWIKI_TALK, |
63 | | - 'بحث_مدیاویکی' => NS_MEDIAWIKI_TALK, |
| 59 | + 'بحث_مدیاویکی' => NS_MEDIAWIKI_TALK, |
64 | 60 | 'مهدیا ویکی گپ' => NS_MEDIAWIKI_TALK, |
65 | 61 | 'الگو' => NS_TEMPLATE, |
66 | | - 'بحث_الگو' => NS_TEMPLATE_TALK, |
| 62 | + 'بحث_الگو' => NS_TEMPLATE_TALK, |
67 | 63 | 'راهنما' => NS_HELP, |
68 | | - 'رانهما' => NS_HELP, |
69 | | - 'رانهمائه_گپ' => NS_HELP_TALK, |
70 | | - 'بحث_راهنما' => NS_HELP_TALK, |
| 64 | + 'بحث_راهنما' => NS_HELP_TALK, |
71 | 65 | 'رانهمای گپ' => NS_HELP_TALK, |
72 | 66 | 'رده' => NS_CATEGORY, |
73 | | - 'بحث_رده' => NS_CATEGORY_TALK, |
| 67 | + 'بحث_رده' => NS_CATEGORY_TALK, |
74 | 68 | ); |
75 | 69 | |
76 | 70 | $magicWords = array( |
Index: trunk/phase3/languages/messages/MessagesSr_ec.php |
— | — | @@ -35,10 +35,10 @@ |
36 | 36 | NS_USER => 'Корисник', |
37 | 37 | NS_USER_TALK => 'Разговор_са_корисником', |
38 | 38 | NS_PROJECT_TALK => 'Разговор_о_$1', |
39 | | - NS_FILE => 'Фајл', |
40 | | - NS_FILE_TALK => 'Разговор_о_фајлу', |
41 | | - NS_MEDIAWIKI => 'МедијаВики', |
42 | | - NS_MEDIAWIKI_TALK => 'Разговор_о_МедијаВикију', |
| 39 | + NS_FILE => 'Датотека', |
| 40 | + NS_FILE_TALK => 'Разговор_о_датотеци', |
| 41 | + NS_MEDIAWIKI => 'Медијавики', |
| 42 | + NS_MEDIAWIKI_TALK => 'Разговор_о_Медијавикију', |
43 | 43 | NS_TEMPLATE => 'Шаблон', |
44 | 44 | NS_TEMPLATE_TALK => 'Разговор_о_шаблону', |
45 | 45 | NS_HELP => 'Помоћ', |
— | — | @@ -68,10 +68,6 @@ |
69 | 69 | |
70 | 70 | 'Слика' => NS_FILE, |
71 | 71 | 'Разговор_о_слици' => NS_FILE_TALK, |
72 | | - "Датотека" => NS_FILE, |
73 | | - "Разговор_о_датотеци" => NS_FILE_TALK, |
74 | | - "Медијавики" => NS_MEDIAWIKI, |
75 | | - "Разговор_о_Медијавикију" => NS_MEDIAWIKI_TALK, |
76 | 72 | 'МедијаВики' => NS_MEDIAWIKI, |
77 | 73 | 'Разговор_о_МедијаВикију' => NS_MEDIAWIKI_TALK, |
78 | 74 | ); |
Index: trunk/phase3/languages/messages/MessagesQug.php |
— | — | @@ -14,25 +14,6 @@ |
15 | 15 | |
16 | 16 | $fallback = 'qu, es'; |
17 | 17 | |
18 | | -$namespaceNames = array( |
19 | | - NS_MEDIA => 'Midya', |
20 | | - NS_SPECIAL => 'Sapak', |
21 | | - NS_TALK => 'Rimanakuy', |
22 | | - NS_USER => 'Rurak', |
23 | | - NS_USER_TALK => 'Rurakpa_rimanakuy', |
24 | | - NS_PROJECT_TALK => '$1-pa_rimanakuy', |
25 | | - NS_FILE => 'Rikcha', |
26 | | - NS_FILE_TALK => 'Rikchapa_rimanakuy', |
27 | | - NS_MEDIAWIKI => 'MediaWiki', |
28 | | - NS_MEDIAWIKI_TALK => 'MediaWikipa_rimanakuy', |
29 | | - NS_TEMPLATE => 'Plantilla', |
30 | | - NS_TEMPLATE_TALK => 'Plantillapa_rimanakuy', |
31 | | - NS_HELP => 'Yanapa', |
32 | | - NS_HELP_TALK => 'Yanapapak_rimanakuy', |
33 | | - NS_CATEGORY => 'Samiyachiy', |
34 | | - NS_CATEGORY_TALK => 'Samiyachiy_rimanakuy', |
35 | | -); |
36 | | - |
37 | 18 | $messages = array( |
38 | 19 | # User preference toggles |
39 | 20 | 'tog-underline' => 'Tinkikunana uraypi aspishpa rikuchina', |
Index: trunk/phase3/languages/messages/MessagesOs.php |
— | — | @@ -17,16 +17,16 @@ |
18 | 18 | $fallback = 'ru'; |
19 | 19 | |
20 | 20 | $namespaceNames = array( |
21 | | - NS_MEDIA => 'Медиа', |
| 21 | + NS_MEDIA => 'Media', |
22 | 22 | NS_SPECIAL => 'Сæрмагонд', |
23 | 23 | NS_TALK => 'Тæрхон', |
24 | 24 | NS_USER => 'Архайæг', |
25 | 25 | NS_USER_TALK => 'Архайæджы_ныхас', |
26 | | - NS_PROJECT_TALK => '{{GRAMMAR:genitive|$1}}_тæрхон', |
27 | | - NS_FILE => 'Файл', |
28 | | - NS_FILE_TALK => 'Файлы_тæрхон', |
| 26 | + NS_PROJECT_TALK => 'Дискусси_$1', |
| 27 | + NS_FILE => 'Ныв', |
| 28 | + NS_FILE_TALK => 'Нывы_тæрхон', |
29 | 29 | NS_MEDIAWIKI => 'MediaWiki', |
30 | | - NS_MEDIAWIKI_TALK => 'MediaWiki-йы_тæрхон', |
| 30 | + NS_MEDIAWIKI_TALK => 'Тæрхон_MediaWiki', |
31 | 31 | NS_TEMPLATE => 'Шаблон', |
32 | 32 | NS_TEMPLATE_TALK => 'Шаблоны_тæрхон', |
33 | 33 | NS_HELP => 'Æххуыс', |
— | — | @@ -38,19 +38,13 @@ |
39 | 39 | $namespaceAliases = array( |
40 | 40 | 'Дискусси' => NS_TALK, |
41 | 41 | 'Архайæджы_дискусси' => NS_USER_TALK, |
42 | | - 'Дискусси_$1' => NS_PROJECT_TALK, |
43 | | - 'Ныв' => NS_FILE, |
44 | | - 'Нывы_тæрхон' => NS_FILE_TALK, |
45 | 42 | 'Нывы_тыххæй_дискусси' => NS_FILE_TALK, |
46 | 43 | 'Дискусси_MediaWiki' => NS_MEDIAWIKI_TALK, |
47 | | - 'Тæрхон_MediaWiki' => NS_MEDIAWIKI_TALK, |
48 | 44 | 'Шаблоны_тыххæй_дискусси' => NS_TEMPLATE_TALK, |
49 | 45 | 'Æххуысы_тыххæй_дискусси' => NS_HELP_TALK, |
50 | 46 | 'Категорийы_тыххæй_дискусси' => NS_CATEGORY_TALK, |
51 | 47 | ); |
52 | 48 | |
53 | | -// Remove Russian aliases |
54 | | -$namespaceGenderAliases = array(); |
55 | 49 | |
56 | 50 | $magicWords = array( |
57 | 51 | 'redirect' => array( '0', '#РАРВЫСТ', '#перенаправление', '#перенапр', '#REDIRECT' ), |
Index: trunk/phase3/languages/messages/MessagesIg.php |
— | — | @@ -12,38 +12,24 @@ |
13 | 13 | */ |
14 | 14 | |
15 | 15 | $namespaceNames = array( |
16 | | - NS_MEDIA => 'Midia', |
| 16 | + NS_MEDIA => 'Nká', |
17 | 17 | NS_SPECIAL => 'Ihü_kárírí', |
18 | 18 | NS_TALK => 'Okwu', |
19 | | - NS_USER => 'Ọbanife', |
20 | | - NS_USER_TALK => 'Okwu_ọbanife', |
| 19 | + NS_USER => 'Ọ\'bànifé', |
| 20 | + NS_USER_TALK => 'Okwu_ọ\'bànifé', |
21 | 21 | NS_PROJECT_TALK => 'Okwu_$1', |
22 | | - NS_FILE => 'Usòrò', |
23 | | - NS_FILE_TALK => 'Okwu_usòrò', |
24 | | - NS_MEDIAWIKI => 'MidiaWiki', |
25 | | - NS_MEDIAWIKI_TALK => 'Okwu_MidiaWiki', |
| 22 | + NS_FILE => 'Ákwúkwó_orünotu', |
| 23 | + NS_FILE_TALK => 'Okwu_ákwúkwó_orünotu', |
| 24 | + NS_MEDIAWIKI => 'NkáWiki', |
| 25 | + NS_MEDIAWIKI_TALK => 'Okwu_NkáWiki', |
26 | 26 | NS_TEMPLATE => 'Àtụ', |
27 | 27 | NS_TEMPLATE_TALK => 'Okwu_àtụ', |
28 | | - NS_HELP => 'Nkwadọ', |
29 | | - NS_HELP_TALK => 'Okwu_nkwadọ', |
30 | | - NS_CATEGORY => 'Òtù', |
31 | | - NS_CATEGORY_TALK => 'Okwu_òtù', |
| 28 | + NS_HELP => 'Nkwádọ', |
| 29 | + NS_HELP_TALK => 'Okwu_nkwádọ', |
| 30 | + NS_CATEGORY => 'Ébéonọr', |
| 31 | + NS_CATEGORY_TALK => 'Okwu_ébéonọr', |
32 | 32 | ); |
33 | 33 | |
34 | | -$namespaceAliases = array( |
35 | | - 'Nká' => NS_MEDIA, |
36 | | - 'Ọ\'bànifé' => NS_USER, |
37 | | - 'Okwu_ọ\'bànifé' => NS_USER_TALK, |
38 | | - 'Ákwúkwó_orünotu' => NS_FILE, |
39 | | - 'Okwu_ákwúkwó_orünotu' => NS_FILE_TALK, |
40 | | - 'NkáWiki' => NS_MEDIAWIKI, |
41 | | - 'Okwu_NkáWiki' => NS_MEDIAWIKI_TALK, |
42 | | - 'Nkwádọ' => NS_HELP, |
43 | | - 'Okwu_nkwádọ' => NS_HELP_TALK, |
44 | | - 'Ébéonọr' => NS_CATEGORY, |
45 | | - 'Okwu_ébéonọr' => NS_CATEGORY_TALK, |
46 | | -); |
47 | | - |
48 | 34 | $specialPageAliases = array( |
49 | 35 | 'Allpages' => array( 'IhüNílé' ), |
50 | 36 | 'Blankpage' => array( 'HịcháIhü' ), |
Index: trunk/phase3/resources/mediawiki.action/mediawiki.action.watch.ajax.js |
— | — | @@ -4,158 +4,152 @@ |
5 | 5 | */ |
6 | 6 | ( function ( $, mw, undefined ) { |
7 | 7 | |
8 | | - /** |
9 | | - * The name of the page to watch or unwatch. |
10 | | - */ |
11 | | - var title = mw.config.get( 'wgRelevantPageName', mw.config.get( 'wgPageName' ) ); |
| 8 | +/** |
| 9 | + * The name of the page to watch or unwatch. |
| 10 | + */ |
| 11 | +var title = mw.config.get( 'wgRelevantPageName', mw.config.get( 'wgPageName' ) ); |
12 | 12 | |
13 | | - /** |
14 | | - * Update the link text, link href attribute and (if applicable) |
15 | | - * "loading" class. |
16 | | - * |
17 | | - * @param $link {jQuery} Anchor tag of (un)watch link. |
18 | | - * @param action {String} One of 'watch', 'unwatch'. |
19 | | - * @param state {String} [optional] 'idle' or 'loading'. Default is 'idle'. |
20 | | - */ |
21 | | - function updateWatchLink( $link, action, state ) { |
22 | | - var accesskeyTip, msgKey, $li; |
23 | | - |
24 | | - // message keys 'watch', 'watching', 'unwatch' or 'unwatching'. |
25 | | - msgKey = state === 'loading' ? action + 'ing' : action; |
26 | | - accesskeyTip = $link.attr( 'title' ).match( mw.util.tooltipAccessKeyRegexp ); |
| 13 | +/** |
| 14 | + * Update the link text, link href attribute and (if applicable) |
| 15 | + * "loading" class. |
| 16 | + * |
| 17 | + * @param $link {jQuery} Anchor tag of (un)watch link |
| 18 | + * @param action {String} One of 'watch', 'unwatch'. |
| 19 | + * @param state {String} [optional] 'idle' or 'loading'. Default is 'idle'. |
| 20 | + */ |
| 21 | +function updateWatchLink( $link, action, state ) { |
| 22 | + // message keys 'watch', 'watching', 'unwatch' or 'unwatching'. |
| 23 | + var msgKey = state === 'loading' ? action + 'ing' : action, |
| 24 | + accesskeyTip = $link.attr( 'title' ).match( mw.util.tooltipAccessKeyRegexp ), |
27 | 25 | $li = $link.closest( 'li' ); |
28 | 26 | |
29 | | - $link |
30 | | - .text( mw.msg( msgKey ) ) |
31 | | - .attr( 'title', mw.msg( 'tooltip-ca-' + action ) + |
32 | | - ( accesskeyTip ? ' ' + accesskeyTip[0] : '' ) |
33 | | - ) |
34 | | - .attr( 'href', mw.util.wikiScript() + '?' + $.param({ |
35 | | - title: title, |
36 | | - action: action |
37 | | - }) |
38 | | - ); |
| 27 | + $link |
| 28 | + .text( mw.msg( msgKey ) ) |
| 29 | + .attr( 'title', mw.msg( 'tooltip-ca-' + action ) + |
| 30 | + ( accesskeyTip ? ' ' + accesskeyTip[0] : '' ) |
| 31 | + ) |
| 32 | + .attr( 'href', mw.util.wikiScript() + '?' + $.param({ |
| 33 | + title: title, |
| 34 | + action: action |
| 35 | + }) |
| 36 | + ); |
39 | 37 | |
40 | | - // Special case for vector icon |
41 | | - if ( $li.hasClass( 'icon' ) ) { |
42 | | - if ( state === 'loading' ) { |
43 | | - $link.addClass( 'loading' ); |
44 | | - } else { |
45 | | - $link.removeClass( 'loading' ); |
46 | | - } |
| 38 | + // Special case for vector icon |
| 39 | + if ( $li.hasClass( 'icon' ) ) { |
| 40 | + if ( state === 'loading' ) { |
| 41 | + $link.addClass( 'loading' ); |
| 42 | + } else { |
| 43 | + $link.removeClass( 'loading' ); |
47 | 44 | } |
48 | 45 | } |
| 46 | +} |
49 | 47 | |
50 | | - /** |
51 | | - * @todo This should be moved somewhere more accessible. |
52 | | - * @param url {String} |
53 | | - * @return {String} The extracted action, defaults to 'view'. |
54 | | - */ |
55 | | - function mwUriGetAction( url ) { |
56 | | - var action, actionPaths, key, i, m, parts; |
| 48 | +/** |
| 49 | + * @todo This should be moved somewhere more accessible. |
| 50 | + * @param url {String} |
| 51 | + * @return {String} The extracted action, defaults to 'view'. |
| 52 | + */ |
| 53 | +function mwUriGetAction( url ) { |
| 54 | + var actionPaths = mw.config.get( 'wgActionPaths' ), |
| 55 | + key, parts, m, action; |
57 | 56 | |
58 | | - actionPaths = mw.config.get( 'wgActionPaths' ); |
| 57 | + // @todo: Does MediaWiki give action path or query param |
| 58 | + // precedence ? If the former, move this to the bottom |
| 59 | + action = mw.util.getParamValue( 'action', url ); |
| 60 | + if ( action !== null ) { |
| 61 | + return action; |
| 62 | + } |
59 | 63 | |
60 | | - // @todo: Does MediaWiki give action path or query param |
61 | | - // precedence ? If the former, move this to the bottom |
62 | | - action = mw.util.getParamValue( 'action', url ); |
63 | | - if ( action !== null ) { |
64 | | - return action; |
65 | | - } |
66 | | - |
67 | | - for ( key in actionPaths ) { |
68 | | - if ( actionPaths.hasOwnProperty( key ) ) { |
69 | | - parts = actionPaths[key].split( '$1' ); |
70 | | - for ( i = 0; i < parts.length; i += 1 ) { |
71 | | - parts[i] = $.escapeRE( parts[i] ); |
72 | | - } |
73 | | - m = new RegExp( parts.join( '(.+)' ) ).exec( url ); |
74 | | - if ( m && m[1] ) { |
75 | | - return key; |
76 | | - } |
77 | | - |
| 64 | + for ( key in actionPaths ) { |
| 65 | + if ( actionPaths.hasOwnProperty( key ) ) { |
| 66 | + parts = actionPaths[key].split( '$1' ); |
| 67 | + for ( i = 0; i < parts.length; i += 1 ) { |
| 68 | + parts[i] = $.escapeRE( parts[i] ); |
78 | 69 | } |
| 70 | + m = new RegExp( parts.join( '(.+)' ) ).exec( url ); |
| 71 | + if ( m && m[1] ) { |
| 72 | + return key; |
| 73 | + } |
| 74 | + |
79 | 75 | } |
80 | | - |
81 | | - return 'view'; |
82 | 76 | } |
83 | 77 | |
84 | | - $( document ).ready( function () { |
85 | | - var $links = $( '.mw-watchlink a, a.mw-watchlink, ' + |
86 | | - '#ca-watch a, #ca-unwatch a, #mw-unwatch-link1, ' + |
87 | | - '#mw-unwatch-link2, #mw-watch-link2, #mw-watch-link1' ); |
| 78 | + return 'view'; |
| 79 | +} |
88 | 80 | |
89 | | - // Allowing people to add inline animated links is a little scary |
90 | | - $links = $links.filter( ':not( #bodyContent *, #content * )' ); |
| 81 | +$( document ).ready( function() { |
| 82 | + var $links = $( '.mw-watchlink a, a.mw-watchlink, ' + |
| 83 | + '#ca-watch a, #ca-unwatch a, #mw-unwatch-link1, ' + |
| 84 | + '#mw-unwatch-link2, #mw-watch-link2, #mw-watch-link1' ); |
91 | 85 | |
92 | | - $links.click( function ( e ) { |
93 | | - var action, api, $link; |
| 86 | + // Allowing people to add inline animated links is a little scary |
| 87 | + $links = $links.filter( ':not( #bodyContent *, #content * )' ); |
94 | 88 | |
| 89 | + $links.click( function( e ) { |
| 90 | + var $link, api, |
95 | 91 | action = mwUriGetAction( this.href ); |
96 | 92 | |
97 | | - if ( action !== 'watch' && action !== 'unwatch' ) { |
98 | | - // Could not extract target action from link url, |
99 | | - // let native browsing handle it further |
100 | | - return true; |
101 | | - } |
102 | | - e.preventDefault(); |
103 | | - e.stopPropagation(); |
| 93 | + if ( action !== 'watch' && action !== 'unwatch' ) { |
| 94 | + // Could not extract target action from link url, |
| 95 | + // let native browsing handle it further |
| 96 | + return true; |
| 97 | + } |
| 98 | + e.preventDefault(); |
| 99 | + e.stopPropagation(); |
| 100 | + |
| 101 | + $link = $( this ); |
104 | 102 | |
105 | | - $link = $( this ); |
| 103 | + updateWatchLink( $link, action, 'loading' ); |
106 | 104 | |
107 | | - updateWatchLink( $link, action, 'loading' ); |
108 | | - |
109 | | - api = new mw.Api(); |
110 | | - api[action]( |
111 | | - title, |
112 | | - // Success |
113 | | - function ( watchResponse ) { |
114 | | - var $li, otherAction; |
115 | | - |
116 | | - otherAction = action === 'watch' ? 'unwatch' : 'watch'; |
| 105 | + api = new mw.Api(); |
| 106 | + api[action]( |
| 107 | + title, |
| 108 | + // Success |
| 109 | + function( watchResponse ) { |
| 110 | + var otherAction = action === 'watch' ? 'unwatch' : 'watch', |
117 | 111 | $li = $link.closest( 'li' ); |
118 | 112 | |
119 | | - mw.util.jsMessage( watchResponse.message, 'ajaxwatch' ); |
| 113 | + mw.util.jsMessage( watchResponse.message, 'ajaxwatch' ); |
120 | 114 | |
121 | | - // Set link to opposite |
122 | | - updateWatchLink( $link, otherAction ); |
| 115 | + // Set link to opposite |
| 116 | + updateWatchLink( $link, otherAction ); |
123 | 117 | |
124 | | - // Most common ID style |
125 | | - if ( $li.prop( 'id' ) === 'ca-' + otherAction || $li.prop( 'id' ) === 'ca-' + action ) { |
126 | | - $li.prop( 'id', 'ca-' + otherAction ); |
127 | | - } |
| 118 | + // Most common ID style |
| 119 | + if ( $li.prop( 'id' ) === 'ca-' + otherAction || $li.prop( 'id' ) === 'ca-' + action ) { |
| 120 | + $li.prop( 'id', 'ca-' + otherAction ); |
| 121 | + } |
| 122 | + |
| 123 | + // Bug 12395 - update the watch checkbox on edit pages when the |
| 124 | + // page is watched or unwatched via the tab. |
| 125 | + if ( watchResponse.watched !== undefined ) { |
| 126 | + $( '#wpWatchthis' ).prop( 'checked', true ); |
| 127 | + } else { |
| 128 | + $( '#wpWatchthis' ).removeProp( 'checked' ); |
| 129 | + } |
| 130 | + }, |
| 131 | + // Error |
| 132 | + function(){ |
128 | 133 | |
129 | | - // Bug 12395 - update the watch checkbox on edit pages when the |
130 | | - // page is watched or unwatched via the tab. |
131 | | - if ( watchResponse.watched !== undefined ) { |
132 | | - $( '#wpWatchthis' ).prop( 'checked', true ); |
133 | | - } else { |
134 | | - $( '#wpWatchthis' ).removeProp( 'checked' ); |
135 | | - } |
136 | | - }, |
137 | | - // Error |
138 | | - function () { |
139 | | - var cleanTitle, html, link; |
| 134 | + // Reset link to non-loading mode |
| 135 | + updateWatchLink( $link, action ); |
| 136 | + |
| 137 | + // Format error message |
| 138 | + var cleanTitle = title.replace( /_/g, ' ' ); |
| 139 | + var link = mw.html.element( |
| 140 | + 'a', { |
| 141 | + 'href': mw.util.wikiGetlink( title ), |
| 142 | + 'title': cleanTitle |
| 143 | + }, cleanTitle |
| 144 | + ); |
| 145 | + var html = mw.msg( 'watcherrortext', link ); |
| 146 | + |
| 147 | + // Report to user about the error |
| 148 | + mw.util.jsMessage( html, 'ajaxwatch' ); |
140 | 149 | |
141 | | - // Reset link to non-loading mode |
142 | | - updateWatchLink( $link, action ); |
143 | | - |
144 | | - // Format error message |
145 | | - cleanTitle = title.replace( /_/g, ' ' ); |
146 | | - link = mw.html.element( |
147 | | - 'a', { |
148 | | - href: mw.util.wikiGetlink( title ), |
149 | | - title: cleanTitle |
150 | | - }, cleanTitle |
151 | | - ); |
152 | | - html = mw.msg( 'watcherrortext', link ); |
153 | | - |
154 | | - // Report to user about the error |
155 | | - mw.util.jsMessage( html, 'ajaxwatch' ); |
156 | | - |
157 | | - } |
158 | | - ); |
159 | | - }); |
| 150 | + } |
| 151 | + ); |
160 | 152 | }); |
161 | 153 | |
162 | | -}( jQuery, mediaWiki ) ); |
| 154 | +}); |
| 155 | + |
| 156 | +})( jQuery, mediaWiki ); |
Index: trunk/phase3/resources/mediawiki.api/mediawiki.api.watch.js |
— | — | @@ -4,51 +4,47 @@ |
5 | 5 | */ |
6 | 6 | ( function( $, mw ) { |
7 | 7 | |
8 | | - /** |
9 | | - * @context {mw.Api} |
10 | | - */ |
11 | | - function doWatchInternal( page, success, err, addParams ) { |
12 | | - var params = { |
13 | | - action: 'watch', |
14 | | - title: String( page ), |
15 | | - token: mw.user.tokens.get( 'watchToken' ), |
16 | | - uselang: mw.config.get( 'wgUserLanguage' ) |
17 | | - }; |
18 | | - function ok( data ) { |
19 | | - success( data.watch ); |
20 | | - } |
21 | | - if ( addParams ) { |
22 | | - $.extend( params, addParams ); |
23 | | - } |
24 | | - return this.post( params, { ok: ok, err: err } ); |
25 | | - } |
26 | | - |
27 | 8 | $.extend( mw.Api.prototype, { |
28 | 9 | /** |
29 | 10 | * Convinience method for 'action=watch'. |
30 | 11 | * |
31 | 12 | * @param page {String|mw.Title} Full page name or instance of mw.Title |
32 | | - * @param success {Function} Callback to which the watch object will be passed. |
33 | | - * Watch object contains properties 'title' (full pagename), 'watched' (boolean) and |
| 13 | + * @param success {Function} callback to which the watch object will be passed |
| 14 | + * watch object contains 'title' (full page name), 'watched' (boolean) and |
34 | 15 | * 'message' (parsed HTML of the 'addedwatchtext' message). |
35 | | - * @param err {Function} Error callback (optional) |
| 16 | + * @param _unwatch {Boolean} Internally used to re-use this logic for unwatch(), |
| 17 | + * do not use outside this module. |
| 18 | + * @param err {Function} callback if error (optional) |
36 | 19 | * @return {jqXHR} |
37 | 20 | */ |
38 | | - watch: function ( page, success, err ) { |
39 | | - return doWatchInternal.call( this, page, success, err ); |
| 21 | + watch: function( page, success, err, _unwatch ) { |
| 22 | + var params, ok; |
| 23 | + params = { |
| 24 | + action: 'watch', |
| 25 | + title: String( page ), |
| 26 | + token: mw.user.tokens.get( 'watchToken' ), |
| 27 | + uselang: mw.config.get( 'wgUserLanguage' ) |
| 28 | + }; |
| 29 | + if ( _unwatch ) { |
| 30 | + params.unwatch = 1; |
| 31 | + } |
| 32 | + ok = function( data ) { |
| 33 | + success( data.watch ); |
| 34 | + }; |
| 35 | + return this.post( params, { ok: ok, err: err } ); |
40 | 36 | }, |
41 | 37 | /** |
42 | 38 | * Convinience method for 'action=watch&unwatch=1'. |
43 | 39 | * |
44 | 40 | * @param page {String|mw.Title} Full page name or instance of mw.Title |
45 | | - * @param success {Function} Callback to which the watch object will be passed. |
46 | | - * Watch object contains properties 'title' (full pagename), 'watched' (boolean) and |
| 41 | + * @param success {Function} callback to which the watch object will be passed |
| 42 | + * watch object contains 'title' (full page name), 'unwatched' (boolean) and |
47 | 43 | * 'message' (parsed HTML of the 'removedwatchtext' message). |
48 | | - * @param err {Function} Error callback (optional) |
| 44 | + * @param err {Function} callback if error (optional) |
49 | 45 | * @return {jqXHR} |
50 | 46 | */ |
51 | | - unwatch: function ( page, success, err ) { |
52 | | - return doWatchInternal.call( this, page, success, err, { unwatch: 1 } ); |
| 47 | + unwatch: function( page, success, err ) { |
| 48 | + return this.watch( page, success, err, true ); |
53 | 49 | } |
54 | 50 | |
55 | 51 | } ); |