Wednesday, 5 September 2018

Proxy HTMLElement

I wanted to check what does a library do with video element I pass to it so I naively did this:

cosnt videoElement = new Proxy(document.querySelector('video'), {
    get(target, key) {
        const name = typeof key === 'symbol'? key.toString() : key;
        console.info(`Accessing video.${ name }`)
        return target[key];
    }
});

But I got an error:

TypeError: Failed to execute 'contains' on 'Node': parameter 1 is not of type 'Node'.

Is there a way to make this work?


EDIT: I have gained some knowledge, with it I updated my proxy as fallow:

cosnt videoElement = document.querySelector('video');
cosnt proxyElement = new Proxy(videoElement , {
    get(target, key) {
        if (key == '___element___') {
            return video;
        }

        const name = typeof key === 'symbol'? key.toString() : key;
        console.info(`Accessing video.${ name }`);
        const value = video[key];
        if (value instanceof Function) {
            return video[key].bind(video);
        } else {
            return video[key];
        }
    },
    set(target, key, value) {
        const name = typeof key === 'symbol'? key.toString() : key;
        console.info(`Writing video.${ name } = ${ value }`);
        video[key] = value;
        return true;
    }
});

It is meant for debugging, so I edited the compiled code and replaced all DOM manipulation references with element.___element___.

Next I found out that there seem to be problems with calling functions trough proxy, so I added the .bind(video) part.

And finally setting values was throwing. So I had to replace target with direct video reference (as matter of fact, I replaced all target references with video, just to be sure), that made it work... I am not sure why or how, but it did.

Questions are:

  • Is this really how it is supposed to be? (the document.body.contains(myProxyElement) part)
  • Setting values to video element throwing when setting inside proxy seemed weird, is it a bug? (3rd point, kinda second too, I suppose it is connected)

Bonus: playground

const video = document.querySelector('video');
const proxy = new Proxy(video, {
  get(target, key) {
    console.log(`Getting video.${typeof key === 'symbol'? key.toString() : key}`);
    const value = video[key];
    if (value instanceof Function) {
      return value.bind(video);
    } else {
      return value;
    }
  },
  set(target, key, value) {
    console.log(`Setting video.${typeof key === 'symbol'? key.toString() : key} =`, value);
    video[key] = value;
    return true;
  }
});

proxy.muted = true;
proxy.play();
proxy.controls = true;
try {
  console.log(document.body.contains(proxy));
} catch (e) {
  console.error('DOM operation failed', e);
}
video { max-width: 100%; }
<video src="//vjs.zencdn.net/v/oceans.mp4">


from Proxy HTMLElement

No comments:

Post a Comment