12

I upgraded my IE from version 10 to 11 and found that my ActiveX custom event couldn't work.

The reason is that IE11 does not support attachEvent any more, and seems I have to use addEventListener. For example previously I used

obj.attachEvent("onSelected", method1); 

and now, it is

obj.addEventListener("onSelected",method1,false); 

After changing the code, the method1 cannot be triggered. I have no idea how to bind custom event, which is implemented in ActiveX plugin, to JS method and make it work on IE11?

yushulx
  • 10,569
  • 7
  • 34
  • 58
  • I seem to recall that when it was removed from IE10, it was kept available in compatibility mode. I'm not sure if IE11 does the same or not. What mode are you trying to run your page in? Have you tried compat mode? – Spudley Jul 29 '13 at 11:22
  • I think your meant to drop the "on" from "onSelected", but I have still been unable to get my ActiveX events in IE11 also. – Schmoo Oct 29 '13 at 07:25

4 Answers4

13

The only way I found so far for IE 11 is using the for...event script blocks:

<script for="myActiveX" event="onSelected(param1, param2)">
  method1(param1, param2);
</script>
<object id="myActiveX" ...></object>

Both elements can also be created dynamically with JavaScript. You only must make sure you set the for attribute with the setAttributemethod:

var handler = document.createElement("script");
handler.setAttribute("for", "myActiveX");
handler.event = "onSelected(param1, param2)";       
handler.appendChild(document.createTextNode("method1(param1, param2);"));
document.body.appendChild(handler);

var activeX = document.createElement("object");
activeX.id = "myActiveX"; 
activeX.codebase = "foobar.cab";
activeX.classid = "CLSID:123456789-1234-1234-1234-123456789012";
document.body.appendChild(activeX);

Older IE versions (IE 8 and older) don't like the above code. For these older browsers you must pass the codebase parameter and for parameter with the createElement method:

var handler = document.createElement('<script for="myActiveX">');
...
var activeX = document.createElement('<object classid="CLSID:123456789-1234-1234-1234-123456789012">');

Newer browsers will throw an exception when encountering this code so to support all IE versions you must catch this exception and then use the other method.

Roman R.
  • 64,446
  • 5
  • 83
  • 139
kayahr
  • 18,296
  • 27
  • 93
  • 139
2

Modifies @Gerrit code to work for anonymous functions, also it simply adds attachEvent functionality back to IE 11 (and polyfill for non ie browsers, although not tested) so the same code can be used. I'm happy I found this page. I was fearful that I would have to do this in VBScript or emulate an older version of IE.

Behavior seems to be the same all the way back to IE5.

Polyfill

if (!window.attachEvent) {
  window.attachEvent = Element.prototype.attachEvent = function (ename, efunction) {
    if (typeof efunction !== 'function') {
      throw new TypeError('Element.prototype.attachEvent - what is trying to be attached is not callable');
    }

    // We got to append somewhere
    var _body = document.getElementsByTagName('body')[0];

    // Get IE Version
    var msie = (function() {
        if (typeof document === "undefined") return false;
        var v = 3, div = document.createElement('div'), a = div.all || [];

        while (div.innerHTML = '<!--[if gt IE '+(++v)+']><br>&lt![endif]-->', a[0]); 

        var _detection = v > 4 ? v : /*@cc_on!@*/false;

        var _version = _detection === true ? 10 : (!(window.ActiveXObject) && "ActiveXObject" in window) === true ? 11 : _detection;

        return _version;

    }());

    // Fix ActiveX not working
    if (msie == 11) {
      var _params = efunction.toString().match(/(\(.*\))\ *{/)[1];
      var _funcName = efunction.toString().match(/^function\s?([^\s(]*)/)[1];
      var _fixAnon = false;

      // Allow for anonymous functions
      if (_funcName == "") {
        _fixAnon = true;
        console.warn('Function name not found. Autogenerating');
        _funcName = "autogenFunction" + Math.floor(Math.random()*9999).toString()
        var _handleFunctionality = "{ var privateFunc = " + efunction.toString() + "; privateFunc.apply(" + _funcName + ", arguments); }";
      }

      // Only one script for|event can be used. Make sure there isn't one already
      var _query = 'script[for=' + this.id + '][event=' + ename + ']';
      var _handle = document.querySelectorAll(_query);
      var _handleFunc = _funcName + _params + ';';

      if (_fixAnon) {
        var _newFuncName = _funcName + _params;
        var _newFunction = "function " + _newFuncName + " " + _handleFunctionality;
        var _newHandle = document.createElement('script');
        _newHandle.type = "text/javascript";
        _newHandle.appendChild(document.createTextNode(_newFunction));
        _body.appendChild(_newHandle);
      }

      // If script for|event exists, reuse it
      if (_handle.length != 0) {
        _handleFunc += _handle[0].textContent;
        _body.removeChild(_handle[0]);
        delete _handle[0];
      }
      _handle = document.createElement('script');
      _handle.setAttribute("for", this.id);
      _handle.event = ename;
      var _handleText = document.createTextNode(_handleFunc);
      _handle.appendChild(document.createTextNode(_handleFunc));
      _body.appendChild(_handle);
    }
    var _event = ename.substr(0,2) == "on" ? ename.substr(2) : ename;

    // Polyfill for non ie browsers
    if (window.addEventListener) this.addEventListener(_event, efunction, false);
  }
}

Example Usage with my ActiveX Object

<script type="text/javascript">
function MyObject_ObjectEvent() {
console.log('I am watching traditionally');
}
var _elem = document.getElementById('MyObject');
_elem.attachEvent('ObjectEvent', function () { console.log('I am watching anonymously') });
_elem.attachEvent('ObjectEvent', MyObject_ObjectEvent);
</script>
Verron Knowles
  • 826
  • 8
  • 9
1

Based on kayahr answer I have created a function which does the event registration in IE 11. Thank you very much! It worked for me!

Here is my code (does not work with anonymous functions as _functionCallback parameter):

function AttachIE11Event(obj, _strEventId, _functionCallback) {
        var nameFromToStringRegex = /^function\s?([^\s(]*)/;
        var paramsFromToStringRegex = /\(\)|\(.+\)/;
        var params = _functionCallback.toString().match(paramsFromToStringRegex)[0];
        var functionName = _functionCallback.name || _functionCallback.toString().match(nameFromToStringRegex)[1];
        var handler;
        try {
            handler = document.createElement("script");
            handler.setAttribute("for", obj.id);
        }
        catch(ex) {
            handler = document.createElement('<script for="' + obj.id + '">');
        }
        handler.event = _strEventId + params;
        handler.appendChild(document.createTextNode(functionName + params + ";"));
        document.body.appendChild(handler);
    };

You have to use browser sniffing, and your code has to look like

if(BrowserDetect.browser == "IE" && BrowserDetect.version >= 11)
   AttachIE11Event(obj, "onSelected", method1);
else if(obj.attachEvent)
   obj.attachEvent("onSelected", method1);
else if(obj.addEventListener)
   obj.addEventListener("onSelected", method1);
Gerrit
  • 502
  • 4
  • 10
-6

ActiveX was removed from the browser in IE10. The technology was old and increasingly unnecessary in an HTML5 world.

You don't mention what the plugin was doing? Can it be replaced with standard code now?

  • 3
    Use of ActiveX controls (other than Flash) is blocked in the "METRO" mode of the IE browser, not in the Desktop mode. – EricLaw Aug 02 '13 at 22:36