Introduce visual differ in the save dialog

Bug: T143350
Change-Id: I1297d0f4bb87e69be3b50220c1830a22dac1bbae
This commit is contained in:
Ed Sanders 2016-10-31 17:17:50 +00:00
parent a3a4ff3d20
commit 335b56728a
8 changed files with 173 additions and 15 deletions

View file

@ -403,7 +403,8 @@
"modules/ve-mw/ui/tools/ve.ui.MWMobileLinkInspectorTool.js"
],
"styles": [
"modules/ve-mw/init/styles/ve.init.mw.MobileArticleTarget.css"
"modules/ve-mw/init/styles/ve.init.mw.MobileArticleTarget.css",
"modules/ve-mw/ui/styles/dialogs/ve.ui.MWMobileSaveDialog.css"
],
"dependencies": [
"ext.visualEditor.base",
@ -513,7 +514,8 @@
"ext.visualEditor.mediawiki",
"ext.visualEditor.core",
"ext.visualEditor.mwcore",
"ext.visualEditor.mwextensions"
"ext.visualEditor.mwextensions",
"oojs-ui.styles.icons-alerts"
],
"messages": [
"accesskey-diff",
@ -1283,6 +1285,9 @@
"visualeditor-savedialog-label-review-good",
"visualeditor-savedialog-label-save-short",
"visualeditor-savedialog-label-warning",
"visualeditor-savedialog-review-nosummary",
"visualeditor-savedialog-review-visual",
"visualeditor-savedialog-review-wikitext",
"visualeditor-savedialog-title-conflict",
"visualeditor-savedialog-title-nochanges",
"visualeditor-savedialog-title-preview",
@ -1318,6 +1323,7 @@
"ext.visualEditor.mwtransclusion",
"ext.visualEditor.mwgallery",
"ext.visualEditor.mwalienextension",
"ext.visualEditor.diffing",
"ext.visualEditor.language",
"ext.visualEditor.icons"
],
@ -1732,6 +1738,56 @@
"mobile"
]
},
"treeDiffer": {
"scripts": [
"lib/ve/lib/treeDiffer/treeDiffer-dist.js"
],
"targets": [
"desktop",
"mobile"
]
},
"diffMatchPatch": {
"scripts": [
"lib/ve/lib/diff-match-patch/diff_match_patch_uncompressed.js"
],
"targets": [
"desktop",
"mobile"
]
},
"ext.visualEditor.diffing": {
"debugScripts": [
"lib/ve/src/ve.DiffTreeNode.js",
"lib/ve/src/ve.DiffMatchPatch.js",
"lib/ve/src/dm/ve.dm.VisualDiff.js",
"lib/ve/src/ui/elements/ve.ui.DiffElement.js",
"lib/ve/src/ui/widgets/ve.ui.ChangeDescriptionsSelectWidget.js"
],
"styles": [
"lib/ve/src/ui/styles/elements/ve.ui.DiffElement.css"
],
"dependencies": [
"ext.visualEditor.core",
"treeDiffer",
"diffMatchPatch"
],
"messages": [
"visualeditor-changedesc-changed",
"visualeditor-changedesc-image-size",
"visualeditor-changedesc-language",
"visualeditor-changedesc-link-href",
"visualeditor-changedesc-no-key",
"visualeditor-changedesc-set",
"visualeditor-changedesc-unknown",
"visualeditor-changedesc-unset",
"visualeditor-diff-no-changes"
],
"targets": [
"desktop",
"mobile"
]
},
"ext.visualEditor.language": {
"scripts": [
"lib/ve/src/dm/annotations/ve.dm.LanguageAnnotation.js",

View file

@ -359,6 +359,9 @@
"visualeditor-savedialog-label-review-good": "Return to save form",
"visualeditor-savedialog-label-save-short": "Save",
"visualeditor-savedialog-label-warning": "Warning",
"visualeditor-savedialog-review-nosummary": "No edit summary",
"visualeditor-savedialog-review-visual": "Visual",
"visualeditor-savedialog-review-wikitext": "Wikitext",
"visualeditor-savedialog-title-conflict": "Conflict",
"visualeditor-savedialog-title-nochanges": "No changes to review",
"visualeditor-savedialog-title-preview": "Preview your changes",

View file

@ -372,6 +372,9 @@
"visualeditor-savedialog-label-review-good": "Label for button to go back to a page in order to save form",
"visualeditor-savedialog-label-save-short": "Short label text for save button on private wikis for use on width-restricted devices like mobile phones. This should be as short as possible.\n{{Identical|Save}}",
"visualeditor-savedialog-label-warning": "Label in front of a save dialog warning sentence, separated by {{msg-mw|colon-separator}}.\n{{Identical|Warning}}",
"visualeditor-savedialog-review-nosummary": "Message shown when no edit summary was provided.",
"visualeditor-savedialog-review-visual": "Label for button to select visual diff mode.",
"visualeditor-savedialog-review-wikitext": "Label for button to select wikitext diff mode.",
"visualeditor-savedialog-title-conflict": "Title for save dialog slide if there is an edit conflict\n{{Identical|Conflict}}",
"visualeditor-savedialog-title-nochanges": "Title for save dialog slide for the wikitext diff if there are no changes",
"visualeditor-savedialog-title-preview": "Title for save dialog slide for the HTML preview from wikitext mode",

View file

@ -35,6 +35,7 @@ ve.init.mw.ArticleTarget = function VeInitMwArticleTarget( pageName, revisionId,
this.saveDeferred = null;
this.captcha = null;
this.docToSave = null;
this.originalDmDoc = null;
this.toolbarSaveButton = null;
this.pageName = pageName;
this.pageExists = mw.config.get( 'wgRelevantArticleId', 0 ) !== 0;
@ -743,7 +744,7 @@ ve.init.mw.ArticleTarget.prototype.showChangesDiff = function ( diffHtml ) {
this.getSurface().getModel().getDocument().once( 'transact',
this.saveDialog.clearDiff.bind( this.saveDialog )
);
this.saveDialog.setDiffAndReview( diffHtml );
this.saveDialog.setDiffAndReview( diffHtml, this.getVisualDiff() );
};
/**
@ -1066,7 +1067,7 @@ ve.init.mw.ArticleTarget.prototype.serializeFail = function () {
* @fires saveReview
*/
ve.init.mw.ArticleTarget.prototype.onSaveDialogReview = function () {
if ( !this.saveDialog.$reviewViewer.find( 'table, pre' ).length ) {
if ( !this.saveDialog.hasDiff ) {
this.emit( 'saveReview' );
this.saveDialog.getActions().setAbilities( { approve: false } );
this.saveDialog.pushPending();
@ -1153,7 +1154,24 @@ ve.init.mw.ArticleTarget.prototype.bindSaveDialogClearDiff = function () {
*/
ve.init.mw.ArticleTarget.prototype.onSaveDialogReviewComplete = function ( wikitext ) {
this.bindSaveDialogClearDiff();
this.saveDialog.setDiffAndReview( $( '<pre>' ).text( wikitext ) );
this.saveDialog.setDiffAndReview( $( '<pre>' ).text( wikitext ), this.getVisualDiff() );
};
/**
* Get a visual diff object for the current document state
*
* @return {ve.dm.VisualDiff|null} Visual diff, or null if not known
*/
ve.init.mw.ArticleTarget.prototype.getVisualDiff = function () {
if ( this.getSurface().getMode() === 'source' ) {
return null;
}
if ( !this.originalDmDoc ) {
// TODO: If switching from source - we need to fetch the original doc
// from the server.
this.originalDmDoc = this.createModelFromDom( this.doc, 'visual' );
}
return new ve.dm.VisualDiff( this.originalDmDoc, this.getSurface().getModel().getDocument() );
};
/**
@ -1250,6 +1268,7 @@ ve.init.mw.ArticleTarget.prototype.clearState = function () {
this.startTimeStamp = null;
this.checkboxes = null;
this.doc = null;
this.originalDmDoc = null;
this.originalHtml = null;
this.section = null;
this.editNotices = [];

View file

@ -29,6 +29,18 @@ ve.ui.MWMobileSaveDialog = function VeUiMwMobileSaveDialog() {
OO.inheritClass( ve.ui.MWMobileSaveDialog, ve.ui.MWSaveDialog );
/* Methods */
/**
* @inheritdoc
*/
ve.ui.MWMobileSaveDialog.prototype.initialize = function () {
// Parent method
ve.ui.MWMobileSaveDialog.super.prototype.initialize.call( this );
this.$reviewVisualDiff.addClass( 'content' );
};
/* Registration */
ve.ui.windowFactory.register( ve.ui.MWMobileSaveDialog );

View file

@ -30,6 +30,7 @@ ve.ui.MWSaveDialog = function VeUiMwSaveDialog( config ) {
this.changedEditSummary = false;
this.canReview = false;
this.canPreview = false;
this.hasDiff = false;
// Initialization
this.$element.addClass( 've-ui-mwSaveDialog' );
@ -117,11 +118,27 @@ ve.ui.MWSaveDialog.static.actions = [
/**
* Set review content and show review panel.
*
* @param {string} content Diff HTML or wikitext
* @param {string} wikitextDiff Diff HTML or wikitext
* @param {ve.dm.VisualDiff} [visualDiff] Visual diff
*/
ve.ui.MWSaveDialog.prototype.setDiffAndReview = function ( content ) {
this.$reviewViewer.empty().append( content );
ve.ui.MWSaveDialog.prototype.setDiffAndReview = function ( wikitextDiff, visualDiff ) {
this.$reviewVisualDiff.empty();
if ( visualDiff ) {
this.diffElement = new ve.ui.DiffElement( visualDiff );
this.diffElement.$document.addClass( 'mw-body-content' );
// TODO: Remove when fixed upstream in Parsoid (T58756)
this.diffElement.$element.find( 'a[rel="mw:ExtLink"]' ).addClass( 'external' );
this.$reviewVisualDiff.append( this.diffElement.$element );
this.reviewModeButtonSelect.getItemFromData( 'visual' ).setDisabled( false );
} else {
// TODO: Support visual diffs in source mode (epic)
this.reviewModeButtonSelect.getItemFromData( 'visual' ).setDisabled( true );
this.reviewModeButtonSelect.selectItemByData( 'source' );
}
this.$reviewWikitextDiff.empty().append( wikitextDiff );
this.actions.setAbilities( { approve: true } );
this.hasDiff = true;
this.popPending();
this.swapPanel( 'review' );
};
@ -164,8 +181,9 @@ ve.ui.MWSaveDialog.prototype.popPending = function () {
* Clear the diff displayed in the review panel, if any.
*/
ve.ui.MWSaveDialog.prototype.clearDiff = function () {
this.$reviewViewer.empty();
this.$reviewWikitextDiff.empty();
this.$previewViewer.empty();
this.hasDiff = false;
};
/**
@ -173,7 +191,6 @@ ve.ui.MWSaveDialog.prototype.clearDiff = function () {
*
* @param {string} panel One of 'save', 'review', 'conflict' or 'nochanges'
* @param {boolean} [noFocus] Don't attempt to focus anything (e.g. while setting up)
* @return {jQuery} The now active panel
* @throws {Error} Unknown saveDialog panel
*/
ve.ui.MWSaveDialog.prototype.swapPanel = function ( panel, noFocus ) {
@ -233,7 +250,7 @@ ve.ui.MWSaveDialog.prototype.swapPanel = function ( panel, noFocus ) {
if ( !currentEditSummaryWikitext || currentEditSummaryWikitext.trim() === '' ) {
// Don't bother with an API request for an empty summary
this.$reviewEditSummary.parent().addClass( 'oo-ui-element-hidden' );
this.$reviewEditSummary.text( ve.msg( 'visualeditor-savedialog-review-nosummary' ) );
} else {
this.$reviewEditSummary.parent()
.removeClass( 'oo-ui-element-hidden' )
@ -256,6 +273,9 @@ ve.ui.MWSaveDialog.prototype.swapPanel = function ( panel, noFocus ) {
} );
}
}
setTimeout( function () {
dialog.updateReviewMode();
} );
break;
case 'nochanges':
mode = 'review';
@ -280,8 +300,6 @@ ve.ui.MWSaveDialog.prototype.swapPanel = function ( panel, noFocus ) {
} );
mw.hook( 've.saveDialog.stateChanged' ).fire();
return dialog;
};
/**
@ -483,15 +501,31 @@ ve.ui.MWSaveDialog.prototype.initialize = function () {
scrollable: true,
padded: true
} );
this.$reviewViewer = $( '<div>' ).addClass( 've-ui-mwSaveDialog-viewer' );
this.$reviewVisualDiff = $( '<div>' ).addClass( 've-ui-mwSaveDialog-viewer' );
this.$reviewWikitextDiff = $( '<div>' ).addClass( 've-ui-mwSaveDialog-viewer' );
this.reviewModeButtonSelect = new OO.ui.ButtonSelectWidget( {
items: [
new OO.ui.ButtonOptionWidget( { data: 'visual', icon: 'eye', label: ve.msg( 'visualeditor-savedialog-review-visual' ) } ),
new OO.ui.ButtonOptionWidget( { data: 'source', icon: 'wikiText', label: ve.msg( 'visualeditor-savedialog-review-wikitext' ) } )
],
classes: [ 've-ui-mwSaveDialog-reviewMode' ]
} );
this.reviewModeButtonSelect.connect( this, { select: 'updateReviewMode' } );
// TODO: Make 'visual' the default
this.reviewModeButtonSelect.selectItemByData( 'source' );
this.$reviewEditSummary = $( '<span>' ).addClass( 've-ui-mwSaveDialog-summaryPreview' ).addClass( 'comment' );
this.$reviewActions = $( '<div>' ).addClass( 've-ui-mwSaveDialog-actions' );
this.reviewPanel.$element.append(
this.reviewModeButtonSelect.$element,
$( '<div>' )
.addClass( 'mw-summary-preview' )
.text( ve.msg( 'summary-preview' ) )
.append( $( '<br>' ), this.$reviewEditSummary ),
this.$reviewViewer,
this.$reviewVisualDiff,
this.$reviewWikitextDiff,
this.$reviewActions
);
@ -552,6 +586,17 @@ ve.ui.MWSaveDialog.prototype.initialize = function () {
this.setupDeferred.resolve();
};
ve.ui.MWSaveDialog.prototype.updateReviewMode = function () {
var isVisual = this.reviewModeButtonSelect.getSelectedItem().getData() === 'visual';
this.$reviewVisualDiff.toggleClass( 'oo-ui-element-hidden', !isVisual );
this.$reviewWikitextDiff.toggleClass( 'oo-ui-element-hidden', isVisual );
this.updateSize();
if ( isVisual ) {
this.diffElement.positionDescriptions();
this.updateSize();
}
};
/**
* @inheritdoc
* @param {Object} [data]

View file

@ -0,0 +1,10 @@
/*!
* VisualEditor MediaWiki UserInterface MWMobileSaveDialog styles.
*
* @copyright 2011-2017 VisualEditor Team and others; see AUTHORS.txt
* @license The MIT License (MIT); see LICENSE.txt
*/
.ve-ui-mwMobileSaveDialog .content {
margin: 0;
}

View file

@ -74,3 +74,13 @@
.ve-ui-mwSaveDialog-messages:empty {
display: none;
}
.ve-ui-mwSaveDialog-reviewMode {
float: right;
margin: 0 0 0 1em;
}
.ve-ui-mwSaveDialog-viewer {
margin-top: 1em;
clear: both;
}