mirror of
https://github.com/titaniumnetwork-dev/Ultraviolet.git
synced 2025-05-13 03:50:01 -04:00

Several bugs were found (and fixed): src/client/index.js:71 the following if() was equivalent to if (false in obj) src/client/dom/element.js:207 the following if() was equivalent to if (!element || false in element) src/client/rewrite/html.js:179 an undefined iterate() was referenced
224 lines
7.5 KiB
JavaScript
224 lines
7.5 KiB
JavaScript
import EventEmitter from 'events';
|
|
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;
|