mirror of
https://gerrit.wikimedia.org/r/mediawiki/extensions/VisualEditor
synced 2024-09-25 03:08:42 +00:00
Make the save dialog an actual dialog
Major changes: * Create a MW specific save dialog class * Widgetize save dialog elements * Simplification of viewPageTarget Minor changes: * Added getWindow method to windowSet and setTitle methods to window class * Add transition css properties to dialog styles Bug: 48566 Bug: 50722 Bug: 51918 Bug: 52175 Bug: 53313 Change-Id: I8c0db01fb8477a9b3d3dfe2a6073ac67869ce40e
This commit is contained in:
parent
5a1a960b19
commit
972c9a46b7
|
@ -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.',
|
||||
|
|
|
@ -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(
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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 = '\
|
||||
<div class="ve-init-mw-viewPageTarget-saveDialog-head">\
|
||||
<div class="ve-init-mw-viewPageTarget-saveDialog-prevButton"></div>\
|
||||
<div class="ve-init-mw-viewPageTarget-saveDialog-closeButton"></div>\
|
||||
<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-save">\
|
||||
<label class="ve-init-mw-viewPageTarget-saveDialog-editSummary-label"\
|
||||
for="ve-init-mw-viewPageTarget-saveDialog-editSummary"\
|
||||
id="ve-init-mw-viewPageTarget-saveDialog-editSummary-label"></label>\
|
||||
<div class="ve-init-mw-viewPageTarget-saveDialog-summary">\
|
||||
<textarea name="editSummary" class="ve-init-mw-viewPageTarget-saveDialog-editSummary"\
|
||||
id="ve-init-mw-viewPageTarget-saveDialog-editSummary" type="text"\
|
||||
rows="4"></textarea>\
|
||||
</div>\
|
||||
<div class="ve-init-mw-viewPageTarget-saveDialog-options">\
|
||||
<div class="ve-init-mw-viewPageTarget-saveDialog-checkboxes">\
|
||||
</div>\
|
||||
<label class="ve-init-mw-viewPageTarget-saveDialog-editSummaryCount"></label>\
|
||||
</div>\
|
||||
<div class="ve-init-mw-viewPageTarget-saveDialog-messages"></div>\
|
||||
<div class="ve-init-mw-viewPageTarget-saveDialog-actions">\
|
||||
<div class="ve-init-mw-viewPageTarget-saveDialog-dirtymsg"></div>\
|
||||
<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-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-conflict">\
|
||||
<div class="ve-init-mw-viewPageTarget-saveDialog-conflict">\
|
||||
</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-nochanges">\
|
||||
<div class="ve-init-mw-viewPageTarget-saveDialog-nochanges">\
|
||||
</div>\
|
||||
</div>\
|
||||
</div>';
|
||||
|
||||
/* Methods */
|
||||
|
||||
/**
|
||||
|
@ -256,10 +200,9 @@ ve.init.mw.ViewPageTarget.prototype.deactivate = function ( override ) {
|
|||
this.detachToolbarButtons();
|
||||
}
|
||||
|
||||
this.resetSaveDialog();
|
||||
this.hideSaveDialog();
|
||||
this.detachSaveDialog();
|
||||
|
||||
this.saveDialog.reset();
|
||||
this.saveDialog.close();
|
||||
// Check we got as far as setting up the surface
|
||||
if ( this.active ) {
|
||||
// If we got as far as setting up the surface, tear that down
|
||||
this.tearDownSurface();
|
||||
|
@ -298,7 +241,6 @@ ve.init.mw.ViewPageTarget.prototype.onLoad = function ( doc ) {
|
|||
this.setupToolbarBetaNotices();
|
||||
this.setupSaveDialog();
|
||||
this.attachToolbarButtons();
|
||||
this.attachSaveDialog();
|
||||
this.restoreScrollPosition();
|
||||
this.restoreEditSection();
|
||||
this.setupBeforeUnloadHandler();
|
||||
|
@ -394,9 +336,8 @@ ve.init.mw.ViewPageTarget.prototype.onSave = function ( html, newid ) {
|
|||
mw.config.set( 'wgCurRevisionId', newid );
|
||||
this.revid = newid;
|
||||
}
|
||||
|
||||
this.hideSaveDialog();
|
||||
this.resetSaveDialog();
|
||||
this.saveDialog.close();
|
||||
this.saveDialog.reset();
|
||||
this.replacePageContent( html );
|
||||
this.setupSectionEditLinks();
|
||||
this.tearDownBeforeUnloadHandler();
|
||||
|
@ -422,21 +363,21 @@ ve.init.mw.ViewPageTarget.prototype.onSaveError = function ( jqXHR, status, data
|
|||
var api, editApi,
|
||||
viewPage = this;
|
||||
|
||||
this.saveDialogSaveButton.setDisabled( false );
|
||||
this.$saveDialogLoadingIcon.hide();
|
||||
this.saveDialog.saveButton.setDisabled( false );
|
||||
this.saveDialog.$loadingIcon.hide();
|
||||
|
||||
this.clearMessage( 'api-save-error' );
|
||||
this.saveDialog.clearMessage( 'api-save-error' );
|
||||
|
||||
// Handle empty response
|
||||
if ( !data ) {
|
||||
this.showMessage(
|
||||
this.saveDialog.showMessage(
|
||||
'api-save-error',
|
||||
ve.msg( 'visualeditor-saveerror', 'Empty server response' ),
|
||||
{
|
||||
wrap: 'error'
|
||||
}
|
||||
);
|
||||
this.saveDialogSaveButton.setDisabled( true );
|
||||
this.saveDialog.saveButton.setDisabled( true );
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -444,7 +385,7 @@ ve.init.mw.ViewPageTarget.prototype.onSaveError = function ( jqXHR, status, data
|
|||
|
||||
// Handle spam blacklist error (either from core or from Extension:SpamBlacklist)
|
||||
if ( editApi && editApi.spamblacklist ) {
|
||||
this.showMessage(
|
||||
this.saveDialog.showMessage(
|
||||
'api-save-error',
|
||||
// TODO: Use mediawiki.language equivalant of Language.php::listToText once it exists
|
||||
ve.msg( 'spamprotectiontext' ) + ' ' + ve.msg( 'spamprotectionmatch', editApi.spamblacklist.split( '|' ).join( ', ' ) ),
|
||||
|
@ -452,14 +393,14 @@ ve.init.mw.ViewPageTarget.prototype.onSaveError = function ( jqXHR, status, data
|
|||
wrap: 'error'
|
||||
}
|
||||
);
|
||||
this.saveDialogSaveButton.setDisabled( true );
|
||||
this.saveDialog.saveButton.setDisabled( true );
|
||||
return;
|
||||
}
|
||||
|
||||
// Handle warnings/errors from Extension:AbuseFilter
|
||||
// TODO: Move this to a plugin
|
||||
if ( editApi && editApi.info && editApi.info.indexOf( 'Hit AbuseFilter:' ) === 0 && editApi.warning ) {
|
||||
this.showMessage(
|
||||
this.saveDialog.showMessage(
|
||||
'api-save-error',
|
||||
$.parseHTML( editApi.warning ),
|
||||
{ wrap: false }
|
||||
|
@ -473,8 +414,8 @@ ve.init.mw.ViewPageTarget.prototype.onSaveError = function ( jqXHR, status, data
|
|||
// Handle token errors
|
||||
if ( data.error && data.error.code === 'badtoken' ) {
|
||||
api = new mw.Api();
|
||||
viewPage.saveDialogSaveButton.setDisabled( true );
|
||||
viewPage.$saveDialogLoadingIcon.show();
|
||||
viewPage.saveDialog.saveButton.setDisabled( true );
|
||||
viewPage.saveDialog.$loadingIcon.show();
|
||||
api.get( {
|
||||
// action=query&meta=userinfo and action=tokens&type=edit can't be combined
|
||||
// but action=query&meta=userinfo and action=query&prop=info can, however
|
||||
|
@ -489,7 +430,7 @@ ve.init.mw.ViewPageTarget.prototype.onSaveError = function ( jqXHR, status, data
|
|||
'intoken': 'edit'
|
||||
} )
|
||||
.always( function () {
|
||||
viewPage.$saveDialogLoadingIcon.hide();
|
||||
viewPage.saveDialog.$loadingIcon.hide();
|
||||
} )
|
||||
.done( function ( data ) {
|
||||
var badTokenText, userMsg,
|
||||
|
@ -511,7 +452,7 @@ ve.init.mw.ViewPageTarget.prototype.onSaveError = function ( jqXHR, status, data
|
|||
viewPage.saveDocument();
|
||||
} else {
|
||||
// The now current session is a different user
|
||||
viewPage.saveDialogSaveButton.setDisabled( false );
|
||||
viewPage.saveDialog.saveButton.setDisabled( false );
|
||||
|
||||
// Trailing space is to separate from the other message.
|
||||
badTokenText = document.createTextNode( mw.msg( 'visualeditor-savedialog-error-badtoken' ) + ' ' );
|
||||
|
@ -526,7 +467,7 @@ ve.init.mw.ViewPageTarget.prototype.onSaveError = function ( jqXHR, status, data
|
|||
'wgUserName': null
|
||||
} );
|
||||
|
||||
viewPage.showMessage(
|
||||
viewPage.saveDialog.showMessage(
|
||||
'api-save-error',
|
||||
$( badTokenText ).add(
|
||||
$.parseHTML( mw.message( 'visualeditor-savedialog-identify-anon' ).parse() )
|
||||
|
@ -545,7 +486,7 @@ ve.init.mw.ViewPageTarget.prototype.onSaveError = function ( jqXHR, status, data
|
|||
.replace( /\$1/g, userInfo.name )
|
||||
);
|
||||
|
||||
viewPage.showMessage(
|
||||
viewPage.saveDialog.showMessage(
|
||||
'api-save-error',
|
||||
$( badTokenText ).add(
|
||||
$.parseHTML( mw.message( userMsg ).parse() )
|
||||
|
@ -573,9 +514,9 @@ ve.init.mw.ViewPageTarget.prototype.onSaveError = function ( jqXHR, status, data
|
|||
input: new ve.ui.TextInputWidget(),
|
||||
id: editApi.captcha.id
|
||||
};
|
||||
this.showMessage(
|
||||
this.saveDialog.showMessage(
|
||||
'api-save-error',
|
||||
$( '<div>').append(
|
||||
$( '<div>' ).append(
|
||||
// msg: simplecaptcha-edit, fancycaptcha-edit, ..
|
||||
$( '<p>' ).append(
|
||||
$( '<strong>' ).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( $( '<pre>' ).text( wikitext ) );
|
||||
|
||||
this.$saveDialogLoadingIcon.hide();
|
||||
this.saveDialogReviewGoodButton.setDisabled( false );
|
||||
this.saveDialog.setDiffAndReview( $( '<pre>' ).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
|
||||
$( '<p>' ).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 = $( '<div class="ve-init-mw-viewPageTarget-saveDialog-message"></div>' );
|
||||
if ( options.wrap !== false ) {
|
||||
$message.append( $( '<p>').append(
|
||||
// visualeditor-savedialog-label-error
|
||||
// visualeditor-savedialog-label-warning
|
||||
$( '<strong>' ).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.
|
||||
*
|
||||
|
|
377
modules/ve-mw/ui/dialogs/ve.ui.MWSaveDialog.js
Normal file
377
modules/ve-mw/ui/dialogs/ve.ui.MWSaveDialog.js
Normal file
|
@ -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.$$( '<div>' ).addClass( 've-ui-mwSaveDialog-summaryLabel' )
|
||||
.html( ve.init.platform.getParsedMessage( 'summary' ) );
|
||||
this.editSummaryInput = new ve.ui.TextInputWidget(
|
||||
{ '$$': this.frame.$$, 'multiline': true, 'placeholder': ve.msg( 'visualeditor-editsummary' ) }
|
||||
);
|
||||
this.editSummaryInput.$.addClass( 've-ui-mwSaveDialog-summary' );
|
||||
this.editSummaryInput.$input
|
||||
.placeholder()
|
||||
.byteLimit( this.editSummaryByteLimit )
|
||||
.prop( 'tabIndex', 0 );
|
||||
this.editSummaryInput.on( 'change', ve.bind( function () {
|
||||
var $textarea = this.editSummaryInput.$input,
|
||||
$editSummaryCount = this.savePanel.$.find( '.ve-ui-mwSaveDialog-editSummary-count' );
|
||||
// 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(
|
||||
saveDialog.editSummaryByteLimit - $.byteLength( $textarea.val() )
|
||||
);
|
||||
} );
|
||||
}, this ) );
|
||||
|
||||
this.$saveOptions = this.frame.$$( '<div>' ).addClass( 've-ui-mwSaveDialog-options' ).append(
|
||||
this.frame.$$( '<div>' ).addClass( 've-ui-mwSaveDialog-checkboxes' ),
|
||||
new ve.ui.InputLabelWidget( { '$$': this.frame.$$, 'label': 'text' } ).$
|
||||
.addClass( 've-ui-mwSaveDialog-editSummary-count' ).text( this.editSummaryByteLimit )
|
||||
);
|
||||
this.$saveMessages = this.frame.$$( '<div>' );
|
||||
this.$saveActions = this.frame.$$( '<div>' ).append(
|
||||
this.frame.$$( '<div>' ).addClass( 've-ui-mwSaveDialog-dirtymsg' )
|
||||
);
|
||||
this.$saveFoot = this.frame.$$( '<div>' ).addClass( 've-ui-mwSaveDialog-foot' ).append(
|
||||
this.frame.$$( '<p>' ).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.$$( '<div>' ).addClass( 've-ui-mwSaveDialog-viewer' );
|
||||
this.$reviewActions = this.frame.$$( '<div>' ).addClass( 've-ui-mwSaveDialog-actions' );
|
||||
this.reviewPanel.$.append( this.$reviewViewer, this.$reviewActions );
|
||||
|
||||
// Conflict panel
|
||||
this.conflictPanel = new ve.ui.PanelLayout( { '$$': this.frame.$$, 'scrollable': true } );
|
||||
this.$conflict = this.frame.$$( '<div>' ).addClass( 've-ui-mwSaveDialog-conflict' )
|
||||
.html( ve.init.platform.getParsedMessage( 'visualeditor-editconflict' ) );
|
||||
this.conflictPanel.$.append( this.$conflict );
|
||||
|
||||
// No changes panel
|
||||
this.nochangesPanel = new ve.ui.PanelLayout( { '$$': this.frame.$$, 'scrollable': true } );
|
||||
this.$noChanges = this.frame.$$( '<div>' ).addClass( 've-ui-mwSaveDialog-nochanges' )
|
||||
.html( ve.init.platform.getParsedMessage( 'visualeditor-diff-nochanges' ) );
|
||||
this.nochangesPanel.$.append( this.$noChanges );
|
||||
|
||||
// Panel stack
|
||||
this.panel = new ve.ui.StackPanelLayout( { '$$': this.frame.$$, 'scrollable': true } );
|
||||
this.panel.$.addClass( 've-ui-mwSaveDialog-panel' );
|
||||
this.panel.addItems( [this.savePanel, this.reviewPanel, this.conflictPanel, this.nochangesPanel], 0 );
|
||||
|
||||
/* Buttons */
|
||||
|
||||
// Save button for "save" panel
|
||||
this.saveButton = new ve.ui.PushButtonWidget( {
|
||||
'label': ve.msg(
|
||||
// visualeditor-savedialog-label-restore, visualeditor-savedialog-label-save
|
||||
'visualeditor-savedialog-label-' + ( this.restoring ? 'restore' : 'save' )
|
||||
),
|
||||
'flags': ['constructive']
|
||||
} );
|
||||
this.saveButton.connect( this, { 'click': 'onSaveButtonClick' } );
|
||||
|
||||
// Review button for "save" panel
|
||||
this.reviewButton = new ve.ui.PushButtonWidget( {
|
||||
'label': ve.msg( 'visualeditor-savedialog-label-review' )
|
||||
} );
|
||||
this.reviewButton.connect( this, { 'click': 'onReviewButtonClick' } );
|
||||
|
||||
// Review good button on "review" panel
|
||||
this.reviewGoodButton = new ve.ui.PushButtonWidget( {
|
||||
'label': ve.msg( 'visualeditor-savedialog-label-review-good' ),
|
||||
'flags': ['constructive']
|
||||
} );
|
||||
this.reviewGoodButton.connect( this, { 'click': 'onReviewGoodButtonClick' } );
|
||||
// Resolve conflict
|
||||
this.resolveConflictButton = new ve.ui.PushButtonWidget( {
|
||||
'label': ve.msg( 'visualeditor-savedialog-label-resolve-conflict' ),
|
||||
'flags': ['constructive']
|
||||
} );
|
||||
this.resolveConflictButton.connect( this, { 'click': 'onResolveConflictButtonClick' } );
|
||||
|
||||
this.$loadingIcon = this.frame.$$( '<div>' ).addClass( 've-ui-mwSaveDialog-working' );
|
||||
|
||||
// Initialization
|
||||
this.$body.append( this.panel.$ );
|
||||
this.$foot.append(
|
||||
this.reviewButton.$,
|
||||
this.saveButton.$,
|
||||
this.reviewGoodButton.$,
|
||||
this.resolveConflictButton.$,
|
||||
this.$loadingIcon
|
||||
);
|
||||
};
|
||||
|
||||
ve.ui.MWSaveDialog.prototype.onSaveButtonClick = function () {
|
||||
this.emit( 'save' );
|
||||
};
|
||||
|
||||
ve.ui.MWSaveDialog.prototype.onReviewButtonClick = function () {
|
||||
this.emit( 'review' );
|
||||
};
|
||||
|
||||
ve.ui.MWSaveDialog.prototype.onReviewGoodButtonClick = function () {
|
||||
this.swapPanel( 'save' );
|
||||
};
|
||||
|
||||
ve.ui.MWSaveDialog.prototype.onResolveConflictButtonClick = function () {
|
||||
this.emit( 'resolve' );
|
||||
};
|
||||
|
||||
/**
|
||||
* Swap state in the save dialog.
|
||||
*
|
||||
* @param {string} panel One of 'save', 'review', 'conflict' or 'nochanges'
|
||||
* @returns {jQuery} The now active panel
|
||||
* @throws {Error} Unknown saveDialog panel
|
||||
*/
|
||||
ve.ui.MWSaveDialog.prototype.swapPanel = function ( panel ) {
|
||||
var dialog = this,
|
||||
panelObj = dialog[panel + 'Panel'];
|
||||
|
||||
if ( ve.indexOf( panel, [ 'save', 'review', 'conflict', 'nochanges' ] ) === -1 ) {
|
||||
throw new Error( 'Unknown saveDialog panel: ' + panel );
|
||||
}
|
||||
|
||||
// Update the window title
|
||||
this.setTitle( ve.msg( 'visualeditor-savedialog-title-' + panel ) );
|
||||
|
||||
// Old messages should not persist after panel changes
|
||||
this.clearAllMessages();
|
||||
|
||||
// Reset save button if we disabled it for e.g. unrecoverable spam error
|
||||
this.saveButton.setDisabled( false );
|
||||
|
||||
switch( panel ) {
|
||||
case 'save':
|
||||
if ( !this.sanityCheckVerified ) {
|
||||
this.showMessage( 'dirtywarning', mw.msg( 'visualeditor-savedialog-warning-dirty' ) );
|
||||
} else {
|
||||
this.saveButton.$.show();
|
||||
this.reviewButton.$.show();
|
||||
this.reviewGoodButton.$.hide();
|
||||
this.resolveConflictButton.$.hide();
|
||||
setTimeout( function () {
|
||||
// fix input reference
|
||||
var $textarea = dialog.editSummaryInput.$input;
|
||||
$textarea.focus();
|
||||
// If message has be pre-filled (e.g. section edit), move cursor to end
|
||||
if ( $textarea.val() !== '' ) {
|
||||
ve.selectEnd( $textarea[0] );
|
||||
}
|
||||
} );
|
||||
}
|
||||
break;
|
||||
case 'conflict':
|
||||
this.saveButton.$.hide();
|
||||
this.reviewButton.$.hide();
|
||||
this.reviewGoodButton.$.hide();
|
||||
this.resolveConflictButton.$.show();
|
||||
break;
|
||||
case 'review':
|
||||
// Make room for the diff by transitioning to a non-small window
|
||||
this.$frame.removeClass( 've-ui-window-frame-small' );
|
||||
/* falls through */
|
||||
case 'nochanges':
|
||||
this.saveButton.$.hide();
|
||||
this.reviewButton.$.hide();
|
||||
this.reviewGoodButton.$.show();
|
||||
this.resolveConflictButton.$.hide();
|
||||
break;
|
||||
}
|
||||
|
||||
if ( panel !== 'review' ) {
|
||||
// Restore original "small" size
|
||||
this.$frame.addClass( 've-ui-window-frame-small' );
|
||||
}
|
||||
|
||||
// Show the target panel
|
||||
this.panel.showItem( panelObj );
|
||||
|
||||
mw.hook( 've.saveDialog.stateChanged' ).fire();
|
||||
|
||||
return dialog;
|
||||
};
|
||||
|
||||
/**
|
||||
* 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.ui.MWSaveDialog.prototype.showMessage = function ( name, message, options ) {
|
||||
var $message;
|
||||
if ( !this.messages[name] ) {
|
||||
options = options || {};
|
||||
if ( options.wrap === undefined ) {
|
||||
options.wrap = 'warning';
|
||||
}
|
||||
$message = $( '<div class="ve-ui-mwSaveDialog-message"></div>' );
|
||||
if ( options.wrap !== false ) {
|
||||
$message.append( $( '<p>').append(
|
||||
// visualeditor-savedialog-label-error
|
||||
// visualeditor-savedialog-label-warning
|
||||
$( '<strong>' ).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 );
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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 */
|
||||
}
|
||||
|
|
|
@ -115,7 +115,7 @@ ve.ui.Window.prototype.initialize = function () {
|
|||
// Properties
|
||||
this.$title = this.$$( '<div class="ve-ui-window-title"></div>' );
|
||||
if ( this.getTitle() ) {
|
||||
this.$title.text( this.getTitle() );
|
||||
this.setTitle();
|
||||
}
|
||||
this.$icon = this.$$( '<div class="ve-ui-window-icon"></div>' )
|
||||
.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 } );
|
||||
|
|
|
@ -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;
|
||||
};
|
||||
|
|
|
@ -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 );
|
||||
|
|
Loading…
Reference in a new issue