/** * Defines and installs the hCaptcha plugin for VisualEditor that displays hCaptcha * when a user needs to complete hCaptcha for a "generic" edit. * A generic edit is an edit where a user needing to fill out a captcha is not * dependent on the content of the edit. * * Returns a callback that should be executed in initPlugins.js after `ve.init.mw.HCaptcha` * is loaded */ module.exports = () => { // Load these here so that in QUnit tests we have a chance to mock utils.js const config = require( './../config.json' ); const ErrorWidget = require( '../ErrorWidget.js' ); const { mapErrorCodeToMessageKey } = require( './../utils.js' ); ve.init.mw.HCaptchaOnLoadHandler = function () {}; OO.inheritClass( ve.init.mw.HCaptchaOnLoadHandler, ve.init.mw.HCaptcha ); /** * Whether the hCaptcha widget is in the process of being rendered in the save dialog * * @type {boolean} */ ve.init.mw.HCaptchaOnLoadHandler.static.isHCaptchaRendering = false; /** * Whether the hCaptcha widget has been rendered in the save dialog * * @type {boolean} */ ve.init.mw.HCaptchaOnLoadHandler.static.isHCaptchaRendered = false; /** * The return value of `hcaptcha.render`, which is the widget ID of the * rendered hCaptcha widget. This can be used by `executeHCaptcha` * to programmatically execute hCaptcha in invisible mode. * * @type {string|null} `null` if no hCaptcha widget is rendered yet */ ve.init.mw.HCaptchaOnLoadHandler.static.widgetId = null; /** * Load the hCaptcha SDK when a user changes content in the VisualEditor editor if * hCaptcha is required for a "generic" edit. * * @return {void} */ ve.init.mw.HCaptchaOnLoadHandler.static.onActivationComplete = function () { if ( !this.shouldRun() ) { return; } const surface = ve.init.target.surface; surface.getModel().getDocument().once( 'transact', () => { this.getReadyPromise(); } ); }; /** * Render the hCaptcha widget if not already being rendered or has been rendered, * as long as hCaptcha is required for a "generic" edit. * * @param {window} win * @return {Promise} */ ve.init.mw.HCaptchaOnLoadHandler.static.renderHCaptcha = function ( win ) { // Return early if not enabled, if the hCaptcha widget is currently being rendered, // or if hCaptcha has already been rendered. // This is needed because this method is called when the state of the dialog changes // and so could be called multiple times. if ( !this.shouldRun() || this.isHCaptchaRendering || this.isHCaptchaRendered ) { return Promise.resolve(); } this.isHCaptchaRendering = true; // Drop any other hCaptcha widget as we are going to add one ourselves in a specific place const saveDialog = ve.init.target.saveDialog; saveDialog.$element.find( '.ext-confirmEdit-visualEditor-hCaptchaContainer' ).remove(); const $hCaptchaContainer = $( '