Событие TextTrackList onchange не работает в IE и Edge - PullRequest
0 голосов
/ 09 июня 2018

Событие TextTrackList.onchange не работает в IE и Edge Chrome и FireFox все работает отлично.

Есть ли альтернатива, которую я могу использовать?Я искал доступные события , но не могу их найти.

Или как мне обойти это?Так он работает среди всех браузеров?

https://www.javascripture.com/TextTrackList

var video = document.getElementById('video');

video.textTracks.addEventListener('change', function () {
  console.log("TextTracks change event fired!");
});
video {
  max-width: 400px;
  max-height: 400px;
}
<video controls id="video">
  <source src="https://www.sample-videos.com/video/mp4/720/big_buck_bunny_720p_30mb.mp4" type="video/mp4" />
  <track label="Caption #1" kind="subtitles" srclang="nl" src="path/to/caption1.vtt">
  <track label="Caption #2" kind="subtitles" srclang="en" src="path/to/caption2.vtt">
  <track label="Caption #3" kind="subtitles" srclang="de" src="path/to/caption3.vtt">
</video>

Ответы [ 2 ]

0 голосов
/ 22 июня 2018

Возможно, вам удастся создать вид полифилла.

Сначала, чтобы определить, поддерживаем мы событие или нет, мы можем проверить ('onchange' in window.TextTrackList).Таким образом, мы можем условно интегрировать наш несовершенный полифилл и оставить правильные реализации без изменений.

Затем мы можем итерировать каждый x-раз по TextTracks нашего TextTrackList, чтобы найти, какой из них является активным, это должен быть тотс mode, установленным на "showing".

Теперь нам просто нужно сохранить предыдущий активный трек и проверить, совпадает ли текущий.В противном случае запустите Event.

Таким образом, простая реализация может быть

// in an outer scope
// textTracks is our TextTrackList object
var active = getActive();

// start polling
poll();

function poll() {
  // schedule next check in a frame
  requestAnimationFrame(poll);
  var current = getActive();

  if (current !== active) {
    active = current; // update the active one
    // dispatchEvent is not supported on TextTrackList in IE...
    onchange({
      target: textTracks
    });
  }
}

function getActive() {
  for (var i = 0; i < textTracks.length; i++) {
    if (textTracks[i].mode === 'showing') {
      return textTracks[i];
    }
  }
}

Но для реализации лучшего полизаполнения мы захотим переопределить исходные addEventListener, removeEventListener и onchange свойства прототипа TextTrackList.

Вот грубая реализация, которая не позаботится о третьем параметре [добавить / удалить] EventListener .

(function() {
  /* Tries to implement an 'change' Event on TextTrackList Objects when not implemented */

  if (window.TextTrackList && !('onchange' in window.TextTrackList.prototype)) {
    var textTracksLists = [], // we will store all the TextTrackLists instances
      polling = false; // and run only one polling loop

    var proto = TextTrackList.prototype,

      original_addEvent = proto.addEventListener,
      original_removeEvent = proto.removeEventListener;

    var onchange = {
      get: getonchange,
      set: setonchange
    };

    Object.defineProperty(proto, 'onchange', onchange);
    Object.defineProperty(proto, 'addEventListener', fnGetter(addListener));
    Object.defineProperty(proto, 'removeEventListener', fnGetter(removeListener));

    function fnGetter(fn) {
      return {
        get: function() {
          return fn;
        }
      };
    }


    /* 	When we add a new EventListener, we attach a new object on our instance
    	This object set as '._fakeevent' will hold informations about
    		the current EventListeners
    		the current onchange handler
    		the parent <video> element if any
    		the current activeTrack
    */
    function initFakeEvent(instance) {
      // first try to grab the video element from where we were generated
      // this is useful to not run useless tests when the video is detached
      var vid_elems = document.querySelectorAll('video'),
        vid_elem = null;
      for (var i = 0; i < vid_elems.length; i++) {
        if (vid_elems[i].textTracks === instance) {
          vid_elem = vid_elems[i];
          break;
        }
      }

      textTracksLists.push(instance);
      instance._fakeevent = {
        parentElement: vid_elem,
        listeners: {
          change: []
        }
      }
      if (!polling) { // if we are the first instance being initialised
        polling = true;
        requestAnimationFrame(poll); // start the checks
      }

      return instance._fakeevent;
    }

    function getonchange() {
      var fakeevent = this._fakeevent;
      if (!fakeevent || typeof fakeevent !== 'object') {
        return null;
      }
      return fakeevent.onchange || null;
    }

    function setonchange(fn) {
      var fakeevent = this._fakeevent;
      if (!fakeevent) {
        fakeevent = initFakeEvent(this);
      }
      if (fn === null) fakeevent.onchange = null;
      if (typeof fn !== 'function') return fn;
      return fakeevent.onchange = fn;
    }

    function addListener(type, fn, options) {
      if (type !== 'change') { // we only handle change for now
        return original_addEvent.bind(this)(type, fn, options);
      }
      if (!fn || typeof fn !== 'object' && typeof fn !== 'function') {
        throw new TypeError('Argument 2 of EventTarget.addEventListener is not an object.');
      }
      var fakeevent = this._fakeevent;
      if (!fakeevent) {
        fakeevent = initFakeEvent(this);
      }
      if (typeof fn === 'object') {
        if (typeof fn.handleEvent === 'function') {
          fn = fn.handleEvent;
        } else return;
      }
      // we don't handle options yet...
      if (fakeevent.listeners[type].indexOf(fn) < 0) {
        fakeevent.listeners[type].push(fn);
      }
    }

    function removeListener(type, fn, options) {
      if (type !== 'change') { // we only handle change for now
        return original_removeEvent.call(this, arguments);
      }
      var fakeevent = this._fakeevent;
      if (!fakeevent || !fn || typeof fn !== 'object' && typeof fn !== 'function') {
        return
      }
      if (typeof fn === 'object') {
        if (typeof fn.handleEvent === 'function') {
          fn = fn.handleEvent;
        } else return;
      }
      // we don't handle options yet...
      var index = fakeevent.listeners[type].indexOf(fn);
      if (index > -1) {
        fakeevent.listeners[type].splice(index, 1);
      }
    }


    function poll() {
      requestAnimationFrame(poll);
      textTracksLists.forEach(check);
    }

    function check(instance) {
      var fakeevent = instance._fakeevent;
      // if the parent vid not in screen, we probably have not changed
      if (fakeevent.parentElement && !fakeevent.parentElement.parentElement) {
        return;
      }
      // get the current active track
      var current = getActiveTrack(instance);
      // has changed
      if (current !== fakeevent.active) {
        if (instance.onchange) {
          try {
            instance.onchange({
              type: 'change',
              target: instance
            });
          } catch (e) {}
        }
        fakeevent.listeners.change.forEach(call, this);
      }
      fakeevent.active = current;
    }

    function getActiveTrack(textTracks) {
      for (var i = 0; i < textTracks.length; i++) {
        if (textTracks[i].mode === 'showing') {
          return textTracks[i];
        }
      }
      return null;
    }

    function call(fn) {
      fn({
        type: 'change',
        target: this
      });
    }


  }
})();

var video = document.getElementById('video');

video.textTracks.onchange = function ontrackchange(e) {
  console.log('changed');
};
video {
  max-width: 400px;
  max-height: 400px;
}
<video controls id="video">
  <source src="https://www.sample-videos.com/video/mp4/720/big_buck_bunny_720p_30mb.mp4" type="video/mp4" />
   <track label="Caption #1" kind="subtitles" srclang="nl" src="path/to/caption1.vtt">
   <track label="Caption #2" kind="subtitles" srclang="en" src="path/to/caption2.vtt">
   <track label="Caption #3" kind="subtitles" srclang="de" src="path/to/caption3.vtt">
</video>
0 голосов
/ 17 июня 2018

Вы правы, это проблема с IE и Edge.Что вы можете сделать, это прослушать событие на дорожке загрузки.Просто обратите внимание, что трек должен находиться в одном и том же домене, в противном случае вы получите ошибку без вывода сообщений (CURS), а в списке событий не появится список событий.

Я создал кодовую рамку, чтобы выможно попробовать https://codepen.io/shahar-polak/project/live/AnVpEw/

ПРИМЕЧАНИЕ: Код вызовет одно событие в IE и Edge и два события в Chrome и Firefox.Убедитесь, что вы проверяете браузер клиента перед использованием в производстве.

const video = document.getElementById('video');
const tracks = Array.from(document.querySelectorAll('track'));
video.textTracks.addEventListener('change', function() {
  console.log('TextTracks change event fired!');
});
// For IE and Edge
tracks.forEach((track) => {
  track.addEventListener("load", function() {
    console.log('change track');
  }, false);
})
video {
  max-width: 400px;
  max-height: 400px;
}
<video controls id="video" >
    <source src="https://www.sample-videos.com/video/mp4/720/big_buck_bunny_720p_30mb.mp4" type="video/mp4"/>
    <track label="Caption #1" kind="subtitles" srclang="nl" src="./en.vtt">
    <track label="Caption #2" kind="subtitles" srclang="en" src="./en.vtt">
    <track label="Caption #3" kind="subtitles" srclang="de" src="https://iandevlin.com/html5/dynamic-track/captions/sintel-en.vtt">
</video>
...