Alex Monk has uploaded a new change for review.

  https://gerrit.wikimedia.org/r/323357

Change subject: [WIP] Undo support
......................................................................

[WIP] Undo support

TODO:
* Inline VE API TODOs
* Check revision deletion? (see EditPage) - may already effectively be handled
* Check content models (see EditPage) - possibly OK to revert non-wikitext
  change, as long as *resulting* revision is wikitext?
* nochange case where newContent=oldContent? probably need to set
  fromEditedState on the server (see EditPage)
* Auto-summary (see EditPage)
* Open save dialog in review mode

Bug: T78550
Change-Id: Ic8b13b6bb129a46934c5ea31c944e3db78fff828
---
M ApiVisualEditor.php
M VisualEditor.hooks.php
M modules/ve-mw/init/targets/ve.init.mw.DesktopArticleTarget.init.js
M modules/ve-mw/init/ve.init.mw.ArticleTarget.js
M modules/ve-mw/init/ve.init.mw.ArticleTargetLoader.js
5 files changed, 77 insertions(+), 24 deletions(-)


  git pull ssh://gerrit.wikimedia.org:29418/mediawiki/extensions/VisualEditor 
refs/changes/57/323357/1

diff --git a/ApiVisualEditor.php b/ApiVisualEditor.php
index 0ff5f49..30c20c7 100644
--- a/ApiVisualEditor.php
+++ b/ApiVisualEditor.php
@@ -219,20 +219,32 @@
                                        $baseTimestamp = 
$latestRevision->getTimestamp();
                                        $oldid = intval( $parserParams['oldid'] 
);
 
+                                       $fetchRevs = [ $oldid ];
+
+                                       $undo = intval( $params['undo'] );
+                                       $undoafter = intval( 
$params['undoafter'] );
+                                       if ( $undo > 0 && $undoafter > 0 ) {
+                                               // TODO: current rev rather 
than oldid here? below too
+                                               $fetchRevs = array_values( 
array_unique( [ $oldid, $undo, $undoafter ] ) );
+                                       }
+                                       $revContents = [];
+
                                        // If requested, request HTML from 
Parsoid/RESTBase
                                        if ( $params['paction'] === 'parse' ) {
-                                               $content = 
$this->requestRestbase(
-                                                       'GET',
-                                                       'page/html/' . 
urlencode( $title->getPrefixedDBkey() ) . '/' . $oldid . '?redirect=false',
-                                                       []
-                                               );
-                                               if ( $content === false ) {
-                                                       $this->dieUsage( 'Error 
contacting the document server', 'docserver' );
+                                               foreach ( $fetchRevs as $rev ) {
+                                                       $revContents[$rev] = 
$this->requestRestbase(
+                                                               'GET',
+                                                               'page/html/' . 
urlencode( $title->getPrefixedDBkey() ) . '/' . $rev . '?redirect=false',
+                                                               []
+                                                       );
+                                                       if ( $revContents[$rev] 
=== false ) {
+                                                               
$this->dieUsage( 'Error contacting the document server to fetch revision ' . 
$rev, 'docserver' );
+                                                       }
                                                }
                                        } elseif ( $params['paction'] === 
'wikitext' ) {
                                                $apiParams = [
                                                        'action' => 'query',
-                                                       'revids' => $oldid,
+                                                       'revids' => implode( 
'|', $fetchRevs ),
                                                        'prop' => 'revisions',
                                                        'rvprop' => 
'content|ids'
                                                ];
@@ -252,19 +264,45 @@
                                                $api->execute();
                                                $result = 
$api->getResult()->getResultData();
                                                $pid = $title->getArticleID();
-                                               $content = false;
+                                               foreach ( $fetchRevs as $rev ) {
+                                                       $revContents[$rev] = 
false;
+                                               }
                                                if ( isset( 
$result['query']['pages'][$pid]['revisions'] ) ) {
                                                        foreach ( 
$result['query']['pages'][$pid]['revisions'] as $revArr ) {
-                                                               if ( 
$revArr['revid'] === $oldid ) {
-                                                                       
$content = $revArr['content'];
-                                                               }
+                                                               
$revContents[$revArr['revid']] = $revArr['content'];
                                                        }
                                                }
-                                               if ( $content === false ) {
-                                                       $this->dieUsage( 'Error 
contacting the document server', 'docserver' );
+                                               foreach ( $fetchRevs as 
$checkRev ) {
+                                                       if ( 
$revContents[$checkRev] === false ) {
+                                                               
$this->dieUsage( 'Error contacting the document server to fetch revision ' . 
$checkRev, 'docserver' );
+                                                       }
                                                }
                                        }
 
+                                       if ( in_array( $params['paction'], 
['parse', 'wikitext'] ) ) {
+                                               if ( $undo > 0 && $undoafter > 
0 ) {
+                                                       // merge
+                                                       if ( 
$revContents[$oldid] == $revContents[$undo] ) {
+                                                               $content = 
$revContents[$undoafter];
+                                                       } else {
+                                                               $ok = wfMerge(
+                                                                       
$revContents[$undo],
+                                                                       
$revContents[$undoafter],
+                                                                       
$revContents[$oldid],
+                                                                       $result
+                                                               );
+
+                                                               if ( !$ok ) {
+                                                                       // 
TODO: error
+                                                                       
wfDebugLog( 'debug', '297' );
+                                                               }
+
+                                                               $content = 
$result;
+                                                       }
+                                               } else {
+                                                       $content = 
$revContents[$oldid];
+                                               }
+                                       }
                                } else {
                                        $content = '';
                                        Hooks::run( 'EditFormPreloadText', [ 
&$content, &$title ] );
@@ -594,6 +632,8 @@
                        'section' => null,
                        'oldid' => null,
                        'pst' => false,
+                       'undo' => null,
+                       'undoafter' => null
                ];
        }
 
diff --git a/VisualEditor.hooks.php b/VisualEditor.hooks.php
index 332bcc2..b72ae12 100644
--- a/VisualEditor.hooks.php
+++ b/VisualEditor.hooks.php
@@ -150,8 +150,6 @@
                        !ApiVisualEditor::isAllowedContentType( $veConfig, 
$title->getContentModel() ) ||
                        // Known parameters that VE does not handle
                        // TODO: Other params too? See identical list in 
ve.init.mw.DesktopArticleTarget.init.js
-                       isset( $params['undo'] ) ||
-                       isset( $params['undoafter'] ) ||
                        isset( $params['editintro'] ) ||
                        isset( $params['preload'] ) ||
                        isset( $params['preloadtitle'] ) ||
diff --git a/modules/ve-mw/init/targets/ve.init.mw.DesktopArticleTarget.init.js 
b/modules/ve-mw/init/targets/ve.init.mw.DesktopArticleTarget.init.js
index 64a1ccf..19d7d02 100644
--- a/modules/ve-mw/init/targets/ve.init.mw.DesktopArticleTarget.init.js
+++ b/modules/ve-mw/init/targets/ve.init.mw.DesktopArticleTarget.init.js
@@ -813,8 +813,6 @@
                if ( init.isAvailable ) {
                        // Load the editor …
                        if (
-                               uri.query.undo === undefined &&
-                               uri.query.undoafter === undefined &&
                                uri.query.editintro === undefined &&
                                uri.query.preload === undefined &&
                                uri.query.preloadtitle === undefined &&
diff --git a/modules/ve-mw/init/ve.init.mw.ArticleTarget.js 
b/modules/ve-mw/init/ve.init.mw.ArticleTarget.js
index 4ac09f4..cd0e0af 100644
--- a/modules/ve-mw/init/ve.init.mw.ArticleTarget.js
+++ b/modules/ve-mw/init/ve.init.mw.ArticleTarget.js
@@ -275,7 +275,10 @@
                                docRevId = parseInt( docRevIdMatches[ 1 ] );
                        }
                }
-               if ( docRevId && docRevId !== this.revid ) {
+               // We check fromEditedState here because when we're undoing a 
revision,
+               // we're going to expect to be editing a revision different 
from the
+               // current one and the easiest way to check this is 
fromEditedState.
+               if ( docRevId && docRevId !== this.revid && 
!this.fromEditedState ) {
                        if ( this.retriedRevIdConflict ) {
                                // Retried already, just error the second time.
                                this.loadFail(
diff --git a/modules/ve-mw/init/ve.init.mw.ArticleTargetLoader.js 
b/modules/ve-mw/init/ve.init.mw.ArticleTargetLoader.js
index 8b62bd9..d3071cf 100644
--- a/modules/ve-mw/init/ve.init.mw.ArticleTargetLoader.js
+++ b/modules/ve-mw/init/ve.init.mw.ArticleTargetLoader.js
@@ -126,11 +126,18 @@
                        var start, apiXhr, restbaseXhr, apiPromise, 
restbasePromise, dataPromise, pageHtmlUrl, headers,
                                switched = false,
                                fromEditedState = false,
+                               undoing = (
+                                       mw.util.getParamValue( 'undo' ) > 0 &&
+                                       mw.util.getParamValue( 'undoafter' ) > 0
+                               ),
+                               canContactRESTBase = ( !undoing && ( 
conf.fullRestbaseUrl || conf.restbaseUrl ) ),
                                data = {
                                        action: 'visualeditor',
-                                       paction: ( conf.fullRestbaseUrl || 
conf.restbaseUrl ) ? 'metadata' : 'parse',
+                                       paction: canContactRESTBase ? 
'metadata' : 'parse',
                                        page: pageName,
-                                       uselang: mw.config.get( 
'wgUserLanguage' )
+                                       uselang: mw.config.get( 
'wgUserLanguage' ),
+                                       undo: mw.util.getParamValue( 'undo' ),
+                                       undoafter: mw.util.getParamValue( 
'undoafter' )
                                };
 
                        // Only request the API to explicitly load the 
currently visible revision if we're restoring
@@ -156,7 +163,7 @@
                                return data;
                        } );
 
-                       if ( conf.fullRestbaseUrl || conf.restbaseUrl ) {
+                       if ( canContactRESTBase ) {
                                ve.track( 'trace.restbaseLoad.enter' );
 
                                // Should be synchronised with 
ApiVisualEditor.php
@@ -238,7 +245,12 @@
                                                restbaseXhr.abort();
                                        } } );
                        } else {
-                               dataPromise = apiPromise.promise( { abort: 
apiXhr.abort } );
+                               dataPromise = apiPromise.then( function ( data 
) {
+                                       if ( data.visualeditor && undoing ) {
+                                               
data.visualeditor.fromEditedState = true;
+                                       }
+                                       return data;
+                               } ).promise( { abort: apiXhr.abort } );
                        }
 
                        return dataPromise;
@@ -249,7 +261,9 @@
                                action: 'visualeditor',
                                paction: 'wikitext',
                                page: pageName,
-                               uselang: mw.config.get( 'wgUserLanguage' )
+                               uselang: mw.config.get( 'wgUserLanguage' ),
+                               undo: mw.util.getParamValue( 'undo' ),
+                               undoafter: mw.util.getParamValue( 'undoafter' )
                        };
 
                        // section should never really be undefined, but check 
just in case

-- 
To view, visit https://gerrit.wikimedia.org/r/323357
To unsubscribe, visit https://gerrit.wikimedia.org/r/settings

Gerrit-MessageType: newchange
Gerrit-Change-Id: Ic8b13b6bb129a46934c5ea31c944e3db78fff828
Gerrit-PatchSet: 1
Gerrit-Project: mediawiki/extensions/VisualEditor
Gerrit-Branch: master
Gerrit-Owner: Alex Monk <[email protected]>

_______________________________________________
MediaWiki-commits mailing list
[email protected]
https://lists.wikimedia.org/mailman/listinfo/mediawiki-commits

Reply via email to