mirror of
https://github.com/titaniumnetwork-dev/Ultraviolet.git
synced 2025-05-15 20:40:01 -04:00
165 lines
No EOL
6.5 KiB
JavaScript
165 lines
No EOL
6.5 KiB
JavaScript
import EventEmitter from "../events.js";
|
|
import HookEvent from "../hook.js";
|
|
|
|
class ElementApi extends EventEmitter {
|
|
constructor(ctx) {
|
|
super();
|
|
this.ctx = ctx;
|
|
this.window = ctx.window;
|
|
this.Audio = this.window.Audio;
|
|
this.Element = this.window.Element;
|
|
this.elemProto = this.Element ? this.Element.prototype : {};
|
|
this.innerHTML = ctx.nativeMethods.getOwnPropertyDescriptor(this.elemProto, 'innerHTML');
|
|
this.outerHTML = ctx.nativeMethods.getOwnPropertyDescriptor(this.elemProto, 'outerHTML');
|
|
this.setAttribute = this.elemProto.setAttribute;
|
|
this.getAttribute = this.elemProto.getAttribute;
|
|
this.removeAttribute = this.elemProto.removeAttribute;
|
|
this.hasAttribute = this.elemProto.hasAttribute;
|
|
this.querySelector = this.elemProto.querySelector;
|
|
this.querySelectorAll = this.elemProto.querySelectorAll;
|
|
this.insertAdjacentHTML = this.elemProto.insertAdjacentHTML;
|
|
this.insertAdjacentText = this.elemProto.insertAdjacentText;
|
|
};
|
|
overrideQuerySelector() {
|
|
this.ctx.override(this.elemProto, 'querySelector', (target, that, args) => {
|
|
if (!args.length) return target.apply(that, args);
|
|
let [ selectors ] = args;
|
|
|
|
const event = new HookEvent({ selectors }, target, that);
|
|
this.emit('querySelector', event);
|
|
|
|
if (event.intercepted) return event.returnValue;
|
|
return event.target.call(event.that, event.data.selectors);
|
|
});
|
|
};
|
|
overrideAttribute() {
|
|
this.ctx.override(this.elemProto, 'getAttribute', (target, that, args) => {
|
|
if (!args.length) return target.apply(that, args);
|
|
let [ name ] = args;
|
|
|
|
const event = new HookEvent({ name }, target, that);
|
|
this.emit('getAttribute', event);
|
|
|
|
if (event.intercepted) return event.returnValue;
|
|
return event.target.call(event.that, event.data.name);
|
|
});
|
|
this.ctx.override(this.elemProto, 'setAttribute', (target, that, args) => {
|
|
if (2 > args.length) return target.apply(that, args);
|
|
let [ name, value ] = args;
|
|
|
|
const event = new HookEvent({ name, value }, target, that);
|
|
this.emit('setAttribute', event);
|
|
|
|
if (event.intercepted) return event.returnValue;
|
|
return event.target.call(event.that, event.data.name, event.data.value);
|
|
});
|
|
this.ctx.override(this.elemProto, 'hasAttribute', (target, that, args) => {
|
|
if (!args.length) return target.apply(that, args);
|
|
let [ name ] = args;
|
|
|
|
const event = new HookEvent({ name }, target, that);
|
|
this.emit('hasAttribute', event);
|
|
|
|
if (event.intercepted) return event.returnValue;
|
|
return event.target.call(event.that, event.data.name);
|
|
});
|
|
this.ctx.override(this.elemProto, 'removeAttribute', (target, that, args) => {
|
|
if (!args.length) return target.apply(that, args);
|
|
let [ name ] = args;
|
|
|
|
const event = new HookEvent({ name }, target, that);
|
|
this.emit('removeAttribute', event);
|
|
|
|
if (event.intercepted) return event.returnValue;
|
|
return event.target.call(event.that, event.data.name);
|
|
});
|
|
};
|
|
overrideAudio() {
|
|
this.ctx.override(this.window, 'Audio', (target, that, args) => {
|
|
if (!args.length) return new target(...args);
|
|
let [ url ] = args;
|
|
|
|
const event = new HookEvent({ url }, target, that);
|
|
this.emit('audio', event);
|
|
|
|
if (event.intercepted) return event.returnValue;
|
|
return new event.target(event.data.url);
|
|
}, true);
|
|
};
|
|
overrideHtml() {
|
|
this.hookProperty(this.Element, 'innerHTML', {
|
|
get: (target, that) => {
|
|
const event = new HookEvent({ value: target.call(that) }, target, that);
|
|
this.emit('getInnerHTML', event);
|
|
|
|
if (event.intercepted) return event.returnValue;
|
|
return event.data.value;
|
|
},
|
|
set: (target, that, [ val ]) => {
|
|
const event = new HookEvent({ value: val }, target, that);
|
|
this.emit('setInnerHTML', event);
|
|
|
|
if (event.intercepted) return event.returnValue;
|
|
target.call(that, event.data.value);
|
|
},
|
|
});
|
|
this.hookProperty(this.Element, 'outerHTML', {
|
|
get: (target, that) => {
|
|
const event = new HookEvent({ value: target.call(that) }, target, that);
|
|
this.emit('getOuterHTML', event);
|
|
|
|
if (event.intercepted) return event.returnValue;
|
|
return event.data.value;
|
|
},
|
|
set: (target, that, [ val ]) => {
|
|
const event = new HookEvent({ value: val }, target, that);
|
|
this.emit('setOuterHTML', event);
|
|
|
|
if (event.intercepted) return event.returnValue;
|
|
target.call(that, event.data.value);
|
|
},
|
|
});
|
|
};
|
|
overrideInsertAdjacentHTML() {
|
|
this.ctx.override(this.elemProto, 'insertAdjacentHTML', (target, that, args) => {
|
|
if (2 > args.length) return target.apply(that, args);
|
|
let [ position, html ] = args;
|
|
|
|
const event = new HookEvent({ position, html }, target, that);
|
|
this.emit('insertAdjacentHTML', event);
|
|
|
|
if (event.intercepted) return event.returnValue;
|
|
return event.target.call(event.that, event.data.position, event.data.html);
|
|
});
|
|
};
|
|
overrideInsertAdjacentText() {
|
|
this.ctx.override(this.elemProto, 'insertAdjacentText', (target, that, args) => {
|
|
if (2 > args.length) return target.apply(that, args);
|
|
let [ position, text ] = args;
|
|
|
|
const event = new HookEvent({ position, text }, target, that);
|
|
this.emit('insertAdjacentText', event);
|
|
|
|
if (event.intercepted) return event.returnValue;
|
|
return event.target.call(event.that, event.data.position, event.data.text);
|
|
});
|
|
};
|
|
hookProperty(element, prop, handler) {
|
|
if (!element || !prop in element) return false;
|
|
|
|
if (this.ctx.nativeMethods.isArray(element)) {
|
|
for (const elem of element) {
|
|
this.hookProperty(elem, prop, handler);
|
|
};
|
|
return true;
|
|
};
|
|
|
|
const proto = element.prototype;
|
|
|
|
this.ctx.overrideDescriptor(proto, prop, handler);
|
|
|
|
return true;
|
|
};
|
|
};
|
|
|
|
export default ElementApi; |