mirror of
https://gerrit.wikimedia.org/r/mediawiki/extensions/ConfirmEdit
synced 2024-11-24 00:04:15 +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": {
|
||||
"scripts": "ve-confirmedit/ve.init.mw.CaptchaSaveErrorHandler.js",
|
||||
"dependencies": "ext.confirmEdit.CaptchaInputWidget",
|
||||
"targets": [
|
||||
"desktop",
|
||||
"mobile"
|
||||
|
@ -106,7 +107,8 @@
|
|||
"APIGetAllowedParams": "ConfirmEditHooks::onAPIGetAllowedParams",
|
||||
"TitleReadWhitelist": "ConfirmEditHooks::onTitleReadWhitelist",
|
||||
"AlternateEditPreview": "ConfirmEditHooks::onAlternateEditPreview",
|
||||
"AuthChangeFormFields": "ConfirmEditHooks::onAuthChangeFormFields"
|
||||
"AuthChangeFormFields": "ConfirmEditHooks::onAuthChangeFormFields",
|
||||
"ResourceLoaderRegisterModules": "ConfirmEditHooks::onResourceLoaderRegisterModules"
|
||||
},
|
||||
"AuthManagerAutoConfig": {
|
||||
"preauth": {
|
||||
|
|
|
@ -249,4 +249,41 @@ class ConfirmEditHooks {
|
|||
|
||||
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 ) {
|
||||
var $captchaImg, msg, question,
|
||||
captchaInput, $captchaDiv, $captchaParagraph,
|
||||
captchaData = ve.getProp( data, 'visualeditoredit', 'edit', 'captcha' );
|
||||
|
||||
captchaInput = new OO.ui.TextInputWidget( { classes: [ 've-ui-saveDialog-captchaInput' ] } );
|
||||
var captchaInput;
|
||||
|
||||
function onCaptchaLoad() {
|
||||
target.saveDialog.updateSize();
|
||||
|
@ -37,6 +33,12 @@ mw.libs.ve.targetLoader.addPlugin( function () {
|
|||
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.
|
||||
captchaInput.on( 'enter', function () {
|
||||
target.saveDialog.executeAction( 'save' );
|
||||
|
@ -44,76 +46,22 @@ mw.libs.ve.targetLoader.addPlugin( function () {
|
|||
|
||||
// Register extra fields
|
||||
target.saveFields.wpCaptchaId = function () {
|
||||
// 'ext.confirmEdit.fancyCaptcha' can update this value if the "Refresh" button is used
|
||||
return $captchaImg ? $captchaImg.data( 'captchaId' ) : captchaData.id;
|
||||
return captchaInput.getCaptchaId();
|
||||
};
|
||||
target.saveFields.wpCaptchaWord = function () {
|
||||
return captchaInput.getValue();
|
||||
return captchaInput.getCaptchaWord();
|
||||
};
|
||||
|
||||
// Unregister extra fields on save attempt
|
||||
target.saveDialog.once( 'save', function () {
|
||||
// Unregister extra fields on save attempt
|
||||
delete target.saveFields.wpCaptchaId;
|
||||
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.
|
||||
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();
|
||||
onCaptchaLoad();
|
||||
|
||||
// Emit event for tracking. TODO: This is a bad design
|
||||
target.emit( 'saveErrorCaptcha' );
|
||||
|
|
Loading…
Reference in a new issue