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-save' => 'Save page',
|
||||||
'visualeditor-savedialog-label-warning' => 'Warning',
|
'visualeditor-savedialog-label-warning' => 'Warning',
|
||||||
'visualeditor-savedialog-title-conflict' => 'Conflict',
|
'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-review' => 'Review your changes',
|
||||||
'visualeditor-savedialog-title-save' => 'Save your changes',
|
'visualeditor-savedialog-title-save' => 'Save your changes',
|
||||||
'visualeditor-savedialog-warning-dirty' => 'Your edit may have been corrupted – please review before saving.',
|
'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.PanelLayout.js',
|
||||||
've/ui/layouts/ve.ui.StackPanelLayout.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.MWMetaDialog.js',
|
||||||
've-mw/ui/dialogs/ve.ui.MWBetaWelcomeDialog.js',
|
've-mw/ui/dialogs/ve.ui.MWBetaWelcomeDialog.js',
|
||||||
've-mw/ui/dialogs/ve.ui.MWMediaInsertDialog.js',
|
've-mw/ui/dialogs/ve.ui.MWMediaInsertDialog.js',
|
||||||
|
@ -559,6 +560,7 @@ $wgResourceModules += array(
|
||||||
'unicodejs.wordbreak',
|
'unicodejs.wordbreak',
|
||||||
'ext.visualEditor.base',
|
'ext.visualEditor.base',
|
||||||
'mediawiki.Title',
|
'mediawiki.Title',
|
||||||
|
'mediawiki.action.history.diff',
|
||||||
'jquery.autoEllipsis',
|
'jquery.autoEllipsis',
|
||||||
),
|
),
|
||||||
'messages' => array(
|
'messages' => array(
|
||||||
|
|
|
@ -121,226 +121,10 @@
|
||||||
color: #555;
|
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 */
|
/* Images */
|
||||||
|
|
||||||
.ve-init-mw-viewPageTarget-loading,
|
.ve-init-mw-viewPageTarget-loading,
|
||||||
.ve-init-mw-viewPageTarget-saveDialog-working {
|
.ve-ui-mwSaveDialog-working {
|
||||||
/* @embed */
|
/* @embed */
|
||||||
background-image: url(images/loading-ltr.gif);
|
background-image: url(images/loading-ltr.gif);
|
||||||
}
|
}
|
||||||
|
|
|
@ -34,9 +34,7 @@ ve.init.mw.ViewPageTarget = function VeInitMwViewPageTarget() {
|
||||||
this.toolbarOffset = null;
|
this.toolbarOffset = null;
|
||||||
this.toolbarCancelButton = null;
|
this.toolbarCancelButton = null;
|
||||||
this.toolbarSaveButton = null;
|
this.toolbarSaveButton = null;
|
||||||
this.saveDialogSlideHistory = [];
|
this.saveDialog = null;
|
||||||
this.saveDialogSaveButton = null;
|
|
||||||
this.saveDialogReviewGoodButton = null;
|
|
||||||
this.toolbarEditNoticesButton = null;
|
this.toolbarEditNoticesButton = null;
|
||||||
this.toolbarEditNotices = null;
|
this.toolbarEditNotices = null;
|
||||||
this.toolbarBetaNoticesButton = null;
|
this.toolbarBetaNoticesButton = null;
|
||||||
|
@ -62,7 +60,6 @@ ve.init.mw.ViewPageTarget = function VeInitMwViewPageTarget() {
|
||||||
this.actFromPopState = false;
|
this.actFromPopState = false;
|
||||||
this.scrollTop = null;
|
this.scrollTop = null;
|
||||||
this.currentUri = currentUri;
|
this.currentUri = currentUri;
|
||||||
this.messages = {};
|
|
||||||
this.section = currentUri.query.vesection || null;
|
this.section = currentUri.query.vesection || null;
|
||||||
this.sectionPositionRestored = false;
|
this.sectionPositionRestored = false;
|
||||||
this.sectionTitleRestored = 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 */
|
/* Methods */
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -256,10 +200,9 @@ ve.init.mw.ViewPageTarget.prototype.deactivate = function ( override ) {
|
||||||
this.detachToolbarButtons();
|
this.detachToolbarButtons();
|
||||||
}
|
}
|
||||||
|
|
||||||
this.resetSaveDialog();
|
this.saveDialog.reset();
|
||||||
this.hideSaveDialog();
|
this.saveDialog.close();
|
||||||
this.detachSaveDialog();
|
// Check we got as far as setting up the surface
|
||||||
|
|
||||||
if ( this.active ) {
|
if ( this.active ) {
|
||||||
// If we got as far as setting up the surface, tear that down
|
// If we got as far as setting up the surface, tear that down
|
||||||
this.tearDownSurface();
|
this.tearDownSurface();
|
||||||
|
@ -298,7 +241,6 @@ ve.init.mw.ViewPageTarget.prototype.onLoad = function ( doc ) {
|
||||||
this.setupToolbarBetaNotices();
|
this.setupToolbarBetaNotices();
|
||||||
this.setupSaveDialog();
|
this.setupSaveDialog();
|
||||||
this.attachToolbarButtons();
|
this.attachToolbarButtons();
|
||||||
this.attachSaveDialog();
|
|
||||||
this.restoreScrollPosition();
|
this.restoreScrollPosition();
|
||||||
this.restoreEditSection();
|
this.restoreEditSection();
|
||||||
this.setupBeforeUnloadHandler();
|
this.setupBeforeUnloadHandler();
|
||||||
|
@ -394,9 +336,8 @@ ve.init.mw.ViewPageTarget.prototype.onSave = function ( html, newid ) {
|
||||||
mw.config.set( 'wgCurRevisionId', newid );
|
mw.config.set( 'wgCurRevisionId', newid );
|
||||||
this.revid = newid;
|
this.revid = newid;
|
||||||
}
|
}
|
||||||
|
this.saveDialog.close();
|
||||||
this.hideSaveDialog();
|
this.saveDialog.reset();
|
||||||
this.resetSaveDialog();
|
|
||||||
this.replacePageContent( html );
|
this.replacePageContent( html );
|
||||||
this.setupSectionEditLinks();
|
this.setupSectionEditLinks();
|
||||||
this.tearDownBeforeUnloadHandler();
|
this.tearDownBeforeUnloadHandler();
|
||||||
|
@ -422,21 +363,21 @@ ve.init.mw.ViewPageTarget.prototype.onSaveError = function ( jqXHR, status, data
|
||||||
var api, editApi,
|
var api, editApi,
|
||||||
viewPage = this;
|
viewPage = this;
|
||||||
|
|
||||||
this.saveDialogSaveButton.setDisabled( false );
|
this.saveDialog.saveButton.setDisabled( false );
|
||||||
this.$saveDialogLoadingIcon.hide();
|
this.saveDialog.$loadingIcon.hide();
|
||||||
|
|
||||||
this.clearMessage( 'api-save-error' );
|
this.saveDialog.clearMessage( 'api-save-error' );
|
||||||
|
|
||||||
// Handle empty response
|
// Handle empty response
|
||||||
if ( !data ) {
|
if ( !data ) {
|
||||||
this.showMessage(
|
this.saveDialog.showMessage(
|
||||||
'api-save-error',
|
'api-save-error',
|
||||||
ve.msg( 'visualeditor-saveerror', 'Empty server response' ),
|
ve.msg( 'visualeditor-saveerror', 'Empty server response' ),
|
||||||
{
|
{
|
||||||
wrap: 'error'
|
wrap: 'error'
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
this.saveDialogSaveButton.setDisabled( true );
|
this.saveDialog.saveButton.setDisabled( true );
|
||||||
return;
|
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)
|
// Handle spam blacklist error (either from core or from Extension:SpamBlacklist)
|
||||||
if ( editApi && editApi.spamblacklist ) {
|
if ( editApi && editApi.spamblacklist ) {
|
||||||
this.showMessage(
|
this.saveDialog.showMessage(
|
||||||
'api-save-error',
|
'api-save-error',
|
||||||
// TODO: Use mediawiki.language equivalant of Language.php::listToText once it exists
|
// TODO: Use mediawiki.language equivalant of Language.php::listToText once it exists
|
||||||
ve.msg( 'spamprotectiontext' ) + ' ' + ve.msg( 'spamprotectionmatch', editApi.spamblacklist.split( '|' ).join( ', ' ) ),
|
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'
|
wrap: 'error'
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
this.saveDialogSaveButton.setDisabled( true );
|
this.saveDialog.saveButton.setDisabled( true );
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Handle warnings/errors from Extension:AbuseFilter
|
// Handle warnings/errors from Extension:AbuseFilter
|
||||||
// TODO: Move this to a plugin
|
// TODO: Move this to a plugin
|
||||||
if ( editApi && editApi.info && editApi.info.indexOf( 'Hit AbuseFilter:' ) === 0 && editApi.warning ) {
|
if ( editApi && editApi.info && editApi.info.indexOf( 'Hit AbuseFilter:' ) === 0 && editApi.warning ) {
|
||||||
this.showMessage(
|
this.saveDialog.showMessage(
|
||||||
'api-save-error',
|
'api-save-error',
|
||||||
$.parseHTML( editApi.warning ),
|
$.parseHTML( editApi.warning ),
|
||||||
{ wrap: false }
|
{ wrap: false }
|
||||||
|
@ -473,8 +414,8 @@ ve.init.mw.ViewPageTarget.prototype.onSaveError = function ( jqXHR, status, data
|
||||||
// Handle token errors
|
// Handle token errors
|
||||||
if ( data.error && data.error.code === 'badtoken' ) {
|
if ( data.error && data.error.code === 'badtoken' ) {
|
||||||
api = new mw.Api();
|
api = new mw.Api();
|
||||||
viewPage.saveDialogSaveButton.setDisabled( true );
|
viewPage.saveDialog.saveButton.setDisabled( true );
|
||||||
viewPage.$saveDialogLoadingIcon.show();
|
viewPage.saveDialog.$loadingIcon.show();
|
||||||
api.get( {
|
api.get( {
|
||||||
// action=query&meta=userinfo and action=tokens&type=edit can't be combined
|
// 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
|
// 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'
|
'intoken': 'edit'
|
||||||
} )
|
} )
|
||||||
.always( function () {
|
.always( function () {
|
||||||
viewPage.$saveDialogLoadingIcon.hide();
|
viewPage.saveDialog.$loadingIcon.hide();
|
||||||
} )
|
} )
|
||||||
.done( function ( data ) {
|
.done( function ( data ) {
|
||||||
var badTokenText, userMsg,
|
var badTokenText, userMsg,
|
||||||
|
@ -511,7 +452,7 @@ ve.init.mw.ViewPageTarget.prototype.onSaveError = function ( jqXHR, status, data
|
||||||
viewPage.saveDocument();
|
viewPage.saveDocument();
|
||||||
} else {
|
} else {
|
||||||
// The now current session is a different user
|
// 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.
|
// Trailing space is to separate from the other message.
|
||||||
badTokenText = document.createTextNode( mw.msg( 'visualeditor-savedialog-error-badtoken' ) + ' ' );
|
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
|
'wgUserName': null
|
||||||
} );
|
} );
|
||||||
|
|
||||||
viewPage.showMessage(
|
viewPage.saveDialog.showMessage(
|
||||||
'api-save-error',
|
'api-save-error',
|
||||||
$( badTokenText ).add(
|
$( badTokenText ).add(
|
||||||
$.parseHTML( mw.message( 'visualeditor-savedialog-identify-anon' ).parse() )
|
$.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 )
|
.replace( /\$1/g, userInfo.name )
|
||||||
);
|
);
|
||||||
|
|
||||||
viewPage.showMessage(
|
viewPage.saveDialog.showMessage(
|
||||||
'api-save-error',
|
'api-save-error',
|
||||||
$( badTokenText ).add(
|
$( badTokenText ).add(
|
||||||
$.parseHTML( mw.message( userMsg ).parse() )
|
$.parseHTML( mw.message( userMsg ).parse() )
|
||||||
|
@ -573,9 +514,9 @@ ve.init.mw.ViewPageTarget.prototype.onSaveError = function ( jqXHR, status, data
|
||||||
input: new ve.ui.TextInputWidget(),
|
input: new ve.ui.TextInputWidget(),
|
||||||
id: editApi.captcha.id
|
id: editApi.captcha.id
|
||||||
};
|
};
|
||||||
this.showMessage(
|
this.saveDialog.showMessage(
|
||||||
'api-save-error',
|
'api-save-error',
|
||||||
$( '<div>').append(
|
$( '<div>' ).append(
|
||||||
// msg: simplecaptcha-edit, fancycaptcha-edit, ..
|
// msg: simplecaptcha-edit, fancycaptcha-edit, ..
|
||||||
$( '<p>' ).append(
|
$( '<p>' ).append(
|
||||||
$( '<strong>' ).text( mw.msg( 'captcha-label' ) ),
|
$( '<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
|
// Handle (other) unknown and/or unrecoverable errors
|
||||||
this.showMessage(
|
this.saveDialog.showMessage(
|
||||||
'api-save-error',
|
'api-save-error',
|
||||||
document.createTextNode(
|
document.createTextNode(
|
||||||
( editApi && editApi.info ) ||
|
( editApi && editApi.info ) ||
|
||||||
|
@ -607,7 +548,7 @@ ve.init.mw.ViewPageTarget.prototype.onSaveError = function ( jqXHR, status, data
|
||||||
wrap: 'error'
|
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 ) {
|
ve.init.mw.ViewPageTarget.prototype.onShowChanges = function ( diffHtml ) {
|
||||||
// Invalidate the viewer diff on next change
|
// Invalidate the viewer diff on next change
|
||||||
this.surface.getModel().connect( this, { 'transact': 'onSurfaceModelTransact' } );
|
this.surface.getModel().connect( this, { 'transact': 'onSurfaceModelTransact' } );
|
||||||
|
this.saveDialog.setDiffAndReview( diffHtml );
|
||||||
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 ) );
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -642,13 +572,7 @@ ve.init.mw.ViewPageTarget.prototype.onShowChanges = function ( diffHtml ) {
|
||||||
ve.init.mw.ViewPageTarget.prototype.onSerialize = function ( wikitext ) {
|
ve.init.mw.ViewPageTarget.prototype.onSerialize = function ( wikitext ) {
|
||||||
// Invalidate the viewer wikitext on next change
|
// Invalidate the viewer wikitext on next change
|
||||||
this.surface.getModel().connect( this, { 'transact': 'onSurfaceModelTransact' } );
|
this.surface.getModel().connect( this, { 'transact': 'onSurfaceModelTransact' } );
|
||||||
|
this.saveDialog.setDiffAndReview( $( '<pre>' ).text( wikitext ) );
|
||||||
this.$saveDialog
|
|
||||||
.find( '.ve-init-mw-viewPageTarget-saveDialog-viewer' )
|
|
||||||
.empty().append( $( '<pre>' ).text( wikitext ) );
|
|
||||||
|
|
||||||
this.$saveDialogLoadingIcon.hide();
|
|
||||||
this.saveDialogReviewGoodButton.setDisabled( false );
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -660,7 +584,7 @@ ve.init.mw.ViewPageTarget.prototype.onSerialize = function ( wikitext ) {
|
||||||
*/
|
*/
|
||||||
ve.init.mw.ViewPageTarget.prototype.onShowChangesError = function ( jqXHR, status ) {
|
ve.init.mw.ViewPageTarget.prototype.onShowChangesError = function ( jqXHR, status ) {
|
||||||
alert( ve.msg( 'visualeditor-differror', 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 ) {
|
ve.init.mw.ViewPageTarget.prototype.onSerializeError = function ( jqXHR, status ) {
|
||||||
alert( ve.msg( 'visualeditor-serializeerror', 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
|
* @method
|
||||||
*/
|
*/
|
||||||
ve.init.mw.ViewPageTarget.prototype.onEditConflict = function () {
|
ve.init.mw.ViewPageTarget.prototype.onEditConflict = function () {
|
||||||
this.$saveDialogLoadingIcon.hide();
|
this.saveDialog.$loadingIcon.hide();
|
||||||
this.swapSaveDialog( 'conflict' );
|
this.saveDialog.swapPanel( 'conflict' );
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -691,8 +615,9 @@ ve.init.mw.ViewPageTarget.prototype.onEditConflict = function () {
|
||||||
* @method
|
* @method
|
||||||
*/
|
*/
|
||||||
ve.init.mw.ViewPageTarget.prototype.onNoChanges = function () {
|
ve.init.mw.ViewPageTarget.prototype.onNoChanges = function () {
|
||||||
this.$saveDialogLoadingIcon.hide();
|
this.saveDialog.$loadingIcon.hide();
|
||||||
this.swapSaveDialog( 'nochanges' );
|
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 () {
|
ve.init.mw.ViewPageTarget.prototype.onSurfaceModelTransact = function () {
|
||||||
// Clear the diff
|
// Clear the diff
|
||||||
this.$saveDialog
|
this.saveDialog.$reviewViewer.empty();
|
||||||
.find( '.ve-init-mw-viewPageTarget-saveDialog-slide-review .ve-init-mw-viewPageTarget-saveDialog-viewer' )
|
|
||||||
.empty();
|
|
||||||
|
|
||||||
this.surface.getModel().disconnect( this, { 'transact': 'onSurfaceModelTransact' } );
|
this.surface.getModel().disconnect( this, { 'transact': 'onSurfaceModelTransact' } );
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -833,8 +755,28 @@ ve.init.mw.ViewPageTarget.prototype.updateToolbarSaveButtonState = function () {
|
||||||
*
|
*
|
||||||
* @method
|
* @method
|
||||||
*/
|
*/
|
||||||
ve.init.mw.ViewPageTarget.prototype.onSaveDialogReviewButtonClick = function () {
|
ve.init.mw.ViewPageTarget.prototype.onSaveDialogReview = function () {
|
||||||
this.swapSaveDialog( 'review' );
|
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
|
* @method
|
||||||
*/
|
*/
|
||||||
ve.init.mw.ViewPageTarget.prototype.onSaveDialogSaveButtonClick = function () {
|
ve.init.mw.ViewPageTarget.prototype.onSaveDialogSave = function () {
|
||||||
this.saveDocument();
|
this.saveDocument();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -864,17 +806,17 @@ ve.init.mw.ViewPageTarget.prototype.saveDocument = function () {
|
||||||
if (
|
if (
|
||||||
+mw.user.options.get( 'forceeditsummary' ) &&
|
+mw.user.options.get( 'forceeditsummary' ) &&
|
||||||
saveOptions.summary === '' &&
|
saveOptions.summary === '' &&
|
||||||
!this.messages.missingsummary
|
!this.saveDialog.messages.missingsummary
|
||||||
) {
|
) {
|
||||||
this.showMessage(
|
this.saveDialog.showMessage(
|
||||||
'missingsummary',
|
'missingsummary',
|
||||||
// Wrap manually since this core message already includes a bold "Warning:" label
|
// Wrap manually since this core message already includes a bold "Warning:" label
|
||||||
$( '<p>' ).append( ve.init.platform.getParsedMessage( 'missingsummary' ) ),
|
$( '<p>' ).append( ve.init.platform.getParsedMessage( 'missingsummary' ) ),
|
||||||
{ wrap: false }
|
{ wrap: false }
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
this.saveDialogSaveButton.setDisabled( true );
|
this.saveDialog.saveButton.setDisabled( true );
|
||||||
this.$saveDialogLoadingIcon.show();
|
this.saveDialog.$loadingIcon.show();
|
||||||
this.save(
|
this.save(
|
||||||
ve.dm.converter.getDomFromData( doc.getFullData(), doc.getStore(), doc.getInternalList() ),
|
ve.dm.converter.getDomFromData( doc.getFullData(), doc.getStore(), doc.getInternalList() ),
|
||||||
saveOptions
|
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.
|
* Handle clicks on the resolve conflict button in the conflict dialog.
|
||||||
*
|
*
|
||||||
* @method
|
* @method
|
||||||
*/
|
*/
|
||||||
ve.init.mw.ViewPageTarget.prototype.onSaveDialogResolveConflictButtonClick = function () {
|
ve.init.mw.ViewPageTarget.prototype.onSaveDialogResolveConflict= function () {
|
||||||
var doc = this.surface.getModel().getDocument();
|
var doc = this.surface.getModel().getDocument();
|
||||||
// Get Wikitext from the DOM, and set up a submit call when it's done
|
// Get Wikitext from the DOM, and set up a submit call when it's done
|
||||||
this.serialize(
|
this.serialize(
|
||||||
|
@ -915,21 +848,21 @@ ve.init.mw.ViewPageTarget.prototype.onSaveDialogResolveConflictButtonClick = fun
|
||||||
*/
|
*/
|
||||||
ve.init.mw.ViewPageTarget.prototype.getSaveOptions = function () {
|
ve.init.mw.ViewPageTarget.prototype.getSaveOptions = function () {
|
||||||
var options = {
|
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,
|
'captchaid': this.captcha && this.captcha.id,
|
||||||
'captchaword': this.captcha && this.captcha.input.getValue()
|
'captchaword': this.captcha && this.captcha.input.getValue()
|
||||||
};
|
};
|
||||||
if ( this.sanityCheckPromise.state() === 'rejected' ) {
|
if ( this.sanityCheckPromise.state() === 'rejected' ) {
|
||||||
options.needcheck = 1;
|
options.needcheck = 1;
|
||||||
}
|
}
|
||||||
if ( this.$saveDialog.find( '#wpMinoredit' ).prop( 'checked' ) ) {
|
if ( this.saveDialog.$saveOptions.find( '#wpMinoredit' ).prop( 'checked' ) ) {
|
||||||
options.minor = 1;
|
options.minor = 1;
|
||||||
}
|
}
|
||||||
if ( this.$saveDialog.find( '#wpWatchthis' ).prop( 'checked' ) ) {
|
if ( this.saveDialog.$saveOptions.find( '#wpWatchthis' ).prop( 'checked' ) ) {
|
||||||
options.watch = 1;
|
options.watch = 1;
|
||||||
}
|
}
|
||||||
this.$saveDialog
|
this.saveDialog.$saveOptions
|
||||||
.find( '.ve-init-mw-viewPageTarget-saveDialog-checkboxes' )
|
.find( '.ve-ui-mwSaveDialog-checkboxes' )
|
||||||
.find( 'input:not(#wpMinoredit, #wpWatchthis)' )
|
.find( 'input:not(#wpMinoredit, #wpWatchthis)' )
|
||||||
.each( function () {
|
.each( function () {
|
||||||
var $this = $( this );
|
var $this = $( this );
|
||||||
|
@ -942,33 +875,6 @@ ve.init.mw.ViewPageTarget.prototype.getSaveOptions = function () {
|
||||||
return options;
|
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.
|
* 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 () {
|
ve.init.mw.ViewPageTarget.prototype.setupSaveDialog = function () {
|
||||||
var sectionTitle = '', viewPage = this;
|
var sectionTitle = '', viewPage = this;
|
||||||
|
|
||||||
// Save button on "save" slide
|
viewPage.saveDialog = this.surface.getDialogs().getWindow( 'mwSave' );
|
||||||
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' } );
|
|
||||||
|
|
||||||
|
|
||||||
if ( viewPage.section ) {
|
if ( viewPage.section ) {
|
||||||
sectionTitle = viewPage.$document.find( 'h1, h2, h3, h4, h5, h6' ).eq( viewPage.section - 1 ).text();
|
sectionTitle = viewPage.$document.find( 'h1, h2, h3, h4, h5, h6' ).eq( viewPage.section - 1 ).text();
|
||||||
sectionTitle = '/* ' + ve.graphemeSafeSubstring( sectionTitle, 0, 244 ) + ' */ ';
|
sectionTitle = '/* ' + ve.graphemeSafeSubstring( sectionTitle, 0, 244 ) + ' */ ';
|
||||||
|
viewPage.saveDialog.editSummaryInput.$input.val( sectionTitle );
|
||||||
viewPage.sectionTitleRestored = true;
|
viewPage.sectionTitleRestored = true;
|
||||||
if ( viewPage.sectionPositionRestored ) {
|
if ( viewPage.sectionPositionRestored ) {
|
||||||
viewPage.onSectionRestored();
|
viewPage.onSectionRestored();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
viewPage.$saveDialog
|
// Connect to save dialog
|
||||||
// Must not use replaceWith because that can't be used on fragement roots,
|
viewPage.saveDialog.connect( this, {
|
||||||
// plus, we want to preserve the reference and class names of the wrapper.
|
'save': 'onSaveDialogSave',
|
||||||
.empty().append( this.constructor.saveDialogTemplate )
|
'review': 'onSaveDialogReview',
|
||||||
// Attach buttons
|
'resolve': 'onSaveDialogResolveConflict'
|
||||||
.find( '.ve-init-mw-viewPageTarget-saveDialog-slide-save' )
|
} );
|
||||||
.find( '.ve-init-mw-viewPageTarget-saveDialog-actions' )
|
// Setup checkboxes
|
||||||
.prepend( viewPage.saveDialogSaveButton.$, viewPage.saveDialogReviewButton.$ )
|
viewPage.saveDialog.setupCheckboxes( ve.getObjectValues( viewPage.checkboxes ).join( '\n' ) );
|
||||||
.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' ) );
|
|
||||||
}
|
|
||||||
);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -1536,208 +1312,11 @@ ve.init.mw.ViewPageTarget.prototype.setupSaveDialog = function () {
|
||||||
* @method
|
* @method
|
||||||
*/
|
*/
|
||||||
ve.init.mw.ViewPageTarget.prototype.showSaveDialog = function () {
|
ve.init.mw.ViewPageTarget.prototype.showSaveDialog = function () {
|
||||||
var viewPage = this;
|
this.toolbarBetaNotices.hide();
|
||||||
|
this.toolbarEditNotices.hide();
|
||||||
viewPage.surface.disable();
|
this.saveDialog.setSanityCheck( this.sanityCheckVerified );
|
||||||
viewPage.$document.css( 'opacity', 0.5 );
|
this.saveDialog.swapPanel( 'save' );
|
||||||
|
this.surface.getDialogs().open( 'mwSave' );
|
||||||
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();
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -2117,63 +1696,6 @@ ve.init.mw.ViewPageTarget.prototype.onSectionRestored = function () {
|
||||||
this.sectionTitleRestored = false;
|
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.
|
* 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;
|
left: 0;
|
||||||
right: 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);
|
background-color: rgba(255,255,255,0.5);
|
||||||
-webkit-animation: ve-ui-fade-in 250ms ease-in-out 0 1 normal;
|
-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;
|
-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;
|
-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;
|
animation: ve-ui-fade-in 250ms ease-in-out 0 1 normal;
|
||||||
}
|
}
|
||||||
|
@ -25,7 +24,6 @@
|
||||||
.ve-ui-dialog-closing {
|
.ve-ui-dialog-closing {
|
||||||
-webkit-animation: ve-ui-fade-in 250ms ease-in-out 0 1 reverse;
|
-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;
|
-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;
|
-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;
|
animation: ve-ui-fade-in 250ms ease-in-out 0 1 reverse;
|
||||||
}
|
}
|
||||||
|
@ -45,22 +43,24 @@
|
||||||
border-radius: 0.5em;
|
border-radius: 0.5em;
|
||||||
box-shadow: 0 0.2em 1em rgba(0, 0, 0, 0.3);
|
box-shadow: 0 0.2em 1em rgba(0, 0, 0, 0.3);
|
||||||
overflow: hidden;
|
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;
|
-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;
|
-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;
|
-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;
|
animation: ve-ui-zoom-in 250ms ease-in-out 0 1 normal;
|
||||||
}
|
}
|
||||||
|
|
||||||
.ve-ui-dialog .ve-ui-window-frame.ve-ui-window-frame-small {
|
.ve-ui-dialog .ve-ui-window-frame-small {
|
||||||
max-width: 600px;
|
width: 600px;
|
||||||
max-height: 300px;
|
max-height: 375px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.ve-ui-dialog-closing .ve-ui-window-frame {
|
.ve-ui-dialog-closing .ve-ui-window-frame {
|
||||||
-webkit-animation: ve-ui-zoom-in 250ms ease-in-out 0 1 reverse;
|
-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;
|
-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;
|
-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;
|
animation: ve-ui-zoom-in 250ms ease-in-out 0 1 reverse;
|
||||||
}
|
}
|
||||||
|
@ -185,3 +185,7 @@
|
||||||
right: 0;
|
right: 0;
|
||||||
box-shadow: 0 0 0.25em rgba(0,0,0,0.25);
|
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
|
// Properties
|
||||||
this.$title = this.$$( '<div class="ve-ui-window-title"></div>' );
|
this.$title = this.$$( '<div class="ve-ui-window-title"></div>' );
|
||||||
if ( this.getTitle() ) {
|
if ( this.getTitle() ) {
|
||||||
this.$title.text( this.getTitle() );
|
this.setTitle();
|
||||||
}
|
}
|
||||||
this.$icon = this.$$( '<div class="ve-ui-window-icon"></div>' )
|
this.$icon = this.$$( '<div class="ve-ui-window-icon"></div>' )
|
||||||
.addClass( 've-ui-icon-' + this.constructor.static.icon );
|
.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 ) {
|
ve.ui.Window.prototype.setSize = function ( width, height ) {
|
||||||
if ( !this.frame.$content ) {
|
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 ) {
|
ve.ui.Window.prototype.fitHeightToContents = function ( min, max ) {
|
||||||
var height = this.frame.$content.outerHeight();
|
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 ) {
|
ve.ui.Window.prototype.fitWidthToContents = function ( min, max ) {
|
||||||
var width = this.frame.$content.outerWidth();
|
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 ) {
|
ve.ui.Window.prototype.setPosition = function ( left, top ) {
|
||||||
this.$.css( { 'left': left, 'top': 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 {string} name Symbolic name of window
|
||||||
* @param {Object} [config] Configuration options to be sent to the window class constructor
|
* @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;
|
var win;
|
||||||
|
|
||||||
if ( !this.factory.lookup( name ) ) {
|
if ( !this.factory.lookup( name ) ) {
|
||||||
|
@ -133,8 +130,19 @@ ve.ui.WindowSet.prototype.open = function ( name, config ) {
|
||||||
this.$.append( win.$ );
|
this.$.append( win.$ );
|
||||||
win.getFrame().load();
|
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;
|
return this;
|
||||||
};
|
};
|
||||||
|
|
|
@ -51,11 +51,11 @@ ve.ui.ButtonWidget = function VeUiButtonWidget( config ) {
|
||||||
.append( this.$label )
|
.append( this.$label )
|
||||||
.attr( {
|
.attr( {
|
||||||
'role': 'button',
|
'role': 'button',
|
||||||
'tabIndex': config.tabIndex || 0,
|
|
||||||
'title': config.title,
|
'title': config.title,
|
||||||
'href': config.href,
|
'href': config.href,
|
||||||
'target': config.target
|
'target': config.target
|
||||||
} );
|
} )
|
||||||
|
.prop( 'tabIndex', config.tabIndex || 0 );
|
||||||
this.$
|
this.$
|
||||||
.addClass( 've-ui-buttonWidget' )
|
.addClass( 've-ui-buttonWidget' )
|
||||||
.append( this.$button );
|
.append( this.$button );
|
||||||
|
|
Loading…
Reference in a new issue