2018-11-23 17:22:13 +00:00
|
|
|
// Captcha "errors" usually aren't errors. We simply don't know about them ahead of time,
|
|
|
|
// so we save once, then (if required) we get an error with a captcha back and try again after
|
|
|
|
// the user solved the captcha.
|
|
|
|
// TODO: ConfirmEdit API is horrible, there is no reliable way to know whether it is a "math",
|
|
|
|
// "question" or "fancy" type of captcha. They all expose differently named properties in the
|
2019-02-10 15:44:37 +00:00
|
|
|
// API for different things in the UI. At this point we only support the SimpleCaptcha and
|
|
|
|
// FancyCaptcha which we very intuitively detect by the presence of a "url" property.
|
2018-11-23 17:22:13 +00:00
|
|
|
mw.libs.ve.targetLoader.addPlugin( function () {
|
2018-11-29 16:51:27 +00:00
|
|
|
|
|
|
|
ve.init.mw.CaptchaSaveErrorHandler = function () {};
|
|
|
|
|
|
|
|
OO.inheritClass( ve.init.mw.CaptchaSaveErrorHandler, ve.init.mw.SaveErrorHandler );
|
|
|
|
|
|
|
|
ve.init.mw.CaptchaSaveErrorHandler.static.name = 'confirmEditCaptchas';
|
|
|
|
|
2018-12-07 19:18:03 +00:00
|
|
|
ve.init.mw.CaptchaSaveErrorHandler.static.matchFunction = function ( data ) {
|
|
|
|
var captchaData = ve.getProp( data, 'visualeditoredit', 'edit', 'captcha' );
|
2018-11-29 16:51:27 +00:00
|
|
|
|
|
|
|
return !!( captchaData && (
|
|
|
|
captchaData.url ||
|
|
|
|
captchaData.type === 'simple' ||
|
|
|
|
captchaData.type === 'math' ||
|
|
|
|
captchaData.type === 'question'
|
|
|
|
) );
|
|
|
|
};
|
|
|
|
|
2018-12-07 19:18:03 +00:00
|
|
|
ve.init.mw.CaptchaSaveErrorHandler.static.process = function ( data, target ) {
|
2018-11-23 17:22:13 +00:00
|
|
|
var $captchaImg, msg, question,
|
|
|
|
captchaInput, $captchaDiv, $captchaParagraph,
|
2018-12-07 19:18:03 +00:00
|
|
|
captchaData = ve.getProp( data, 'visualeditoredit', 'edit', 'captcha' );
|
2018-11-23 17:22:13 +00:00
|
|
|
|
|
|
|
captchaInput = new OO.ui.TextInputWidget( { classes: [ 've-ui-saveDialog-captchaInput' ] } );
|
|
|
|
|
|
|
|
function onCaptchaLoad() {
|
|
|
|
target.saveDialog.updateSize();
|
|
|
|
captchaInput.focus();
|
|
|
|
captchaInput.scrollElementIntoView();
|
|
|
|
}
|
|
|
|
|
|
|
|
// Save when pressing 'Enter' in captcha field as it is single line.
|
|
|
|
captchaInput.on( 'enter', function () {
|
|
|
|
target.saveDialog.executeAction( 'save' );
|
|
|
|
} );
|
|
|
|
|
|
|
|
// Register extra fields
|
|
|
|
target.saveFields.wpCaptchaId = function () {
|
2020-03-24 00:07:00 +00:00
|
|
|
// 'ext.confirmEdit.fancyCaptcha' can update this value if the "Refresh" button is used
|
|
|
|
return $captchaImg ? $captchaImg.data( 'captchaId' ) : captchaData.id;
|
2018-11-23 17:22:13 +00:00
|
|
|
};
|
|
|
|
target.saveFields.wpCaptchaWord = function () {
|
|
|
|
return captchaInput.getValue();
|
|
|
|
};
|
|
|
|
|
|
|
|
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' );
|
2018-11-29 00:30:05 +00:00
|
|
|
$captchaParagraph.append( mw.message( 'fancycaptcha-edit' ).parseDom() );
|
2018-11-23 17:22:13 +00:00
|
|
|
$captchaImg = $( '<img>' )
|
|
|
|
.attr( 'src', captchaData.url )
|
2020-03-24 00:07:00 +00:00
|
|
|
.data( 'captchaId', captchaData.id )
|
2018-11-23 17:22:13 +00:00
|
|
|
.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;
|
|
|
|
}
|
2019-11-15 16:46:40 +00:00
|
|
|
// Messages documented above
|
|
|
|
// eslint-disable-next-line mediawiki/msg-doc
|
2018-11-29 00:30:05 +00:00
|
|
|
$captchaParagraph.append( mw.message( msg ).parseDom(), '<br>', question );
|
2018-11-23 17:22:13 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-11-29 00:30:05 +00:00
|
|
|
ve.targetLinksToNewWindow( $captchaParagraph[ 0 ] );
|
2018-11-23 17:22:13 +00:00
|
|
|
$captchaDiv.append( captchaInput.$element );
|
|
|
|
|
|
|
|
// ProcessDialog's error system isn't great for this yet.
|
|
|
|
target.saveDialog.clearMessage( 'api-save-error' );
|
2020-03-23 22:06:24 +00:00
|
|
|
target.saveDialog.showMessage( 'api-save-error', $captchaDiv, { wrap: false } );
|
2018-11-23 17:22:13 +00:00
|
|
|
target.saveDialog.popPending();
|
|
|
|
|
|
|
|
// Emit event for tracking. TODO: This is a bad design
|
|
|
|
target.emit( 'saveErrorCaptcha' );
|
2018-11-29 16:51:27 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
ve.init.mw.saveErrorHandlerFactory.register( ve.init.mw.CaptchaSaveErrorHandler );
|
2018-11-23 17:22:13 +00:00
|
|
|
|
|
|
|
} );
|