In IE8 when the user is meant to be automatically logged out the following javascript error occurs:

Webpage error details

User Agent: Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 6.1; Trident/4.0; chromeframe/30.0.1599.101; SLCC2; .NET CLR 2.0.50727; .NET CLR 3.5.30729; .NET CLR 3.0.30729; Media Center PC 6.0; .NET CLR 1.1.4322; InfoPath.2)
Timestamp: Thu, 21 Nov 2013 09:58:45 UTC

Message: Can't move focus to the control because it is invisible, not enabled, or of a type that does not accept the focus.
Line: 3
Char: 3117
Code: 0
URI: http://10.30.20.86/sites/all/modules/thirdparty/jquery_update/replace/jq...

According to this Stack Overflow post (http://stackoverflow.com/questions/3452281/greybox-cant-move-focus-to-th...) the .focus() command needs to be moved into a setTimeout to solve the problem.

I've had a look in autologout.js but can't see a .focus command so not sure how to fix this...

Support from Acquia helps fund testing for Drupal Acquia logo

Comments

pacproduct’s picture

We have the same issue here, and debugging this in IE8 is painful.

Initially, we thought we could upgrade to JQuery 1.9 as it does solve the issue, but also breaks a lot of other stuff on our site. So it is not an acceptable option for us.

As a first attempt, and based on the example given in...
http://stackoverflow.com/questions/9023247/overriding-the-js-focus-metho...
... redefining the focus() function for HTMLButtonElement seems to solve the problem in IE8. I'm not a JS expert though, so the following code is probably enhanceable:

HTMLButtonElement.prototype.originalFocusFunction = HTMLButtonElement.prototype.focus;
HTMLButtonElement.prototype.focus = function () {
  return function() {
    setTimeout(function () {
        HTMLButtonElement.prototype.originalFocusFunction.apply(this, arguments);
      },
      0
    );
  }
}();

That seems pretty hacky though, so I would consider that as a preliminary investigation that needs more work.
Besides, that piece of code is more of general workaround to fix the behaviour of focus() in IE8 than a fix directly related to the autologout module. This being said, it still feels like Autologout is not compatible with (JQuery 1.8 + IE8).

This code should be fired only when we are in IE8. But even then, it means that we would be changing the behaviour of the focus() function for all HTMLButtonElements.

I cannot think of a better solution at the moment.

johnennew’s picture

Are you guys using ckeditor as your rich text editor? if so, what version?

pacproduct’s picture

We are using the CKEditor library version 3.2.1, with the Drupal module "ckeditor" 7.x-1.9.

I cannot see how it is relevant to this issue?

johnennew’s picture

I'm trying to diagnose which part of the autologout JS is causing your issue, which is not always present. There is specific code in there to react to CKEditor events to keep a user logged in if they are typing into a ckeditor field, this is liable to be connected to focus events. It may be a combination of modules that are triggering this behaviour.

thurulingas’s picture

We also have a solution that doesn't require setting the timeout, but is still overriding the .focus function. The code is slightly more legible:

  HTMLButtonElement.prototype.originalFocus = HTMLInputElement.prototype.focus;
  HTMLButtonElement.prototype.focus = function () {
    if (
      this.style.display != 'none' &&
      this.style.visibility != 'hidden' &&
      !this.disabled && this.type != 'hidden' &&
      this.style.width != '0px' &&
      this.style.width != '0%' &&
      this.style.width != 0
      ) {
        HTMLButtonElement.prototype.originalFocus.apply(this, arguments);
    }
  }

but suffers from the same problems as pacproduct's solution above, in that it is too broad-brush for the specific issue here. We'll continue to iterate on the above and see where it gets us.

johnennew’s picture

Version: 7.x-4.3 » 7.x-4.x-dev
Status: Active » Needs review
FileSize
816 bytes

Thanks everyone for continuing to look into this. Is anyone able to try removing the ckeditor code and seeing if the problem persists?

Patch attached.

pacproduct’s picture

When the problem occurs, an Exception is triggered here, in the JQuery library v1.8.2, on line 2977:

...
l.2975:	// Prevent re-triggering of the same event, since we already bubbled it above
l.2976:	jQuery.event.triggered = type;
l.2977:	elem[ type ](); // <<<< FAILS HERE
l.2978:	jQuery.event.triggered = undefined;
...

At that moment, IE8 says that: Can't move focus to the control because it is invisible, not enabled, or of a type that does not accept the focus.

That happens when autologout.js 7.x-4.2+8-dev tries to create the logout modal popup, on line 117:

...
l.117:        return $('<div> ' +  localSettings.message + '</div>').dialog({ // <<<< FAILS HERE
l.118:          modal: true,
l.119:               closeOnEscape: false,
l.120:               width: "auto",
l.121:               dialogClass: 'autologout-dialog',
l.122:               title: localSettings.title,
l.123:               buttons: buttons,
l.124:               close: function(event, ui) {
l.125:                 logout();
l.126:               }
l.127:        });
...

I'm gonna try your patch now, and will let you know.

pacproduct’s picture

I'm afraid the patch #6 does not solve the problem in our case.
It still fails on the same function calls.

johnennew’s picture

Thanks for trying pacproduct, that makes sense given your findings in #7

johnennew’s picture

Do we just need to create that div then and add it to the page before turning it into a dialogue?

pacproduct’s picture

EDIT: Please ignore the code in this comment. See #13 for the fixed version.

I am not sure.
According to http://stackoverflow.com/questions/14622689/ie8-jquery-error-at-line-ele..., the element needs to get "repainted" by IE before we can call focus() on it (it doesn't seem to be a sure thing though).
Which would explain why using setTimeout() to defer its execution works, even with 0ms.

Besides, the call actually fails to set the focus to the "Close button", so I don't think that attaching the div to the DOM first would make any difference.

As a quick workaround for now, we came up with a small module that includes the following JS code in a hook_init(), and it solves the issue for us (it is basically a enhanced version of the initial code I posted above):

(function () {
  // Figure out if current browser is IE8:
  var div = document.createElement("div");
  div.innerHTML = "<!--[if IE 8 ]><i></i><![endif]-->";
  var isIE8 = (div.getElementsByTagName("i").length == 1);
  
  // Current browser is IE8, override the focus function to defer its execution:
  if (isIE8) {
    Element.prototype.originalFocusFunction = Element.prototype.focus;
    Element.prototype.focus = function () {
      return function() {
        setTimeout(
          function () {
            Element.prototype.originalFocusFunction.apply(this, arguments);
          },
          0
        );
      }
    }();
  }
})();

We'll investigate a bit more by spinning up a fresh version of Drupal 7.23, with only jquery_update (configured to give us JQuery 1.8.2) and autologout 7.x-4.2+8-dev, to see if the problem is caused by a module conflict, or if it is just the combination of IE8 + Jquery 1.8.3 that causes the issue.

thurulingas’s picture

FileSize
117.68 KB

Just to confirm, I've uploaded a screengrab of the IE8 window showing the error with a new install of Drupal 7.23, having added Autologout 7.x-2.2-dev and using jquery_update set to jQuery 1.8, with no other modules installed or activated beyond the standard install.

pacproduct’s picture

Further testing showed that "this" was pointing at the window element instead of the right element. The following code should now apply to the correct element:

(function () {
  // Figure out if current browser is IE8:
  var div = document.createElement("div");
  div.innerHTML = "<!--[if IE 8 ]><i></i><![endif]-->";
  var isIE8 = (div.getElementsByTagName("i").length == 1);
  
  // Current browser is IE8, override the focus function to delay
  // its execution:
  if (isIE8) {
    Element.prototype.originalFocusFunction = Element.prototype.focus;
    Element.prototype.focus = function () {
      return function() {
        var that = this;
        
        setTimeout(
          function() {
              Element.prototype.originalFocusFunction.apply(that, arguments);
          },
          0
        );
      }
    }();
  }
})();
johnennew’s picture

Status: Needs review » Needs work

Hi @pacproduct, Any chance of a patch submission for this?

pacproduct’s picture

Well, I thought this piece of code was not really part of the Automated logout module.
The bug is more in JQuery and/or IE depending on how you look at it...

So on our project, this fix is added by a custom module so it fixes the "focus" function in all cases.

johnennew’s picture

Status: Needs work » Closed (won't fix)

Thanks for the update - I'll mark this as will not fix unless someone else thinks there is a generic fix for this module specifically and can supply a tested patch.