* @file
* @ingroup SpecialPage
*/
-use MediaWiki\MediaWikiServices;
-/**
- * Used to show archived pages and eventually restore them.
- *
- * @ingroup SpecialPage
- */
-class PageArchive {
- /** @var Title */
- protected $title;
-
- /** @var Status */
- protected $fileStatus;
-
- /** @var Status */
- protected $revisionStatus;
-
- /** @var Config */
- protected $config;
-
- function __construct( $title, Config $config = null ) {
- if ( is_null( $title ) ) {
- throw new MWException( __METHOD__ . ' given a null title.' );
- }
- $this->title = $title;
- if ( $config === null ) {
- wfDebug( __METHOD__ . ' did not have a Config object passed to it' );
- $config = MediaWikiServices::getInstance()->getMainConfig();
- }
- $this->config = $config;
- }
-
- public function doesWrites() {
- return true;
- }
-
- /**
- * List all deleted pages recorded in the archive table. Returns result
- * wrapper with (ar_namespace, ar_title, count) fields, ordered by page
- * namespace/title.
- *
- * @return ResultWrapper
- */
- public static function listAllPages() {
- $dbr = wfGetDB( DB_REPLICA );
-
- return self::listPages( $dbr, '' );
- }
-
- /**
- * List deleted pages recorded in the archive table matching the
- * given title prefix.
- * Returns result wrapper with (ar_namespace, ar_title, count) fields.
- *
- * @param string $prefix Title prefix
- * @return ResultWrapper
- */
- public static function listPagesByPrefix( $prefix ) {
- $dbr = wfGetDB( DB_REPLICA );
-
- $title = Title::newFromText( $prefix );
- if ( $title ) {
- $ns = $title->getNamespace();
- $prefix = $title->getDBkey();
- } else {
- // Prolly won't work too good
- // @todo handle bare namespace names cleanly?
- $ns = 0;
- }
-
- $conds = [
- 'ar_namespace' => $ns,
- 'ar_title' . $dbr->buildLike( $prefix, $dbr->anyString() ),
- ];
-
- return self::listPages( $dbr, $conds );
- }
-
- /**
- * @param IDatabase $dbr
- * @param string|array $condition
- * @return bool|ResultWrapper
- */
- protected static function listPages( $dbr, $condition ) {
- return $dbr->select(
- [ 'archive' ],
- [
- 'ar_namespace',
- 'ar_title',
- 'count' => 'COUNT(*)'
- ],
- $condition,
- __METHOD__,
- [
- 'GROUP BY' => [ 'ar_namespace', 'ar_title' ],
- 'ORDER BY' => [ 'ar_namespace', 'ar_title' ],
- 'LIMIT' => 100,
- ]
- );
- }
-
- /**
- * List the revisions of the given page. Returns result wrapper with
- * (ar_minor_edit, ar_timestamp, ar_user, ar_user_text, ar_comment) fields.
- *
- * @return ResultWrapper
- */
- function listRevisions() {
- $dbr = wfGetDB( DB_REPLICA );
-
- $tables = [ 'archive' ];
-
- $fields = [
- 'ar_minor_edit', 'ar_timestamp', 'ar_user', 'ar_user_text',
- 'ar_comment', 'ar_len', 'ar_deleted', 'ar_rev_id', 'ar_sha1',
- ];
-
- if ( $this->config->get( 'ContentHandlerUseDB' ) ) {
- $fields[] = 'ar_content_format';
- $fields[] = 'ar_content_model';
- }
-
- $conds = [ 'ar_namespace' => $this->title->getNamespace(),
- 'ar_title' => $this->title->getDBkey() ];
-
- $options = [ 'ORDER BY' => 'ar_timestamp DESC' ];
-
- $join_conds = [];
-
- ChangeTags::modifyDisplayQuery(
- $tables,
- $fields,
- $conds,
- $join_conds,
- $options,
- ''
- );
-
- return $dbr->select( $tables,
- $fields,
- $conds,
- __METHOD__,
- $options,
- $join_conds
- );
- }
-
- /**
- * List the deleted file revisions for this page, if it's a file page.
- * Returns a result wrapper with various filearchive fields, or null
- * if not a file page.
- *
- * @return ResultWrapper
- * @todo Does this belong in Image for fuller encapsulation?
- */
- function listFiles() {
- if ( $this->title->getNamespace() != NS_FILE ) {
- return null;
- }
-
- $dbr = wfGetDB( DB_REPLICA );
- return $dbr->select(
- 'filearchive',
- ArchivedFile::selectFields(),
- [ 'fa_name' => $this->title->getDBkey() ],
- __METHOD__,
- [ 'ORDER BY' => 'fa_timestamp DESC' ]
- );
- }
-
- /**
- * Return a Revision object containing data for the deleted revision.
- * Note that the result *may* or *may not* have a null page ID.
- *
- * @param string $timestamp
- * @return Revision|null
- */
- function getRevision( $timestamp ) {
- $dbr = wfGetDB( DB_REPLICA );
-
- $fields = [
- 'ar_rev_id',
- 'ar_text',
- 'ar_comment',
- 'ar_user',
- 'ar_user_text',
- 'ar_timestamp',
- 'ar_minor_edit',
- 'ar_flags',
- 'ar_text_id',
- 'ar_deleted',
- 'ar_len',
- 'ar_sha1',
- ];
-
- if ( $this->config->get( 'ContentHandlerUseDB' ) ) {
- $fields[] = 'ar_content_format';
- $fields[] = 'ar_content_model';
- }
-
- $row = $dbr->selectRow( 'archive',
- $fields,
- [ 'ar_namespace' => $this->title->getNamespace(),
- 'ar_title' => $this->title->getDBkey(),
- 'ar_timestamp' => $dbr->timestamp( $timestamp ) ],
- __METHOD__ );
-
- if ( $row ) {
- return Revision::newFromArchiveRow( $row, [ 'title' => $this->title ] );
- }
-
- return null;
- }
-
- /**
- * Return the most-previous revision, either live or deleted, against
- * the deleted revision given by timestamp.
- *
- * May produce unexpected results in case of history merges or other
- * unusual time issues.
- *
- * @param string $timestamp
- * @return Revision|null Null when there is no previous revision
- */
- function getPreviousRevision( $timestamp ) {
- $dbr = wfGetDB( DB_REPLICA );
-
- // Check the previous deleted revision...
- $row = $dbr->selectRow( 'archive',
- 'ar_timestamp',
- [ 'ar_namespace' => $this->title->getNamespace(),
- 'ar_title' => $this->title->getDBkey(),
- 'ar_timestamp < ' .
- $dbr->addQuotes( $dbr->timestamp( $timestamp ) ) ],
- __METHOD__,
- [
- 'ORDER BY' => 'ar_timestamp DESC',
- 'LIMIT' => 1 ] );
- $prevDeleted = $row ? wfTimestamp( TS_MW, $row->ar_timestamp ) : false;
-
- $row = $dbr->selectRow( [ 'page', 'revision' ],
- [ 'rev_id', 'rev_timestamp' ],
- [
- 'page_namespace' => $this->title->getNamespace(),
- 'page_title' => $this->title->getDBkey(),
- 'page_id = rev_page',
- 'rev_timestamp < ' .
- $dbr->addQuotes( $dbr->timestamp( $timestamp ) ) ],
- __METHOD__,
- [
- 'ORDER BY' => 'rev_timestamp DESC',
- 'LIMIT' => 1 ] );
- $prevLive = $row ? wfTimestamp( TS_MW, $row->rev_timestamp ) : false;
- $prevLiveId = $row ? intval( $row->rev_id ) : null;
-
- if ( $prevLive && $prevLive > $prevDeleted ) {
- // Most prior revision was live
- return Revision::newFromId( $prevLiveId );
- } elseif ( $prevDeleted ) {
- // Most prior revision was deleted
- return $this->getRevision( $prevDeleted );
- }
-
- // No prior revision on this page.
- return null;
- }
-
- /**
- * Get the text from an archive row containing ar_text, ar_flags and ar_text_id
- *
- * @param object $row Database row
- * @return string
- */
- function getTextFromRow( $row ) {
- if ( is_null( $row->ar_text_id ) ) {
- // An old row from MediaWiki 1.4 or previous.
- // Text is embedded in this row in classic compression format.
- return Revision::getRevisionText( $row, 'ar_' );
- }
-
- // New-style: keyed to the text storage backend.
- $dbr = wfGetDB( DB_REPLICA );
- $text = $dbr->selectRow( 'text',
- [ 'old_text', 'old_flags' ],
- [ 'old_id' => $row->ar_text_id ],
- __METHOD__ );
-
- return Revision::getRevisionText( $text );
- }
-
- /**
- * Fetch (and decompress if necessary) the stored text of the most
- * recently edited deleted revision of the page.
- *
- * If there are no archived revisions for the page, returns NULL.
- *
- * @return string|null
- */
- function getLastRevisionText() {
- $dbr = wfGetDB( DB_REPLICA );
- $row = $dbr->selectRow( 'archive',
- [ 'ar_text', 'ar_flags', 'ar_text_id' ],
- [ 'ar_namespace' => $this->title->getNamespace(),
- 'ar_title' => $this->title->getDBkey() ],
- __METHOD__,
- [ 'ORDER BY' => 'ar_timestamp DESC' ] );
-
- if ( $row ) {
- return $this->getTextFromRow( $row );
- }
-
- return null;
- }
-
- /**
- * Quick check if any archived revisions are present for the page.
- *
- * @return bool
- */
- function isDeleted() {
- $dbr = wfGetDB( DB_REPLICA );
- $n = $dbr->selectField( 'archive', 'COUNT(ar_title)',
- [ 'ar_namespace' => $this->title->getNamespace(),
- 'ar_title' => $this->title->getDBkey() ],
- __METHOD__
- );
-
- return ( $n > 0 );
- }
-
- /**
- * Restore the given (or all) text and file revisions for the page.
- * Once restored, the items will be removed from the archive tables.
- * The deletion log will be updated with an undeletion notice.
- *
- * This also sets Status objects, $this->fileStatus and $this->revisionStatus
- * (depending what operations are attempted).
- *
- * @param array $timestamps Pass an empty array to restore all revisions,
- * otherwise list the ones to undelete.
- * @param string $comment
- * @param array $fileVersions
- * @param bool $unsuppress
- * @param User $user User performing the action, or null to use $wgUser
- * @param string|string[] $tags Change tags to add to log entry
- * ($user should be able to add the specified tags before this is called)
- * @return array(number of file revisions restored, number of image revisions
- * restored, log message) on success, false on failure.
- */
- function undelete( $timestamps, $comment = '', $fileVersions = [],
- $unsuppress = false, User $user = null, $tags = null
- ) {
- // If both the set of text revisions and file revisions are empty,
- // restore everything. Otherwise, just restore the requested items.
- $restoreAll = empty( $timestamps ) && empty( $fileVersions );
-
- $restoreText = $restoreAll || !empty( $timestamps );
- $restoreFiles = $restoreAll || !empty( $fileVersions );
-
- if ( $restoreFiles && $this->title->getNamespace() == NS_FILE ) {
- $img = wfLocalFile( $this->title );
- $img->load( File::READ_LATEST );
- $this->fileStatus = $img->restore( $fileVersions, $unsuppress );
- if ( !$this->fileStatus->isOK() ) {
- return false;
- }
- $filesRestored = $this->fileStatus->successCount;
- } else {
- $filesRestored = 0;
- }
-
- if ( $restoreText ) {
- $this->revisionStatus = $this->undeleteRevisions( $timestamps, $unsuppress, $comment );
- if ( !$this->revisionStatus->isOK() ) {
- return false;
- }
-
- $textRestored = $this->revisionStatus->getValue();
- } else {
- $textRestored = 0;
- }
-
- // Touch the log!
-
- if ( $textRestored && $filesRestored ) {
- $reason = wfMessage( 'undeletedrevisions-files' )
- ->numParams( $textRestored, $filesRestored )->inContentLanguage()->text();
- } elseif ( $textRestored ) {
- $reason = wfMessage( 'undeletedrevisions' )->numParams( $textRestored )
- ->inContentLanguage()->text();
- } elseif ( $filesRestored ) {
- $reason = wfMessage( 'undeletedfiles' )->numParams( $filesRestored )
- ->inContentLanguage()->text();
- } else {
- wfDebug( "Undelete: nothing undeleted...\n" );
-
- return false;
- }
-
- if ( trim( $comment ) != '' ) {
- $reason .= wfMessage( 'colon-separator' )->inContentLanguage()->text() . $comment;
- }
-
- if ( $user === null ) {
- global $wgUser;
- $user = $wgUser;
- }
-
- $logEntry = new ManualLogEntry( 'delete', 'restore' );
- $logEntry->setPerformer( $user );
- $logEntry->setTarget( $this->title );
- $logEntry->setComment( $reason );
- $logEntry->setTags( $tags );
-
- Hooks::run( 'ArticleUndeleteLogEntry', [ $this, &$logEntry, $user ] );
-
- $logid = $logEntry->insert();
- $logEntry->publish( $logid );
-
- return [ $textRestored, $filesRestored, $reason ];
- }
-
- /**
- * This is the meaty bit -- It restores archived revisions of the given page
- * to the revision table.
- *
- * @param array $timestamps Pass an empty array to restore all revisions,
- * otherwise list the ones to undelete.
- * @param bool $unsuppress Remove all ar_deleted/fa_deleted restrictions of seletected revs
- * @param string $comment
- * @throws ReadOnlyError
- * @return Status Status object containing the number of revisions restored on success
- */
- private function undeleteRevisions( $timestamps, $unsuppress = false, $comment = '' ) {
- if ( wfReadOnly() ) {
- throw new ReadOnlyError();
- }
-
- $dbw = wfGetDB( DB_MASTER );
- $dbw->startAtomic( __METHOD__ );
-
- $restoreAll = empty( $timestamps );
-
- # Does this page already exist? We'll have to update it...
- $article = WikiPage::factory( $this->title );
- # Load latest data for the current page (T33179)
- $article->loadPageData( 'fromdbmaster' );
- $oldcountable = $article->isCountable();
-
- $page = $dbw->selectRow( 'page',
- [ 'page_id', 'page_latest' ],
- [ 'page_namespace' => $this->title->getNamespace(),
- 'page_title' => $this->title->getDBkey() ],
- __METHOD__,
- [ 'FOR UPDATE' ] // lock page
- );
-
- if ( $page ) {
- $makepage = false;
- # Page already exists. Import the history, and if necessary
- # we'll update the latest revision field in the record.
-
- # Get the time span of this page
- $previousTimestamp = $dbw->selectField( 'revision', 'rev_timestamp',
- [ 'rev_id' => $page->page_latest ],
- __METHOD__ );
-
- if ( $previousTimestamp === false ) {
- wfDebug( __METHOD__ . ": existing page refers to a page_latest that does not exist\n" );
-
- $status = Status::newGood( 0 );
- $status->warning( 'undeleterevision-missing' );
- $dbw->endAtomic( __METHOD__ );
-
- return $status;
- }
- } else {
- # Have to create a new article...
- $makepage = true;
- $previousTimestamp = 0;
- }
-
- $oldWhere = [
- 'ar_namespace' => $this->title->getNamespace(),
- 'ar_title' => $this->title->getDBkey(),
- ];
- if ( !$restoreAll ) {
- $oldWhere['ar_timestamp'] = array_map( [ &$dbw, 'timestamp' ], $timestamps );
- }
-
- $fields = [
- 'ar_id',
- 'ar_rev_id',
- 'rev_id',
- 'ar_text',
- 'ar_comment',
- 'ar_user',
- 'ar_user_text',
- 'ar_timestamp',
- 'ar_minor_edit',
- 'ar_flags',
- 'ar_text_id',
- 'ar_deleted',
- 'ar_page_id',
- 'ar_len',
- 'ar_sha1'
- ];
-
- if ( $this->config->get( 'ContentHandlerUseDB' ) ) {
- $fields[] = 'ar_content_format';
- $fields[] = 'ar_content_model';
- }
-
- /**
- * Select each archived revision...
- */
- $result = $dbw->select(
- [ 'archive', 'revision' ],
- $fields,
- $oldWhere,
- __METHOD__,
- /* options */
- [ 'ORDER BY' => 'ar_timestamp' ],
- [ 'revision' => [ 'LEFT JOIN', 'ar_rev_id=rev_id' ] ]
- );
-
- $rev_count = $result->numRows();
- if ( !$rev_count ) {
- wfDebug( __METHOD__ . ": no revisions to restore\n" );
-
- $status = Status::newGood( 0 );
- $status->warning( "undelete-no-results" );
- $dbw->endAtomic( __METHOD__ );
-
- return $status;
- }
-
- // We use ar_id because there can be duplicate ar_rev_id even for the same
- // page. In this case, we may be able to restore the first one.
- $restoreFailedArIds = [];
-
- // Map rev_id to the ar_id that is allowed to use it. When checking later,
- // if it doesn't match, the current ar_id can not be restored.
-
- // Value can be an ar_id or -1 (-1 means no ar_id can use it, since the
- // rev_id is taken before we even start the restore).
- $allowedRevIdToArIdMap = [];
-
- $latestRestorableRow = null;
-
- foreach ( $result as $row ) {
- if ( $row->ar_rev_id ) {
- // rev_id is taken even before we start restoring.
- if ( $row->ar_rev_id === $row->rev_id ) {
- $restoreFailedArIds[] = $row->ar_id;
- $allowedRevIdToArIdMap[$row->ar_rev_id] = -1;
- } else {
- // rev_id is not taken yet in the DB, but it might be taken
- // by a prior revision in the same restore operation. If
- // not, we need to reserve it.
- if ( isset( $allowedRevIdToArIdMap[$row->ar_rev_id] ) ) {
- $restoreFailedArIds[] = $row->ar_id;
- } else {
- $allowedRevIdToArIdMap[$row->ar_rev_id] = $row->ar_id;
- $latestRestorableRow = $row;
- }
- }
- } else {
- // If ar_rev_id is null, there can't be a collision, and a
- // rev_id will be chosen automatically.
- $latestRestorableRow = $row;
- }
- }
-
- $result->seek( 0 ); // move back
-
- $oldPageId = 0;
- if ( $latestRestorableRow !== null ) {
- $oldPageId = (int)$latestRestorableRow->ar_page_id; // pass this to ArticleUndelete hook
-
- // grab the content to check consistency with global state before restoring the page.
- $revision = Revision::newFromArchiveRow( $latestRestorableRow,
- [
- 'title' => $article->getTitle(), // used to derive default content model
- ]
- );
- $user = User::newFromName( $revision->getUserText( Revision::RAW ), false );
- $content = $revision->getContent( Revision::RAW );
-
- // NOTE: article ID may not be known yet. prepareSave() should not modify the database.
- $status = $content->prepareSave( $article, 0, -1, $user );
- if ( !$status->isOK() ) {
- $dbw->endAtomic( __METHOD__ );
-
- return $status;
- }
- }
-
- $newid = false; // newly created page ID
- $restored = 0; // number of revisions restored
- /** @var Revision $revision */
- $revision = null;
-
- // If there are no restorable revisions, we can skip most of the steps.
- if ( $latestRestorableRow === null ) {
- $failedRevisionCount = $rev_count;
- } else {
- if ( $makepage ) {
- // Check the state of the newest to-be version...
- if ( !$unsuppress
- && ( $latestRestorableRow->ar_deleted & Revision::DELETED_TEXT )
- ) {
- $dbw->endAtomic( __METHOD__ );
-
- return Status::newFatal( "undeleterevdel" );
- }
- // Safe to insert now...
- $newid = $article->insertOn( $dbw, $latestRestorableRow->ar_page_id );
- if ( $newid === false ) {
- // The old ID is reserved; let's pick another
- $newid = $article->insertOn( $dbw );
- }
- $pageId = $newid;
- } else {
- // Check if a deleted revision will become the current revision...
- if ( $latestRestorableRow->ar_timestamp > $previousTimestamp ) {
- // Check the state of the newest to-be version...
- if ( !$unsuppress
- && ( $latestRestorableRow->ar_deleted & Revision::DELETED_TEXT )
- ) {
- $dbw->endAtomic( __METHOD__ );
-
- return Status::newFatal( "undeleterevdel" );
- }
- }
-
- $newid = false;
- $pageId = $article->getId();
- }
-
- foreach ( $result as $row ) {
- // Check for key dupes due to needed archive integrity.
- if ( $row->ar_rev_id && $allowedRevIdToArIdMap[$row->ar_rev_id] !== $row->ar_id ) {
- continue;
- }
- // Insert one revision at a time...maintaining deletion status
- // unless we are specifically removing all restrictions...
- $revision = Revision::newFromArchiveRow( $row,
- [
- 'page' => $pageId,
- 'title' => $this->title,
- 'deleted' => $unsuppress ? 0 : $row->ar_deleted
- ] );
-
- $revision->insertOn( $dbw );
- $restored++;
-
- Hooks::run( 'ArticleRevisionUndeleted',
- [ &$this->title, $revision, $row->ar_page_id ] );
- }
-
- // Now that it's safely stored, take it out of the archive
- // Don't delete rows that we failed to restore
- $toDeleteConds = $oldWhere;
- $failedRevisionCount = count( $restoreFailedArIds );
- if ( $failedRevisionCount > 0 ) {
- $toDeleteConds[] = 'ar_id NOT IN ( ' . $dbw->makeList( $restoreFailedArIds ) . ' )';
- }
-
- $dbw->delete( 'archive',
- $toDeleteConds,
- __METHOD__ );
- }
-
- $status = Status::newGood( $restored );
-
- if ( $failedRevisionCount > 0 ) {
- $status->warning(
- wfMessage( 'undeleterevision-duplicate-revid', $failedRevisionCount ) );
- }
-
- // Was anything restored at all?
- if ( $restored ) {
- $created = (bool)$newid;
- // Attach the latest revision to the page...
- $wasnew = $article->updateIfNewerOn( $dbw, $revision );
- if ( $created || $wasnew ) {
- // Update site stats, link tables, etc
- $article->doEditUpdates(
- $revision,
- User::newFromName( $revision->getUserText( Revision::RAW ), false ),
- [
- 'created' => $created,
- 'oldcountable' => $oldcountable,
- 'restored' => true
- ]
- );
- }
-
- Hooks::run( 'ArticleUndelete', [ &$this->title, $created, $comment, $oldPageId ] );
- if ( $this->title->getNamespace() == NS_FILE ) {
- DeferredUpdates::addUpdate( new HTMLCacheUpdate( $this->title, 'imagelinks' ) );
- }
- }
-
- $dbw->endAtomic( __METHOD__ );
-
- return $status;
- }
-
- /**
- * @return Status
- */
- function getFileStatus() {
- return $this->fileStatus;
- }
-
- /**
- * @return Status
- */
- function getRevisionStatus() {
- return $this->revisionStatus;
- }
-}
+use Wikimedia\Rdbms\ResultWrapper;
/**
* Special page allowing users with the appropriate permissions to view
/** @var Title */
private $mTargetObj;
+ /**
+ * @var string Search prefix
+ */
+ private $mSearchPrefix;
function __construct() {
parent::__construct( 'Undelete', 'deletedhistory' );
function showSearchForm() {
$out = $this->getOutput();
$out->setPageTitle( $this->msg( 'undelete-search-title' ) );
- $out->addHTML(
- Xml::openElement( 'form', [ 'method' => 'get', 'action' => wfScript() ] ) .
- Xml::fieldset( $this->msg( 'undelete-search-box' )->text() ) .
+ $fuzzySearch = $this->getRequest()->getVal( 'fuzzy', true );
+
+ $out->enableOOUI();
+
+ $fields[] = new OOUI\ActionFieldLayout(
+ new OOUI\TextInputWidget( [
+ 'name' => 'prefix',
+ 'inputId' => 'prefix',
+ 'infusable' => true,
+ 'value' => $this->mSearchPrefix,
+ 'autofocus' => true,
+ ] ),
+ new OOUI\ButtonInputWidget( [
+ 'label' => $this->msg( 'undelete-search-submit' )->text(),
+ 'flags' => [ 'primary', 'progressive' ],
+ 'inputId' => 'searchUndelete',
+ 'type' => 'submit',
+ ] ),
+ [
+ 'label' => new OOUI\HtmlSnippet(
+ $this->msg(
+ $fuzzySearch ? 'undelete-search-full' : 'undelete-search-prefix'
+ )->parse()
+ ),
+ 'align' => 'left',
+ ]
+ );
+
+ $fieldset = new OOUI\FieldsetLayout( [
+ 'label' => $this->msg( 'undelete-search-box' )->text(),
+ 'items' => $fields,
+ ] );
+
+ $form = new OOUI\FormLayout( [
+ 'method' => 'get',
+ 'action' => wfScript(),
+ ] );
+
+ $form->appendContent(
+ $fieldset,
+ new OOUI\HtmlSnippet(
Html::hidden( 'title', $this->getPageTitle()->getPrefixedDBkey() ) .
- Html::rawElement(
- 'label',
- [ 'for' => 'prefix' ],
- $this->msg( 'undelete-search-prefix' )->parse()
- ) .
- Xml::input(
- 'prefix',
- 20,
- $this->mSearchPrefix,
- [ 'id' => 'prefix', 'autofocus' => '' ]
- ) . ' ' .
- Xml::submitButton( $this->msg( 'undelete-search-submit' )->text() ) .
- Xml::closeElement( 'fieldset' ) .
- Xml::closeElement( 'form' )
+ Html::hidden( 'fuzzy', $fuzzySearch )
+ )
+ );
+
+ $out->addHTML(
+ new OOUI\PanelLayout( [
+ 'expanded' => false,
+ 'padded' => true,
+ 'framed' => true,
+ 'content' => $form,
+ ] )
);
# List undeletable articles
if ( $this->mSearchPrefix ) {
- $result = PageArchive::listPagesByPrefix( $this->mSearchPrefix );
+ // For now, we enable search engine match only when specifically asked to
+ // by using fuzzy=1 parameter.
+ if ( $fuzzySearch ) {
+ $result = PageArchive::listPagesBySearch( $this->mSearchPrefix );
+ } else {
+ $result = PageArchive::listPagesByPrefix( $this->mSearchPrefix );
+ }
$this->showList( $result );
}
}
$linkRenderer = $this->getLinkRenderer();
$undelete = $this->getPageTitle();
- $out->addHTML( "<ul>\n" );
+ $out->addHTML( "<ul id='undeleteResultsList'>\n" );
foreach ( $result as $row ) {
$title = Title::makeTitleSafe( $row->ar_namespace, $row->ar_title );
if ( $title !== null ) {
);
}
$revs = $this->msg( 'undeleterevisions' )->numParams( $row->count )->parse();
- $out->addHTML( "<li>{$item} ({$revs})</li>\n" );
+ $out->addHTML( "<li class='undeleteResult'>{$item} ({$revs})</li>\n" );
}
$result->free();
$out->addHTML( "</ul>\n" );
$archive = new PageArchive( $this->mTargetObj, $this->getConfig() );
Hooks::run( 'UndeleteForm::showHistory', [ &$archive, $this->mTargetObj ] );
- /*
- $text = $archive->getLastRevisionText();
- if( is_null( $text ) ) {
- $out->addWikiMsg( 'nohistory' );
- return;
- }
- */
+
$out->addHTML( '<div class="mw-undelete-history">' );
if ( $this->mAllowed ) {
$out->addWikiMsg( 'undeletehistory' );
}
if ( $this->mAllowed ) {
+ $out->enableOOUI();
+
$action = $this->getPageTitle()->getLocalURL( [ 'action' => 'submit' ] );
# Start the form here
- $top = Xml::openElement(
- 'form',
- [ 'method' => 'post', 'action' => $action, 'id' => 'undelete' ]
- );
- $out->addHTML( $top );
+ $form = new OOUI\FormLayout( [
+ 'method' => 'post',
+ 'action' => $action,
+ 'id' => 'undelete',
+ ] );
}
# Show relevant lines from the deletion log:
}
if ( $this->mAllowed && ( $haveRevisions || $haveFiles ) ) {
- # Format the user-visible controls (comment field, submission button)
- # in a nice little table
+ $fields[] = new OOUI\Layout( [
+ 'content' => new OOUI\HtmlSnippet( $this->msg( 'undeleteextrahelp' )->parseAsBlock() )
+ ] );
+
+ $fields[] = new OOUI\FieldLayout(
+ new OOUI\TextInputWidget( [
+ 'name' => 'wpComment',
+ 'inputId' => 'wpComment',
+ 'infusable' => true,
+ 'value' => $this->mComment,
+ 'autofocus' => true,
+ ] ),
+ [
+ 'label' => $this->msg( 'undeletecomment' )->text(),
+ 'align' => 'top',
+ ]
+ );
+
+ $fields[] = new OOUI\FieldLayout(
+ new OOUI\Widget( [
+ 'content' => new OOUI\HorizontalLayout( [
+ 'items' => [
+ new OOUI\ButtonInputWidget( [
+ 'name' => 'restore',
+ 'inputId' => 'mw-undelete-submit',
+ 'value' => '1',
+ 'label' => $this->msg( 'undeletebtn' )->text(),
+ 'flags' => [ 'primary', 'progressive' ],
+ 'type' => 'submit',
+ ] ),
+ new OOUI\ButtonInputWidget( [
+ 'name' => 'invert',
+ 'inputId' => 'mw-undelete-invert',
+ 'value' => '1',
+ 'label' => $this->msg( 'undeleteinvert' )->text()
+ ] ),
+ ]
+ ] )
+ ] )
+ );
+
if ( $this->getUser()->isAllowed( 'suppressrevision' ) ) {
- $unsuppressBox =
- "<tr>
- <td> </td>
- <td class='mw-input'>" .
- Xml::checkLabel( $this->msg( 'revdelete-unsuppress' )->text(),
- 'wpUnsuppress', 'mw-undelete-unsuppress', $this->mUnsuppress ) .
- "</td>
- </tr>";
- } else {
- $unsuppressBox = '';
+ $fields[] = new OOUI\FieldLayout(
+ new OOUI\CheckboxInputWidget( [
+ 'name' => 'wpUnsuppress',
+ 'inputId' => 'mw-undelete-unsuppress',
+ 'value' => '1',
+ ] ),
+ [
+ 'label' => $this->msg( 'revdelete-unsuppress' )->text(),
+ 'align' => 'inline',
+ ]
+ );
}
- $table = Xml::fieldset( $this->msg( 'undelete-fieldset-title' )->text() ) .
- Xml::openElement( 'table', [ 'id' => 'mw-undelete-table' ] ) .
- "<tr>
- <td colspan='2' class='mw-undelete-extrahelp'>" .
- $this->msg( 'undeleteextrahelp' )->parseAsBlock() .
- "</td>
- </tr>
- <tr>
- <td class='mw-label'>" .
- Xml::label( $this->msg( 'undeletecomment' )->text(), 'wpComment' ) .
- "</td>
- <td class='mw-input'>" .
- Xml::input(
- 'wpComment',
- 50,
- $this->mComment,
- [ 'id' => 'wpComment', 'autofocus' => '' ]
- ) .
- "</td>
- </tr>
- <tr>
- <td> </td>
- <td class='mw-submit'>" .
- Xml::submitButton(
- $this->msg( 'undeletebtn' )->text(),
- [ 'name' => 'restore', 'id' => 'mw-undelete-submit' ]
- ) . ' ' .
- Xml::submitButton(
- $this->msg( 'undeleteinvert' )->text(),
- [ 'name' => 'invert', 'id' => 'mw-undelete-invert' ]
- ) .
- "</td>
- </tr>" .
- $unsuppressBox .
- Xml::closeElement( 'table' ) .
- Xml::closeElement( 'fieldset' );
-
- $out->addHTML( $table );
+ $fieldset = new OOUI\FieldsetLayout( [
+ 'label' => $this->msg( 'undelete-fieldset-title' )->text(),
+ 'id' => 'mw-undelete-table',
+ 'items' => $fields,
+ ] );
+
+ $form->appendContent(
+ new OOUI\PanelLayout( [
+ 'expanded' => false,
+ 'padded' => true,
+ 'framed' => true,
+ 'content' => $fieldset,
+ ] ),
+ new OOUI\HtmlSnippet(
+ Html::hidden( 'target', $this->mTarget ) .
+ Html::hidden( 'wpEditToken', $this->getUser()->getEditToken() )
+ )
+ );
}
- $out->addHTML( Xml::element( 'h2', null, $this->msg( 'history' )->text() ) . "\n" );
+ $history = '';
+ $history .= Xml::element( 'h2', null, $this->msg( 'history' )->text() ) . "\n";
if ( $haveRevisions ) {
# Show the page's stored (deleted) history
if ( $this->getUser()->isAllowed( 'deleterevision' ) ) {
- $out->addHTML( Html::element(
+ $history .= Html::element(
'button',
[
'name' => 'revdel',
'class' => 'deleterevision-log-submit mw-log-deleterevision-button'
],
$this->msg( 'showhideselectedversions' )->text()
- ) . "\n" );
+ ) . "\n";
}
- $out->addHTML( '<ul>' );
+ $history .= '<ul class="mw-undelete-revlist">';
$remaining = $revisions->numRows();
$earliestLiveTime = $this->mTargetObj->getEarliestRevTime();
foreach ( $revisions as $row ) {
$remaining--;
- $out->addHTML( $this->formatRevisionRow( $row, $earliestLiveTime, $remaining ) );
+ $history .= $this->formatRevisionRow( $row, $earliestLiveTime, $remaining );
}
$revisions->free();
- $out->addHTML( '</ul>' );
+ $history .= '</ul>';
} else {
$out->addWikiMsg( 'nohistory' );
}
if ( $haveFiles ) {
- $out->addHTML( Xml::element( 'h2', null, $this->msg( 'filehist' )->text() ) . "\n" );
- $out->addHTML( '<ul>' );
+ $history .= Xml::element( 'h2', null, $this->msg( 'filehist' )->text() ) . "\n";
+ $history .= '<ul class="mw-undelete-revlist">';
foreach ( $files as $row ) {
- $out->addHTML( $this->formatFileRow( $row ) );
+ $history .= $this->formatFileRow( $row );
}
$files->free();
- $out->addHTML( '</ul>' );
+ $history .= '</ul>';
}
if ( $this->mAllowed ) {
# Slip in the hidden controls here
$misc = Html::hidden( 'target', $this->mTarget );
$misc .= Html::hidden( 'wpEditToken', $this->getUser()->getEditToken() );
- $misc .= Xml::closeElement( 'form' );
- $out->addHTML( $misc );
+ $history .= $misc;
+
+ $form->appendContent( new OOUI\HtmlSnippet( $history ) );
+ $out->addHTML( $form );
+ } else {
+ $out->addHTML( $history );
}
return true;
// Show revision undeletion warnings and errors
$status = $archive->getRevisionStatus();
if ( $status && !$status->isGood() ) {
- $out->wrapWikiMsg(
- "<div class=\"error\" id=\"mw-error-cannotundelete\">\n$1\n</div>",
- 'cannotundelete'
+ $out->addWikiText( '<div class="error" id="mw-error-cannotundelete">' .
+ $status->getWikiText(
+ 'cannotundelete',
+ 'cannotundelete'
+ ) . '</div>'
);
}