fix iframe parent issue
This commit is contained in:
parent
a9701ba57d
commit
c04822bc0f
4 changed files with 44 additions and 28 deletions
|
|
@ -31,6 +31,7 @@ import Message, {
|
|||
Type as MType,
|
||||
UserID,
|
||||
WSChannel,
|
||||
RemoveNode,
|
||||
} from './messages.gen.js'
|
||||
import Nodes from './nodes/index.js'
|
||||
import type { Options as ObserverOptions } from './observer/top_observer.js'
|
||||
|
|
@ -41,6 +42,7 @@ import type { Options as SessOptions } from './session.js'
|
|||
import Session from './session.js'
|
||||
import Ticker from './ticker.js'
|
||||
import { MaintainerOptions } from './nodes/maintainer.js'
|
||||
import vElTree from './observer/vTree.js'
|
||||
|
||||
interface TypedWorker extends Omit<Worker, 'postMessage'> {
|
||||
postMessage(data: ToWorkerData): void
|
||||
|
|
@ -273,6 +275,10 @@ export default class App {
|
|||
'usability-test': true,
|
||||
}
|
||||
private emptyBatchCounter = 0
|
||||
private readonly vTree = new vElTree((id: number) => {
|
||||
this.nodes.unregisterNodeById(id)
|
||||
this.send(RemoveNode(id))
|
||||
})
|
||||
|
||||
constructor(
|
||||
projectKey: string,
|
||||
|
|
@ -362,7 +368,7 @@ export default class App {
|
|||
forceNgOff: Boolean(options.forceNgOff),
|
||||
maintainer: this.options.nodes?.maintainer,
|
||||
})
|
||||
this.observer = new Observer({ app: this, options })
|
||||
this.observer = new Observer({ app: this, options, vTree: this.vTree })
|
||||
this.ticker = new Ticker(this)
|
||||
this.ticker.attach(() => this.commit())
|
||||
this.debug = new Logger(this.options.__debug__)
|
||||
|
|
|
|||
|
|
@ -20,8 +20,9 @@ import {
|
|||
isUseElement,
|
||||
hasTag,
|
||||
isCommentNode,
|
||||
isDocument,
|
||||
} from '../guards.js'
|
||||
import vElTree from './vTree.js'
|
||||
import VirtualNodeTree from './vTree.js'
|
||||
|
||||
const iconCache = {}
|
||||
const svgUrlCache = {}
|
||||
|
|
@ -183,10 +184,10 @@ enum RecentsType {
|
|||
|
||||
export default abstract class Observer {
|
||||
/** object tree where key is node id, value is null if it has no children, or object with same structure */
|
||||
private readonly vTree = new vElTree((id: number) => {
|
||||
this.app.nodes.unregisterNodeById(id)
|
||||
this.app.send(RemoveNode(id))
|
||||
})
|
||||
// private readonly vTree = new vElTree((id: number) => {
|
||||
// this.app.nodes.unregisterNodeById(id)
|
||||
// this.app.send(RemoveNode(id))
|
||||
// })
|
||||
private readonly observer: MutationObserver
|
||||
private readonly commited: Array<boolean | undefined> = []
|
||||
private readonly recents: Map<number, RecentsType> = new Map()
|
||||
|
|
@ -199,7 +200,9 @@ export default abstract class Observer {
|
|||
protected readonly app: App,
|
||||
protected readonly isTopContext = false,
|
||||
options: { disableSprites: boolean } = { disableSprites: false },
|
||||
public vTree: VirtualNodeTree,
|
||||
) {
|
||||
this.vTree = vTree
|
||||
this.disableSprites = options.disableSprites
|
||||
this.observer = createMutationObserver(
|
||||
this.app.safe((mutations) => {
|
||||
|
|
@ -513,7 +516,6 @@ export default abstract class Observer {
|
|||
;(el as HTMLElement | SVGElement).style.width = `${width}px`
|
||||
;(el as HTMLElement | SVGElement).style.height = `${height}px`
|
||||
}
|
||||
this.vTree.addNode(id, parentID ?? null)
|
||||
this.app.send(CreateElementNode(id, parentID, index, el.tagName, isSVGElement(node)))
|
||||
}
|
||||
for (let i = 0; i < el.attributes.length; i++) {
|
||||
|
|
@ -521,7 +523,6 @@ export default abstract class Observer {
|
|||
this.sendNodeAttribute(id, el, attr.nodeName, attr.value)
|
||||
}
|
||||
} else if (isTextNode(node)) {
|
||||
this.vTree.addNode(id, parentID ?? null)
|
||||
// for text node id != 0, hence parentID !== undefined and parent is Element
|
||||
this.app.send(CreateTextNode(id, parentID as number, index))
|
||||
this.sendNodeData(id, parent as Element, node.data)
|
||||
|
|
|
|||
|
|
@ -23,8 +23,9 @@ export default class TopObserver extends Observer {
|
|||
private readonly options: Options
|
||||
private readonly iframeOffsets: IFrameOffsets = new IFrameOffsets()
|
||||
readonly app: App
|
||||
public iframes: Map<number, HTMLIFrameElement> = new Map()
|
||||
|
||||
constructor(params: { app: App; options: Partial<Options> }) {
|
||||
constructor(params: { app: App; options: Partial<Options>; vTree: any }) {
|
||||
const opts = Object.assign(
|
||||
{
|
||||
captureIFrames: true,
|
||||
|
|
@ -32,17 +33,37 @@ export default class TopObserver extends Observer {
|
|||
},
|
||||
params.options,
|
||||
)
|
||||
super(params.app, true, opts)
|
||||
super(params.app, true, opts, params.vTree)
|
||||
this.app = params.app
|
||||
this.options = opts
|
||||
this.vTree = params.vTree
|
||||
// IFrames
|
||||
this.app.nodes.attachNodeCallback((node) => {
|
||||
const nodeId = this.app.nodes.getID(node);
|
||||
if (
|
||||
hasTag(node, 'iframe') &&
|
||||
((this.options.captureIFrames && !hasOpenreplayAttribute(node, 'obscured')) ||
|
||||
hasOpenreplayAttribute(node, 'capture'))
|
||||
) {
|
||||
this.handleIframe(node)
|
||||
if (nodeId) {
|
||||
this.iframes.set(nodeId, node)
|
||||
}
|
||||
}
|
||||
if (nodeId || nodeId === 0) {
|
||||
if (node.parentNode) {
|
||||
const parentId = this.app.nodes.getID(node.parentNode)
|
||||
this.vTree.addNode(nodeId, parentId ?? null)
|
||||
}
|
||||
else {
|
||||
for (const iframe of this.iframes.entries()) {
|
||||
const [iframeId, iframeElement] = iframe
|
||||
if (iframeElement?.contentDocument === node) {
|
||||
this.vTree.addNode(nodeId, iframeId)
|
||||
this.iframes.delete(iframeId)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
|
|
@ -86,7 +107,7 @@ export default class TopObserver extends Observer {
|
|||
this.app.debug.info('doc already observed for', id)
|
||||
return
|
||||
}
|
||||
const observer = new IFrameObserver(this.app)
|
||||
const observer = new IFrameObserver(this.app, false, undefined, this.vTree)
|
||||
this.iframeObservers.set(iframe, observer)
|
||||
this.docObservers.set(currentDoc, observer)
|
||||
this.iframeObserversArr.push(observer)
|
||||
|
|
@ -114,7 +135,7 @@ export default class TopObserver extends Observer {
|
|||
|
||||
private shadowRootObservers: WeakMap<ShadowRoot, ShadowRootObserver> = new WeakMap()
|
||||
private handleShadowRoot(shRoot: ShadowRoot) {
|
||||
const observer = new ShadowRootObserver(this.app)
|
||||
const observer = new ShadowRootObserver(this.app, false, undefined, this.vTree)
|
||||
this.shadowRootObservers.set(shRoot, observer)
|
||||
observer.observe(shRoot.host)
|
||||
}
|
||||
|
|
@ -130,6 +151,7 @@ export default class TopObserver extends Observer {
|
|||
return shadow
|
||||
}
|
||||
this.app.nodes.clear()
|
||||
this.vTree.clearAll()
|
||||
// Can observe documentElement (<html>) here, because it is not supposed to be changing.
|
||||
// However, it is possible in some exotic cases and may cause an ignorance of the newly created <html>
|
||||
// In this case context.document have to be observed, but this will cause
|
||||
|
|
@ -157,7 +179,7 @@ export default class TopObserver extends Observer {
|
|||
}
|
||||
this.app.nodes.clear()
|
||||
this.app.nodes.syntheticMode(frameOder)
|
||||
const iframeObserver = new IFrameObserver(this.app)
|
||||
const iframeObserver = new IFrameObserver(this.app, false, undefined, this.vTree)
|
||||
this.iframeObservers.set(window.document, iframeObserver)
|
||||
iframeObserver.syntheticObserve(rootNodeId, window.document)
|
||||
}
|
||||
|
|
@ -168,8 +190,10 @@ export default class TopObserver extends Observer {
|
|||
this.iframeObserversArr.forEach((observer) => observer.disconnect())
|
||||
this.iframeObserversArr = []
|
||||
this.iframeObservers = new WeakMap()
|
||||
this.iframes.clear()
|
||||
this.shadowRootObservers = new WeakMap()
|
||||
this.docObservers = new WeakMap()
|
||||
super.disconnect()
|
||||
this.vTree.clearAll()
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -7,7 +7,6 @@ export default class VirtualNodeTree {
|
|||
|
||||
addNode(id: number, parentId: number | null = null) {
|
||||
this.nodeParents[id] = parentId;
|
||||
console.log(id, parentId, this.tree, this.nodeParents)
|
||||
if (parentId === null) {
|
||||
this.tree[id] = null;
|
||||
} else {
|
||||
|
|
@ -21,7 +20,6 @@ export default class VirtualNodeTree {
|
|||
}
|
||||
|
||||
removeNode(id: number) {
|
||||
console.log('del', id, this)
|
||||
if (!(id in this.nodeParents)) {
|
||||
// throw new Error(`Node ${id} doesn't exist`); ? since its just for tracking, nothing
|
||||
return;
|
||||
|
|
@ -107,16 +105,3 @@ export default class VirtualNodeTree {
|
|||
this.nodeParents = {};
|
||||
}
|
||||
}
|
||||
|
||||
// TODO add tests
|
||||
// const tree = new VirtualNodeTree();
|
||||
|
||||
// tree.addNode(0);
|
||||
// tree.addNode(1, 0);
|
||||
// tree.addNode(2, 1);
|
||||
// tree.addNode(3, 1);
|
||||
// tree.addNode(4, 3);
|
||||
// console.log({ ...tree.tree });
|
||||
|
||||
// tree.removeNode(1)
|
||||
// console.log(tree.tree)
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue