ui: adjusting slot placement and classes
This commit is contained in:
parent
7a85f318b6
commit
8603439716
4 changed files with 98 additions and 61 deletions
|
|
@ -110,7 +110,7 @@ abstract class VParent<T extends Node = Node> extends VNode<T> {
|
|||
/* Inserting */
|
||||
this.mountChildren();
|
||||
if (this.notMontedChildren.size !== 0) {
|
||||
console.error('VParent: Something went wrong with children insertion');
|
||||
console.error('VParent: Something went wrong with children insertion', this.notMontedChildren);
|
||||
}
|
||||
/* Removing in-between */
|
||||
const { node } = this;
|
||||
|
|
@ -155,62 +155,6 @@ export class VDocument extends VParent<Document> {
|
|||
}
|
||||
}
|
||||
|
||||
export class VSlot extends VElement {
|
||||
assignedNodes: VChild[] = [];
|
||||
|
||||
addAssigned(child: VChild) {
|
||||
if (this.assignedNodes.indexOf(child) === -1) {
|
||||
this.assignedNodes.push(child);
|
||||
this.notMontedChildren.add(child);
|
||||
}
|
||||
}
|
||||
|
||||
removeAssigned(child: VChild) {
|
||||
this.assignedNodes = this.assignedNodes.filter((c) => c !== child);
|
||||
this.notMontedChildren.delete(child);
|
||||
}
|
||||
|
||||
private mountAssigned() {
|
||||
let nextMounted: VChild | null = null;
|
||||
for (let i = this.assignedNodes.length - 1; i >= 0; i--) {
|
||||
const child = this.assignedNodes[i];
|
||||
if (this.notMontedChildren.has(child)) {
|
||||
this.node.insertBefore(
|
||||
child.node,
|
||||
nextMounted ? nextMounted.node : null,
|
||||
);
|
||||
this.notMontedChildren.delete(child);
|
||||
}
|
||||
if (!this.notMontedChildren.has(child)) {
|
||||
nextMounted = child;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
applyChanges() {
|
||||
if (this.assignedNodes.length > 0) {
|
||||
this.assignedNodes.forEach((c) => c.applyChanges());
|
||||
this.mountAssigned();
|
||||
const { node } = this;
|
||||
const realChildren = node.childNodes;
|
||||
if (realChildren.length > 0) {
|
||||
for (let j = 0; j < this.assignedNodes.length; j++) {
|
||||
while (realChildren[j] !== this.assignedNodes[j].node) {
|
||||
if (isNode(realChildren[j])) {
|
||||
node.removeChild(realChildren[j]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
while (realChildren.length > this.assignedNodes.length) {
|
||||
node.removeChild(node.lastChild as Node);
|
||||
}
|
||||
} else {
|
||||
super.applyChanges();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export class VShadowRoot extends VParent<ShadowRoot> {
|
||||
constructor(protected readonly createNode: () => ShadowRoot) {
|
||||
super();
|
||||
|
|
@ -353,6 +297,62 @@ export class VElement extends VParent<Element> {
|
|||
}
|
||||
}
|
||||
|
||||
export class VSlot extends VElement {
|
||||
assignedNodes: VChild[] = [];
|
||||
|
||||
addAssigned(child: VChild) {
|
||||
if (this.assignedNodes.indexOf(child) === -1) {
|
||||
this.assignedNodes.push(child);
|
||||
this.notMontedChildren.add(child);
|
||||
}
|
||||
}
|
||||
|
||||
removeAssigned(child: VChild) {
|
||||
this.assignedNodes = this.assignedNodes.filter((c) => c !== child);
|
||||
this.notMontedChildren.delete(child);
|
||||
}
|
||||
|
||||
private mountAssigned() {
|
||||
let nextMounted: VChild | null = null;
|
||||
for (let i = this.assignedNodes.length - 1; i >= 0; i--) {
|
||||
const child = this.assignedNodes[i];
|
||||
if (this.notMontedChildren.has(child)) {
|
||||
this.node.insertBefore(
|
||||
child.node,
|
||||
nextMounted ? nextMounted.node : null,
|
||||
);
|
||||
this.notMontedChildren.delete(child);
|
||||
}
|
||||
if (!this.notMontedChildren.has(child)) {
|
||||
nextMounted = child;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
applyChanges() {
|
||||
if (this.assignedNodes.length > 0) {
|
||||
this.assignedNodes.forEach((c) => c.applyChanges());
|
||||
this.mountAssigned();
|
||||
const { node } = this;
|
||||
const realChildren = node.childNodes;
|
||||
if (realChildren.length > 0) {
|
||||
for (let j = 0; j < this.assignedNodes.length; j++) {
|
||||
while (realChildren[j] !== this.assignedNodes[j].node) {
|
||||
if (isNode(realChildren[j])) {
|
||||
node.removeChild(realChildren[j]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
while (realChildren.length > this.assignedNodes.length) {
|
||||
node.removeChild(node.lastChild as Node);
|
||||
}
|
||||
} else {
|
||||
super.applyChanges();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export class VHTMLElement extends VElement {
|
||||
constructor(node: HTMLElement) {
|
||||
super('HTML', false);
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
{
|
||||
"name": "@openreplay/tracker",
|
||||
"description": "The OpenReplay tracker main package",
|
||||
"version": "17.0.0-beta.0",
|
||||
"version": "17.1.0",
|
||||
"keywords": [
|
||||
"logging",
|
||||
"replay"
|
||||
|
|
|
|||
|
|
@ -45,6 +45,7 @@ type TagTypeMap = {
|
|||
style: HTMLStyleElement | SVGStyleElement
|
||||
link: HTMLLinkElement
|
||||
canvas: HTMLCanvasElement
|
||||
slot: HTMLSlotElement
|
||||
}
|
||||
export function hasTag<T extends keyof TagTypeMap>(
|
||||
el: Node,
|
||||
|
|
|
|||
|
|
@ -11,7 +11,8 @@ import {
|
|||
UnbindNodes,
|
||||
SetNodeAttribute,
|
||||
AdoptedSSInsertRuleURLBased,
|
||||
AdoptedSSAddOwner
|
||||
AdoptedSSAddOwner,
|
||||
SetNodeSlot,
|
||||
} from '../messages.gen.js'
|
||||
import App from '../index.js'
|
||||
import {
|
||||
|
|
@ -199,6 +200,7 @@ export default abstract class Observer {
|
|||
private readonly indexes: Array<number> = []
|
||||
private readonly attributesMap: Map<number, Set<string>> = new Map()
|
||||
private readonly textSet: Set<number> = new Set()
|
||||
private readonly slotMap: Map<number, number | undefined> = new Map()
|
||||
private readonly disableSprites: boolean = false
|
||||
/**
|
||||
* this option means that, instead of using link element with href to load css,
|
||||
|
|
@ -428,6 +430,18 @@ export default abstract class Observer {
|
|||
|
||||
private bindNode(node: Node): void {
|
||||
const [id, isNew] = this.app.nodes.registerNode(node)
|
||||
if (isElementNode(node) && hasTag(node, 'slot')) {
|
||||
this.app.nodes.attachNodeListener(node, 'slotchange', () => {
|
||||
const sl = node as HTMLSlotElement
|
||||
sl.assignedNodes({ flatten: true }).forEach((n) => {
|
||||
const nid = this.app.nodes.getID(n)
|
||||
if (nid !== undefined) {
|
||||
this.recents.set(nid, RecentsType.Removed)
|
||||
this.commitNode(nid)
|
||||
}
|
||||
})
|
||||
})
|
||||
}
|
||||
if (isNew) {
|
||||
this.recents.set(id, RecentsType.New)
|
||||
} else if (this.recents.get(id) !== RecentsType.New) {
|
||||
|
|
@ -463,6 +477,9 @@ export default abstract class Observer {
|
|||
|
||||
private unbindTree(node: Node) {
|
||||
const id = this.app.nodes.unregisterNode(node)
|
||||
if (id !== undefined) {
|
||||
this.slotMap.delete(id)
|
||||
}
|
||||
if (id !== undefined && this.recents.get(id) === RecentsType.Removed) {
|
||||
// Sending RemoveNode only for parent to maintain
|
||||
this.app.send(RemoveNode(id))
|
||||
|
|
@ -501,8 +518,8 @@ export default abstract class Observer {
|
|||
if (isRootNode(node)) {
|
||||
return true
|
||||
}
|
||||
// @ts-ignore SALESFORCE
|
||||
const parent = node.assignedSlot ? node.assignedSlot : node.parentNode
|
||||
const slot = (node as any).assignedSlot as HTMLSlotElement | null
|
||||
const parent = node.parentNode
|
||||
let parentID: number | undefined
|
||||
|
||||
// Disable parent check for the upper context HTMLHtmlElement, because it is root there... (before)
|
||||
|
|
@ -576,10 +593,29 @@ export default abstract class Observer {
|
|||
this.app.send(CreateTextNode(id, parentID as number, index))
|
||||
this.throttledSetNodeData(id, parent as Element, node.data)
|
||||
}
|
||||
if (slot) {
|
||||
const slotID = this.app.nodes.getID(slot)
|
||||
console.log('Openreplay: slotID', slotID, 'for node', id, node, 'slot', slot)
|
||||
if (slotID !== undefined) {
|
||||
this.slotMap.set(id, slotID)
|
||||
this.app.send(SetNodeSlot(id, slotID))
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
if (recentsType === RecentsType.Removed && parentID !== undefined) {
|
||||
this.app.send(MoveNode(id, parentID, index))
|
||||
console.log('RM Openreplay', id, node, 'slot', slot)
|
||||
if (slot) {
|
||||
const slotID = this.app.nodes.getID(slot)
|
||||
if (slotID !== undefined && this.slotMap.get(id) !== slotID) {
|
||||
this.slotMap.set(id, slotID)
|
||||
this.app.send(SetNodeSlot(id, slotID))
|
||||
}
|
||||
} else if (this.slotMap.has(id)) {
|
||||
this.slotMap.delete(id)
|
||||
this.app.send(SetNodeSlot(id, 0))
|
||||
}
|
||||
}
|
||||
const attr = this.attributesMap.get(id)
|
||||
if (attr !== undefined) {
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue