diff --git a/.eslintignore b/.eslintignore
index df482daf18..670f54e68f 100644
--- a/.eslintignore
+++ b/.eslintignore
@@ -6,6 +6,6 @@
/docs/
# Language files written automatically by TranslateWiki
-/i18n/**/*.json
-!/i18n/**/en.json
-!/i18n/**/qqq.json
+**/i18n/**/*.json
+!**/i18n/**/en.json
+!**/i18n/**/qqq.json
diff --git a/extension.json b/extension.json
index 3f07b04c0c..18a133ebc0 100644
--- a/extension.json
+++ b/extension.json
@@ -180,6 +180,10 @@
"value": false,
"description": "For testing only. Tag edits for the Edit Check project."
},
+ "VisualEditorEditCheck": {
+ "value": false,
+ "description": "Enable experimental Edit Check feature."
+ },
"VisualEditorUseSingleEditTab": {
"value": false
}
@@ -220,7 +224,8 @@
"i18n/ve-mw",
"i18n/ve-mw/api",
"i18n/ve-mw/mwlanguagevariant",
- "i18n/ve-wmf"
+ "i18n/ve-wmf",
+ "modules/editcheck/i18n"
]
},
"ExtensionMessagesFiles": {
@@ -604,10 +609,32 @@
"ext.visualEditor.editCheck": {
"group": "visualEditorA",
"scripts": [
- "modules/editcheck/init.js"
+ "modules/editcheck/init.js",
+ "modules/editcheck/EditCheckContextItem.js",
+ "modules/editcheck/EditCheckInspector.js"
+ ],
+ "styles": [
+ "modules/editcheck/EditCheck.less"
+ ],
+ "dependencies": [
+ "ext.visualEditor.core",
+ "ext.visualEditor.mwsave"
+ ],
+ "messages": [
+ "editcheck-dialog-action-no",
+ "editcheck-dialog-action-yes",
+ "editcheck-dialog-addref-description",
+ "editcheck-dialog-addref-reject-question",
+ "editcheck-dialog-addref-reject-description",
+ "editcheck-dialog-addref-reject-no-info",
+ "editcheck-dialog-addref-reject-already-cited",
+ "editcheck-dialog-addref-reject-not-sure",
+ "editcheck-dialog-addref-reject-other",
+ "editcheck-dialog-addref-success-notify",
+ "editcheck-dialog-addref-title",
+ "editcheck-dialog-title",
+ "visualeditor-backbutton-tooltip"
],
- "dependencies": [],
- "messages": [],
"targets": [
"desktop",
"mobile"
diff --git a/includes/Hooks.php b/includes/Hooks.php
index 1b23718480..6f15f5e0dd 100644
--- a/includes/Hooks.php
+++ b/includes/Hooks.php
@@ -1085,6 +1085,7 @@ class Hooks implements TextSlotDiffRendererTablePrefixHook {
),
'useChangeTagging' => $veConfig->get( 'VisualEditorUseChangeTagging' ),
'editCheckTagging' => $veConfig->get( 'VisualEditorEditCheckTagging' ),
+ 'editCheck' => $veConfig->get( 'VisualEditorEditCheck' ),
'namespacesWithSubpages' => $namespacesWithSubpagesEnabled,
'specialBooksources' => urldecode( SpecialPage::getTitleFor( 'Booksources' )->getPrefixedURL() ),
'rebaserUrl' => $coreConfig->get( 'VisualEditorRebaserURL' ),
diff --git a/modules/editcheck/EditCheck.less b/modules/editcheck/EditCheck.less
new file mode 100644
index 0000000000..ec4559c447
--- /dev/null
+++ b/modules/editcheck/EditCheck.less
@@ -0,0 +1,35 @@
+/* Toolbar */
+
+.ve-ui-toolbar-group-title {
+ font-weight: bold;
+ flex: 5 !important; /* stylelint-disable-line declaration-no-important */
+ line-height: 3em;
+}
+
+/* Context item */
+
+.ve-ui-editCheckContextItem {
+ > .ve-ui-linearContextItem-head {
+ background: #fce7fe;
+ }
+
+ &-actions {
+ margin-top: 16px;
+ }
+}
+
+/* Selections */
+
+.ve-ce-surface-selections-editCheck .ve-ce-surface-selection {
+ opacity: 0.2;
+}
+
+.ve-ce-surface-selections-editCheck .ve-ce-surface-selection > div {
+ mix-blend-mode: darken;
+ // Adjust target colours to account for 50% opacity
+ background: ( #fce7fe - 0.8 * ( #fff ) ) / 0.2;
+ // border: 1px solid ( ( #d02aac - 0.8 * ( #fff ) ) / 0.2 );
+ border-radius: 2px;
+ padding: 2px;
+ margin: -2px 0 0 -2px;
+}
diff --git a/modules/editcheck/EditCheckContextItem.js b/modules/editcheck/EditCheckContextItem.js
new file mode 100644
index 0000000000..ea2a55cea8
--- /dev/null
+++ b/modules/editcheck/EditCheckContextItem.js
@@ -0,0 +1,126 @@
+/*!
+ * VisualEditor EditCheckContextItem class.
+ *
+ * @copyright 2011-2019 VisualEditor Team and others; see http://ve.mit-license.org
+ */
+
+/**
+ * Context item shown after a rich text paste.
+ *
+ * @class
+ * @extends ve.ui.PersistentContextItem
+ *
+ * @constructor
+ * @param {ve.ui.LinearContext} context Context the item is in
+ * @param {ve.dm.Model} model Model the item is related to
+ * @param {Object} [config]
+ */
+ve.ui.EditCheckContextItem = function VeUiEditCheckContextItem() {
+ // Parent constructor
+ ve.ui.EditCheckContextItem.super.apply( this, arguments );
+
+ // Initialization
+ this.$element.addClass( 've-ui-editCheckContextItem' );
+};
+
+/* Inheritance */
+
+OO.inheritClass( ve.ui.EditCheckContextItem, ve.ui.PersistentContextItem );
+
+/* Static Properties */
+
+ve.ui.EditCheckContextItem.static.name = 'editCheck';
+
+ve.ui.EditCheckContextItem.static.icon = 'quotes';
+
+ve.ui.EditCheckContextItem.static.label = OO.ui.deferMsg( 'editcheck-dialog-addref-title' );
+
+/* Methods */
+
+/**
+ * @inheritdoc
+ */
+ve.ui.EditCheckContextItem.prototype.renderBody = function () {
+ // Prompt panel
+ var acceptButton = new OO.ui.ButtonWidget( {
+ label: ve.msg( 'editcheck-dialog-action-yes' ),
+ icon: 'check'
+ } );
+ var rejectButton = new OO.ui.ButtonWidget( {
+ label: ve.msg( 'editcheck-dialog-action-no' ),
+ icon: 'close'
+ } );
+
+ acceptButton.connect( this, { click: 'onAcceptClick' } );
+ rejectButton.connect( this, { click: 'onRejectClick' } );
+
+ // HACK: Suppress close button on mobile context
+ if ( this.context.isMobile() ) {
+ this.context.closeButton.toggle( false );
+ }
+
+ this.$body.append(
+ $( '
' ).text( ve.msg( 'editcheck-dialog-addref-description' ) ),
+ $( '
' ).addClass( 've-ui-editCheckContextItem-actions' ).append(
+ acceptButton.$element, rejectButton.$element
+ )
+ );
+};
+
+ve.ui.EditCheckContextItem.prototype.close = function ( data ) {
+ // HACK: Un-suppress close button on mobile context
+ if ( this.context.isMobile() ) {
+ this.context.closeButton.toggle( true );
+ }
+ this.data.saveProcessDeferred.resolve( data );
+};
+
+ve.ui.EditCheckContextItem.prototype.onAcceptClick = function () {
+ var contextItem = this;
+ var fragment = this.data.fragment;
+ var windowAction = ve.ui.actionFactory.create( 'window', this.context.getSurface() );
+ fragment.collapseToEnd().select();
+
+ windowAction.open( 'citoid' ).then( function ( instance ) {
+ return instance.closing;
+ } ).then( function ( data ) {
+ if ( !data ) {
+ // Reference was not inserted - re-open this context
+ setTimeout( function () {
+ // Deactivate again for mobile after teardown has modified selections
+ contextItem.context.getSurface().getView().deactivate();
+ contextItem.context.afterContextChange();
+ }, 500 );
+ } else {
+ // Edit check inspector is already closed by this point, but
+ // we need to end the workflow.
+ contextItem.close( data );
+ }
+ } );
+};
+
+ve.ui.EditCheckContextItem.prototype.onRejectClick = function () {
+ var contextItem = this;
+ var windowAction = ve.ui.actionFactory.create( 'window', this.context.getSurface() );
+ windowAction.open(
+ 'editCheckInspector',
+ {
+ fragment: this.data.fragment,
+ saveProcessDeferred: this.data.saveProcessDeferred
+ }
+ ).then( function ( instance ) {
+ // contextItem.openingCitoid = false;
+ return instance.closing;
+ } ).then( function ( data ) {
+ if ( !data ) {
+ // Form was closed, re-open this context
+ contextItem.context.afterContextChange();
+ } else {
+ contextItem.close( data );
+ }
+ } );
+};
+
+/* Registration */
+
+ve.ui.contextItemFactory.register( ve.ui.EditCheckContextItem );
diff --git a/modules/editcheck/EditCheckInspector.js b/modules/editcheck/EditCheckInspector.js
new file mode 100644
index 0000000000..4ab2ee1c75
--- /dev/null
+++ b/modules/editcheck/EditCheckInspector.js
@@ -0,0 +1,151 @@
+/*!
+ * VisualEditor UserInterface EditCheckInspector class.
+ *
+ * @copyright 2011-2020 VisualEditor Team and others; see http://ve.mit-license.org
+ */
+
+/**
+ * Edit check inspector
+ *
+ * @class
+ * @extends ve.ui.FragmentInspector
+ *
+ * @constructor
+ * @param {Object} [config] Configuration options
+ */
+ve.ui.EditCheckInspector = function VeUiEditCheckInspector( config ) {
+ // Parent constructor
+ ve.ui.EditCheckInspector.super.call( this, config );
+
+ // Pre-initialization
+ this.$element.addClass( 've-ui-editCheckInspector' );
+};
+
+/* Inheritance */
+
+OO.inheritClass( ve.ui.EditCheckInspector, ve.ui.FragmentInspector );
+
+ve.ui.EditCheckInspector.static.name = 'editCheckInspector';
+
+// ve.ui.EditCheckInspector.static.title = OO.ui.deferMsg( 'editcheck-dialog-title' );
+ve.ui.EditCheckInspector.static.title = OO.ui.deferMsg( 'editcheck-dialog-addref-title' );
+
+// ve.ui.EditCheckInspector.static.size = 'context';
+
+ve.ui.EditCheckInspector.static.actions = [
+ {
+ label: OO.ui.deferMsg( 'visualeditor-dialog-action-cancel' ),
+ flags: [ 'safe', 'back' ],
+ modes: [ 'mobile', 'desktop' ]
+ },
+ {
+ action: 'continue',
+ icon: 'next',
+ flags: [ 'primary', 'progressive' ],
+ modes: [ 'mobile' ]
+ }
+];
+
+/* Methods */
+
+/**
+ * @inheritdoc
+ */
+ve.ui.EditCheckInspector.prototype.initialize = function () {
+ // Parent method
+ ve.ui.EditCheckInspector.super.prototype.initialize.call( this );
+
+ // Survey panel
+ this.answerRadioSelect = new OO.ui.RadioSelectWidget( {
+ items: [
+ new OO.ui.RadioOptionWidget( {
+ data: 'no-info',
+ label: ve.msg( 'editcheck-dialog-addref-reject-no-info' )
+ } ),
+ new OO.ui.RadioOptionWidget( {
+ data: 'already-cited',
+ label: ve.msg( 'editcheck-dialog-addref-reject-already-cited' )
+ } ),
+ new OO.ui.RadioOptionWidget( {
+ data: 'not-sure',
+ label: ve.msg( 'editcheck-dialog-addref-reject-not-sure' )
+ } ),
+ new OO.ui.RadioOptionWidget( {
+ data: 'other',
+ label: ve.msg( 'editcheck-dialog-addref-reject-other' )
+ } )
+ ]
+ } );
+ this.answerRadioSelect.connect( this, { select: 'updateActions' } );
+
+ this.answerConfirm = new OO.ui.ButtonWidget( {
+ flags: [ 'progressive' ],
+ framed: false,
+ label: 'Continue',
+ disabled: true
+ } );
+ this.answerConfirm.toggle( !OO.ui.isMobile() );
+ this.answerConfirm.connect( this, { click: [ 'executeAction', 'continue' ] } );
+
+ this.form.addItems(
+ new OO.ui.FieldsetLayout( {
+ label: ve.msg( 'editcheck-dialog-addref-reject-question' ),
+ items: [
+ new OO.ui.FieldLayout( this.answerRadioSelect, {
+ label: ve.msg( 'editcheck-dialog-addref-reject-description' ),
+ align: 'top'
+ } ),
+ new OO.ui.FieldLayout( this.answerConfirm, {
+ align: 'left'
+ } )
+ ]
+ } )
+ );
+};
+
+ve.ui.EditCheckInspector.prototype.updateActions = function () {
+ this.answerConfirm.setDisabled( !this.answerRadioSelect.findSelectedItem() );
+};
+
+/**
+ * @inheritdoc
+ */
+ve.ui.EditCheckInspector.prototype.getSetupProcess = function ( data ) {
+ data = data || {};
+ return ve.ui.EditCheckInspector.super.prototype.getSetupProcess.call( this, data )
+ .first( function () {
+ this.surface = data.surface;
+ this.saveProcessDeferred = data.saveProcessDeferred;
+ this.answerRadioSelect.selectItem( null );
+ }, this );
+};
+
+/**
+ * @inheritdoc
+ */
+ve.ui.EditCheckInspector.prototype.getReadyProcess = function ( data ) {
+ return ve.ui.EditCheckInspector.super.prototype.getReadyProcess.call( this, data )
+ .first( function () {
+ this.actions.setMode( OO.ui.isMobile() ? 'mobile' : 'desktop' );
+ }, this );
+};
+
+ve.ui.EditCheckInspector.prototype.getActionProcess = function ( action ) {
+ if ( action === '' ) {
+ return new OO.ui.Process( function () {
+ this.close();
+ }, this );
+ }
+
+ if ( action === 'continue' ) {
+ return new OO.ui.Process( function () {
+ this.close( { action: 'reject', reason: this.answerRadioSelect.findSelectedItem().getData() } );
+ }, this );
+ }
+
+ return ve.ui.EditCheckInspector.super.prototype.getActionProcess.call( this, action );
+};
+
+/* Registration */
+
+ve.ui.windowFactory.register( ve.ui.EditCheckInspector );
diff --git a/modules/editcheck/i18n/en.json b/modules/editcheck/i18n/en.json
new file mode 100644
index 0000000000..fa8dac812f
--- /dev/null
+++ b/modules/editcheck/i18n/en.json
@@ -0,0 +1,14 @@
+{
+ "editcheck-dialog-action-no": "No",
+ "editcheck-dialog-action-yes": "Yes",
+ "editcheck-dialog-addref-description": "Help readers understand where this information is coming from by adding a citation.",
+ "editcheck-dialog-addref-reject-question": "Why are you not adding a citation?",
+ "editcheck-dialog-addref-reject-description": "Other editors would value learning more about your decision to dismiss the citation.",
+ "editcheck-dialog-addref-reject-no-info": "I didn't add new information",
+ "editcheck-dialog-addref-reject-already-cited": "My changes are already cited earlier",
+ "editcheck-dialog-addref-reject-not-sure": "I'm not sure what citation to add",
+ "editcheck-dialog-addref-reject-other": "Other",
+ "editcheck-dialog-addref-success-notify": "Thank you for adding a citation!",
+ "editcheck-dialog-addref-title": "Add a citation",
+ "editcheck-dialog-title": "Before publishing"
+}
diff --git a/modules/editcheck/i18n/fr.json b/modules/editcheck/i18n/fr.json
new file mode 100644
index 0000000000..7aa3b5510d
--- /dev/null
+++ b/modules/editcheck/i18n/fr.json
@@ -0,0 +1,14 @@
+{
+ "editcheck-dialog-action-no": "Non",
+ "editcheck-dialog-action-yes": "Oui",
+ "editcheck-dialog-addref-description": "Aidez les lecteurs à comprendre d'où proviennent ces informations en ajoutant une source.",
+ "editcheck-dialog-addref-reject-question": "Pourquoi n'ajoutez-vous pas une source ?",
+ "editcheck-dialog-addref-reject-description": "Les autres éditeurs aimeraient en savoir plus sur votre décision de ne pas ajouter une source.",
+ "editcheck-dialog-addref-reject-no-info": "Je n'ai pas ajouté de nouvelles informations",
+ "editcheck-dialog-addref-reject-already-cited": "Mes modifications sont déjà sourcées plus haut",
+ "editcheck-dialog-addref-reject-not-sure": "Je ne sais pas quelle source ajouter",
+ "editcheck-dialog-addref-reject-other": "Autre",
+ "editcheck-dialog-addref-success-notify": "Merci d'avoir ajouté une source !",
+ "editcheck-dialog-addref-title": "Ajouter une source",
+ "editcheck-dialog-title": "Avant de publier"
+}
diff --git a/modules/editcheck/i18n/qqq.json b/modules/editcheck/i18n/qqq.json
new file mode 100644
index 0000000000..3b123f7400
--- /dev/null
+++ b/modules/editcheck/i18n/qqq.json
@@ -0,0 +1,14 @@
+{
+ "editcheck-dialog-action-no": "Label for the no option when asking users if they want to add a citation.",
+ "editcheck-dialog-action-yes": "Label for the no option when asking users if they want to add a citation.",
+ "editcheck-dialog-addref-description": "Help text explaining why it is helpful to add a citation.",
+ "editcheck-dialog-addref-reject-question": "Heading for form question asking why the user didn't add a citation.",
+ "editcheck-dialog-addref-reject-description": "Help text for form question asking why the user didn't add a citation.",
+ "editcheck-dialog-addref-reject-no-info": "Answer option in repsonse to {{msg-mw|editcheck-dialog-addref-reject-question}}",
+ "editcheck-dialog-addref-reject-already-cited": "Answer option in repsonse to {{msg-mw|editcheck-dialog-addref-reject-question}}",
+ "editcheck-dialog-addref-reject-not-sure": "Answer option in repsonse to {{msg-mw|editcheck-dialog-addref-reject-question}}",
+ "editcheck-dialog-addref-reject-other": "Answer option in repsonse to {{msg-mw|editcheck-dialog-addref-reject-question}}",
+ "editcheck-dialog-addref-success-notify": "Notification messages shown after a citation is added successfully.",
+ "editcheck-dialog-addref-title": "Title for the edit check context asking user to add a citation.",
+ "editcheck-dialog-title": "Title shown in the toolbar while the user is in the add a citation workflow."
+}
diff --git a/modules/editcheck/init.js b/modules/editcheck/init.js
index b2009aad8e..7cb270f6a3 100644
--- a/modules/editcheck/init.js
+++ b/modules/editcheck/init.js
@@ -1,20 +1,20 @@
mw.editcheck = {};
/**
- * Check if added content in the document model might need a reference
+ * Find added content in the document model that might need a reference
*
* @param {ve.dm.DocumentModel} documentModel Document model
* @param {boolean} [includeReferencedContent] Include content ranges that already
* have a reference.
- * @return {boolean}
+ * @return {ve.dm.Selection[]} Content ranges that might need a reference
*/
-mw.editcheck.doesAddedContentNeedReference = function ( documentModel, includeReferencedContent ) {
+mw.editcheck.findAddedContentNeedingReference = function ( documentModel, includeReferencedContent ) {
if ( mw.config.get( 'wgNamespaceNumber' ) !== mw.config.get( 'wgNamespaceIds' )[ '' ] ) {
- return false;
+ return [];
}
if ( !documentModel.completeHistory.getLength() ) {
- return false;
+ return [];
}
var operations;
try {
@@ -23,7 +23,7 @@ mw.editcheck.doesAddedContentNeedReference = function ( documentModel, includeRe
// TransactionSquasher can sometimes throw errors; until T333710 is
// fixed just count this as not needing a reference.
mw.errorLogger.logError( err, 'error.visualeditor' );
- return false;
+ return [];
}
var ranges = [];
@@ -45,7 +45,7 @@ mw.editcheck.doesAddedContentNeedReference = function ( documentModel, includeRe
// Reached the end of the doc / start of internal list, stop searching
return offset < endOffset;
} );
- return ranges.some( function ( range ) {
+ var addedTextRanges = ranges.filter( function ( range ) {
var minimumCharacters = 50;
// 1. Check that at least minimumCharacters characters have been inserted sequentially
if ( range.getLength() >= minimumCharacters ) {
@@ -66,6 +66,10 @@ mw.editcheck.doesAddedContentNeedReference = function ( documentModel, includeRe
}
return false;
} );
+
+ return addedTextRanges.map( function ( range ) {
+ return new ve.dm.LinearSelection( range );
+ } );
};
/**
@@ -118,3 +122,152 @@ if ( mw.config.get( 'wgVisualEditorConfig' ).editCheckTagging ) {
};
} );
}
+
+if ( mw.config.get( 'wgVisualEditorConfig' ).editCheck ) {
+ mw.hook( 've.preSaveProcess' ).add( function ( saveProcess, target ) {
+ var surface = target.getSurface();
+
+ var selections = mw.editcheck.findAddedContentNeedingReference( surface.getModel().getDocument() );
+
+ if ( selections.length ) {
+ var surfaceView = surface.getView();
+ var toolbar = target.getToolbar();
+ var reviewToolbar = new ve.ui.PositionedTargetToolbar( target, target.toolbarConfig );
+ reviewToolbar.setup( [
+ {
+ name: 'back',
+ type: 'bar',
+ include: [ 'editCheckBack' ]
+ },
+ // Placeholder toolbar groups
+ // TODO: Make a proper TitleTool?
+ {
+ name: 'title',
+ type: 'bar',
+ include: []
+ },
+ {
+ name: 'save',
+ // TODO: MobileArticleTarget should ignore 'align'
+ align: OO.ui.isMobile() ? 'before' : 'after',
+ type: 'bar',
+ include: [ 'showSaveDisabled' ]
+ }
+ ], surface );
+
+ reviewToolbar.items[ 1 ].$element.removeClass( 'oo-ui-toolGroup-empty' );
+ reviewToolbar.items[ 1 ].$group.append(
+ $( '' ).addClass( 've-ui-editCheck-toolbar-title' ).text( ve.msg( 'editcheck-dialog-title' ) )
+ );
+ if ( OO.ui.isMobile() ) {
+ reviewToolbar.$element.addClass( 've-init-mw-mobileArticleTarget-toolbar' );
+ }
+ target.toolbar.$element.before( reviewToolbar.$element );
+ target.toolbar = reviewToolbar;
+
+ var selection = selections[ 0 ];
+ var highlightNodes = surfaceView.getDocument().selectNodes( selection.getCoveringRange(), 'branches' ).map( function ( spec ) {
+ return spec.node;
+ } );
+
+ surfaceView.drawSelections( 'editCheck', [ ve.ce.Selection.static.newFromModel( selection, surfaceView ) ] );
+ surfaceView.setReviewMode( true, highlightNodes );
+ toolbar.toggle( false );
+ target.onContainerScroll();
+
+ saveProcess.next( function () {
+ var saveProcessDeferred = ve.createDeferred();
+ var fragment = surface.getModel().getFragment( selection, true );
+
+ var context = surface.getContext();
+
+ // Select the found content to correctly the context on desktop
+ fragment.select();
+ // Deactivate to prevent selection suppressing mobile context
+ surface.getView().deactivate();
+
+ context.addPersistentSource( {
+ embeddable: false,
+ data: {
+ fragment: fragment,
+ saveProcessDeferred: saveProcessDeferred
+ },
+ name: 'editCheck'
+ } );
+
+ // Once the context is positioned, clear the selection
+ setTimeout( function () {
+ surface.getModel().setNullSelection();
+ } );
+
+ return saveProcessDeferred.promise().then( function ( data ) {
+ context.removePersistentSource( 'editCheck' );
+
+ surfaceView.drawSelections( 'editCheck', [] );
+ surfaceView.setReviewMode( false );
+
+ reviewToolbar.$element.remove();
+ toolbar.toggle( true );
+ target.toolbar = toolbar;
+ target.onContainerScroll();
+
+ // Check the user inserted a citation
+ if ( data && data.action ) {
+ if ( data.action !== 'reject' ) {
+ mw.notify( ve.msg( 'editcheck-dialog-addref-success-notify' ), { type: 'success' } );
+ }
+ var delay = ve.createDeferred();
+ // If they inserted, wait 2 seconds on desktop before showing save dialog
+ setTimeout( function () {
+ delay.resolve();
+ }, !OO.ui.isMobile() && data.action !== 'reject' ? 2000 : 0 );
+ return delay.promise();
+ } else {
+ return ve.createDeferred().reject().promise();
+ }
+ } );
+ } );
+ }
+ } );
+}
+
+ve.ui.EditCheckBack = function VeUiEditCheckBack() {
+ // Parent constructor
+ ve.ui.EditCheckBack.super.apply( this, arguments );
+
+ this.setDisabled( false );
+};
+OO.inheritClass( ve.ui.EditCheckBack, ve.ui.Tool );
+ve.ui.EditCheckBack.static.name = 'editCheckBack';
+ve.ui.EditCheckBack.static.icon = 'previous';
+ve.ui.EditCheckBack.static.autoAddToCatchall = false;
+ve.ui.EditCheckBack.static.autoAddToGroup = false;
+ve.ui.EditCheckBack.static.title =
+ OO.ui.deferMsg( 'visualeditor-backbutton-tooltip' );
+ve.ui.EditCheckBack.prototype.onSelect = function () {
+ var context = this.toolbar.getSurface().getContext();
+ if ( context.inspector ) {
+ context.inspector.close();
+ } else {
+ context.items[ 0 ].close();
+ }
+ this.setActive( false );
+};
+ve.ui.EditCheckBack.prototype.onUpdateState = function () {
+ this.setDisabled( false );
+};
+ve.ui.toolFactory.register( ve.ui.EditCheckBack );
+
+ve.ui.EditCheckSaveDisabled = function VeUiEditCheckSaveDisabled() {
+ // Parent constructor
+ ve.ui.EditCheckSaveDisabled.super.apply( this, arguments );
+};
+OO.inheritClass( ve.ui.EditCheckSaveDisabled, ve.ui.MWSaveTool );
+ve.ui.EditCheckSaveDisabled.static.name = 'showSaveDisabled';
+ve.ui.EditCheckSaveDisabled.static.autoAddToCatchall = false;
+ve.ui.EditCheckSaveDisabled.static.autoAddToGroup = false;
+ve.ui.EditCheckSaveDisabled.prototype.onUpdateState = function () {
+ this.setDisabled( true );
+};
+
+ve.ui.toolFactory.register( ve.ui.EditCheckSaveDisabled );
diff --git a/modules/ve-mw/init/targets/ve.init.mw.ArticleTarget.js b/modules/ve-mw/init/targets/ve.init.mw.ArticleTarget.js
index 770c757ff4..1e413e452a 100644
--- a/modules/ve-mw/init/targets/ve.init.mw.ArticleTarget.js
+++ b/modules/ve-mw/init/targets/ve.init.mw.ArticleTarget.js
@@ -1548,11 +1548,11 @@ ve.init.mw.ArticleTarget.prototype.save = function ( doc, options ) {
) {
var documentModel = this.getSurface().getModel().getDocument();
// New content needing a reference
- if ( mw.editcheck.doesAddedContentNeedReference( documentModel ) ) {
+ if ( mw.editcheck.findAddedContentNeedingReference( documentModel ).length ) {
taglist.push( 'editcheck-references' );
}
// New content, regardless of if it needs a reference
- if ( mw.editcheck.doesAddedContentNeedReference( documentModel, true ) ) {
+ if ( mw.editcheck.findAddedContentNeedingReference( documentModel, true ).length ) {
taglist.push( 'editcheck-newcontent' );
}
}
diff --git a/modules/ve-mw/preinit/ve.init.mw.ArticleTargetLoader.js b/modules/ve-mw/preinit/ve.init.mw.ArticleTargetLoader.js
index 3e4bf0be7c..785bc8e1cd 100644
--- a/modules/ve-mw/preinit/ve.init.mw.ArticleTargetLoader.js
+++ b/modules/ve-mw/preinit/ve.init.mw.ArticleTargetLoader.js
@@ -37,7 +37,7 @@
modules.push( 'ext.visualEditor.mwwikitext' );
}
- if ( conf.editCheckTagging ) {
+ if ( conf.editCheckTagging || conf.editCheck ) {
modules.push( 'ext.visualEditor.editCheck' );
}