Пользовательское событие ActiveX не может работать в IE11

Я обновил свой IE с 10 до 11 и обнаружил, что мое специальное событие ActiveX не может работать.

Причина в том, что IE11 больше не поддерживает attachEvent, и мне кажется, что я должен использовать addEventListener. Например, ранее я использовал

obj.attachEvent("onSelected", method1); 

и теперь это

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

После изменения кода метод1 не может быть запущен. Я не знаю, как связать настраиваемое событие, которое реализовано в плагине ActiveX, с JS-методом и заставить его работать в IE11?

Ответ 1

Единственным способом, который я нашел до сих пор для IE 11, является использование блоков for...event script:

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

Оба элемента также могут быть созданы динамически с помощью JavaScript. Вы должны убедиться, что вы установили атрибут for с помощью метода setAttribute:

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);

Старые версии IE (IE 8 и старше) не нравятся приведенному выше коду. Для этих старых браузеров вы должны передать параметр codebase и for с помощью метода createElement:

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

Новые браузеры генерируют исключение при встрече с этим кодом, поэтому для поддержки всех версий IE вы должны поймать это исключение, а затем использовать другой метод.

Ответ 2

Изменяет код @Gerrit для работы анонимных функций, также он просто добавляет функции attachEvent обратно в IE 11 (и polyfill для не точечных браузеров, хотя и не проверен), поэтому можно использовать один и тот же код. Я рад, что нашел эту страницу. Я боялся, что мне придется делать это в VBScript или эмулировать более старую версию IE.

Поведение похоже на то же, что и в 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 : /*@[email protected]*/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);
  }
}

Пример использования моего объекта ActiveX

<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>

Ответ 3

Основываясь на ответе kayahr, я создал функцию, которая регистрирует событие в IE 11. Большое спасибо! Это сработало для меня!

Вот мой код (не работает с анонимными функциями как параметр _functionCallback):

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);
    };

Вы должны использовать обнюхивание браузером, и ваш код должен выглядеть как

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);

Ответ 4

ActiveX был удален из браузера в IE10. Технология была старой и все более ненужной в мире HTML5.

Вы не упомянули, что делает плагин? Можно ли заменить его стандартным кодом?