diff --git a/recaptcha.js b/recaptcha.js new file mode 100644 index 0000000..220966f --- /dev/null +++ b/recaptcha.js @@ -0,0 +1,18 @@ +(function ($, window, document) { + + Drupal.behaviors.recaptcha = { + widgets: {}, + attach: function (context, settings) { + // Check if the reCAPTCHA script is loaded yet. If not, don't worry: the + // onload callback recaptchaOnLoad() will make sure that this function is + // called again once grecaptcha is defined. + if (typeof(grecaptcha) === 'undefined' || typeof(grecaptcha.render) === 'undefined' ) { + return; + } + $('.g-recaptcha', context).once('drupal-recaptcha').each(function () { + Drupal.behaviors.recaptcha.widgets[this.id] = grecaptcha.render(this, $(this).data()); + }); + } + }; + +})(jQuery, window, document); diff --git a/recaptcha.module b/recaptcha.module index 1e65aab..0af8234 100644 --- a/recaptcha.module +++ b/recaptcha.module @@ -68,7 +68,7 @@ function recaptcha_permission() { /** * Implements hook_captcha(). */ -function recaptcha_captcha($op, $captcha_type = '') { +function recaptcha_captcha($op, $captcha_type = '', $captcha_sid = '') { global $language; switch ($op) { @@ -101,6 +101,7 @@ function recaptcha_captcha($op, $captcha_type = '') { } $attributes = array( + 'id'=>'g-recaptcha'.$captcha_sid, 'class' => 'g-recaptcha', 'data-sitekey' => $recaptcha_site_key, 'data-theme' => variable_get('recaptcha_theme', 'light'), @@ -114,15 +115,49 @@ function recaptcha_captcha($op, $captcha_type = '') { $captcha['form']['recaptcha_widget'] = array( '#markup' => '', '#suffix' => $noscript, + '#attached' => array( + 'js' => array( + drupal_get_path('module', 'recaptcha') . '/recaptcha.js', + ), + ), + ); + + // The reCAPTHCHA onload callback must be defined before the + // reCAPTHCHA script itself is loaded. Since the reCAPTHCHA script is + // currently added with drupal_add_html_head(), we must do the same + // here so we can control the ordering of the script tags in . + // The recaptchaOnLoad() function tries to initialize the recaptcha's + // on the page. If the Drupal behavior is not available yet, don't + // worry: Drupal's attachBehaviors() will take care of it later. + $onload_js = << 'script', + '#value' => $onload_js, + '#weight' => -1, ); + drupal_add_html_head($data, 'recaptcha_onload'); // @todo: #1664602: D7 does not yet support "async" in drupal_add_js(). // drupal_add_js(url('https://www.google.com/recaptcha/api.js', array('query' => array('hl' => $language->language), 'absolute' => TRUE)), array('defer' => TRUE, 'async' => TRUE, 'type' => 'external')); $data = array( '#tag' => 'script', '#value' => '', + '#weight' => 0, '#attributes' => array( - 'src' => url('https://www.google.com/recaptcha/api.js', array('query' => array('hl' => $language->language), 'absolute' => TRUE)), + 'src' => url('https://www.google.com/recaptcha/api.js', array( + 'absolute' => TRUE, + 'query' => array( + 'hl' => $language->language, + 'onload' => 'recaptchaOnLoad', + 'render' => 'explicit', + ), + )), 'async' => 'async', 'defer' => 'defer', ), diff --git a/recaptcha.test b/recaptcha.test index 4afedf7..0d35de6 100644 --- a/recaptcha.test +++ b/recaptcha.test @@ -127,13 +127,17 @@ class ReCaptchaBasicTest extends DrupalWebTestCase { // Check if there is a reCAPTCHA on the login form. $this->drupalGet('user'); - $this->assertRaw($grecaptcha, '[testReCaptchaOnLoginForm]: reCAPTCHA is shown on form.'); - $this->assertRaw('', '[testReCaptchaOnLoginForm]: reCAPTCHA is shown on form.'); + $captcha_sid = $this->getCaptchaSid(); + $grecaptcha = '
'; + $this->assertRaw($grecaptcha, '[testReCaptchaOnLoginForm]: reCAPTCHA is shown on form.' . $grecaptcha); + $this->assertRaw('', '[testReCaptchaOnLoginForm]: reCAPTCHA API script is present.'); $this->assertNoRaw($grecaptcha . '