diff --git a/extension.json b/extension.json index 2d14a5fe0..2ba4dd3d9 100644 --- a/extension.json +++ b/extension.json @@ -60,6 +60,7 @@ "ext.visualEditor.core.utils.parsing" ], "messages": [ + "discussiontools-error-lint", "discussiontools-error-comment-disappeared", "discussiontools-error-comment-is-transcluded", "discussiontools-error-comment-is-transcluded-title", diff --git a/i18n/en.json b/i18n/en.json index 025c8da89..5bae16827 100644 --- a/i18n/en.json +++ b/i18n/en.json @@ -23,6 +23,7 @@ "discussiontools-error-comment-disappeared": "Could not find the comment you're replying to on the page. It might have been deleted or moved to another page. Please reload the page and try again.", "discussiontools-error-comment-is-transcluded": "This comment can't be replied to using this tool. Please try using the full page editor instead.", "discussiontools-error-comment-is-transcluded-title": "This comment can't be replied to here (yet), because it is loaded from another page. Please go to [[$1]] to reply to it.", + "discussiontools-error-lint": "Comments on this page can't be replied to because of an error in the wikitext. You can learn about this error by [$1 reading the documentation], ask for help by [$2 posting here] or fix the error by [$3 opening the full page editor].", "tag-discussiontools": "-", "tag-discussiontools-description": "Edit made using DiscussionTools", "tag-discussiontools-edit": "Edit comment", diff --git a/i18n/qqq.json b/i18n/qqq.json index a06fd9c9f..3e9a8d1e1 100644 --- a/i18n/qqq.json +++ b/i18n/qqq.json @@ -25,6 +25,7 @@ "discussiontools-replywidget-reply": "Label for the button to submit a reply in the reply widget", "discussiontools-replywidget-terms-click": "Terms of use for posting a reply.\n\n* $1 is the label of the button to be clicked, e.g. {{msg-mw|discussiontools-replywidget-reply}}.", "discussiontools-replywidget-transcluded": "Message explaining that the comment will be saved on a different page than the one you're viewing right now (because it was transcluded from it). Parameter: $1 – page name", + "discussiontools-error-lint": "Error message. Parameters:\n* $1 – URL to documentation on mediawiki.org\n* $2 – URL to talk page on mediawiki.org\n* $3 – URL to the editor (action=edit)", "discussiontools-error-comment-disappeared": "Error message.", "discussiontools-error-comment-is-transcluded": "Error message.", "discussiontools-error-comment-is-transcluded-title": "Error message. Parameter: $1 – page name", diff --git a/includes/DiscussionToolsHooks.php b/includes/DiscussionToolsHooks.php index 57cf71f6d..e1e54383b 100644 --- a/includes/DiscussionToolsHooks.php +++ b/includes/DiscussionToolsHooks.php @@ -77,6 +77,15 @@ class DiscussionToolsHooks { 'ext.discussionTools.init' ] ); } + + if ( $actionName === 'edit' && $req->getVal( 'dtlinterror' ) ) { + // TODO: Should we copy this module from the Linter extension? + $output->addJsConfigVars( [ + 'wgLinterErrorLocation' => + array_map( 'intval', explode( '-', $req->getVal( 'dtlinterror' ), 2 ) ), + ] ); + $output->addModules( 'ext.linter.edit' ); + } } /** diff --git a/modules/controller.js b/modules/controller.js index 25463f64a..8d8b52f4a 100644 --- a/modules/controller.js +++ b/modules/controller.js @@ -350,7 +350,10 @@ function getPageData( pageName, oldId ) { } pageDataCache[ pageName ][ oldId ] = mw.loader.using( 'ext.visualEditor.targetLoader' ).then( function () { return mw.libs.ve.targetLoader.requestPageData( - 'visual', pageName, { oldId: oldId } + 'visual', pageName, { + oldId: oldId, + lint: true + } ); }, function () { // Clear on failure @@ -372,7 +375,8 @@ function getParsoidCommentData( pageName, oldId, commentId ) { return getPageData( pageName, oldId ) .then( function ( response ) { - var data, comment, transcludedFrom, transcludedErrMsg, mwTitle, follow; + var data, comment, transcludedFrom, transcludedErrMsg, mwTitle, follow, + lintErrors, lintLocation, lintType; data = response.visualeditor; parsoidDoc = ve.parseXhtml( data.content ); @@ -430,6 +434,27 @@ function getParsoidCommentData( pageName, oldId, commentId ) { } ] } ).promise(); } + if ( response.visualeditor.lint ) { + // Only lint errors that break editing, namely 'fostered' + lintErrors = response.visualeditor.lint.filter( function ( item ) { + return item.type === 'fostered'; + } ); + + if ( lintErrors.length ) { + // This only reports the first error + lintLocation = lintErrors[ 0 ].dsr.slice( 0, 2 ).join( '-' ); + lintType = lintErrors[ 0 ].type; + + return $.Deferred().reject( 'lint', { errors: [ { + code: 'lint', + html: mw.message( 'discussiontools-error-lint', + 'https://www.mediawiki.org/wiki/Special:MyLanguage/Help:Lint_errors/' + lintType, + 'https://www.mediawiki.org/wiki/Special:MyLanguage/Help_talk:Lint_errors/' + lintType, + mw.util.getUrl( pageName, { action: 'edit', dtlinterror: lintLocation } ) ).parse() + } ] } ).promise(); + } + } + return { comment: parsoidCommentsById[ commentId ], doc: parsoidDoc,