mw.ViewPageTarget: Make 'review' step optional in save flow

Summary:

Instead of having a button "Review and save" that opens with a
diff and leads the user to the "Report a bug" and "Save page"
slides respectively, make it more like the default EditPage.

There is now a "Save page" button that opens with the save
form with a button to "Review changes" (diff) or "Save page".

The "Report a bug" slide has been unlinked from the UI and is
no longer accessible for now.

As a result of the UI no longer requesting a diff upfront this
also means we will no longer detect "nochanges" event (when it
turns out the submittted revision matches the latest version).

This is unfortunate as it was a nice feature to detect it
before the user spends time writing the edit summary) but it
is the same as how the default EditPage works.

Changes:

Improved interface messages.

Adapted "nochanges" caption to the new context (it is no
longer shown when clicking "Save page", it is now shown as a
result of clicking "Show changes").

Now that the "save" slide is accessible from multiple paths
it is needed to keep track of slide changes in a history
array. Previously the slide tree was 1 level deep with
everything descending from "review". Now it starts at "save"
and can go in multiple directions including a loop from
save>review>save. We also need to toggle the "Prev" button
based on history instead of based on whether or not we are
on the "first" slide.

Hid the "saveDialogReviewWrongButton" from the review slide.
We're approaching wider launches and this will not scale to
a wider audience.

Bug: 49258
Change-Id: I90de95f6337eeddd794b75d56543d8d152421a6f
This commit is contained in:
Timo Tijhof 2013-06-07 21:00:38 +02:00
parent 5aac2f756c
commit d5868a0f13
3 changed files with 89 additions and 53 deletions

View file

@ -37,18 +37,19 @@ $messages['en'] = array(
'visualeditor-dialog-action-cancel' => 'Cancel',
'visualeditor-dialog-action-close' => 'Close',
'visualeditor-toolbar-cancel' => 'Cancel',
'visualeditor-toolbar-savedialog' => 'Review and save',
'visualeditor-toolbar-savedialog' => 'Save page',
'visualeditor-savedialog-title-conflict' => 'Conflict',
'visualeditor-savedialog-title-nochanges' => 'No changes',
'visualeditor-savedialog-title-review' => 'Review your changes',
'visualeditor-savedialog-title-report' => 'Report a problem',
'visualeditor-savedialog-title-report' => 'Report a problem with the editing system',
'visualeditor-savedialog-title-save' => 'Save your changes',
'visualeditor-savedialog-label-review-wrong' => 'Something is wrong',
'visualeditor-savedialog-label-review-good' => 'Looks good to me',
'visualeditor-savedialog-label-review-wrong' => 'Report a bug',
'visualeditor-savedialog-label-review-good' => 'Return to save form',
'visualeditor-savedialog-label-report' => 'Report problem',
'visualeditor-savedialog-label-resolve-conflict' => 'Resolve conflict',
'visualeditor-savedialog-label-create' => 'Create page',
'visualeditor-savedialog-label-save' => 'Save page',
'visualeditor-savedialog-label-review' => 'Review your changes',
'visualeditor-savedialog-label-restore' => 'Restore page',
'visualeditor-editnotices-tool' => '$1 {{PLURAL:$1|notice|notices}}',
'visualeditor-feedback-tool' => 'Leave feedback',
@ -105,7 +106,7 @@ $messages['en'] = array(
'visualeditor-saveerror' => 'Error saving data to server: $1.',
'visualeditor-editconflict' => 'Your changes could not be saved because of an edit conflict. Would you like to resolve the conflict manually?',
'visualeditor-editsummary' => 'Describe what you changed',
'visualeditor-problem' => 'Describe what went wrong',
'visualeditor-problem' => 'Describe what went wrong with the wikitext serialization',
'visualeditor-aliennode-tooltip' => 'Sorry, this element cannot be edited using the VisualEditor',
'visualeditor-descriptionpagelink' => 'Project:VisualEditor',
'visualeditor-alphawarning' => 'You are using an alpha version of the [[{{MediaWiki:Visualeditor-descriptionpagelink}}|VisualEditor]]. It may be slow and make erroneous changes—please check each edit that you make.',
@ -113,7 +114,7 @@ $messages['en'] = array(
'visualeditor-report-notice' => 'I understand that by clicking "Report problem" I will transmit my changes and my feedback, which will be stored for analysis. I agree to provide feedback in accordance with the [[{{MediaWiki:Visualeditor-report-link}}|Terms of Use]].',
'visualeditor-report-link' => 'foundation:Terms of Use',
'visualeditor-feedback-link' => 'Project:VisualEditor/Feedback',
'visualeditor-diff-nochanges' => 'Your edit has been ignored because you have made no changes to the text.',
'visualeditor-diff-nochanges' => 'Could not start the review because your revision matches the latest version of this page.',
);
/** Message documentation (Message documentation)
@ -183,19 +184,21 @@ See also:
{{Identical|Close}}',
'visualeditor-toolbar-cancel' => 'Label text for button to cancel editing in the VisualEditor
{{Identical|Close}}',
'visualeditor-toolbar-savedialog' => 'Label text for button to trigger review and save interface',
'visualeditor-toolbar-savedialog' => 'Label text for button to open save dialog
{{Identical|Savearticle}}',
'visualeditor-savedialog-title-conflict' => 'Title for edit conflict slide',
'visualeditor-savedialog-title-nochanges' => 'Title for no changes slide',
'visualeditor-savedialog-title-review' => 'Title for reviewing slide',
'visualeditor-savedialog-title-report' => 'Title for reporting slide',
'visualeditor-savedialog-title-save' => 'Title for saving slide',
'visualeditor-savedialog-label-review-wrong' => 'Label for button to trigger report dialog',
'visualeditor-savedialog-label-review-good' => 'Label for button to progress to save dialog',
'visualeditor-savedialog-label-review-good' => 'Label for button to go back to the save form',
'visualeditor-savedialog-label-report' => 'Label for button to trigger report',
'visualeditor-savedialog-label-resolve-conflict' => 'Label for button to start resoliving an edit conflict',
'visualeditor-savedialog-label-create' => 'Label text for save button when the user is creating a new page',
'visualeditor-savedialog-label-save' => 'Label text for save button when the user is editing a current revision of an extant page.
{{Identical|Save page}}',
'visualeditor-savedialog-label-review' => 'Label for button to go to the review dialog to review the diff',
'visualeditor-savedialog-label-restore' => 'Label text for save button when the user is editing a previous revision',
'visualeditor-editnotices-tool' => 'Text of tool in the toolbar that shows edit notices (such as [[MediaWiki:editnotice-0]] and [[MediaWiki:editnotice-8/en]]) as a pop-up',
'visualeditor-feedback-tool' => 'Text of tool in the toolbar that lets users provide feedback',

View file

@ -187,6 +187,7 @@ $wgResourceModules += array(
'visualeditor-savedialog-label-resolve-conflict',
'visualeditor-savedialog-label-create',
'visualeditor-savedialog-label-save',
'visualeditor-savedialog-label-review',
'visualeditor-savedialog-label-restore',
'visualeditor-savedialog-label-report',
),

View file

@ -35,6 +35,7 @@ ve.init.mw.ViewPageTarget = function VeInitMwViewPageTarget() {
this.$spinner = $( '<div class="ve-init-mw-viewPageTarget-loading"></div>' );
this.toolbarCancelButton = null;
this.toolbarSaveButton = null;
this.saveDialogSlideHistory = [];
this.saveDialogSaveButton = null;
this.saveDialogReviewWrongButton = null;
this.saveDialogReviewGoodButton = null;
@ -185,27 +186,6 @@ ve.init.mw.ViewPageTarget.saveDialogTemplate = '\
<div class="ve-init-mw-viewPageTarget-saveDialog-title"></div>\
</div>\
<div class="ve-init-mw-viewPageTarget-saveDialog-body">\
<div class="ve-init-mw-viewPageTarget-saveDialog-slide ve-init-mw-viewPageTarget-saveDialog-slide-review">\
<div class="ve-init-mw-viewPageTarget-saveDialog-viewer"></div>\
<div class="ve-init-mw-viewPageTarget-saveDialog-actions">\
<div class="ve-init-mw-viewPageTarget-saveDialog-working"></div>\
</div>\
<div style="clear: both;"></div>\
</div>\
<div class="ve-init-mw-viewPageTarget-saveDialog-slide ve-init-mw-viewPageTarget-saveDialog-slide-report">\
<div class="ve-init-mw-viewPageTarget-saveDialog-report">\
<textarea name="problem" class="ve-init-mw-viewPageTarget-saveDialog-problem"\
id="ve-init-mw-viewPageTarget-saveDialog-problem" type="text"\
rows="4"></textarea>\
</div>\
<div class="ve-init-mw-viewPageTarget-saveDialog-actions">\
<div class="ve-init-mw-viewPageTarget-saveDialog-working"></div>\
</div>\
<div style="clear: both;"></div>\
<div class="ve-init-mw-viewPageTarget-saveDialog-foot">\
<p class="ve-init-mw-viewPageTarget-saveDialog-report-notice"></p>\
</div>\
</div>\
<div class="ve-init-mw-viewPageTarget-saveDialog-slide ve-init-mw-viewPageTarget-saveDialog-slide-save">\
<div class="ve-init-mw-viewPageTarget-saveDialog-summary">\
<textarea name="editSummary" class="ve-init-mw-viewPageTarget-saveDialog-editSummary"\
@ -232,6 +212,27 @@ ve.init.mw.ViewPageTarget.saveDialogTemplate = '\
<p class="ve-init-mw-viewPageTarget-saveDialog-license"></p>\
</div>\
</div>\
<div class="ve-init-mw-viewPageTarget-saveDialog-slide ve-init-mw-viewPageTarget-saveDialog-slide-review">\
<div class="ve-init-mw-viewPageTarget-saveDialog-viewer"></div>\
<div class="ve-init-mw-viewPageTarget-saveDialog-actions">\
<div class="ve-init-mw-viewPageTarget-saveDialog-working"></div>\
</div>\
<div style="clear: both;"></div>\
</div>\
<div class="ve-init-mw-viewPageTarget-saveDialog-slide ve-init-mw-viewPageTarget-saveDialog-slide-report">\
<div class="ve-init-mw-viewPageTarget-saveDialog-report">\
<textarea name="problem" class="ve-init-mw-viewPageTarget-saveDialog-problem"\
id="ve-init-mw-viewPageTarget-saveDialog-problem" type="text"\
rows="4"></textarea>\
</div>\
<div class="ve-init-mw-viewPageTarget-saveDialog-actions">\
<div class="ve-init-mw-viewPageTarget-saveDialog-working"></div>\
</div>\
<div style="clear: both;"></div>\
<div class="ve-init-mw-viewPageTarget-saveDialog-foot">\
<p class="ve-init-mw-viewPageTarget-saveDialog-report-notice"></p>\
</div>\
</div>\
<div class="ve-init-mw-viewPageTarget-saveDialog-slide ve-init-mw-viewPageTarget-saveDialog-slide-conflict">\
<div class="ve-init-mw-viewPageTarget-saveDialog-conflict">\
</div>\
@ -658,6 +659,15 @@ ve.init.mw.ViewPageTarget.prototype.onSurfaceModelHistory = function () {
this.toolbarSaveButton.setDisabled( !this.edited && !this.restoring );
};
/**
* Handle clicks on the review button in the save dialog.
*
* @method
*/
ve.init.mw.ViewPageTarget.prototype.onSaveDialogReviewButtonClick = function () {
this.swapSaveDialog( 'review' );
};
/**
* Handle clicks on the save button in the save dialog.
*
@ -759,11 +769,14 @@ ve.init.mw.ViewPageTarget.prototype.onSaveDialogCloseButtonClick = function () {
* @param {jQuery.Event} e Mouse click event
*/
ve.init.mw.ViewPageTarget.prototype.onSaveDialogPrevButtonClick = function () {
// Hard code "review" for now.
// Although we have more than 2 slides, slide "report" and "save" are both
// branches of "review". Later this could terminate the path based on an
// array or object, or keep a .history array even...
this.swapSaveDialog( 'review' );
var history = this.saveDialogSlideHistory;
if ( history.length < 2 ) {
throw new Error( 'PrevButton was triggered without a history' );
}
// Pop off current slide
history.pop();
// Navigate to last slide
this.swapSaveDialog( history[ history.length -1 ], { fromHistory: true } );
};
/**
@ -1101,17 +1114,26 @@ ve.init.mw.ViewPageTarget.prototype.getSaveDialogHtml = function ( callback ) {
ve.init.mw.ViewPageTarget.prototype.setupSaveDialog = function () {
var viewPage = this;
// Save button on "save" slide
this.saveDialogSaveButton = new ve.ui.ButtonWidget( {
'label': ve.msg(
// visualeditor-savedialog-label-restore, visualeditor-savedialog-label-save
'visualeditor-savedialog-label-' + ( viewPage.restoring ? 'restore' : 'save' )
),
'flags': ['constructive']
} );
this.saveDialogSaveButton.connect( this, { 'click': 'onSaveDialogSaveButtonClick' } );
// Review button on "save" slide
this.saveDialogReviewButton = new ve.ui.ButtonWidget( {
'label': ve.msg(
'visualeditor-savedialog-label-review'
)
} );
this.saveDialogReviewButton.connect( this, { 'click': 'onSaveDialogReviewButtonClick' } );
this.saveDialogReviewWrongButton = new ve.ui.ButtonWidget( {
'label': ve.msg( 'visualeditor-savedialog-label-review-wrong' ),
'flags': ['primary']
'label': ve.msg( 'visualeditor-savedialog-label-review-wrong' )
} );
this.saveDialogReviewWrongButton.connect(
this, { 'click': 'onSaveDialogReviewWrongButtonClick' }
@ -1145,15 +1167,12 @@ ve.init.mw.ViewPageTarget.prototype.setupSaveDialog = function () {
// Attach buttons
.find( '.ve-init-mw-viewPageTarget-saveDialog-slide-save' )
.find( '.ve-init-mw-viewPageTarget-saveDialog-actions' )
.prepend( viewPage.saveDialogSaveButton.$ )
.prepend( viewPage.saveDialogSaveButton.$, viewPage.saveDialogReviewButton.$ )
.end()
.end()
.find( '.ve-init-mw-viewPageTarget-saveDialog-slide-review' )
.find( '.ve-init-mw-viewPageTarget-saveDialog-actions' )
.prepend(
viewPage.saveDialogReviewGoodButton.$,
viewPage.saveDialogReviewWrongButton.$
)
.prepend( viewPage.saveDialogReviewGoodButton.$ )
.end()
.end()
.find( '.ve-init-mw-viewPageTarget-saveDialog-slide-report' )
@ -1280,7 +1299,7 @@ ve.init.mw.ViewPageTarget.prototype.showSaveDialog = function () {
viewPage.$toolbarEditNotices.fadeOut( 'fast' );
viewPage.swapSaveDialog( 'review' );
viewPage.swapSaveDialog( 'save' );
viewPage.$saveDialog.fadeIn( 'fast', function () {
// Initial size
@ -1359,30 +1378,43 @@ ve.init.mw.ViewPageTarget.prototype.resetSaveDialog = function () {
};
/**
* Swap state in the save dialog (forwards or backwards).
* Swap state in the save dialog.
*
* @method
* @param {string} slide One of 'review', 'report', 'save', 'conflict' or 'nochanges'
* @param {string} slide One of 'save', 'review', 'report', 'conflict' or 'nochanges'
* @param {Object} [options]
* @param {boolean} [options.fromHistory] Whether this swap was triggered from interaction
* with the slide history (e.g. surpresses pushing of target slide in the history again).
* @return {jQuery} The now active slide.
* @throws {Error} Unknown saveDialog slide
*/
ve.init.mw.ViewPageTarget.prototype.swapSaveDialog = function ( slide ) {
var $slide, $viewer, doc = this.surface.getModel().getDocument();
if ( ve.indexOf( slide, [ 'review', 'report', 'save', 'conflict', 'nochanges' ] ) === -1 ) {
ve.init.mw.ViewPageTarget.prototype.swapSaveDialog = function ( slide, options ) {
var $slide, $viewer,
doc = this.surface.getModel().getDocument();
if ( ve.indexOf( slide, [ 'save', 'review', 'report', 'conflict', 'nochanges' ] ) === -1 ) {
throw new Error( 'Unknown saveDialog slide: ' + slide );
}
options = options || {};
if ( !options.fromHistory ) {
this.saveDialogSlideHistory.push( slide );
}
$slide = this.$saveDialog.find( '.ve-init-mw-viewPageTarget-saveDialog-slide-' + slide );
this.$saveDialog
// Hide prev button on first slides
// Hide "prev" button when (back) on the first slide
.find( '.ve-init-mw-viewPageTarget-saveDialog-prevButton' )
.toggle( ve.indexOf( slide, [ 'review', 'nochanges' ] ) === -1 )
.toggle( this.saveDialogSlideHistory.length >= 2 )
.end()
// Update title
// Give grep a chance to find the usages:
// visualeditor-savedialog-title-review, visualeditor-savedialog-title-report,
// visualeditor-savedialog-title-save
// Update title to one of:
// - visualeditor-savedialog-title-save
// - visualeditor-savedialog-title-review
// - visualeditor-savedialog-title-report
// - visualeditor-savedialog-title-conflict
// - visualeditor-savedialog-title-nochanges
.find( '.ve-init-mw-viewPageTarget-saveDialog-title' )
.text( ve.msg( 'visualeditor-savedialog-title-' + slide ) )
.end()