diff --git a/extension.json b/extension.json index 9a38382c9..747b81787 100644 --- a/extension.json +++ b/extension.json @@ -99,7 +99,11 @@ "dependencies": [ "ext.discussionTools.init", "mediawiki.widgets.AbandonEditDialog" - ] + ], + "optionalDependencies": { + "ConfirmEdit": "ext.confirmEdit.CaptchaInputWidget" + }, + "factory": "DiscussionToolsData::addOptionalDependencies" }, "ext.discussionTools.ReplyWidgetPlain": { "packageFiles": [ diff --git a/includes/DiscussionToolsData.php b/includes/DiscussionToolsData.php index 374891f10..b6b6aea80 100644 --- a/includes/DiscussionToolsData.php +++ b/includes/DiscussionToolsData.php @@ -116,4 +116,23 @@ class DiscussionToolsData { }, $messagesKeys ) ); } + + /** + * Add optional dependencies to a ResourceLoader module definition depending on loaded extensions. + * + * @param array $info + * @return ResourceLoaderModule + */ + public static function addOptionalDependencies( array $info ) { + $extensionRegistry = ExtensionRegistry::getInstance(); + + foreach ( $info['optionalDependencies'] as $ext => $deps ) { + if ( $extensionRegistry->isLoaded( $ext ) ) { + $info['dependencies'] = array_merge( $info['dependencies'], (array)$deps ); + } + } + + $class = $info['class'] ?? ResourceLoaderFileModule::class; + return new $class( $info ); + } } diff --git a/modules/controller.js b/modules/controller.js index b7168ef1e..519a34345 100644 --- a/modules/controller.js +++ b/modules/controller.js @@ -267,6 +267,8 @@ function save( widget, parsoidData ) { baserevid: pageData.oldId, starttimestamp: pageData.startTimeStamp, etag: pageData.etag, + captchaid: widget.captchaInput && widget.captchaInput.getCaptchaId(), + captchaword: widget.captchaInput && widget.captchaInput.getCaptchaWord(), assert: mw.user.isAnon() ? 'anon' : 'user', assertuser: mw.user.getName() || undefined, dttags: [ diff --git a/modules/dt.ui.ReplyWidget.js b/modules/dt.ui.ReplyWidget.js index 733a59a54..9780d6e5b 100644 --- a/modules/dt.ui.ReplyWidget.js +++ b/modules/dt.ui.ReplyWidget.js @@ -421,15 +421,39 @@ ReplyWidget.prototype.onReplyClick = function () { pagedeleted: 'editPageDeleted' }; - widget.errorMessage = new OO.ui.MessageWidget( { - type: 'error', - label: widget.api.getErrorMessage( data ) - } ); - widget.errorMessage.$element.insertBefore( widget.replyBodyWidget.$element ); - - if ( data.edit && data.edit.captcha ) { - code = 'captcha'; + if ( widget.captchaMessage ) { + widget.captchaMessage.$element.detach(); } + widget.captchaInput = undefined; + + if ( OO.getProp( data, 'visualeditoredit', 'edit', 'captcha' ) ) { + code = 'captcha'; + + widget.captchaInput = new mw.libs.confirmEdit.CaptchaInputWidget( + OO.getProp( data, 'visualeditoredit', 'edit', 'captcha' ) + ); + // Save when pressing 'Enter' in captcha field as it is single line. + widget.captchaInput.on( 'enter', function () { + widget.onReplyClick(); + } ); + + widget.captchaMessage = new OO.ui.MessageWidget( { + type: 'notice', + label: widget.captchaInput.$element + } ); + widget.captchaMessage.$element.insertAfter( widget.$preview ); + + widget.captchaInput.focus(); + widget.captchaInput.scrollElementIntoView(); + + } else { + widget.errorMessage = new OO.ui.MessageWidget( { + type: 'error', + label: widget.api.getErrorMessage( data ) + } ); + widget.errorMessage.$element.insertBefore( widget.replyBodyWidget.$element ); + } + logger( { action: 'saveFailure', message: code, diff --git a/modules/dt.ui.ReplyWidget.less b/modules/dt.ui.ReplyWidget.less index e5849e4c1..52c471d98 100644 --- a/modules/dt.ui.ReplyWidget.less +++ b/modules/dt.ui.ReplyWidget.less @@ -51,7 +51,9 @@ padding: 0.5em 1em; &:empty { - display: none; + height: 0; + padding: 0; + overflow: hidden; } &:before { @@ -64,15 +66,14 @@ } } - .oo-ui-messageWidget { + .oo-ui-messageWidget, + .dt-ui-replyWidget-preview { margin-bottom: 0.5em; } &-anonWarning { display: flex; align-items: center; - margin-top: 1em; - margin-bottom: 0.5em; &.oo-ui-messageWidget-block { padding: 8px 12px;