mirror of
https://gerrit.wikimedia.org/r/mediawiki/extensions/ConfirmEdit
synced 2024-11-24 08:13:53 +00:00
Merge "Extract CaptchaInputWidget from VE code for use in other extensions"
This commit is contained in:
commit
7db678474c
|
@ -76,6 +76,7 @@
|
||||||
},
|
},
|
||||||
"ext.confirmEdit.visualEditor": {
|
"ext.confirmEdit.visualEditor": {
|
||||||
"scripts": "ve-confirmedit/ve.init.mw.CaptchaSaveErrorHandler.js",
|
"scripts": "ve-confirmedit/ve.init.mw.CaptchaSaveErrorHandler.js",
|
||||||
|
"dependencies": "ext.confirmEdit.CaptchaInputWidget",
|
||||||
"targets": [
|
"targets": [
|
||||||
"desktop",
|
"desktop",
|
||||||
"mobile"
|
"mobile"
|
||||||
|
@ -106,7 +107,8 @@
|
||||||
"APIGetAllowedParams": "ConfirmEditHooks::onAPIGetAllowedParams",
|
"APIGetAllowedParams": "ConfirmEditHooks::onAPIGetAllowedParams",
|
||||||
"TitleReadWhitelist": "ConfirmEditHooks::onTitleReadWhitelist",
|
"TitleReadWhitelist": "ConfirmEditHooks::onTitleReadWhitelist",
|
||||||
"AlternateEditPreview": "ConfirmEditHooks::onAlternateEditPreview",
|
"AlternateEditPreview": "ConfirmEditHooks::onAlternateEditPreview",
|
||||||
"AuthChangeFormFields": "ConfirmEditHooks::onAuthChangeFormFields"
|
"AuthChangeFormFields": "ConfirmEditHooks::onAuthChangeFormFields",
|
||||||
|
"ResourceLoaderRegisterModules": "ConfirmEditHooks::onResourceLoaderRegisterModules"
|
||||||
},
|
},
|
||||||
"AuthManagerAutoConfig": {
|
"AuthManagerAutoConfig": {
|
||||||
"preauth": {
|
"preauth": {
|
||||||
|
|
|
@ -249,4 +249,41 @@ class ConfirmEditHooks {
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* ResourceLoaderRegisterModules hook handler.
|
||||||
|
*
|
||||||
|
* @param ResourceLoader $resourceLoader
|
||||||
|
*/
|
||||||
|
public static function onResourceLoaderRegisterModules( ResourceLoader $resourceLoader ) {
|
||||||
|
$extensionRegistry = ExtensionRegistry::getInstance();
|
||||||
|
$messages = [];
|
||||||
|
|
||||||
|
$messages[] = 'colon-separator';
|
||||||
|
$messages[] = 'captcha-edit';
|
||||||
|
$messages[] = 'captcha-label';
|
||||||
|
|
||||||
|
if ( $extensionRegistry->isLoaded( 'QuestyCaptcha' ) ) {
|
||||||
|
$messages[] = 'questycaptcha-edit';
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( $extensionRegistry->isLoaded( 'FancyCaptcha' ) ) {
|
||||||
|
$messages[] = 'fancycaptcha-edit';
|
||||||
|
$messages[] = 'fancycaptcha-reload-text';
|
||||||
|
$messages[] = 'fancycaptcha-imgcaptcha-ph';
|
||||||
|
}
|
||||||
|
|
||||||
|
$resourceLoader->register( [
|
||||||
|
'ext.confirmEdit.CaptchaInputWidget' => [
|
||||||
|
'localBasePath' => dirname( __DIR__ ),
|
||||||
|
'remoteExtPath' => 'ConfirmEdit',
|
||||||
|
'scripts' => 'resources/libs/ext.confirmEdit.CaptchaInputWidget.js',
|
||||||
|
'styles' => 'resources/libs/ext.confirmEdit.CaptchaInputWidget.less',
|
||||||
|
'messages' => $messages,
|
||||||
|
'dependencies' => 'oojs-ui-core',
|
||||||
|
'targets' => [ 'desktop', 'mobile' ],
|
||||||
|
]
|
||||||
|
] );
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
5
resources/libs/.eslintrc.json
Normal file
5
resources/libs/.eslintrc.json
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
{
|
||||||
|
"globals": {
|
||||||
|
"OO": false
|
||||||
|
}
|
||||||
|
}
|
108
resources/libs/ext.confirmEdit.CaptchaInputWidget.js
Normal file
108
resources/libs/ext.confirmEdit.CaptchaInputWidget.js
Normal file
|
@ -0,0 +1,108 @@
|
||||||
|
mw.libs.confirmEdit = {};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @class
|
||||||
|
* @extends OO.ui.TextInputWidget
|
||||||
|
*
|
||||||
|
* @constructor
|
||||||
|
* @param {Object} [captchaData] Value of 'captcha' property returned from action=edit API
|
||||||
|
* @param {Object} [config] Configuration options
|
||||||
|
*/
|
||||||
|
mw.libs.confirmEdit.CaptchaInputWidget = function MwWidgetsCaptchaInputWidget( captchaData, config ) {
|
||||||
|
config = config || {};
|
||||||
|
|
||||||
|
// Parent constructor
|
||||||
|
mw.libs.confirmEdit.CaptchaInputWidget.parent.call( this, $.extend( {
|
||||||
|
placeholder: mw.msg( 'fancycaptcha-imgcaptcha-ph' )
|
||||||
|
}, config ) );
|
||||||
|
|
||||||
|
// Properties
|
||||||
|
this.$captchaImg = null;
|
||||||
|
this.captchaId = null;
|
||||||
|
|
||||||
|
// Initialization
|
||||||
|
this.$element.addClass( 'mw-confirmEdit-captchaInputWidget' );
|
||||||
|
this.$element.prepend( this.makeCaptchaInterface( captchaData ) );
|
||||||
|
};
|
||||||
|
|
||||||
|
/* Setup */
|
||||||
|
|
||||||
|
OO.inheritClass( mw.libs.confirmEdit.CaptchaInputWidget, OO.ui.TextInputWidget );
|
||||||
|
|
||||||
|
/* Events */
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @event load
|
||||||
|
*
|
||||||
|
* A load event is emitted when the CAPTCHA image loads.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* Methods */
|
||||||
|
|
||||||
|
mw.libs.confirmEdit.CaptchaInputWidget.prototype.makeCaptchaInterface = function ( captchaData ) {
|
||||||
|
var $captchaImg, msg, question,
|
||||||
|
$captchaDiv, $captchaParagraph;
|
||||||
|
|
||||||
|
$captchaParagraph = $( '<div>' ).append(
|
||||||
|
$( '<strong>' ).text( mw.msg( 'captcha-label' ) ),
|
||||||
|
document.createTextNode( mw.msg( 'colon-separator' ) )
|
||||||
|
);
|
||||||
|
$captchaDiv = $( '<div>' ).append( $captchaParagraph );
|
||||||
|
|
||||||
|
if ( captchaData.url ) {
|
||||||
|
// FancyCaptcha
|
||||||
|
// Based on FancyCaptcha::getFormInformation() and ext.confirmEdit.fancyCaptcha.js
|
||||||
|
mw.loader.load( 'ext.confirmEdit.fancyCaptcha' );
|
||||||
|
$captchaDiv.addClass( 'fancycaptcha-captcha-container' );
|
||||||
|
$captchaParagraph.append( mw.message( 'fancycaptcha-edit' ).parseDom() );
|
||||||
|
$captchaImg = $( '<img>' )
|
||||||
|
.attr( 'src', captchaData.url )
|
||||||
|
.data( 'captchaId', captchaData.id )
|
||||||
|
.addClass( 'fancycaptcha-image' )
|
||||||
|
.on( 'load', this.emit.bind( this, 'load' ) );
|
||||||
|
$captchaDiv.append(
|
||||||
|
$captchaImg,
|
||||||
|
' ',
|
||||||
|
$( '<a>' ).addClass( 'fancycaptcha-reload' ).text( mw.msg( 'fancycaptcha-reload-text' ) )
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
if ( captchaData.type === 'simple' || captchaData.type === 'math' ) {
|
||||||
|
// SimpleCaptcha and MathCaptcha
|
||||||
|
msg = 'captcha-edit';
|
||||||
|
} else if ( captchaData.type === 'question' ) {
|
||||||
|
// QuestyCaptcha
|
||||||
|
msg = 'questycaptcha-edit';
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( msg ) {
|
||||||
|
switch ( captchaData.mime ) {
|
||||||
|
case 'text/html':
|
||||||
|
question = $.parseHTML( captchaData.question );
|
||||||
|
break;
|
||||||
|
case 'text/plain':
|
||||||
|
question = document.createTextNode( captchaData.question );
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
// Messages documented above
|
||||||
|
// eslint-disable-next-line mediawiki/msg-doc
|
||||||
|
$captchaParagraph.append( mw.message( msg ).parseDom(), '<br>', question );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( $captchaImg ) {
|
||||||
|
this.$captchaImg = $captchaImg;
|
||||||
|
} else {
|
||||||
|
this.captchaId = captchaData.id;
|
||||||
|
}
|
||||||
|
|
||||||
|
return $captchaDiv;
|
||||||
|
};
|
||||||
|
|
||||||
|
mw.libs.confirmEdit.CaptchaInputWidget.prototype.getCaptchaId = function () {
|
||||||
|
// 'ext.confirmEdit.fancyCaptcha' can update this value if the "Refresh" button is used
|
||||||
|
return this.$captchaImg ? this.$captchaImg.data( 'captchaId' ) : this.captchaId;
|
||||||
|
};
|
||||||
|
|
||||||
|
mw.libs.confirmEdit.CaptchaInputWidget.prototype.getCaptchaWord = function () {
|
||||||
|
return this.getValue();
|
||||||
|
};
|
9
resources/libs/ext.confirmEdit.CaptchaInputWidget.less
Normal file
9
resources/libs/ext.confirmEdit.CaptchaInputWidget.less
Normal file
|
@ -0,0 +1,9 @@
|
||||||
|
.mw-confirmEdit-captchaInputWidget {
|
||||||
|
.fancycaptcha-image {
|
||||||
|
margin-top: 0.5em;
|
||||||
|
}
|
||||||
|
|
||||||
|
.oo-ui-inputWidget-input {
|
||||||
|
margin-top: 0.5em;
|
||||||
|
}
|
||||||
|
}
|
|
@ -25,11 +25,7 @@ mw.libs.ve.targetLoader.addPlugin( function () {
|
||||||
};
|
};
|
||||||
|
|
||||||
ve.init.mw.CaptchaSaveErrorHandler.static.process = function ( data, target ) {
|
ve.init.mw.CaptchaSaveErrorHandler.static.process = function ( data, target ) {
|
||||||
var $captchaImg, msg, question,
|
var captchaInput;
|
||||||
captchaInput, $captchaDiv, $captchaParagraph,
|
|
||||||
captchaData = ve.getProp( data, 'visualeditoredit', 'edit', 'captcha' );
|
|
||||||
|
|
||||||
captchaInput = new OO.ui.TextInputWidget( { classes: [ 've-ui-saveDialog-captchaInput' ] } );
|
|
||||||
|
|
||||||
function onCaptchaLoad() {
|
function onCaptchaLoad() {
|
||||||
target.saveDialog.updateSize();
|
target.saveDialog.updateSize();
|
||||||
|
@ -37,6 +33,12 @@ mw.libs.ve.targetLoader.addPlugin( function () {
|
||||||
captchaInput.scrollElementIntoView();
|
captchaInput.scrollElementIntoView();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
captchaInput = new mw.libs.confirmEdit.CaptchaInputWidget(
|
||||||
|
ve.getProp( data, 'visualeditoredit', 'edit', 'captcha' )
|
||||||
|
);
|
||||||
|
ve.targetLinksToNewWindow( captchaInput.$element[ 0 ] );
|
||||||
|
|
||||||
|
captchaInput.on( 'load', onCaptchaLoad );
|
||||||
// Save when pressing 'Enter' in captcha field as it is single line.
|
// Save when pressing 'Enter' in captcha field as it is single line.
|
||||||
captchaInput.on( 'enter', function () {
|
captchaInput.on( 'enter', function () {
|
||||||
target.saveDialog.executeAction( 'save' );
|
target.saveDialog.executeAction( 'save' );
|
||||||
|
@ -44,76 +46,22 @@ mw.libs.ve.targetLoader.addPlugin( function () {
|
||||||
|
|
||||||
// Register extra fields
|
// Register extra fields
|
||||||
target.saveFields.wpCaptchaId = function () {
|
target.saveFields.wpCaptchaId = function () {
|
||||||
// 'ext.confirmEdit.fancyCaptcha' can update this value if the "Refresh" button is used
|
return captchaInput.getCaptchaId();
|
||||||
return $captchaImg ? $captchaImg.data( 'captchaId' ) : captchaData.id;
|
|
||||||
};
|
};
|
||||||
target.saveFields.wpCaptchaWord = function () {
|
target.saveFields.wpCaptchaWord = function () {
|
||||||
return captchaInput.getValue();
|
return captchaInput.getCaptchaWord();
|
||||||
};
|
};
|
||||||
|
// Unregister extra fields on save attempt
|
||||||
target.saveDialog.once( 'save', function () {
|
target.saveDialog.once( 'save', function () {
|
||||||
// Unregister extra fields on save attempt
|
|
||||||
delete target.saveFields.wpCaptchaId;
|
delete target.saveFields.wpCaptchaId;
|
||||||
delete target.saveFields.wpCaptchaWord;
|
delete target.saveFields.wpCaptchaWord;
|
||||||
} );
|
} );
|
||||||
|
|
||||||
$captchaParagraph = $( '<p>' ).append(
|
|
||||||
$( '<strong>' ).text( mw.msg( 'captcha-label' ) ),
|
|
||||||
document.createTextNode( mw.msg( 'colon-separator' ) )
|
|
||||||
);
|
|
||||||
$captchaDiv = $( '<div>' ).append( $captchaParagraph );
|
|
||||||
|
|
||||||
if ( captchaData.url ) {
|
|
||||||
// FancyCaptcha
|
|
||||||
// Based on FancyCaptcha::getFormInformation() (https://git.io/v6mml) and
|
|
||||||
// ext.confirmEdit.fancyCaptcha.js in the ConfirmEdit extension.
|
|
||||||
mw.loader.load( 'ext.confirmEdit.fancyCaptcha' );
|
|
||||||
$captchaDiv.addClass( 'fancycaptcha-captcha-container' );
|
|
||||||
$captchaParagraph.append( mw.message( 'fancycaptcha-edit' ).parseDom() );
|
|
||||||
$captchaImg = $( '<img>' )
|
|
||||||
.attr( 'src', captchaData.url )
|
|
||||||
.data( 'captchaId', captchaData.id )
|
|
||||||
.addClass( 'fancycaptcha-image' )
|
|
||||||
.on( 'load', onCaptchaLoad );
|
|
||||||
$captchaDiv.append(
|
|
||||||
$captchaImg,
|
|
||||||
' ',
|
|
||||||
$( '<a>' ).addClass( 'fancycaptcha-reload' ).text( mw.msg( 'fancycaptcha-reload-text' ) )
|
|
||||||
);
|
|
||||||
} else {
|
|
||||||
if ( captchaData.type === 'simple' || captchaData.type === 'math' ) {
|
|
||||||
// SimpleCaptcha and MathCaptcha
|
|
||||||
msg = 'captcha-edit';
|
|
||||||
} else if ( captchaData.type === 'question' ) {
|
|
||||||
// QuestyCaptcha
|
|
||||||
msg = 'questycaptcha-edit';
|
|
||||||
}
|
|
||||||
|
|
||||||
if ( msg ) {
|
|
||||||
switch ( captchaData.mime ) {
|
|
||||||
case 'text/html':
|
|
||||||
question = $.parseHTML( captchaData.question );
|
|
||||||
// TODO: Search for images and wait for them to load
|
|
||||||
setTimeout( onCaptchaLoad );
|
|
||||||
break;
|
|
||||||
case 'text/plain':
|
|
||||||
question = document.createTextNode( captchaData.question );
|
|
||||||
setTimeout( onCaptchaLoad );
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
// Messages documented above
|
|
||||||
// eslint-disable-next-line mediawiki/msg-doc
|
|
||||||
$captchaParagraph.append( mw.message( msg ).parseDom(), '<br>', question );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
ve.targetLinksToNewWindow( $captchaParagraph[ 0 ] );
|
|
||||||
$captchaDiv.append( captchaInput.$element );
|
|
||||||
|
|
||||||
// ProcessDialog's error system isn't great for this yet.
|
// ProcessDialog's error system isn't great for this yet.
|
||||||
target.saveDialog.clearMessage( 'api-save-error' );
|
target.saveDialog.clearMessage( 'api-save-error' );
|
||||||
target.saveDialog.showMessage( 'api-save-error', $captchaDiv, { wrap: false } );
|
target.saveDialog.showMessage( 'api-save-error', captchaInput.$element, { wrap: false } );
|
||||||
target.saveDialog.popPending();
|
target.saveDialog.popPending();
|
||||||
|
onCaptchaLoad();
|
||||||
|
|
||||||
// Emit event for tracking. TODO: This is a bad design
|
// Emit event for tracking. TODO: This is a bad design
|
||||||
target.emit( 'saveErrorCaptcha' );
|
target.emit( 'saveErrorCaptcha' );
|
||||||
|
|
Loading…
Reference in a new issue