Soviut
Soviut

Reputation: 91555

How can I wrap the HTML5 video element's currentTime property?

I'm developing a video player as part of a learning module system. Certain modules require that the user not be able to (easily) skip ahead in the video. I understand that this would normally be considered a bad user experience, but it's essential in this case.

I've been able to override the video.currentTime property by doing the following. It prevents skipping, but I need to be able to turn it on and off conditionally.

Object.defineProperty(videoElement, 'currentTime', {
  enumerable: true,
  configurable: true,
  get: function() {
    // return from original currentTime
  },
  set: function(newValue) {
    // intercept values here
  }
});

how I can reference the original video.currentTime property in my getter and setter? Unfortunately, Object.getOwnPropertyDescriptor(videoElement, 'currentTime'); returns undefined.

Upvotes: 2

Views: 994

Answers (2)

Svetlin Mladenov
Svetlin Mladenov

Reputation: 4427

If disabling seeking (skipping) is what you want to do then here is my solution:

var video = document.getElementById('video');
var supposedCurrentTime = 0;
video.addEventListener('timeupdate', function() {
  if (!video.seeking) {
        supposedCurrentTime = video.currentTime;
  }
});
// prevent user from seeking
video.addEventListener('seeking', function() {
  // guard agains infinite recursion:
  // user seeks, seeking is fired, currentTime is modified, seeking is fired, current time is modified, ....
  var delta = video.currentTime - supposedCurrentTime;
  if (Math.abs(delta) > 0.01) {
    console.log("Seeking is disabled");
    video.currentTime = supposedCurrentTime;
  }
});
// delete the following event handler if rewind is not required
video.addEventListener('ended', function() {
  // reset state in order to allow for rewind
    supposedCurrentTime = 0;
});

This code simply restores video.currentTime to its last known value when seeking. This effectively cancels the seeking process. There is no need to override/wrap currentTime.

The problem with wrapping currentTime is that if a user is smart enough to select the video element and set its currentTime property then may be the user is smart enough to call:

Object.getOwnPropertyDescriptor(HTMLMediaElement.prototype,
       'currentTime').set.call(videoElement, videoElement.duration);

Upvotes: 1

Julien Grégoire
Julien Grégoire

Reputation: 17134

There may be a more elegant way to do this, but calling the currentTime getter of the prototype (in this case the HTMLMediaElement prototype) on your object will give you the actual currentTime. So this will prevent setting but allow getting:

  Object.defineProperty(videoElement, 'currentTime', {
      enumerable: true,
      configurable: true,
      get: function() {
        var ct = Object.getOwnPropertyDescriptor(HTMLMediaElement.prototype,
           'currentTime').get.call(this);
        return ct;
      },
      set: function(newValue) {
        // intercept values here
      }
    });

Upvotes: 3

Related Questions