tracker: testing tree thing
This commit is contained in:
parent
b91f5df89f
commit
a9701ba57d
4 changed files with 140 additions and 2 deletions
|
|
@ -1,7 +1,7 @@
|
|||
{
|
||||
"name": "@openreplay/tracker",
|
||||
"description": "The OpenReplay tracker main package",
|
||||
"version": "16.1.3",
|
||||
"version": "16.1.2-beta.2",
|
||||
"keywords": [
|
||||
"logging",
|
||||
"replay"
|
||||
|
|
|
|||
|
|
@ -98,6 +98,13 @@ export default class Nodes {
|
|||
return id
|
||||
}
|
||||
|
||||
unregisterNodeById(id: number): void {
|
||||
const node = this.nodes.get(id)
|
||||
if (node) {
|
||||
this.unregisterNode(node)
|
||||
}
|
||||
}
|
||||
|
||||
cleanTree() {
|
||||
// sadly we keep empty items in array here resulting in some memory still being used
|
||||
// but its still better than keeping dead nodes or undef elements
|
||||
|
|
|
|||
|
|
@ -21,6 +21,7 @@ import {
|
|||
hasTag,
|
||||
isCommentNode,
|
||||
} from '../guards.js'
|
||||
import vElTree from './vTree.js'
|
||||
|
||||
const iconCache = {}
|
||||
const svgUrlCache = {}
|
||||
|
|
@ -181,6 +182,11 @@ 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 observer: MutationObserver
|
||||
private readonly commited: Array<boolean | undefined> = []
|
||||
private readonly recents: Map<number, RecentsType> = new Map()
|
||||
|
|
@ -412,6 +418,7 @@ export default abstract class Observer {
|
|||
if (id !== undefined && this.recents.get(id) === RecentsType.Removed) {
|
||||
// Sending RemoveNode only for parent to maintain
|
||||
this.app.send(RemoveNode(id))
|
||||
this.vTree.removeNode(id)
|
||||
|
||||
// Unregistering all the children in order to clear the memory
|
||||
const walker = document.createTreeWalker(
|
||||
|
|
@ -506,7 +513,7 @@ 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++) {
|
||||
|
|
@ -514,6 +521,7 @@ 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)
|
||||
|
|
@ -586,5 +594,6 @@ export default abstract class Observer {
|
|||
disconnect(): void {
|
||||
this.observer.disconnect()
|
||||
this.clear()
|
||||
this.vTree.clearAll()
|
||||
}
|
||||
}
|
||||
|
|
|
|||
122
tracker/tracker/src/main/app/observer/vTree.ts
Normal file
122
tracker/tracker/src/main/app/observer/vTree.ts
Normal file
|
|
@ -0,0 +1,122 @@
|
|||
export default class VirtualNodeTree {
|
||||
tree: any = { 0: null }
|
||||
nodeParents: any = { 0: null}
|
||||
constructor(
|
||||
private readonly onRemoveNode: (id: number) => void
|
||||
) {}
|
||||
|
||||
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 {
|
||||
const parentNode = this.findNode(parentId);
|
||||
if (parentNode === null) {
|
||||
this.updateNode(parentId, {});
|
||||
}
|
||||
|
||||
this.findNode(parentId)[id] = null;
|
||||
}
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
const childrenIds = Object.keys(this.nodeParents).filter(
|
||||
nodeId => this.nodeParents[nodeId] === id
|
||||
);
|
||||
|
||||
for (const childId of childrenIds) {
|
||||
this.removeNode(parseInt(childId));
|
||||
}
|
||||
|
||||
const parentId = this.nodeParents[id];
|
||||
|
||||
if (parentId === null) {
|
||||
delete this.tree[id];
|
||||
} else {
|
||||
const parentNode = this.findNode(parentId);
|
||||
delete parentNode[id];
|
||||
this.onRemoveNode(id);
|
||||
if (Object.keys(parentNode).length === 0) {
|
||||
this.updateNode(parentId, null);
|
||||
}
|
||||
}
|
||||
delete this.nodeParents[id];
|
||||
}
|
||||
|
||||
getPath(id: number) {
|
||||
if (!(id in this.nodeParents) && id !== 0) {
|
||||
// throw new Error(`Node ${id} doesn't exist`);
|
||||
return;
|
||||
}
|
||||
|
||||
const path: any[] = [];
|
||||
let currentId = id;
|
||||
|
||||
while (currentId !== null) {
|
||||
path.unshift(currentId);
|
||||
currentId = this.nodeParents[currentId];
|
||||
}
|
||||
|
||||
return path.join('.');
|
||||
}
|
||||
|
||||
findNode(id: number) {
|
||||
const path = this.getPath(id);
|
||||
if (!path) return;
|
||||
return this.getNodeByPath(path);
|
||||
}
|
||||
|
||||
updateNode(id: number, value: any) {
|
||||
const path = this.getPath(id);
|
||||
if (!path) return;
|
||||
this.setNodeByPath(path, value);
|
||||
}
|
||||
|
||||
getNodeByPath(path: string) {
|
||||
const ids = path.split('.');
|
||||
let node = this.tree;
|
||||
|
||||
for (const id of ids) {
|
||||
node = node[id];
|
||||
if (node === undefined) return null;
|
||||
}
|
||||
|
||||
return node;
|
||||
}
|
||||
|
||||
setNodeByPath(path: string, value: number) {
|
||||
const ids = path.split('.');
|
||||
let node = this.tree;
|
||||
|
||||
for (let i = 0; i < ids.length - 1; i++) {
|
||||
node = node[ids[i]];
|
||||
}
|
||||
|
||||
node[ids[ids.length - 1]] = value;
|
||||
}
|
||||
|
||||
clearAll = () => {
|
||||
this.tree = {};
|
||||
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