diff --git a/scripts/minify.ts b/scripts/minify.ts index 72cdba12..05a4114f 100644 --- a/scripts/minify.ts +++ b/scripts/minify.ts @@ -78,6 +78,7 @@ function managlePropsPlugin(): Plugin { $firstScriptId$: '', $forward$: '', $forwardToWorkerAccess$: '', + $htmlConstructors$: '', $immediateSetters$: '', $importScripts$: '', $instanceId$: '', diff --git a/src/lib/sandbox/messenger.ts b/src/lib/sandbox/messenger.ts index 63818e91..fb4766e4 100644 --- a/src/lib/sandbox/messenger.ts +++ b/src/lib/sandbox/messenger.ts @@ -10,19 +10,18 @@ import { WorkerMessageType, } from '../types'; import { initializedWorkerScript, readNextScript } from './read-main-scripts'; -import { readMainInterfaces } from './read-interfaces'; +import { readMainInterfaces } from './read-main-interfaces'; export const onMessageFromWebWorker = ( winCtx: MainWindowContext, msg: MessageFromWorkerToSandbox ) => { const msgType = msg[0]; - const doc = winCtx.$window$.document; + const win = winCtx.$window$; + const doc = win.document; if (msgType === WorkerMessageType.MainDataRequestFromWorker) { // web worker has requested data from the main thread - const firstScriptId = getAndSetInstanceId(winCtx, doc.querySelector('script')); - const mainInterfaces = readMainInterfaces(winCtx.$window$, doc); const initWebWorkerData: InitWebWorkerData = { $winId$: winCtx.$winId$, $parentWinId$: winCtx.$parentWinId$, @@ -32,8 +31,9 @@ export const onMessageFromWebWorker = ( $documentReadyState$: doc.readyState, $documentReferrer$: doc.referrer, $documentTitle$: doc.title, - $firstScriptId$: firstScriptId, - $interfaces$: mainInterfaces, + $firstScriptId$: getAndSetInstanceId(winCtx, doc.querySelector('script')), + $htmlConstructors$: Object.getOwnPropertyNames(win).filter((c) => c.startsWith('HTML')), + $interfaces$: readMainInterfaces(win, doc), $libPath$: new URL(winCtx.$libPath$, winCtx.$url$) + '', $url$: winCtx.$url$, }; diff --git a/src/lib/sandbox/read-interfaces.ts b/src/lib/sandbox/read-main-interfaces.ts similarity index 100% rename from src/lib/sandbox/read-interfaces.ts rename to src/lib/sandbox/read-main-interfaces.ts diff --git a/src/lib/types.ts b/src/lib/types.ts index 57056e22..51fe0a92 100644 --- a/src/lib/types.ts +++ b/src/lib/types.ts @@ -86,6 +86,7 @@ export interface InitWebWorkerData { $documentReferrer$: string; $documentTitle$: string; $firstScriptId$: number; + $htmlConstructors$: string[]; $interfaces$: InterfaceInfo[]; $libPath$?: string; $url$: string; diff --git a/src/lib/web-worker/init-worker.ts b/src/lib/web-worker/init-worker.ts index 369e8fab..4b841bbd 100644 --- a/src/lib/web-worker/init-worker.ts +++ b/src/lib/web-worker/init-worker.ts @@ -1,4 +1,4 @@ -import { InitWebWorkerData, InterfaceType } from '../types'; +import type { InitWebWorkerData } from '../types'; import { initWebWorkerGlobal } from './worker-global'; import { Location } from './worker-location'; import { logWorker, TOP_WIN_ID } from '../utils'; @@ -22,7 +22,11 @@ export const initWebWorker = (self: Worker, initWebWorkerData: InitWebWorkerData webWorkerCtx.$location$ = new Location(initWebWorkerData.$url$); - initWebWorkerGlobal(self, initWebWorkerData.$interfaces$[InterfaceType.Window][1]); + initWebWorkerGlobal( + self, + initWebWorkerData.$interfaces$[0][1], + initWebWorkerData.$htmlConstructors$ + ); webWorkerCtx.$isInitialized$ = true; }; diff --git a/src/lib/web-worker/worker-constructors.ts b/src/lib/web-worker/worker-constructors.ts index cf76c4cc..8d875141 100644 --- a/src/lib/web-worker/worker-constructors.ts +++ b/src/lib/web-worker/worker-constructors.ts @@ -1,10 +1,9 @@ import { InterfaceType, NodeName } from '../types'; -import { HTMLAnchorElement } from './worker-anchor'; +import { HTMLDocument } from './worker-document'; import { HTMLElement } from './worker-element'; -import { HTMLScriptElement } from './worker-script'; import { Node } from './worker-node'; -import { Window, HTMLIFrameElement } from './worker-iframe'; -import { WorkerDocumentElementChild, HTMLDocument } from './worker-document'; +import { toUpper } from '../utils'; +import { Window } from './worker-iframe'; import { WorkerProxy } from './worker-instance'; export const constructInstance = ( @@ -45,10 +44,21 @@ const getConstructor = (interfaceType: InterfaceType, nodeName?: string): typeof }; export const getElementConstructor = (nodeName: string): typeof HTMLElement => - ({ - A: HTMLAnchorElement, - BODY: WorkerDocumentElementChild, - HEAD: WorkerDocumentElementChild, - IFRAME: HTMLIFrameElement, - SCRIPT: HTMLScriptElement, - }[nodeName] || HTMLElement); + elementConstructors[nodeName] || HTMLElement; + +export const elementConstructors: { [tagName: string]: typeof HTMLElement } = {}; + +export const getTagNameFromConstructor = (t: string) => { + t = toUpper(t.substr(4).replace('Element', '')); + if (t === 'IMAGE') { + return 'IMG'; + } else if (t === 'PARAGRAPH') { + return 'P'; + } else if (t === 'TABLEROW') { + return 'TR'; + } else if (t === 'TableCell') { + return 'TD'; + } else { + return t; + } +}; diff --git a/src/lib/web-worker/worker-global.ts b/src/lib/web-worker/worker-global.ts index 56761b81..d792f00d 100644 --- a/src/lib/web-worker/worker-global.ts +++ b/src/lib/web-worker/worker-global.ts @@ -1,12 +1,26 @@ import { callMethod } from './worker-proxy'; -import { constructInstance } from './worker-constructors'; +import { + constructInstance, + elementConstructors, + getTagNameFromConstructor, +} from './worker-constructors'; +import { HTMLAnchorElement } from './worker-anchor'; +import { HTMLDocument, WorkerDocumentElementChild } from './worker-document'; +import { HTMLElement } from './worker-element'; +import { HTMLIFrameElement, Window } from './worker-iframe'; import { HTMLImageElement } from './worker-image'; +import { HTMLScriptElement } from './worker-script'; import { InstanceIdKey, webWorkerCtx, WinIdKey } from './worker-constants'; import { InterfaceType, MemberTypeInfo, PlatformInstanceId } from '../types'; import { nextTick, TOP_WIN_ID } from '../utils'; +import { Node } from './worker-node'; import { sendBeacon } from './worker-exec'; -export const initWebWorkerGlobal = (self: any, windowMemberTypeInfo: MemberTypeInfo) => { +export const initWebWorkerGlobal = ( + self: any, + windowMemberTypeInfo: MemberTypeInfo, + htmlCstrNames: string[] +) => { self[WinIdKey] = webWorkerCtx.$winId$; self[InstanceIdKey] = PlatformInstanceId.window; @@ -29,7 +43,6 @@ export const initWebWorkerGlobal = (self: any, windowMemberTypeInfo: MemberTypeI self.localStorage = constructInstance(InterfaceType.Storage, PlatformInstanceId.localStorage); self.sessionStorage = constructInstance(InterfaceType.Storage, PlatformInstanceId.sessionStorage); - self.Image = HTMLImageElement; navigator.sendBeacon = sendBeacon; self.self = self.window = self; @@ -45,4 +58,24 @@ export const initWebWorkerGlobal = (self: any, windowMemberTypeInfo: MemberTypeI self.top = constructInstance(InterfaceType.Window, PlatformInstanceId.window, TOP_WIN_ID); } + + self.HTMLDocument = self.Document = HTMLDocument; + self.HTMLElement = self.Element = HTMLElement; + self.Image = HTMLImageElement; + self.Node = Node; + self.Window = Window; + + htmlCstrNames.map((htmlCstrName) => { + if (!self[htmlCstrName]) { + elementConstructors[getTagNameFromConstructor(htmlCstrName)] = self[htmlCstrName] = + Object.defineProperty(class extends HTMLElement {}, 'name', { + value: htmlCstrName, + }); + } + }); + + elementConstructors.A = self.HTMLAnchorElement = HTMLAnchorElement; + elementConstructors.BODY = elementConstructors.HEAD = WorkerDocumentElementChild; + elementConstructors.IFRAME = self.HTMLIFrameElement = HTMLIFrameElement; + elementConstructors.SCRIPT = self.HTMLScriptElement = HTMLScriptElement; }; diff --git a/tests/platform/anchor/anchor.spec.ts b/tests/platform/anchor/anchor.spec.ts index 3039ac76..c3faac9a 100644 --- a/tests/platform/anchor/anchor.spec.ts +++ b/tests/platform/anchor/anchor.spec.ts @@ -7,6 +7,10 @@ test('anchor', async ({ page }) => { const testAnchor = page.locator('#testAnchor'); await expect(testAnchor).toHaveText('/platform/anchor/some/other/path'); + await page.waitForSelector('.testAnchorConstructor'); + const testAnchorConstructor = page.locator('#testAnchorConstructor'); + await expect(testAnchorConstructor).toHaveText('HTMLAnchorElement HTMLAnchorElement'); + await page.waitForSelector('.testCreateAnchorNoAppend'); const testCreateAnchorNoAppend = page.locator('#testCreateAnchorNoAppend'); await expect(testCreateAnchorNoAppend).toHaveText('/platform/anchor/no-append-child'); diff --git a/tests/platform/anchor/index.html b/tests/platform/anchor/index.html index b2eb68da..c86e733a 100644 --- a/tests/platform/anchor/index.html +++ b/tests/platform/anchor/index.html @@ -68,6 +68,18 @@

Anchor

+
  • + constructor.name +
    + +
  • +
  • createElement('a'), no appendChild
    diff --git a/tests/platform/element/element.spec.ts b/tests/platform/element/element.spec.ts index c42dcf39..6b99b885 100644 --- a/tests/platform/element/element.spec.ts +++ b/tests/platform/element/element.spec.ts @@ -55,4 +55,7 @@ test('element', async ({ page }) => { const testAttrsStyleValue = page.locator('#testAttrsStyleValue'); await expect(testAttrsStyleValue).toHaveText('color: red'); await expect(testAttrsStyleValue).toHaveCSS('color', 'rgb(255, 0, 0)'); + + const testParagraphConstructor = page.locator('#testParagraphConstructor'); + await expect(testParagraphConstructor).toHaveText('HTMLParagraphElement HTMLParagraphElement'); }); diff --git a/tests/platform/element/index.html b/tests/platform/element/index.html index 70ff9454..786ccbff 100644 --- a/tests/platform/element/index.html +++ b/tests/platform/element/index.html @@ -258,6 +258,17 @@

    Element

  • +
  • + paragraph constructor.name +

    + +
  • + +
  • + Window.name + + +
  • + +
  • + Worker HTML Constructors + + +
  • + +
  • + Main HTML Constructors + + +
  • +