diff --git a/uv.zip b/uv.zip new file mode 100644 index 0000000..0e0f041 Binary files /dev/null and b/uv.zip differ diff --git a/uv/uv.bundle.js b/uv/uv.bundle.js index ee061a0..099a868 100644 --- a/uv/uv.bundle.js +++ b/uv/uv.bundle.js @@ -37639,8 +37639,15 @@ class AttrApi extends _events_js__WEBPACK_IMPORTED_MODULE_0__["default"] { this.attrProto = this.Attr.prototype || {}; this.value = ctx.nativeMethods.getOwnPropertyDescriptor(this.attrProto, 'value'); this.name = ctx.nativeMethods.getOwnPropertyDescriptor(this.attrProto, 'name'); + this.getNamedItem = this.attrProto.getNamedItem || null; + this.setNamedItem = this.attrProto.setNamedItem || null; + this.removeNamedItem = this.attrProto.removeNamedItem || null; + this.getNamedItemNS = this.attrProto.getNamedItemNS || null; + this.setNamedItemNS = this.attrProto.setNamedItemNS || null; + this.removeNamedItemNS = this.attrProto.removeNamedItemNS || null; + this.item = this.attrProto.item || null; }; - override() { + overrideNameValue() { this.ctx.overrideDescriptor(this.attrProto, 'name', { get: (target, that) => { const event = new _hook_js__WEBPACK_IMPORTED_MODULE_1__["default"]({ value: target.call(that) }, target, that); @@ -37668,6 +37675,78 @@ class AttrApi extends _events_js__WEBPACK_IMPORTED_MODULE_0__["default"] { } }); }; + overrideItemMethods() { + this.ctx.override(this.attrProto, 'getNamedItem', (target, that, args) => { + if (!args.length) return target.apply(that, args); + let [ name ] = args; + + const event = new _hook_js__WEBPACK_IMPORTED_MODULE_1__["default"]({ name }, target, that); + this.emit('getNamedItem', event); + + if (event.intercepted) return event.returnValue; + return event.target.call(event.that, event.data.name); + }); + this.ctx.override(this.attrProto, 'setNamedItem', (target, that, args) => { + if (2 > args.length) return target.apply(that, args); + let [ name, value ] = args; + + const event = new _hook_js__WEBPACK_IMPORTED_MODULE_1__["default"]({ name, value }, target, that); + this.emit('setNamedItem', event); + + if (event.intercepted) return event.returnValue; + return event.target.call(event.that, event.data.name, event.data.value); + }); + this.ctx.override(this.attrProto, 'removeNamedItem', (target, that, args) => { + if (!args.length) return target.apply(that, args); + let [ name ] = args; + + const event = new _hook_js__WEBPACK_IMPORTED_MODULE_1__["default"]({ name }, target, that); + this.emit('removeNamedItem', event); + + if (event.intercepted) return event.returnValue; + return event.target.call(event.that, event.data.name); + }); + this.ctx.override(this.attrProto, 'item', (target, that, args) => { + if (!args.length) return target.apply(that, args); + let [ index ] = args; + + const event = new _hook_js__WEBPACK_IMPORTED_MODULE_1__["default"]({ index }, target, that); + this.emit('item', event); + + if (event.intercepted) return event.returnValue; + return event.target.call(event.that, event.data.name); + }); + this.ctx.override(this.attrProto, 'getNamedItemNS', (target, that, args) => { + if (2 > args.length) return target.apply(that, args); + let [ namespace, localName ] = args; + + const event = new _hook_js__WEBPACK_IMPORTED_MODULE_1__["default"]({ namespace, localName }, target, that); + this.emit('getNamedItemNS', event); + + if (event.intercepted) return event.returnValue; + return event.target.call(event.that, event.data.namespace, event.data.localName); + }); + this.ctx.override(this.attrProto, 'setNamedItemNS', (target, that, args) => { + if (!args.length) return target.apply(that, args); + let [ attr ] = args; + + const event = new _hook_js__WEBPACK_IMPORTED_MODULE_1__["default"]({ attr }, target, that); + this.emit('setNamedItemNS', event); + + if (event.intercepted) return event.returnValue; + return event.target.call(event.that, event.data.name); + }); + this.ctx.override(this.attrProto, 'removeNamedItemNS', (target, that, args) => { + if (2 > args.length) return target.apply(that, args); + let [ namespace, localName ] = args; + + const event = new _hook_js__WEBPACK_IMPORTED_MODULE_1__["default"]({ namespace, localName }, target, that); + this.emit('removeNamedItemNS', event); + + if (event.intercepted) return event.returnValue; + return event.target.call(event.that, event.data.namespace, event.data.localName); + }); + }; }; /* harmony default export */ const __WEBPACK_DEFAULT_EXPORT__ = (AttrApi); @@ -38173,6 +38252,9 @@ class EventSourceApi extends _events_js__WEBPACK_IMPORTED_MODULE_0__["default"] this.EventSource = this.window.EventSource || {}; this.esProto = this.EventSource.prototype || {}; this.url = ctx.nativeMethods.getOwnPropertyDescriptor(this.esProto, 'url'); + this.CONNECTING = 0; + this.OPEN = 1; + this.CLOSED = 2; }; overrideConstruct() { this.ctx.override(this.window, 'EventSource', (target, that, args) => { @@ -38185,6 +38267,12 @@ class EventSourceApi extends _events_js__WEBPACK_IMPORTED_MODULE_0__["default"] if (event.intercepted) return event.returnValue; return new event.target(event.data.url, event.data.config); }, true); + + if ('EventSource' in this.window) { + this.window.EventSource.CONNECTING = this.CONNECTING; + this.window.EventSource.OPEN = this.OPEN; + this.window.EventSource.CLOSED = this.CLOSED; + }; }; overrideUrl() { this.ctx.overrideDescriptor(this.esProto, 'url', { @@ -38298,14 +38386,19 @@ __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ "default": () => (__WEBPACK_DEFAULT_EXPORT__) /* harmony export */ }); -class LocationApi { +/* harmony import */ var _events_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(155); + + +class LocationApi extends _events_js__WEBPACK_IMPORTED_MODULE_0__["default"] { constructor(ctx) { + super(); this.ctx = ctx; this.window = ctx.window; this.location = this.window.location; this.WorkerLocation = this.ctx.worker ? this.window.WorkerLocation : null; this.workerLocProto = this.WorkerLocation ? this.WorkerLocation.prototype : {}; this.keys = ['href', 'protocol', 'host', 'hostname', 'port', 'pathname', 'search', 'hash', 'origin']; + this.HashChangeEvent = this.window.HashChangeEvent || null; this.href = this.WorkerLocation ? ctx.nativeMethods.getOwnPropertyDescriptor(this.workerLocProto, 'href') : ctx.nativeMethods.getOwnPropertyDescriptor(this.location, 'href'); }; @@ -38342,7 +38435,7 @@ class LocationApi { that.location.href = wrap(val); break; case 'hash': - that.location.hash = val; + that.emit('hashchange', emulation.href, (val.trim().startsWith('#') ? new URL(val.trim(), emulation.href).href : new URL('#' + val.trim(), emulation.href).href), that); break; default: const url = new URL(emulation.href); @@ -39035,7 +39128,6 @@ __webpack_require__.r(__webpack_exports__); -//import { call, destructureDeclaration, dynamicImport, getProperty, importDeclaration, setProperty, sourceMethods, wrapEval, wrapIdentifier } from './rewrite.script.js'; @@ -39049,7 +39141,6 @@ const reserved_chars = "%"; class Ultraviolet { constructor(options = {}) { this.prefix = options.prefix || '/service/'; - //this.urlRegex = /^(#|about:|data:|mailto:|javascript:)/; this.urlRegex = /^(#|about:|data:|mailto:)/ this.rewriteUrl = options.rewriteUrl || this.rewriteUrl; this.sourceUrl = options.sourceUrl || this.sourceUrl; diff --git a/uv/uv.handler.js b/uv/uv.handler.js index e4b5c33..f5fb33a 100644 --- a/uv/uv.handler.js +++ b/uv/uv.handler.js @@ -77,6 +77,12 @@ async function __uvHook(window, config = {}, bare = '/bare/') { __uv.meta = window.parent.__uv.meta; }; + if (window.EventTarget) { + __uv.addEventListener = window.EventTarget.prototype.addEventListener; + __uv.removeListener = window.EventTarget.prototype.removeListener; + __uv.dispatchEvent = window.EventTarget.prototype.dispatchEvent; + }; + // Storage wrappers client.nativeMethods.defineProperty(client.storage.storeProto, '__uv$storageObj', { get() { @@ -151,6 +157,7 @@ async function __uvHook(window, config = {}, bare = '/bare/') { methodPrefix + 'url', methodPrefix + 'modifiedStyle', methodPrefix + 'config', + methodPrefix + 'dispatched', 'Ultraviolet', '__uvHook', ]; @@ -436,7 +443,7 @@ async function __uvHook(window, config = {}, bare = '/bare/') { client.element.setAttribute.call(that, __uv.attributePrefix + '-attr-href', val) target.call(that, __uv.rewriteUrl(val)); }, - }); + }); client.element.hookProperty([HTMLScriptElement, HTMLAudioElement, HTMLVideoElement, HTMLMediaElement, HTMLImageElement, HTMLInputElement, HTMLEmbedElement, HTMLIFrameElement, HTMLTrackElement, HTMLSourceElement], 'src', { get: (target, that) => { @@ -884,6 +891,32 @@ async function __uvHook(window, config = {}, bare = '/bare/') { }); }); + // Proper hash emulation. + if (!!window.window) { + __uv.addEventListener.call(window, 'hashchange', event => { + if (event.__uv$dispatched) return false; + event.stopImmediatePropagation(); + const hash = window.location.hash; + client.history.replaceState.call(window.history, '', '', event.oldURL); + __uv.location.hash = hash; + }); + }; + + client.location.on('hashchange', (oldUrl, newUrl, ctx) => { + if (ctx.HashChangeEvent && client.history.replaceState) { + client.history.replaceState.call(window.history, '', '', __uv.rewriteUrl(newUrl)); + + const event = new ctx.HashChangeEvent('hashchange', { newURL: newUrl, oldURL: oldUrl }); + + client.nativeMethods.defineProperty(event, methodPrefix + 'dispatched', { + value: true, + enumerable: false, + }); + + __uv.dispatchEvent.call(window, event); + }; + }); + // Hooking functions & descriptors client.fetch.overrideRequest(); client.fetch.overrideUrl(); @@ -896,7 +929,7 @@ async function __uvHook(window, config = {}, bare = '/bare/') { // client.element.overrideQuerySelector(); client.node.overrideBaseURI(); client.node.overrideTextContent(); - client.attribute.override(); + client.attribute.overrideNameValue(); client.document.overrideDomain(); client.document.overrideURL(); client.document.overrideDocumentURI();