diff --git a/VisualEditor.i18n.php b/VisualEditor.i18n.php index 6b924fa7ff..5b9827a683 100644 --- a/VisualEditor.i18n.php +++ b/VisualEditor.i18n.php @@ -185,7 +185,7 @@ $messages['en'] = array( 'visualeditor-savedialog-label-save' => 'Save page', 'visualeditor-savedialog-label-warning' => 'Warning', 'visualeditor-savedialog-title-conflict' => 'Conflict', - 'visualeditor-savedialog-title-nochanges' => 'No changes', + 'visualeditor-savedialog-title-nochanges' => 'No changes to review', 'visualeditor-savedialog-title-review' => 'Review your changes', 'visualeditor-savedialog-title-save' => 'Save your changes', 'visualeditor-savedialog-warning-dirty' => 'Your edit may have been corrupted – please review before saving.', diff --git a/VisualEditor.php b/VisualEditor.php index 6a9e71f07b..6fc9632cf4 100644 --- a/VisualEditor.php +++ b/VisualEditor.php @@ -502,6 +502,7 @@ $wgResourceModules += array( 've/ui/layouts/ve.ui.PanelLayout.js', 've/ui/layouts/ve.ui.StackPanelLayout.js', + 've-mw/ui/dialogs/ve.ui.MWSaveDialog.js', 've-mw/ui/dialogs/ve.ui.MWMetaDialog.js', 've-mw/ui/dialogs/ve.ui.MWBetaWelcomeDialog.js', 've-mw/ui/dialogs/ve.ui.MWMediaInsertDialog.js', @@ -559,6 +560,7 @@ $wgResourceModules += array( 'unicodejs.wordbreak', 'ext.visualEditor.base', 'mediawiki.Title', + 'mediawiki.action.history.diff', 'jquery.autoEllipsis', ), 'messages' => array( diff --git a/modules/ve-mw/init/styles/ve.init.mw.ViewPageTarget.css b/modules/ve-mw/init/styles/ve.init.mw.ViewPageTarget.css index d40c1c5c79..a8a86d8b16 100644 --- a/modules/ve-mw/init/styles/ve.init.mw.ViewPageTarget.css +++ b/modules/ve-mw/init/styles/ve.init.mw.ViewPageTarget.css @@ -121,226 +121,10 @@ color: #555; } -/* Save dialog styles */ - -.ve-init-mw-viewPageTarget-toolbarTracker { - position: absolute; - top: 0; - height: 0; - overflow: visible; -} - -.ve-init-mw-viewPageTarget-toolbarTracker-floating { - position: fixed; - z-index: 100; -} - -.ve-init-mw-viewPageTarget-saveDialog .ve-ui-pushButtonWidget { - float: right; - margin-left: 0.5em; - font-size: 0.8em; -} - -.ve-init-mw-viewPageTarget-saveDialog-working { - display: none; - float: right; - height: 2em; - width: 128px; - margin-right: 1em; - background-position: right center; - background-repeat: no-repeat; -} - -.ve-init-mw-viewPageTarget-saveDialog { - display: none; - top: 0.25em; - right: 0.5em; - width: 29em; - min-width: 29em; - font-family: sans-serif; - position: absolute; - border: solid 1px #ccc; - border-radius: 0.25em; - background-color: #fff; - box-shadow: 0 0.15em 0.5em 0 rgba(0, 0, 0, 0.2); - padding: 2.5em 0.75em 0.75em 0.75em; - margin: 0 0 0 0.5em; - z-index: 3; - - /* slide-diff can get quite long, handle overflow */ - /* max-height set from javascript */ - overflow-x: auto; -} - -.ve-init-mw-viewPageTarget-saveDialog-head { - position: absolute; - top: 0.4em; - left: 0.5em; - right: 0.5em; -} - -.ve-init-mw-viewPageTarget-saveDialog-title { - height: 2em; - line-height: 2em; - color: #333; - font-size: 0.9em; - float: left; - margin: 0 0.5em; -} - -.ve-init-mw-viewPageTarget-saveDialog-prevButton { - float: left; - position: relative; - top: 0.1em; - width: 1.5em; - height: 1.5em; - cursor: pointer; - opacity: 0.8; - /* @see ve.init.mw.Icons */ - background-position: left top; - background-repeat: no-repeat; - padding-right: 0.5em; - border-right: 1px solid #eee; - margin-right: 0.5em; -} - -.ve-init-mw-viewPageTarget-saveDialog-closeButton { - float: right; - position: relative; - top: 0.1em; - width: 1.5em; - height: 1.5em; - cursor: pointer; - opacity: 0.8; - /* @see ve.init.mw.Icons */ - background-position: right top; - background-repeat: no-repeat; -} - -.ve-init-mw-viewPageTarget-saveDialog-body { - border-top: 1px solid #ddd; - padding-top: 1em; -} - -.ve-init-mw-viewPageTarget-saveDialog-slide { - display: none; -} - -.ve-init-mw-viewPageTarget-saveDialog-slide-review .ve-init-mw-viewPageTarget-saveDialog-viewer { - margin-bottom: 1em; -} - -.ve-init-mw-viewPageTarget-saveDialog-slide-review .ve-init-mw-viewPageTarget-saveDialog-viewer pre { - margin: 0; -} - -.ve-init-mw-viewPageTarget-saveDialog-slide-review .ve-init-mw-viewPageTarget-saveDialog-viewer .diff { - font-size: 0.8em; -} - -.ve-init-mw-viewPageTarget-saveDialog-foot { - padding-top: 1em; -} - -.ve-init-mw-viewPageTarget-saveDialog-dirtymsg, -.ve-init-mw-viewPageTarget-saveDialog-license, -.ve-init-mw-viewPageTarget-saveDialog-report-notice { - font-size: 0.7em; - line-height: 1.25em; - padding: 0; - margin: 0; - color: #999; -} - - -.ve-init-mw-viewPageTarget-saveDialog-dirtymsg { - float: right; -} - -.ve-init-mw-viewPageTarget-saveDialog-summary, -.ve-init-mw-viewPageTarget-saveDialog-report { - background-color: #fff; - border: solid 1px #cccccc; - padding: 0.5em; - border-radius: 0.25em 0.25em 0 0; -} - -.ve-init-mw-viewPageTarget-saveDialog-report { - margin-bottom: 1em; - border-radius: 0.25em; -} - -.ve-init-mw-viewPageTarget-saveDialog-summary-focused, -.ve-init-mw-viewPageTarget-saveDialog-report-focused { - border-color: #aaa; -} - -.ve-init-mw-viewPageTarget-saveDialog-conflict { - margin-bottom: 1em; -} - -.ve-init-mw-viewPageTarget-saveDialog-messages, -.ve-init-mw-viewPageTarget-saveDialog-conflict, -.ve-init-mw-viewPageTarget-saveDialog-nochanges { - font-size: 0.8em; -} - -.ve-init-mw-viewPageTarget-saveDialog-options { - position: relative; - background-color: #f7f7f7; - margin-bottom: 1em; - border: solid 1px #cccccc; - border-top: none; - border-radius: 0 0 0.25em 0.25em; - min-height: 2.25em; -} - -.ve-init-mw-viewPageTarget-saveDialog-body label { - font-size: 0.8em; - line-height: 3em; -} - -.ve-init-mw-viewPageTarget-saveDialog input[type="checkbox"] { - margin: 0 0.5em 0 1em; - line-height: 3em; -} - -.ve-init-mw-viewPageTarget-saveDialog-body .ve-init-mw-viewPageTarget-saveDialog-editSummary-label { - line-height: 2em; -} - -.ve-init-mw-viewPageTarget-saveDialog-editSummaryCount { - position: absolute; - right: 0; - top: 0; - bottom: 0; - border-left: solid 1px #eee; - line-height: 3em; - padding: 0 1em; - color: #aaa; -} - -.ve-init-mw-viewPageTarget-saveDialog-editSummary, -.ve-init-mw-viewPageTarget-saveDialog-problem { - border: none; - background-color: transparent; - margin: 0; - padding: 0; - resize: none; - font-size: 0.8em; - font-family: sans-serif; - height: 5em; -} - -.ve-init-mw-viewPageTarget-saveDialog-editSummary:focus, -.ve-init-mw-viewPageTarget-saveDialog-problem:focus { - outline: none; -} - /* Images */ .ve-init-mw-viewPageTarget-loading, -.ve-init-mw-viewPageTarget-saveDialog-working { +.ve-ui-mwSaveDialog-working { /* @embed */ background-image: url(images/loading-ltr.gif); } diff --git a/modules/ve-mw/init/targets/ve.init.mw.ViewPageTarget.js b/modules/ve-mw/init/targets/ve.init.mw.ViewPageTarget.js index 99a3d60549..13c1602109 100644 --- a/modules/ve-mw/init/targets/ve.init.mw.ViewPageTarget.js +++ b/modules/ve-mw/init/targets/ve.init.mw.ViewPageTarget.js @@ -34,9 +34,7 @@ ve.init.mw.ViewPageTarget = function VeInitMwViewPageTarget() { this.toolbarOffset = null; this.toolbarCancelButton = null; this.toolbarSaveButton = null; - this.saveDialogSlideHistory = []; - this.saveDialogSaveButton = null; - this.saveDialogReviewGoodButton = null; + this.saveDialog = null; this.toolbarEditNoticesButton = null; this.toolbarEditNotices = null; this.toolbarBetaNoticesButton = null; @@ -62,7 +60,6 @@ ve.init.mw.ViewPageTarget = function VeInitMwViewPageTarget() { this.actFromPopState = false; this.scrollTop = null; this.currentUri = currentUri; - this.messages = {}; this.section = currentUri.query.vesection || null; this.sectionPositionRestored = false; this.sectionTitleRestored = false; @@ -153,59 +150,6 @@ ve.init.mw.ViewPageTarget.compatibility = { } }; -// TODO: Accessibility tooltips and logical tab order for prevButton and closeButton. -ve.init.mw.ViewPageTarget.saveDialogTemplate = '\ -
' ).append(
$( '' ).text( mw.msg( 'captcha-label' ) ),
@@ -594,7 +535,7 @@ ve.init.mw.ViewPageTarget.prototype.onSaveError = function ( jqXHR, status, data
}
// Handle (other) unknown and/or unrecoverable errors
- this.showMessage(
+ this.saveDialog.showMessage(
'api-save-error',
document.createTextNode(
( editApi && editApi.info ) ||
@@ -607,7 +548,7 @@ ve.init.mw.ViewPageTarget.prototype.onSaveError = function ( jqXHR, status, data
wrap: 'error'
}
);
- this.saveDialogSaveButton.setDisabled( true );
+ this.saveDialog.saveButton.setDisabled( true );
};
/**
@@ -619,18 +560,7 @@ ve.init.mw.ViewPageTarget.prototype.onSaveError = function ( jqXHR, status, data
ve.init.mw.ViewPageTarget.prototype.onShowChanges = function ( diffHtml ) {
// Invalidate the viewer diff on next change
this.surface.getModel().connect( this, { 'transact': 'onSurfaceModelTransact' } );
-
- mw.loader.using( 'mediawiki.action.history.diff', ve.bind( function () {
- this.$saveDialog
- .find( '.ve-init-mw-viewPageTarget-saveDialog-viewer' )
- .empty().append( diffHtml );
-
- this.$saveDialogLoadingIcon.hide();
- this.saveDialogReviewGoodButton.setDisabled( false );
-
- }, this ), ve.bind( function () {
- this.onSaveError( null, 'Module load failed' );
- }, this ) );
+ this.saveDialog.setDiffAndReview( diffHtml );
};
/**
@@ -642,13 +572,7 @@ ve.init.mw.ViewPageTarget.prototype.onShowChanges = function ( diffHtml ) {
ve.init.mw.ViewPageTarget.prototype.onSerialize = function ( wikitext ) {
// Invalidate the viewer wikitext on next change
this.surface.getModel().connect( this, { 'transact': 'onSurfaceModelTransact' } );
-
- this.$saveDialog
- .find( '.ve-init-mw-viewPageTarget-saveDialog-viewer' )
- .empty().append( $( ' ' ).append( ve.init.platform.getParsedMessage( 'missingsummary' ) ),
{ wrap: false }
);
} else {
- this.saveDialogSaveButton.setDisabled( true );
- this.$saveDialogLoadingIcon.show();
+ this.saveDialog.saveButton.setDisabled( true );
+ this.saveDialog.$loadingIcon.show();
this.save(
ve.dm.converter.getDomFromData( doc.getFullData(), doc.getStore(), doc.getInternalList() ),
saveOptions
@@ -882,21 +824,12 @@ ve.init.mw.ViewPageTarget.prototype.saveDocument = function () {
}
};
-/**
- * Handle clicks on the review "Good" button in the save dialog.
- *
- * @method
- */
-ve.init.mw.ViewPageTarget.prototype.onSaveDialogReviewGoodButtonClick = function () {
- this.swapSaveDialog( 'save' );
-};
-
/**
* Handle clicks on the resolve conflict button in the conflict dialog.
*
* @method
*/
-ve.init.mw.ViewPageTarget.prototype.onSaveDialogResolveConflictButtonClick = function () {
+ve.init.mw.ViewPageTarget.prototype.onSaveDialogResolveConflict= function () {
var doc = this.surface.getModel().getDocument();
// Get Wikitext from the DOM, and set up a submit call when it's done
this.serialize(
@@ -915,21 +848,21 @@ ve.init.mw.ViewPageTarget.prototype.onSaveDialogResolveConflictButtonClick = fun
*/
ve.init.mw.ViewPageTarget.prototype.getSaveOptions = function () {
var options = {
- 'summary': this.$saveDialog.find( '#ve-init-mw-viewPageTarget-saveDialog-editSummary' ).val(),
+ 'summary': this.saveDialog.editSummaryInput.$input.val(),
'captchaid': this.captcha && this.captcha.id,
'captchaword': this.captcha && this.captcha.input.getValue()
};
if ( this.sanityCheckPromise.state() === 'rejected' ) {
options.needcheck = 1;
}
- if ( this.$saveDialog.find( '#wpMinoredit' ).prop( 'checked' ) ) {
+ if ( this.saveDialog.$saveOptions.find( '#wpMinoredit' ).prop( 'checked' ) ) {
options.minor = 1;
}
- if ( this.$saveDialog.find( '#wpWatchthis' ).prop( 'checked' ) ) {
+ if ( this.saveDialog.$saveOptions.find( '#wpWatchthis' ).prop( 'checked' ) ) {
options.watch = 1;
}
- this.$saveDialog
- .find( '.ve-init-mw-viewPageTarget-saveDialog-checkboxes' )
+ this.saveDialog.$saveOptions
+ .find( '.ve-ui-mwSaveDialog-checkboxes' )
.find( 'input:not(#wpMinoredit, #wpWatchthis)' )
.each( function () {
var $this = $( this );
@@ -942,33 +875,6 @@ ve.init.mw.ViewPageTarget.prototype.getSaveOptions = function () {
return options;
};
-/**
- * Handle clicks on the close button in the save dialog.
- *
- * @method
- * @param {jQuery.Event} e Mouse click event
- */
-ve.init.mw.ViewPageTarget.prototype.onSaveDialogCloseButtonClick = function () {
- this.hideSaveDialog();
-};
-
-/**
- * Handle clicks on the previous view button in the save dialog.
- *
- * @method
- * @param {jQuery.Event} e Mouse click event
- */
-ve.init.mw.ViewPageTarget.prototype.onSaveDialogPrevButtonClick = function () {
- 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 } );
-};
-
/**
* Set up the list of edit notices.
*
@@ -1379,155 +1285,25 @@ ve.init.mw.ViewPageTarget.prototype.detachToolbarButtons = function () {
ve.init.mw.ViewPageTarget.prototype.setupSaveDialog = function () {
var sectionTitle = '', viewPage = this;
- // Save button on "save" slide
- this.saveDialogSaveButton = new ve.ui.PushButtonWidget( {
- '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.PushButtonWidget( {
- 'label': ve.msg(
- 'visualeditor-savedialog-label-review'
- )
- } );
- this.saveDialogReviewButton.connect( this, { 'click': 'onSaveDialogReviewButtonClick' } );
-
- this.saveDialogReviewGoodButton = new ve.ui.PushButtonWidget( {
- 'label': ve.msg( 'visualeditor-savedialog-label-review-good' ),
- 'flags': ['constructive']
- } );
- this.saveDialogReviewGoodButton.connect(
- this, { 'click': 'onSaveDialogReviewGoodButtonClick' }
- );
-
- this.saveDialogResolveConflictButton = new ve.ui.PushButtonWidget( {
- 'label': ve.msg( 'visualeditor-savedialog-label-resolve-conflict' ),
- 'flags': ['constructive']
- } );
- this.saveDialogResolveConflictButton.connect( this, { 'click': 'onSaveDialogResolveConflictButtonClick' } );
-
+ viewPage.saveDialog = this.surface.getDialogs().getWindow( 'mwSave' );
if ( viewPage.section ) {
sectionTitle = viewPage.$document.find( 'h1, h2, h3, h4, h5, h6' ).eq( viewPage.section - 1 ).text();
sectionTitle = '/* ' + ve.graphemeSafeSubstring( sectionTitle, 0, 244 ) + ' */ ';
+ viewPage.saveDialog.editSummaryInput.$input.val( sectionTitle );
viewPage.sectionTitleRestored = true;
if ( viewPage.sectionPositionRestored ) {
viewPage.onSectionRestored();
}
}
- viewPage.$saveDialog
- // Must not use replaceWith because that can't be used on fragement roots,
- // plus, we want to preserve the reference and class names of the wrapper.
- .empty().append( this.constructor.saveDialogTemplate )
- // Attach buttons
- .find( '.ve-init-mw-viewPageTarget-saveDialog-slide-save' )
- .find( '.ve-init-mw-viewPageTarget-saveDialog-actions' )
- .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.$ )
- .end()
- .end()
- .find( '.ve-init-mw-viewPageTarget-saveDialog-slide-conflict' )
- .find( '.ve-init-mw-viewPageTarget-saveDialog-actions' )
- .prepend( viewPage.saveDialogResolveConflictButton.$ )
- .end()
- .end()
- .find( '.ve-init-mw-viewPageTarget-saveDialog-closeButton' )
- .click( ve.bind( viewPage.onSaveDialogCloseButtonClick, viewPage ) )
- .end()
- .find( '.ve-init-mw-viewPageTarget-saveDialog-prevButton' )
- .click( ve.bind( viewPage.onSaveDialogPrevButtonClick, viewPage ) )
- .end()
- // Attach contents
- .find( '#ve-init-mw-viewPageTarget-saveDialog-editSummary-label' )
- .html( ve.init.platform.getParsedMessage( 'summary' ) )
- .end()
- .find( '#ve-init-mw-viewPageTarget-saveDialog-editSummary' )
- .attr( {
- 'placeholder': ve.msg( 'visualeditor-editsummary' )
- } )
- .val( sectionTitle )
- .placeholder()
- .byteLimit( viewPage.editSummaryByteLimit )
- .on( {
- 'focus': function () {
- $( this ).parent().addClass(
- 've-init-mw-viewPageTarget-saveDialog-summary-focused'
- );
- },
- 'blur': function () {
- $( this ).parent().removeClass(
- 've-init-mw-viewPageTarget-saveDialog-summary-focused'
- );
- },
- 'keyup keydown mouseup cut paste change focus blur': function () {
- var $textarea = $( this ),
- $editSummaryCount = $textarea
- .closest( '.ve-init-mw-viewPageTarget-saveDialog-slide-save' )
- .find( '.ve-init-mw-viewPageTarget-saveDialog-editSummaryCount' );
- // TODO: This looks a bit weird, there is no unit in the UI, just numbers
- // Users likely assume characters but then it seems to count down quicker
- // than expected. Facing users with the word "byte" is bad? (bug 40035)
- setTimeout( function () {
- $editSummaryCount.text(
- viewPage.editSummaryByteLimit - $.byteLength( $textarea.val() )
- );
- } );
- }
- } )
- .end()
- .find( '.ve-init-mw-viewPageTarget-saveDialog-editSummaryCount' )
- .text( viewPage.editSummaryByteLimit )
- .end()
- .find( '.ve-init-mw-viewPageTarget-saveDialog-checkboxes' )
- .html( ve.getObjectValues( viewPage.checkboxes ).join( '\n' ) )
- .find( 'a' )
- .attr( 'target', '_blank' )
- .end()
- .find( '#wpMinoredit' )
- .prop( 'checked', +mw.user.options.get( 'minordefault' ) )
- .end()
- .find( '#wpWatchthis' )
- .prop( 'checked',
- mw.user.options.get( 'watchdefault' ) ||
- ( mw.user.options.get( 'watchcreations' ) && !viewPage.pageExists ) ||
- mw.config.get( 'wgVisualEditor' ).isPageWatched
- )
- .end()
- .end()
- .find( '.ve-init-mw-viewPageTarget-saveDialog-license' )
- .html( ve.init.platform.getParsedMessage( 'copyrightwarning' ) )
- .end()
- .find( '.ve-init-mw-viewPageTarget-saveDialog-conflict' )
- .html( ve.init.platform.getParsedMessage( 'visualeditor-editconflict' ) )
- .end()
- .find( '.ve-init-mw-viewPageTarget-saveDialog-nochanges' )
- .html( ve.init.platform.getParsedMessage( 'visualeditor-diff-nochanges' ) )
- ;
-
- // Get reference to loading icon
- viewPage.$saveDialogLoadingIcon = viewPage.$saveDialog
- .find( '.ve-init-mw-viewPageTarget-saveDialog-working' );
-
- // Hook onto the 'watch' event on by mediawiki.page.watch.ajax.js
- // Triggered when mw.page.watch.updateWatchLink(link, action) is called
- $( '#ca-watch, #ca-unwatch' )
- .on(
- 'watchpage.mw',
- function ( e, action ) {
- viewPage.$saveDialog
- .find( '#wpWatchthis' )
- .prop( 'checked', ( action === 'watch' ) );
- }
- );
+ // Connect to save dialog
+ viewPage.saveDialog.connect( this, {
+ 'save': 'onSaveDialogSave',
+ 'review': 'onSaveDialogReview',
+ 'resolve': 'onSaveDialogResolveConflict'
+ } );
+ // Setup checkboxes
+ viewPage.saveDialog.setupCheckboxes( ve.getObjectValues( viewPage.checkboxes ).join( '\n' ) );
};
/**
@@ -1536,208 +1312,11 @@ ve.init.mw.ViewPageTarget.prototype.setupSaveDialog = function () {
* @method
*/
ve.init.mw.ViewPageTarget.prototype.showSaveDialog = function () {
- var viewPage = this;
-
- viewPage.surface.disable();
- viewPage.$document.css( 'opacity', 0.5 );
-
- viewPage.toolbarBetaNotices.hide();
- viewPage.toolbarEditNotices.hide();
-
- viewPage.swapSaveDialog( 'save' );
-
- viewPage.$saveDialog.fadeIn( 'fast', function () {
- // Initial size
- viewPage.onResizeSaveDialog();
- } );
-
- $( document ).on( 'keydown.ve-savedialog', function ( e ) {
- // Escape
- if ( e.which === ve.Keys.ESCAPE ) {
- viewPage.onSaveDialogCloseButtonClick();
- }
- } );
-
- $( window ).on( 'resize.ve-savedialog', ve.bind( viewPage.onResizeSaveDialog, viewPage ) );
-};
-
-/**
- * Update window-size related aspects of the save dialog
- *
- * @method
- */
-ve.init.mw.ViewPageTarget.prototype.onResizeSaveDialog = function () {
- var $d = this.$saveDialog, $w = $( window );
-
- // Available space for css-height is window height,
- // without the space between the dialog and the window top,
- // without the space above/below between css-height and outerHeight.
- $d.css( 'max-height',
- $w.height() -
- ( $d.offset().top - $w.scrollTop() ) -
- ( $d.outerHeight( true ) - $d.height() ) -
- 20 // shadow
- );
-};
-
-/**
- * Hide the save dialog
- */
-ve.init.mw.ViewPageTarget.prototype.hideSaveDialog = function () {
- // Reset history on close (bug 49481)
- this.saveDialogSlideHistory.length = 0;
- this.$saveDialog.fadeOut( 'fast' );
- if ( this.$document ) {
- this.$document.focus();
- }
- $( document ).off( 'keydown.ve-savedialog' );
- $( window ).off( 'resize', this.onResizeSaveDialog );
-
- if ( this.surface ) {
- this.surface.enable();
- this.$document.css( 'opacity', '' );
- }
-};
-
-/**
- * Reset the fields of the save dialog.
- *
- * TODO: Maybe call this more cleverly only when the document changes, so that closing and
- * re-opening the saveDialog doesn't remove the user input and the diff cache.
- *
- * @method
- */
-ve.init.mw.ViewPageTarget.prototype.resetSaveDialog = function () {
- this.$saveDialog
- .find( '#ve-init-mw-viewPageTarget-saveDialog-editSummary' )
- .val( '' )
- .end()
- .find( '#wpMinoredit' )
- .prop( 'checked', false )
- .end()
- // Clear the diff
- .find( '.ve-init-mw-viewPageTarget-saveDialog-viewer' )
- .empty();
-};
-
-/**
- * Swap state in the save dialog.
- *
- * @method
- * @param {string} slide One of 'save', 'review', '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).
- * @returns {jQuery} The now active slide.
- * @throws {Error} Unknown saveDialog slide
- */
-ve.init.mw.ViewPageTarget.prototype.swapSaveDialog = function ( slide, options ) {
- var $slide, $viewer,
- doc = this.surface.getModel().getDocument();
-
- if ( ve.indexOf( slide, [ 'save', 'review', '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 when (back) on the first slide
- .find( '.ve-init-mw-viewPageTarget-saveDialog-prevButton' )
- .toggle( this.saveDialogSlideHistory.length >= 2 )
- .end()
- // Update title to one of:
- // - visualeditor-savedialog-title-save
- // - visualeditor-savedialog-title-review
- // - visualeditor-savedialog-title-conflict
- // - visualeditor-savedialog-title-nochanges
- .find( '.ve-init-mw-viewPageTarget-saveDialog-title' )
- .text( ve.msg( 'visualeditor-savedialog-title-' + slide ) )
- .end()
- // Hide other slides
- .find( '.ve-init-mw-viewPageTarget-saveDialog-slide' )
- .not( $slide )
- .hide();
-
- // Old messages should not persist after slide changes
- this.clearAllMessages();
- // Reset save button if we disabled it for e.g. unrecoverable spam error
- this.saveDialogSaveButton.setDisabled( false );
-
- if ( slide === 'save' ) {
- if ( !this.sanityCheckVerified ) {
- this.showMessage( 'dirtywarning', mw.msg( 'visualeditor-savedialog-warning-dirty' ) );
- }
- }
-
- if ( slide === 'review' ) {
- this.sanityCheckVerified = true;
- $viewer = $slide.find( '.ve-init-mw-viewPageTarget-saveDialog-viewer' );
- if ( !$viewer.find( 'table, pre' ).length ) {
- this.saveDialogReviewGoodButton.setDisabled( true );
- this.$saveDialogLoadingIcon.show();
- if ( this.pageExists ) {
- // Has no callback, handled via target.onShowChanges
- this.showChanges(
- ve.dm.converter.getDomFromData( doc.getFullData(), doc.getStore(), doc.getInternalList() )
- );
- } else {
- this.serialize(
- ve.dm.converter.getDomFromData( doc.getFullData(), doc.getStore(), doc.getInternalList() ),
- ve.bind( this.onSerialize, this )
- );
- }
- }
- this.$saveDialog.css( 'width', '100%' );
- } else {
- this.$saveDialog.css( 'width', '' );
- }
-
- // Show the target slide
- $slide.show();
-
- mw.hook( 've.saveDialog.stateChanged' ).fire();
-
- if ( slide === 'save' ) {
- setTimeout( function () {
- var $textarea = $slide.find( '#ve-init-mw-viewPageTarget-saveDialog-editSummary' );
- $textarea.focus();
- // If message has be pre-filled (e.g. section edit), move cursor to end
- if ( $textarea.val() !== '' ) {
- ve.selectEnd( $textarea[0] );
- }
- } );
- }
-
- return $slide;
-};
-
-/**
- * Add the save dialog to the user interface.
- *
- * @method
- */
-ve.init.mw.ViewPageTarget.prototype.attachSaveDialog = function () {
- this.surface.$globalOverlay.append(
- this.$toolbarTracker.append(
- this.$saveDialog
- )
- );
-};
-
-/**
- * Remove the save dialog from the user interface.
- *
- * @method
- */
-ve.init.mw.ViewPageTarget.prototype.detachSaveDialog = function () {
- this.$saveDialog.detach();
+ this.toolbarBetaNotices.hide();
+ this.toolbarEditNotices.hide();
+ this.saveDialog.setSanityCheck( this.sanityCheckVerified );
+ this.saveDialog.swapPanel( 'save' );
+ this.surface.getDialogs().open( 'mwSave' );
};
/**
@@ -2117,63 +1696,6 @@ ve.init.mw.ViewPageTarget.prototype.onSectionRestored = function () {
this.sectionTitleRestored = false;
};
-/**
- * Show a message in the save dialog.
- *
- * @param {string} name Message's unique name
- * @param {string|jQuery|Array} message Message content (string of HTML, jQuery object or array of
- * Node objects)
- * @param {Object} [options]
- * @param {boolean} [options.wrap="warning"] Whether to wrap the message in a paragraph and if
- * so, how. One of "warning", "error" or false.
- */
-ve.init.mw.ViewPageTarget.prototype.showMessage = function ( name, message, options ) {
- var $message;
- if ( !this.messages[name] ) {
- options = options || {};
- if ( options.wrap === undefined ) {
- options.wrap = 'warning';
- }
- $message = $( ' ').append(
- // visualeditor-savedialog-label-error
- // visualeditor-savedialog-label-warning
- $( '' ).text( mw.msg( 'visualeditor-savedialog-label-' + options.wrap ) ),
- document.createTextNode( mw.msg( 'colon-separator' ) ),
- message
- ) );
- } else {
- $message.append( message );
- }
- this.$saveDialog.find( '.ve-init-mw-viewPageTarget-saveDialog-messages' )
- .append( $message );
-
- this.messages[name] = $message;
- }
-};
-
-/**
- * Remove a message from the save dialog.
- * @param {string} name Message's unique name
- */
-ve.init.mw.ViewPageTarget.prototype.clearMessage = function ( name ) {
- if ( this.messages[name] ) {
- this.messages[name].remove();
- delete this.messages[name];
- }
-};
-
-/**
- * Remove all messages from the save dialog.
- */
-ve.init.mw.ViewPageTarget.prototype.clearAllMessages = function () {
- this.$saveDialog
- .find( '.ve-init-mw-viewPageTarget-saveDialog-messages' )
- .empty();
- this.messages = {};
-};
-
/**
* Add onbeforunload handler.
*
diff --git a/modules/ve-mw/ui/dialogs/ve.ui.MWSaveDialog.js b/modules/ve-mw/ui/dialogs/ve.ui.MWSaveDialog.js
new file mode 100644
index 0000000000..07bb726b00
--- /dev/null
+++ b/modules/ve-mw/ui/dialogs/ve.ui.MWSaveDialog.js
@@ -0,0 +1,377 @@
+/*!
+ * VisualEditor UserInterface MWSaveDialog class.
+ *
+ * @copyright 2011-2013 VisualEditor Team and others; see AUTHORS.txt
+ * @license The MIT License (MIT); see LICENSE.txt
+ */
+
+/*global mw */
+
+/**
+ * Dialog for saving MediaWiki articles.
+ *
+ * @class
+ * @extends ve.ui.MWDialog
+ *
+ * @constructor
+ * @param {ve.ui.Surface} surface
+ * @param {Object} [config] Config options
+ */
+ve.ui.MWSaveDialog = function VeUiMWSaveDialog( surface, config ) {
+ // Configuration initialization
+ config = ve.extendObject( { 'small': true }, config );
+
+ // Parent constructor
+ ve.ui.MWDialog.call( this, surface, config );
+
+ // Properties
+ this.sanityCheckVerified = false;
+ this.editSummaryByteLimit = 255;
+ this.restoring = false;
+ this.messages = {};
+};
+
+/* Inheritance */
+
+ve.inheritClass( ve.ui.MWSaveDialog, ve.ui.MWDialog );
+
+/* Static Properties */
+
+ve.ui.MWSaveDialog.static.name = 'mwSave';
+
+ve.ui.MWSaveDialog.static.titleMessage = 'visualeditor-savedialog-title-save';
+
+/* Methods */
+
+/**
+ * @inheritdoc
+ */
+ve.ui.MWSaveDialog.prototype.initialize = function () {
+ var saveDialog = this;
+ // Parent method
+ ve.ui.MWDialog.prototype.initialize.call( this );
+
+ // Properties
+ this.savePanel = new ve.ui.PanelLayout( { '$$': this.frame.$$, 'scrollable': true } );
+
+ // Save panel
+ this.$editSummaryLabel = this.frame.$$( ' ' ).addClass( 've-ui-mwSaveDialog-license' )
+ .html( ve.init.platform.getParsedMessage( 'copyrightwarning' ) )
+ );
+ this.savePanel.$.append(
+ this.$editSummaryLabel,
+ this.editSummaryInput.$,
+ this.$saveOptions,
+ this.$saveMessages,
+ this.$saveActions,
+ this.$saveFoot
+ );
+
+ // Review panel
+ this.reviewPanel = new ve.ui.PanelLayout( { '$$': this.frame.$$, 'scrollable': true } );
+ this.$reviewViewer = this.frame.$$( ' ').append(
+ // visualeditor-savedialog-label-error
+ // visualeditor-savedialog-label-warning
+ $( '' ).text( mw.msg( 'visualeditor-savedialog-label-' + options.wrap ) ),
+ document.createTextNode( mw.msg( 'colon-separator' ) ),
+ message
+ ) );
+ } else {
+ $message.append( message );
+ }
+ this.$saveMessages.append( $message );
+
+ this.messages[name] = $message;
+ }
+};
+
+/**
+ * Remove a message from the save dialog.
+ * @param {string} name Message's unique name
+ */
+ve.ui.MWSaveDialog.prototype.clearMessage = function ( name ) {
+ if ( this.messages[name] ) {
+ this.messages[name].remove();
+ delete this.messages[name];
+ }
+};
+
+/**
+ * Remove all messages from the save dialog.
+ */
+ve.ui.MWSaveDialog.prototype.clearAllMessages = function () {
+ this.$saveMessages.empty();
+ this.messages = {};
+};
+
+/**
+ * Reset the fields of the save dialog.
+ *
+ * @method
+ */
+ve.ui.MWSaveDialog.prototype.reset = function () {
+ // Reset summary input
+ this.editSummaryInput.$input.val( '' );
+ // Uncheck minoredit
+ this.$saveOptions.find( '.ve-ui-mwSaveDialog-checkboxes' )
+ .find( '#wpMinoredit' ).prop( 'checked', false );
+ // Clear the diff
+ this.$reviewViewer.empty();
+};
+
+/**
+ * Initialize MediaWiki page specific checkboxes
+ *
+ * @param {string} checkboxes Multiline HTML
+ */
+ve.ui.MWSaveDialog.prototype.setupCheckboxes = function ( checkboxes ) {
+ this.$saveOptions.find( '.ve-ui-mwSaveDialog-checkboxes' )
+ .html( checkboxes )
+ .find( 'a' )
+ .attr( 'target', '_blank' )
+ .end()
+ .find( '#wpMinoredit' )
+ .prop( 'checked', mw.user.options.get( 'minordefault' ) )
+ .prop( 'tabIndex', 0 )
+ .end()
+ .find( '#wpWatchthis' )
+ .prop( 'checked',
+ mw.user.options.get( 'watchdefault' ) ||
+ ( mw.user.options.get( 'watchcreations' ) && !this.pageExists ) ||
+ mw.config.get( 'wgVisualEditor' ).isPageWatched
+ ).prop( 'tabIndex', 0 );
+ // TODO: Need to set all checkboxes provided by api tabindex to 0 for proper accessibility
+};
+
+/**
+ * Set review content and show review panel
+ *
+ * @param {string} content Diff HTML or wikitext
+ */
+ve.ui.MWSaveDialog.prototype.setDiffAndReview = function ( content ) {
+ this.$reviewViewer.empty().append( content );
+ this.reviewGoodButton.setDisabled( false );
+ this.$loadingIcon.hide();
+ this.swapPanel( 'review' );
+};
+
+/**
+ * Set sanity check flag
+ *
+ * @param {boolean} verified Status of sanity check
+ */
+ve.ui.MWSaveDialog.prototype.setSanityCheck = function ( verified ) {
+ this.sanityCheckVerified = !!verified;
+};
+
+/* Registration */
+
+ve.ui.dialogFactory.register( ve.ui.MWSaveDialog );
diff --git a/modules/ve-mw/ui/styles/ve.ui.MWDialog.css b/modules/ve-mw/ui/styles/ve.ui.MWDialog.css
index 7157ca66d0..1222dd6fe3 100644
--- a/modules/ve-mw/ui/styles/ve.ui.MWDialog.css
+++ b/modules/ve-mw/ui/styles/ve.ui.MWDialog.css
@@ -88,3 +88,95 @@
left: 0;
right: 0;
}
+
+/* ve.ui.MWSaveDialog */
+
+.ve-ui-mwSaveDialog-panel {
+ margin: 1.25em;
+}
+
+.ve-ui-mwSaveDialog-summaryLabel {
+ padding: 0.25em 0;
+}
+
+.ve-ui-mwSaveDialog-summary {
+ width: 100%;
+ background-color: #fff;
+ border: solid 1px #ccc;
+ padding: 0.5em;
+ border-radius: 0.25em 0.25em 0 0;
+}
+
+.ve-ui-mwSaveDialog-summary textarea {
+ margin: 0;
+ padding: 0;
+ resize: none;
+ height: 80px;
+ border: none;
+ box-shadow: none;
+ background-color: transparent;
+}
+
+.ve-ui-mwSaveDialog-summary textarea:focus,
+.ve-ui-mwSaveDialog-summary textarea:active {
+ box-shadow: none;
+}
+
+.ve-ui-mwSaveDialog-foot {
+ margin: 0.5em;
+}
+
+.ve-ui-mwSaveDialog-options {
+ position: relative;
+ background-color: #f7f7f7;
+ border: solid 1px #ccc;
+ border-top: none;
+ border-radius: 0 0 0.25em 0.25em;
+ min-height: 3em;
+}
+
+.ve-ui-mwSaveDialog-checkboxes {
+ margin-right: 3.25em; /* Hack to prevent overlap on edit summary count */
+ line-height: 3em;
+ padding: 0 0.75em;
+}
+
+.ve-ui-mwSaveDialog-checkboxes label {
+ padding-right: 0.75em;
+ vertical-align: middle;
+}
+
+.ve-ui-mwSaveDialog-checkboxes input {
+ vertical-align: middle;
+}
+
+.ve-ui-mwSaveDialog-editSummary-count {
+ position: absolute;
+ right: 0;
+ top: 0;
+ bottom: 0;
+ border-left: solid 1px #eee;
+ line-height: 3em;
+ padding: 0 1em;
+ color: #aaa;
+}
+
+.ve-ui-mwSaveDialog-working {
+ display: none;
+ float: right;
+ height: 2.5em;
+ width: 128px;
+ margin-right: 1em;
+ background-position: right center;
+ background-repeat: no-repeat;
+}
+
+.ve-ui-mwSaveDialog-license,
+.ve-ui-mwSaveDialog-dirtymsg,
+.ve-ui-mwSaveDialog-report-notice {
+ font-size: 0.85em;
+ line-height: 1.25em;
+ padding: 0;
+ margin: 0;
+ color: #999;
+}
diff --git a/modules/ve/ui/styles/ve.ui.Dialog.css b/modules/ve/ui/styles/ve.ui.Dialog.css
index 9c463cd46b..d2101b30b4 100644
--- a/modules/ve/ui/styles/ve.ui.Dialog.css
+++ b/modules/ve/ui/styles/ve.ui.Dialog.css
@@ -17,7 +17,6 @@
background-color: rgba(255,255,255,0.5);
-webkit-animation: ve-ui-fade-in 250ms ease-in-out 0 1 normal;
-moz-animation: ve-ui-fade-in 250ms ease-in-out 0 1 normal;
- -ms-animation: ve-ui-fade-in 250ms ease-in-out 0 1 normal;
-o-animation: ve-ui-fade-in 250ms ease-in-out 0 1 normal;
animation: ve-ui-fade-in 250ms ease-in-out 0 1 normal;
}
@@ -25,7 +24,6 @@
.ve-ui-dialog-closing {
-webkit-animation: ve-ui-fade-in 250ms ease-in-out 0 1 reverse;
-moz-animation: ve-ui-fade-in 250ms ease-in-out 0 1 reverse;
- -ms-animation: ve-ui-fade-in 250ms ease-in-out 0 1 reverse;
-o-animation: ve-ui-fade-in 250ms ease-in-out 0 1 reverse;
animation: ve-ui-fade-in 250ms ease-in-out 0 1 reverse;
}
@@ -45,22 +43,24 @@
border-radius: 0.5em;
box-shadow: 0 0.2em 1em rgba(0, 0, 0, 0.3);
overflow: hidden;
+ -webkit-transition: all 250ms ease-in-out;
+ -moz-transition: all 250ms ease-in-out;
+ -o-transition: all 250ms ease-in-out;
+ transition: all 250ms ease-in-out;
-webkit-animation: ve-ui-zoom-in 250ms ease-in-out 0 1 normal;
-moz-animation: ve-ui-zoom-in 250ms ease-in-out 0 1 normal;
- -ms-animation: ve-ui-zoom-in 250ms ease-in-out 0 1 normal;
-o-animation: ve-ui-zoom-in 250ms ease-in-out 0 1 normal;
animation: ve-ui-zoom-in 250ms ease-in-out 0 1 normal;
}
-.ve-ui-dialog .ve-ui-window-frame.ve-ui-window-frame-small {
- max-width: 600px;
- max-height: 300px;
+.ve-ui-dialog .ve-ui-window-frame-small {
+ width: 600px;
+ max-height: 375px;
}
.ve-ui-dialog-closing .ve-ui-window-frame {
-webkit-animation: ve-ui-zoom-in 250ms ease-in-out 0 1 reverse;
-moz-animation: ve-ui-zoom-in 250ms ease-in-out 0 1 reverse;
- -ms-animation: ve-ui-zoom-in 250ms ease-in-out 0 1 reverse;
-o-animation: ve-ui-zoom-in 250ms ease-in-out 0 1 reverse;
animation: ve-ui-zoom-in 250ms ease-in-out 0 1 reverse;
}
@@ -185,3 +185,7 @@
right: 0;
box-shadow: 0 0 0.25em rgba(0,0,0,0.25);
}
+
+.ve-ui-window-body .ve-ce-documentNode {
+ padding: 1.875em; /* 1.5/0.8 */
+}
diff --git a/modules/ve/ui/ve.ui.Window.js b/modules/ve/ui/ve.ui.Window.js
index 4bccb6b10b..df3f8461a3 100644
--- a/modules/ve/ui/ve.ui.Window.js
+++ b/modules/ve/ui/ve.ui.Window.js
@@ -115,7 +115,7 @@ ve.ui.Window.prototype.initialize = function () {
// Properties
this.$title = this.$$( '' );
if ( this.getTitle() ) {
- this.$title.text( this.getTitle() );
+ this.setTitle();
}
this.$icon = this.$$( '' )
.addClass( 've-ui-icon-' + this.constructor.static.icon );
@@ -214,8 +214,10 @@ ve.ui.Window.prototype.getTitle = function () {
};
/**
+ * Set the size of window frame.
*
- * @method
+ * @param {number} [width=auto] Custom width
+ * @param {number} [height=auto] Custom height
*/
ve.ui.Window.prototype.setSize = function ( width, height ) {
if ( !this.frame.$content ) {
@@ -229,8 +231,19 @@ ve.ui.Window.prototype.setSize = function ( width, height ) {
};
/**
+ * Set the title of the window.
*
- * @method
+ * @param {string} [customTitle] Custom title, override the static.titleMessage
+ */
+ve.ui.Window.prototype.setTitle = function ( customTitle ) {
+ this.$title.text( customTitle || this.getTitle() );
+};
+
+/**
+ * Set the height of window to fit with contents.
+ *
+ * @param {number} [min=0] Min height
+ * @param {number} [max] Max height (defaults to content's outer height)
*/
ve.ui.Window.prototype.fitHeightToContents = function ( min, max ) {
var height = this.frame.$content.outerHeight();
@@ -241,7 +254,10 @@ ve.ui.Window.prototype.fitHeightToContents = function ( min, max ) {
};
/**
+ * Set the width of window to fit with contents.
*
+ * @param {number} [min=0] Min height
+ * @param {number} [max] Max height (defaults to content's outer width)
*/
ve.ui.Window.prototype.fitWidthToContents = function ( min, max ) {
var width = this.frame.$content.outerWidth();
@@ -252,8 +268,10 @@ ve.ui.Window.prototype.fitWidthToContents = function ( min, max ) {
};
/**
+ * Set the position of window to fit with contents..
*
- * @method
+ * @param {string} left Left offset
+ * @param {string} top Top offset
*/
ve.ui.Window.prototype.setPosition = function ( left, top ) {
this.$.css( { 'left': left, 'top': top } );
diff --git a/modules/ve/ui/ve.ui.WindowSet.js b/modules/ve/ui/ve.ui.WindowSet.js
index 9bf2ba5c09..a09e5a4288 100644
--- a/modules/ve/ui/ve.ui.WindowSet.js
+++ b/modules/ve/ui/ve.ui.WindowSet.js
@@ -105,16 +105,13 @@ ve.ui.WindowSet.prototype.getCurrent = function () {
};
/**
- * Opens a given window.
+ * Return a given window.
*
- * Any already open dialog will be closed.
- *
- * @method
* @param {string} name Symbolic name of window
* @param {Object} [config] Configuration options to be sent to the window class constructor
- * @chainable
+ * @return {ve.ui.Window} Window with specified name
*/
-ve.ui.WindowSet.prototype.open = function ( name, config ) {
+ve.ui.WindowSet.prototype.getWindow = function ( name, config ) {
var win;
if ( !this.factory.lookup( name ) ) {
@@ -133,8 +130,19 @@ ve.ui.WindowSet.prototype.open = function ( name, config ) {
this.$.append( win.$ );
win.getFrame().load();
}
+ return this.windows[name];
+};
- this.windows[name].open();
-
+/**
+ * Opens a given window.
+ *
+ * Any already open dialog will be closed.
+ *
+ * @param {string} name Symbolic name of window
+ * @param {Object} [config] Config options to be sent to the window class constructor
+ * @chainable
+ */
+ve.ui.WindowSet.prototype.open = function ( name, config ) {
+ this.getWindow( name, config ).open();
return this;
};
diff --git a/modules/ve/ui/widgets/ve.ui.ButtonWidget.js b/modules/ve/ui/widgets/ve.ui.ButtonWidget.js
index 751943d7ae..192a511b2b 100644
--- a/modules/ve/ui/widgets/ve.ui.ButtonWidget.js
+++ b/modules/ve/ui/widgets/ve.ui.ButtonWidget.js
@@ -51,11 +51,11 @@ ve.ui.ButtonWidget = function VeUiButtonWidget( config ) {
.append( this.$label )
.attr( {
'role': 'button',
- 'tabIndex': config.tabIndex || 0,
'title': config.title,
'href': config.href,
'target': config.target
- } );
+ } )
+ .prop( 'tabIndex', config.tabIndex || 0 );
this.$
.addClass( 've-ui-buttonWidget' )
.append( this.$button );
' ).text( wikitext ) );
-
- this.$saveDialogLoadingIcon.hide();
- this.saveDialogReviewGoodButton.setDisabled( false );
+ this.saveDialog.setDiffAndReview( $( '
' ).text( wikitext ) );
};
/**
@@ -660,7 +584,7 @@ ve.init.mw.ViewPageTarget.prototype.onSerialize = function ( wikitext ) {
*/
ve.init.mw.ViewPageTarget.prototype.onShowChangesError = function ( jqXHR, status ) {
alert( ve.msg( 'visualeditor-differror', status ) );
- this.$saveDialogLoadingIcon.hide();
+ this.saveDialog.$loadingIcon.hide();
};
/**
@@ -672,7 +596,7 @@ ve.init.mw.ViewPageTarget.prototype.onShowChangesError = function ( jqXHR, statu
*/
ve.init.mw.ViewPageTarget.prototype.onSerializeError = function ( jqXHR, status ) {
alert( ve.msg( 'visualeditor-serializeerror', status ) );
- this.$saveDialogLoadingIcon.hide();
+ this.saveDialog.$loadingIcon.hide();
};
/**
@@ -681,8 +605,8 @@ ve.init.mw.ViewPageTarget.prototype.onSerializeError = function ( jqXHR, status
* @method
*/
ve.init.mw.ViewPageTarget.prototype.onEditConflict = function () {
- this.$saveDialogLoadingIcon.hide();
- this.swapSaveDialog( 'conflict' );
+ this.saveDialog.$loadingIcon.hide();
+ this.saveDialog.swapPanel( 'conflict' );
};
/**
@@ -691,8 +615,9 @@ ve.init.mw.ViewPageTarget.prototype.onEditConflict = function () {
* @method
*/
ve.init.mw.ViewPageTarget.prototype.onNoChanges = function () {
- this.$saveDialogLoadingIcon.hide();
- this.swapSaveDialog( 'nochanges' );
+ this.saveDialog.$loadingIcon.hide();
+ this.saveDialog.swapPanel( 'nochanges' );
+ this.saveDialog.reviewGoodButton.setDisabled( false );
};
/**
@@ -778,10 +703,7 @@ ve.init.mw.ViewPageTarget.prototype.onToolbarFeedbackToolClick = function () {
*/
ve.init.mw.ViewPageTarget.prototype.onSurfaceModelTransact = function () {
// Clear the diff
- this.$saveDialog
- .find( '.ve-init-mw-viewPageTarget-saveDialog-slide-review .ve-init-mw-viewPageTarget-saveDialog-viewer' )
- .empty();
-
+ this.saveDialog.$reviewViewer.empty();
this.surface.getModel().disconnect( this, { 'transact': 'onSurfaceModelTransact' } );
};
@@ -833,8 +755,28 @@ ve.init.mw.ViewPageTarget.prototype.updateToolbarSaveButtonState = function () {
*
* @method
*/
-ve.init.mw.ViewPageTarget.prototype.onSaveDialogReviewButtonClick = function () {
- this.swapSaveDialog( 'review' );
+ve.init.mw.ViewPageTarget.prototype.onSaveDialogReview = function () {
+ var doc = this.surface.getModel().getDocument();
+ this.sanityCheckVerified = true;
+ this.saveDialog.setSanityCheck( this.sanityCheckVerified );
+
+ if ( !this.saveDialog.$reviewViewer.find( 'table, pre' ).length ) {
+ this.saveDialog.reviewGoodButton.setDisabled( true );
+ this.saveDialog.$loadingIcon.show();
+ if ( this.pageExists ) {
+ // Has no callback, handled via target.onShowChanges
+ this.showChanges(
+ ve.dm.converter.getDomFromData( doc.getFullData(), doc.getStore(), doc.getInternalList() )
+ );
+ } else {
+ this.serialize(
+ ve.dm.converter.getDomFromData( doc.getFullData(), doc.getStore(), doc.getInternalList() ),
+ ve.bind( this.onSerialize, this )
+ );
+ }
+ } else {
+ this.saveDialog.swapPanel( 'review' );
+ }
};
/**
@@ -842,7 +784,7 @@ ve.init.mw.ViewPageTarget.prototype.onSaveDialogReviewButtonClick = function ()
*
* @method
*/
-ve.init.mw.ViewPageTarget.prototype.onSaveDialogSaveButtonClick = function () {
+ve.init.mw.ViewPageTarget.prototype.onSaveDialogSave = function () {
this.saveDocument();
};
@@ -864,17 +806,17 @@ ve.init.mw.ViewPageTarget.prototype.saveDocument = function () {
if (
+mw.user.options.get( 'forceeditsummary' ) &&
saveOptions.summary === '' &&
- !this.messages.missingsummary
+ !this.saveDialog.messages.missingsummary
) {
- this.showMessage(
+ this.saveDialog.showMessage(
'missingsummary',
// Wrap manually since this core message already includes a bold "Warning:" label
$( '