ui: use slot name as target

This commit is contained in:
nick-delirium 2025-06-06 11:38:53 +02:00
parent 9f4852bd38
commit 8b568ee027
No known key found for this signature in database
GPG key ID: 93ABD695DF5FDBA0
2 changed files with 18 additions and 121 deletions

View file

@ -9,7 +9,6 @@ import FocusManager from './FocusManager';
import SelectionManager from './SelectionManager';
import {
StyleElement,
VSpriteMap,
OnloadStyleSheet,
VDocument,
VElement,
@ -55,14 +54,12 @@ export default class DOMManager extends ListWalker<Message> {
*/
private olStyleSheets: Map<number, OnloadStyleSheet> = new Map();
/** @depreacted since tracker 4.0.2 Mapping by nodeID */
private olStyleSheetsDeprecated: Map<number, OnloadStyleSheet> = new Map();
private upperBodyId: number = -1;
private nodeScrollManagers: Map<number, ListWalker<SetNodeScroll>> =
new Map();
private stylesManager: StylesManager;
private focusManager: FocusManager = new FocusManager(this.vElements);
private selectionManager: SelectionManager;
private nodeSlots: Map<number, { slotID: number; host: any }> = new Map();
private readonly screen: Screen;
private readonly isMobile: boolean;
private readonly stringDict: Record<number, string>;
@ -72,7 +69,7 @@ export default class DOMManager extends ListWalker<Message> {
};
public readonly time: number;
private virtualMode = false;
private hasSlots = false
private hasSlots = false;
private showVModeBadge?: () => void;
constructor(params: {
@ -286,42 +283,26 @@ export default class DOMManager extends ListWalker<Message> {
logger.error('SetNodeSlot: Node not found', msg);
return;
}
if (msg.slotID > 0) {
const slotElem = this.vElements.get(msg.slotID);
if (!(slotElem instanceof VSlot)) {
logger.error('SetNodeSlot: Slot not found', msg);
return;
}
const host = vChild.parentNode;
if (host && (vChild as any).assignedSlot !== slotElem) {
if (vChild.node.parentNode === (host as any).node) {
host.node.removeChild(vChild.node);
if (vChild instanceof VElement) {
const slotName = (slotElem.node as HTMLSlotElement).name;
if (slotName && slotName !== 'default') {
vChild.setAttribute('slot', slotName);
} else {
// if el goes to default slot, we don't need attr
vChild.removeAttribute('slot');
}
(host as any).notMontedChildren?.delete(vChild);
slotElem.addAssigned(vChild);
(vChild as any).assignedSlot = slotElem;
this.nodeSlots.set(msg.id, { slotID: msg.slotID, host });
}
} else {
if (vChild.assignedSlot) {
const slotElem = vChild.assignedSlot as VSlot;
slotElem.removeAssigned(vChild);
if (vChild.parentNode) {
const host = vChild.parentNode;
const siblings = host['children'] as any[];
const index = siblings.indexOf(vChild);
let next: Node | null = null;
for (let i = index + 1; i < siblings.length; i++) {
const sib = siblings[i];
if (!sib.assignedSlot) {
next = sib.node;
break;
}
}
host.node.insertBefore(vChild.node, next);
}
vChild.assignedSlot = null;
this.nodeSlots.delete(msg.id);
if (vChild instanceof VElement) {
vChild.removeAttribute('slot');
}
}
return;

View file

@ -58,7 +58,7 @@ export abstract class VNode<T extends Node = Node> {
public abstract applyChanges(): void;
}
type VChild = VElement | VText | VSpriteMap;
type VChild = VElement | VText;
abstract class VParent<T extends Node = Node> extends VNode<T> {
/**
*/
@ -163,46 +163,6 @@ export class VShadowRoot extends VParent<ShadowRoot> {
export type VRoot = VDocument | VShadowRoot;
export class VSpriteMap extends VParent<Element> {
parentNode: VParent | null =
null; /** Should be modified only by he parent itself */
private newAttributes: Map<string, string | false> = new Map();
constructor(
readonly tagName: string,
readonly isSVG = true,
public readonly index: number,
private readonly nodeId: number,
) {
super();
this.createNode();
}
protected createNode() {
try {
const element = document.createElementNS(
'http://www.w3.org/2000/svg',
this.tagName,
);
element.dataset.openreplayId = this.nodeId.toString();
return element;
} catch (e) {
console.error(
'Openreplay: Player received invalid html tag',
this.tagName,
e,
);
return document.createElement(this.tagName.replace(/[^a-z]/gi, ''));
}
}
applyChanges() {
// this is a hack to prevent the sprite map from being removed from the DOM
return null;
}
}
export class VElement extends VParent<Element> {
parentNode: VParent | null =
null; /** Should be modified only by he parent itself */
@ -298,58 +258,14 @@ 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;
}
}
protected createNode() {
const element = super.createNode() as HTMLSlotElement;
return element;
}
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();
}
super.applyChanges();
// todo safety checks here ?
}
}