Problems with new Google reCAPTCHA in IE when insi

2019-01-17 23:13发布

问题:

reCAPTCHA works perfectly well in Chrome.

However, (only when reCAPTCHA iframe is inside a dialog box or a modal) in IE the placeholder won't go away.

Whatever the user writes is considered part of the placeholder (I think) and the "verify" button won't be enabled to be clicked.

The picture explains this:

The same code works perfectly well in all browsers when I take the recaptcha div outside the modal

<html lang="en">
<head>
    <link href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.1/css/bootstrap.min.css" rel="stylesheet">
    <script src="https://www.google.com/recaptcha/api.js?onload=onloadCallback&render=explicit" async defer></script>
    <script src="https://code.jquery.com/jquery-2.1.3.min.js"></script>
    <script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.1/js/bootstrap.min.js"></script>
    <script type="text/javascript">
    var onloadCallback = function() {
        grecaptcha.render('html_element', {
          'sitekey' : '6Lc7PAATAAAAAE7JwcA7tNEDIrczjCCUvi3GiK4L'
      });
    };
    </script>
</head>
<body>
    <div class="container">
        <button type="button" class="btn btn-primary btn-lg" data-toggle="modal" data-target="#myModal">
          Launch modal
      </button>
      <!-- Modal -->
      <div class="modal fade" id="myModal" tabindex="-1" role="dialog" aria-labelledby="myModalLabel" aria-hidden="true">
          <div class="modal-dialog">
            <div class="modal-content">
                <form action="?" method="POST">
                  <div id="html_element"></div>
                  <br>
                  <input type="submit" value="Submit">
              </form>
          </div>
      </div>
  </div>
</div>
</body>
</html>

回答1:

The problem is generated by the the modal component of Bootstrap.

When the modal is about to appear this function is called:

Modal.prototype.enforceFocus = function () {
    $(document)
    .off('focusin.bs.modal') // guard against infinite focus loop
    .on('focusin.bs.modal', $.proxy(function (e) {
        if (this.$element[0] !== e.target && !this.$element.has(e.target).length) {
            this.$element.trigger('focus')
        }
    }, this))
}

The function adds a "focusin" event to the document to be sure that the focus is still inside the modal; if the focus goes to another element outside the modal then the latter immediately obtain it back.
Therefore, when you click inside the recaptcha form the focus' conflict causes the Internet Explorer bug.

Anyway, one possible solution is to override that method and disable the focus-back behaviour when a recaptcha component obtain the focus, but this is quite difficult to do because there is no control over the recaptcha html (how can you know if e.target is an element of recaptcha?).

My solution is to completely disable this behavior, to do this just override the enforceFocus function with an empty function:

$.fn.modal.Constructor.prototype.enforceFocus = function () { };

A more elegant solution would be apreciated. :)



回答2:

Old recaptcha, i.e. version 1.0 works ok on the modal



回答3:

To follow up on the response by 'Digibusiness', A little more elegant would be to override the entire bootstrap function with a practical one (on your page load - the document.ready function would be a good place). This way, you can refer only to IE when overrding + only to iframes loaded on the modal, hence not screwing accessibility(which have become a big deal these days) all over the site just for a specific iframe-over-modal-on-a-specific-browser functionallity fix.

  • The code goes follows:

    if (window.navigator.userAgent.indexOf("MSIE ") > 0 || !!navigator.userAgent.match(/Trident.*rv\:11\./)) {  // If Internet Explorer
        $.fn.modal.Constructor.prototype.enforceFocus = function () {
            $(document)
            .off('focusin.bs.modal') // guard against infinite focus loop
            .on('focusin.bs.modal', $.proxy(function (e) {
                if (this.$element[0] !== e.target && !this.$element.has(e.target).length) {
                    if (e.target.nodeName !== "IFRAME") {
                        this.$element.trigger('focus')
                    }
                }
            }, this))
        }
    }