This commit is contained in:
Delirium 2025-06-06 10:37:06 -06:00 committed by GitHub
commit e0c455be74
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
24 changed files with 2357 additions and 1983 deletions

View file

@ -10,5 +10,5 @@ func IsMobileType(id int) bool {
}
func IsDOMType(id int) bool {
return 0 == id || 4 == id || 5 == id || 6 == id || 7 == id || 8 == id || 9 == id || 10 == id || 11 == id || 12 == id || 13 == id || 14 == id || 15 == id || 16 == id || 18 == id || 19 == id || 20 == id || 34 == id || 35 == id || 37 == id || 38 == id || 49 == id || 50 == id || 51 == id || 43 == id || 52 == id || 54 == id || 55 == id || 57 == id || 58 == id || 59 == id || 60 == id || 61 == id || 67 == id || 68 == id || 69 == id || 70 == id || 71 == id || 72 == id || 73 == id || 74 == id || 75 == id || 76 == id || 77 == id || 113 == id || 114 == id || 117 == id || 118 == id || 119 == id || 122 == id || 93 == id || 96 == id || 100 == id || 101 == id || 102 == id || 103 == id || 104 == id || 105 == id || 106 == id || 111 == id
return 0 == id || 4 == id || 5 == id || 6 == id || 7 == id || 8 == id || 9 == id || 10 == id || 11 == id || 12 == id || 13 == id || 14 == id || 15 == id || 16 == id || 18 == id || 19 == id || 20 == id || 34 == id || 35 == id || 36 == id || 37 == id || 38 == id || 49 == id || 50 == id || 51 == id || 43 == id || 52 == id || 54 == id || 55 == id || 57 == id || 58 == id || 59 == id || 60 == id || 61 == id || 65 == id || 67 == id || 68 == id || 69 == id || 70 == id || 71 == id || 72 == id || 73 == id || 74 == id || 75 == id || 76 == id || 77 == id || 113 == id || 114 == id || 117 == id || 118 == id || 119 == id || 122 == id || 93 == id || 96 == id || 100 == id || 101 == id || 102 == id || 103 == id || 104 == id || 105 == id || 106 == id || 111 == id
}

View file

@ -37,6 +37,7 @@ const (
MsgPageEvent = 33
MsgStringDictGlobal = 34
MsgSetNodeAttributeDictGlobal = 35
MsgNodeAnimationResult = 36
MsgCSSInsertRule = 37
MsgCSSDeleteRule = 38
MsgFetch = 39
@ -65,6 +66,7 @@ const (
MsgIssueEventDeprecated = 62
MsgTechnicalInfo = 63
MsgCustomIssue = 64
MsgSetNodeSlot = 65
MsgAssetCache = 66
MsgCSSInsertRuleURLBased = 67
MsgMouseClick = 68
@ -124,7 +126,6 @@ const (
MsgMobileIssueEvent = 111
)
type Timestamp struct {
message
Timestamp uint64
@ -291,7 +292,6 @@ func (msg *SetViewportScroll) TypeID() int {
type CreateDocument struct {
message
}
func (msg *CreateDocument) Encode() []byte {
@ -1070,6 +1070,29 @@ func (msg *SetNodeAttributeDictGlobal) TypeID() int {
return 35
}
type NodeAnimationResult struct {
message
ID uint64
Styles string
}
func (msg *NodeAnimationResult) Encode() []byte {
buf := make([]byte, 21+len(msg.Styles))
buf[0] = 36
p := 1
p = WriteUint(msg.ID, buf, p)
p = WriteString(msg.Styles, buf, p)
return buf[:p]
}
func (msg *NodeAnimationResult) Decode() Message {
return msg
}
func (msg *NodeAnimationResult) TypeID() int {
return 36
}
type CSSInsertRule struct {
message
ID uint64
@ -1806,6 +1829,29 @@ func (msg *CustomIssue) TypeID() int {
return 64
}
type SetNodeSlot struct {
message
ID uint64
SlotID uint64
}
func (msg *SetNodeSlot) Encode() []byte {
buf := make([]byte, 21)
buf[0] = 65
p := 1
p = WriteUint(msg.ID, buf, p)
p = WriteUint(msg.SlotID, buf, p)
return buf[:p]
}
func (msg *SetNodeSlot) Decode() Message {
return msg
}
func (msg *SetNodeSlot) TypeID() int {
return 65
}
type AssetCache struct {
message
URL string
@ -3374,4 +3420,3 @@ func (msg *MobileIssueEvent) Decode() Message {
func (msg *MobileIssueEvent) TypeID() int {
return 111
}

View file

@ -633,6 +633,18 @@ func DecodeSetNodeAttributeDictGlobal(reader BytesReader) (Message, error) {
return msg, err
}
func DecodeNodeAnimationResult(reader BytesReader) (Message, error) {
var err error = nil
msg := &NodeAnimationResult{}
if msg.ID, err = reader.ReadUint(); err != nil {
return nil, err
}
if msg.Styles, err = reader.ReadString(); err != nil {
return nil, err
}
return msg, err
}
func DecodeCSSInsertRule(reader BytesReader) (Message, error) {
var err error = nil
msg := &CSSInsertRule{}
@ -1107,6 +1119,18 @@ func DecodeCustomIssue(reader BytesReader) (Message, error) {
return msg, err
}
func DecodeSetNodeSlot(reader BytesReader) (Message, error) {
var err error = nil
msg := &SetNodeSlot{}
if msg.ID, err = reader.ReadUint(); err != nil {
return nil, err
}
if msg.SlotID, err = reader.ReadUint(); err != nil {
return nil, err
}
return msg, err
}
func DecodeAssetCache(reader BytesReader) (Message, error) {
var err error = nil
msg := &AssetCache{}
@ -2250,6 +2274,8 @@ func ReadMessage(t uint64, reader BytesReader) (Message, error) {
return DecodeStringDictGlobal(reader)
case 35:
return DecodeSetNodeAttributeDictGlobal(reader)
case 36:
return DecodeNodeAnimationResult(reader)
case 37:
return DecodeCSSInsertRule(reader)
case 38:
@ -2306,6 +2332,8 @@ func ReadMessage(t uint64, reader BytesReader) (Message, error) {
return DecodeTechnicalInfo(reader)
case 64:
return DecodeCustomIssue(reader)
case 65:
return DecodeSetNodeSlot(reader)
case 66:
return DecodeAssetCache(reader)
case 67:

View file

@ -356,6 +356,14 @@ class SetNodeAttributeDictGlobal(Message):
self.value = value
class NodeAnimationResult(Message):
__id__ = 36
def __init__(self, id, styles):
self.id = id
self.styles = styles
class CSSInsertRule(Message):
__id__ = 37
@ -626,6 +634,14 @@ class CustomIssue(Message):
self.payload = payload
class SetNodeSlot(Message):
__id__ = 65
def __init__(self, id, slot_id):
self.id = id
self.slot_id = slot_id
class AssetCache(Message):
__id__ = 66

View file

@ -535,6 +535,17 @@ cdef class SetNodeAttributeDictGlobal(PyMessage):
self.value = value
cdef class NodeAnimationResult(PyMessage):
cdef public int __id__
cdef public unsigned long id
cdef public str styles
def __init__(self, unsigned long id, str styles):
self.__id__ = 36
self.id = id
self.styles = styles
cdef class CSSInsertRule(PyMessage):
cdef public int __id__
cdef public unsigned long id
@ -935,6 +946,17 @@ cdef class CustomIssue(PyMessage):
self.payload = payload
cdef class SetNodeSlot(PyMessage):
cdef public int __id__
cdef public unsigned long id
cdef public unsigned long slot_id
def __init__(self, unsigned long id, unsigned long slot_id):
self.__id__ = 65
self.id = id
self.slot_id = slot_id
cdef class AssetCache(PyMessage):
cdef public int __id__
cdef public str url

View file

@ -373,6 +373,12 @@ class MessageCodec(Codec):
value=self.read_uint(reader)
)
if message_id == 36:
return NodeAnimationResult(
id=self.read_uint(reader),
styles=self.read_string(reader)
)
if message_id == 37:
return CSSInsertRule(
id=self.read_uint(reader),
@ -587,6 +593,12 @@ class MessageCodec(Codec):
payload=self.read_string(reader)
)
if message_id == 65:
return SetNodeSlot(
id=self.read_uint(reader),
slot_id=self.read_uint(reader)
)
if message_id == 66:
return AssetCache(
url=self.read_string(reader)

View file

@ -471,6 +471,12 @@ cdef class MessageCodec:
value=self.read_uint(reader)
)
if message_id == 36:
return NodeAnimationResult(
id=self.read_uint(reader),
styles=self.read_string(reader)
)
if message_id == 37:
return CSSInsertRule(
id=self.read_uint(reader),
@ -685,6 +691,12 @@ cdef class MessageCodec:
payload=self.read_string(reader)
)
if message_id == 65:
return SetNodeSlot(
id=self.read_uint(reader),
slot_id=self.read_uint(reader)
)
if message_id == 66:
return AssetCache(
url=self.read_string(reader)

View file

@ -9,7 +9,6 @@ import FocusManager from './FocusManager';
import SelectionManager from './SelectionManager';
import {
StyleElement,
VSpriteMap,
OnloadStyleSheet,
VDocument,
VElement,
@ -17,6 +16,7 @@ import {
VShadowRoot,
VText,
OnloadVRoot,
VSlot,
} from './VirtualDOM';
import { deleteRule, insertRule } from './safeCSSRules';
@ -54,7 +54,6 @@ 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();
@ -70,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: {
@ -278,6 +277,36 @@ export default class DOMManager extends ListWalker<Message> {
this.stylesManager.reset();
return;
}
case MType.SetNodeSlot: {
const vChild = this.vElements.get(msg.id) || this.vTexts.get(msg.id);
if (!vChild) {
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;
}
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');
}
}
} else {
if (vChild instanceof VElement) {
vChild.removeAttribute('slot');
}
}
return;
}
case MType.CreateTextNode: {
const vText = new VText();
this.vTexts.set(msg.id, vText);
@ -286,7 +315,10 @@ export default class DOMManager extends ListWalker<Message> {
}
case MType.CreateElementNode: {
// if (msg.tag.toLowerCase() === 'canvas') msg.tag = 'video'
const vElem = new VElement(msg.tag, msg.svg, msg.index, msg.id);
const vElem =
msg.tag === 'SLOT'
? new VSlot(msg.tag, msg.svg, msg.index, msg.id)
: new VElement(msg.tag, msg.svg, msg.index, msg.id);
if (['STYLE', 'style', 'LINK'].includes(msg.tag)) {
vElem.prioritized = true;
}

View file

@ -16,7 +16,7 @@ type Callback<T> = (o: T) => void;
*/
export abstract class VNode<T extends Node = Node> {
protected abstract createNode(): T;
assignedSlot: VSlot | null = null;
private _node: T | null;
/**
@ -58,13 +58,13 @@ 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> {
/**
*/
protected children: VChild[] = [];
private notMontedChildren: Set<VChild> = new Set();
protected notMontedChildren: Set<VChild> = new Set();
insertChildAt(child: VChild, index: number) {
if (child.parentNode) {
@ -85,6 +85,9 @@ abstract class VParent<T extends Node = Node> extends VNode<T> {
let nextMounted: VChild | null = null;
for (let i = this.children.length - 1; i >= 0; i--) {
const child = this.children[i];
if (child.assignedSlot) {
continue;
}
if (
this.notMontedChildren.has(child) &&
(!shouldInsert || shouldInsert(child)) // is there a better way of not-knowing about subclass logic on prioritized insertion?
@ -107,14 +110,15 @@ 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;
const realChildren = node.childNodes;
if (realChildren.length > 0 && this.children.length > 0) {
for (let j = 0; j < this.children.length; j++) {
while (realChildren[j] !== this.children[j].node) {
const expected = this.children.filter((c) => !c.assignedSlot);
if (realChildren.length > 0 && expected.length > 0) {
for (let j = 0; j < expected.length; j++) {
while (realChildren[j] !== expected[j].node) {
if (isNode(realChildren[j])) {
node.removeChild(realChildren[j]);
}
@ -122,7 +126,7 @@ abstract class VParent<T extends Node = Node> extends VNode<T> {
}
}
/* Removing tail */
while (realChildren.length > this.children.length) {
while (realChildren.length > expected.length) {
node.removeChild(
node.lastChild as Node,
); /* realChildren.length > this.children.length >= 0 so it is not null */
@ -159,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 */
@ -293,6 +257,18 @@ export class VElement extends VParent<Element> {
}
}
export class VSlot extends VElement {
protected createNode() {
const element = super.createNode() as HTMLSlotElement;
return element;
}
applyChanges() {
super.applyChanges();
// todo safety checks here ?
}
}
export class VHTMLElement extends VElement {
constructor(node: HTMLElement) {
super('HTML', false);

View file

@ -255,6 +255,16 @@ export default class RawMessageReader extends PrimitiveReader {
};
}
case 36: {
const id = this.readUint(); if (id === null) { return resetPointer() }
const styles = this.readString(); if (styles === null) { return resetPointer() }
return {
tp: MType.NodeAnimationResult,
id,
styles,
};
}
case 37: {
const id = this.readUint(); if (id === null) { return resetPointer() }
const rule = this.readString(); if (rule === null) { return resetPointer() }
@ -547,6 +557,16 @@ export default class RawMessageReader extends PrimitiveReader {
};
}
case 65: {
const id = this.readUint(); if (id === null) { return resetPointer() }
const slotID = this.readUint(); if (slotID === null) { return resetPointer() }
return {
tp: MType.SetNodeSlot,
id,
slotID,
};
}
case 67: {
const id = this.readUint(); if (id === null) { return resetPointer() }
const rule = this.readString(); if (rule === null) { return resetPointer() }

View file

@ -4,7 +4,7 @@
import { MType } from './raw.gen'
const IOS_TYPES = [90,91,92,93,94,95,96,97,98,100,101,102,103,104,105,106,107,110,111]
const DOM_TYPES = [0,4,5,6,7,8,9,10,11,12,13,14,15,16,18,19,20,34,35,37,38,49,50,51,43,52,54,55,57,58,59,60,61,67,68,69,70,71,72,73,74,75,76,77,113,114,117,118,119,122]
const DOM_TYPES = [0,4,5,6,7,8,9,10,11,12,13,14,15,16,18,19,20,34,35,36,37,38,49,50,51,43,52,54,55,57,58,59,60,61,65,67,68,69,70,71,72,73,74,75,76,77,113,114,117,118,119,122]
export function isDOMType(t: MType) {
return DOM_TYPES.includes(t)
}

View file

@ -25,6 +25,7 @@ import type {
RawConsoleLog,
RawStringDictGlobal,
RawSetNodeAttributeDictGlobal,
RawNodeAnimationResult,
RawCssInsertRule,
RawCssDeleteRule,
RawFetch,
@ -48,6 +49,7 @@ import type {
RawLongTask,
RawSetNodeAttributeURLBased,
RawSetCssDataURLBased,
RawSetNodeSlot,
RawCssInsertRuleURLBased,
RawMouseClick,
RawMouseClickDeprecated,
@ -132,6 +134,8 @@ export type StringDictGlobal = RawStringDictGlobal & Timed
export type SetNodeAttributeDictGlobal = RawSetNodeAttributeDictGlobal & Timed
export type NodeAnimationResult = RawNodeAnimationResult & Timed
export type CssInsertRule = RawCssInsertRule & Timed
export type CssDeleteRule = RawCssDeleteRule & Timed
@ -178,6 +182,8 @@ export type SetNodeAttributeURLBased = RawSetNodeAttributeURLBased & Timed
export type SetCssDataURLBased = RawSetCssDataURLBased & Timed
export type SetNodeSlot = RawSetNodeSlot & Timed
export type CssInsertRuleURLBased = RawCssInsertRuleURLBased & Timed
export type MouseClick = RawMouseClick & Timed

View file

@ -23,6 +23,7 @@ export const enum MType {
ConsoleLog = 22,
StringDictGlobal = 34,
SetNodeAttributeDictGlobal = 35,
NodeAnimationResult = 36,
CssInsertRule = 37,
CssDeleteRule = 38,
Fetch = 39,
@ -46,6 +47,7 @@ export const enum MType {
LongTask = 59,
SetNodeAttributeURLBased = 60,
SetCssDataURLBased = 61,
SetNodeSlot = 65,
CssInsertRuleURLBased = 67,
MouseClick = 68,
MouseClickDeprecated = 69,
@ -225,6 +227,12 @@ export interface RawSetNodeAttributeDictGlobal {
value: number,
}
export interface RawNodeAnimationResult {
tp: MType.NodeAnimationResult,
id: number,
styles: string,
}
export interface RawCssInsertRule {
tp: MType.CssInsertRule,
id: number,
@ -394,6 +402,12 @@ export interface RawSetCssDataURLBased {
baseURL: string,
}
export interface RawSetNodeSlot {
tp: MType.SetNodeSlot,
id: number,
slotID: number,
}
export interface RawCssInsertRuleURLBased {
tp: MType.CssInsertRuleURLBased,
id: number,
@ -703,4 +717,4 @@ export interface RawMobileIssueEvent {
}
export type RawMessage = RawTimestamp | RawSetPageLocationDeprecated | RawSetViewportSize | RawSetViewportScroll | RawCreateDocument | RawCreateElementNode | RawCreateTextNode | RawMoveNode | RawRemoveNode | RawSetNodeAttribute | RawRemoveNodeAttribute | RawSetNodeData | RawSetCssData | RawSetNodeScroll | RawSetInputValue | RawSetInputChecked | RawMouseMove | RawNetworkRequestDeprecated | RawConsoleLog | RawStringDictGlobal | RawSetNodeAttributeDictGlobal | RawCssInsertRule | RawCssDeleteRule | RawFetch | RawProfiler | RawOTable | RawReduxDeprecated | RawVuex | RawMobX | RawNgRx | RawGraphQlDeprecated | RawPerformanceTrack | RawStringDictDeprecated | RawSetNodeAttributeDictDeprecated | RawStringDict | RawSetNodeAttributeDict | RawResourceTimingDeprecatedDeprecated | RawConnectionInformation | RawSetPageVisibility | RawLoadFontFace | RawSetNodeFocus | RawLongTask | RawSetNodeAttributeURLBased | RawSetCssDataURLBased | RawCssInsertRuleURLBased | RawMouseClick | RawMouseClickDeprecated | RawCreateIFrameDocument | RawAdoptedSsReplaceURLBased | RawAdoptedSsReplace | RawAdoptedSsInsertRuleURLBased | RawAdoptedSsInsertRule | RawAdoptedSsDeleteRule | RawAdoptedSsAddOwner | RawAdoptedSsRemoveOwner | RawZustand | RawNetworkRequest | RawWsChannel | RawResourceTiming | RawIncident | RawLongAnimationTask | RawSelectionChange | RawMouseThrashing | RawResourceTimingDeprecated | RawTabChange | RawTabData | RawCanvasNode | RawTagTrigger | RawRedux | RawSetPageLocation | RawGraphQl | RawMobileEvent | RawMobileScreenChanges | RawMobileClickEvent | RawMobileInputEvent | RawMobilePerformanceEvent | RawMobileLog | RawMobileInternalError | RawMobileNetworkCall | RawMobileSwipeEvent | RawMobileIssueEvent;
export type RawMessage = RawTimestamp | RawSetPageLocationDeprecated | RawSetViewportSize | RawSetViewportScroll | RawCreateDocument | RawCreateElementNode | RawCreateTextNode | RawMoveNode | RawRemoveNode | RawSetNodeAttribute | RawRemoveNodeAttribute | RawSetNodeData | RawSetCssData | RawSetNodeScroll | RawSetInputValue | RawSetInputChecked | RawMouseMove | RawNetworkRequestDeprecated | RawConsoleLog | RawStringDictGlobal | RawSetNodeAttributeDictGlobal | RawNodeAnimationResult | RawCssInsertRule | RawCssDeleteRule | RawFetch | RawProfiler | RawOTable | RawReduxDeprecated | RawVuex | RawMobX | RawNgRx | RawGraphQlDeprecated | RawPerformanceTrack | RawStringDictDeprecated | RawSetNodeAttributeDictDeprecated | RawStringDict | RawSetNodeAttributeDict | RawResourceTimingDeprecatedDeprecated | RawConnectionInformation | RawSetPageVisibility | RawLoadFontFace | RawSetNodeFocus | RawLongTask | RawSetNodeAttributeURLBased | RawSetCssDataURLBased | RawSetNodeSlot | RawCssInsertRuleURLBased | RawMouseClick | RawMouseClickDeprecated | RawCreateIFrameDocument | RawAdoptedSsReplaceURLBased | RawAdoptedSsReplace | RawAdoptedSsInsertRuleURLBased | RawAdoptedSsInsertRule | RawAdoptedSsDeleteRule | RawAdoptedSsAddOwner | RawAdoptedSsRemoveOwner | RawZustand | RawNetworkRequest | RawWsChannel | RawResourceTiming | RawIncident | RawLongAnimationTask | RawSelectionChange | RawMouseThrashing | RawResourceTimingDeprecated | RawTabChange | RawTabData | RawCanvasNode | RawTagTrigger | RawRedux | RawSetPageLocation | RawGraphQl | RawMobileEvent | RawMobileScreenChanges | RawMobileClickEvent | RawMobileInputEvent | RawMobilePerformanceEvent | RawMobileLog | RawMobileInternalError | RawMobileNetworkCall | RawMobileSwipeEvent | RawMobileIssueEvent;

View file

@ -24,6 +24,7 @@ export const TP_MAP = {
22: MType.ConsoleLog,
34: MType.StringDictGlobal,
35: MType.SetNodeAttributeDictGlobal,
36: MType.NodeAnimationResult,
37: MType.CssInsertRule,
38: MType.CssDeleteRule,
39: MType.Fetch,
@ -47,6 +48,7 @@ export const TP_MAP = {
59: MType.LongTask,
60: MType.SetNodeAttributeURLBased,
61: MType.SetCssDataURLBased,
65: MType.SetNodeSlot,
67: MType.CssInsertRuleURLBased,
68: MType.MouseClick,
69: MType.MouseClickDeprecated,

View file

@ -186,6 +186,12 @@ type TrSetNodeAttributeDictGlobal = [
value: number,
]
type TrNodeAnimationResult = [
type: 36,
id: number,
styles: string,
]
type TrCSSInsertRule = [
type: 37,
id: number,
@ -372,6 +378,12 @@ type TrCustomIssue = [
payload: string,
]
type TrSetNodeSlot = [
type: 65,
id: number,
slotID: number,
]
type TrCSSInsertRuleURLBased = [
type: 67,
id: number,
@ -621,7 +633,7 @@ type TrWebVitals = [
]
export type TrackerMessage = TrTimestamp | TrSetPageLocationDeprecated | TrSetViewportSize | TrSetViewportScroll | TrCreateDocument | TrCreateElementNode | TrCreateTextNode | TrMoveNode | TrRemoveNode | TrSetNodeAttribute | TrRemoveNodeAttribute | TrSetNodeData | TrSetNodeScroll | TrSetInputTarget | TrSetInputValue | TrSetInputChecked | TrMouseMove | TrNetworkRequestDeprecated | TrConsoleLog | TrPageLoadTiming | TrPageRenderTiming | TrCustomEvent | TrUserID | TrUserAnonymousID | TrMetadata | TrStringDictGlobal | TrSetNodeAttributeDictGlobal | TrCSSInsertRule | TrCSSDeleteRule | TrFetch | TrProfiler | TrOTable | TrStateAction | TrReduxDeprecated | TrVuex | TrMobX | TrNgRx | TrGraphQLDeprecated | TrPerformanceTrack | TrStringDictDeprecated | TrSetNodeAttributeDictDeprecated | TrStringDict | TrSetNodeAttributeDict | TrResourceTimingDeprecatedDeprecated | TrConnectionInformation | TrSetPageVisibility | TrLoadFontFace | TrSetNodeFocus | TrLongTask | TrSetNodeAttributeURLBased | TrSetCSSDataURLBased | TrTechnicalInfo | TrCustomIssue | TrCSSInsertRuleURLBased | TrMouseClick | TrMouseClickDeprecated | TrCreateIFrameDocument | TrAdoptedSSReplaceURLBased | TrAdoptedSSInsertRuleURLBased | TrAdoptedSSDeleteRule | TrAdoptedSSAddOwner | TrAdoptedSSRemoveOwner | TrJSException | TrZustand | TrBatchMetadata | TrPartitionedMessage | TrNetworkRequest | TrWSChannel | TrResourceTiming | TrIncident | TrLongAnimationTask | TrInputChange | TrSelectionChange | TrMouseThrashing | TrUnbindNodes | TrResourceTimingDeprecated | TrTabChange | TrTabData | TrCanvasNode | TrTagTrigger | TrRedux | TrSetPageLocation | TrGraphQL | TrWebVitals
export type TrackerMessage = TrTimestamp | TrSetPageLocationDeprecated | TrSetViewportSize | TrSetViewportScroll | TrCreateDocument | TrCreateElementNode | TrCreateTextNode | TrMoveNode | TrRemoveNode | TrSetNodeAttribute | TrRemoveNodeAttribute | TrSetNodeData | TrSetNodeScroll | TrSetInputTarget | TrSetInputValue | TrSetInputChecked | TrMouseMove | TrNetworkRequestDeprecated | TrConsoleLog | TrPageLoadTiming | TrPageRenderTiming | TrCustomEvent | TrUserID | TrUserAnonymousID | TrMetadata | TrStringDictGlobal | TrSetNodeAttributeDictGlobal | TrNodeAnimationResult | TrCSSInsertRule | TrCSSDeleteRule | TrFetch | TrProfiler | TrOTable | TrStateAction | TrReduxDeprecated | TrVuex | TrMobX | TrNgRx | TrGraphQLDeprecated | TrPerformanceTrack | TrStringDictDeprecated | TrSetNodeAttributeDictDeprecated | TrStringDict | TrSetNodeAttributeDict | TrResourceTimingDeprecatedDeprecated | TrConnectionInformation | TrSetPageVisibility | TrLoadFontFace | TrSetNodeFocus | TrLongTask | TrSetNodeAttributeURLBased | TrSetCSSDataURLBased | TrTechnicalInfo | TrCustomIssue | TrSetNodeSlot | TrCSSInsertRuleURLBased | TrMouseClick | TrMouseClickDeprecated | TrCreateIFrameDocument | TrAdoptedSSReplaceURLBased | TrAdoptedSSInsertRuleURLBased | TrAdoptedSSDeleteRule | TrAdoptedSSAddOwner | TrAdoptedSSRemoveOwner | TrJSException | TrZustand | TrBatchMetadata | TrPartitionedMessage | TrNetworkRequest | TrWSChannel | TrResourceTiming | TrIncident | TrLongAnimationTask | TrInputChange | TrSelectionChange | TrMouseThrashing | TrUnbindNodes | TrResourceTimingDeprecated | TrTabChange | TrTabData | TrCanvasNode | TrTagTrigger | TrRedux | TrSetPageLocation | TrGraphQL | TrWebVitals
export default function translate(tMsg: TrackerMessage): RawMessage | null {
switch(tMsg[0]) {
@ -799,6 +811,14 @@ export default function translate(tMsg: TrackerMessage): RawMessage | null {
}
}
case 36: {
return {
tp: MType.NodeAnimationResult,
id: tMsg[1],
styles: tMsg[2],
}
}
case 37: {
return {
tp: MType.CssInsertRule,
@ -1014,6 +1034,14 @@ export default function translate(tMsg: TrackerMessage): RawMessage | null {
}
}
case 65: {
return {
tp: MType.SetNodeSlot,
id: tMsg[1],
slotID: tMsg[2],
}
}
case 67: {
return {
tp: MType.CssInsertRuleURLBased,

View file

@ -220,6 +220,11 @@ message 35, 'SetNodeAttributeDictGlobal' do
uint 'Value'
end
message 36, 'NodeAnimationResult' do
uint 'ID'
string 'Styles'
end
# DEPRECATED since 4.0.2 in favor of AdoptedSSInsertRule + AdoptedSSAddOwner
message 37, 'CSSInsertRule' do
uint 'ID'
@ -396,7 +401,10 @@ message 64, 'CustomIssue', :replayer => false do
string 'Name'
string 'Payload'
end
message 65, 'SetNodeSlot' do
uint 'ID'
uint 'SlotID'
end
message 66, 'AssetCache', :replayer => false, :tracker => false do
string 'URL'
end
@ -659,4 +667,4 @@ message 127, 'SessionSearch', :tracker => false, :replayer => false do
uint 'Partition'
end
# FREE 2, 35, 36, 65, 87, 88, 89
# FREE 2, 87, 88, 89

View file

@ -1,7 +1,7 @@
{
"name": "@openreplay/tracker",
"description": "The OpenReplay tracker main package",
"version": "17.0.0-beta.0",
"version": "17.1.0-beta.11",
"keywords": [
"logging",
"replay"

View file

@ -29,6 +29,7 @@ export declare const enum Type {
Metadata = 30,
StringDictGlobal = 34,
SetNodeAttributeDictGlobal = 35,
NodeAnimationResult = 36,
CSSInsertRule = 37,
CSSDeleteRule = 38,
Fetch = 39,
@ -55,6 +56,7 @@ export declare const enum Type {
SetCSSDataURLBased = 61,
TechnicalInfo = 63,
CustomIssue = 64,
SetNodeSlot = 65,
CSSInsertRuleURLBased = 67,
MouseClick = 68,
MouseClickDeprecated = 69,
@ -270,6 +272,12 @@ export type SetNodeAttributeDictGlobal = [
/*value:*/ number,
]
export type NodeAnimationResult = [
/*type:*/ Type.NodeAnimationResult,
/*id:*/ number,
/*styles:*/ string,
]
export type CSSInsertRule = [
/*type:*/ Type.CSSInsertRule,
/*id:*/ number,
@ -456,6 +464,12 @@ export type CustomIssue = [
/*payload:*/ string,
]
export type SetNodeSlot = [
/*type:*/ Type.SetNodeSlot,
/*id:*/ number,
/*slotID:*/ number,
]
export type CSSInsertRuleURLBased = [
/*type:*/ Type.CSSInsertRuleURLBased,
/*id:*/ number,
@ -705,5 +719,5 @@ export type WebVitals = [
]
type Message = Timestamp | SetPageLocationDeprecated | SetViewportSize | SetViewportScroll | CreateDocument | CreateElementNode | CreateTextNode | MoveNode | RemoveNode | SetNodeAttribute | RemoveNodeAttribute | SetNodeData | SetNodeScroll | SetInputTarget | SetInputValue | SetInputChecked | MouseMove | NetworkRequestDeprecated | ConsoleLog | PageLoadTiming | PageRenderTiming | CustomEvent | UserID | UserAnonymousID | Metadata | StringDictGlobal | SetNodeAttributeDictGlobal | CSSInsertRule | CSSDeleteRule | Fetch | Profiler | OTable | StateAction | ReduxDeprecated | Vuex | MobX | NgRx | GraphQLDeprecated | PerformanceTrack | StringDictDeprecated | SetNodeAttributeDictDeprecated | StringDict | SetNodeAttributeDict | ResourceTimingDeprecatedDeprecated | ConnectionInformation | SetPageVisibility | LoadFontFace | SetNodeFocus | LongTask | SetNodeAttributeURLBased | SetCSSDataURLBased | TechnicalInfo | CustomIssue | CSSInsertRuleURLBased | MouseClick | MouseClickDeprecated | CreateIFrameDocument | AdoptedSSReplaceURLBased | AdoptedSSInsertRuleURLBased | AdoptedSSDeleteRule | AdoptedSSAddOwner | AdoptedSSRemoveOwner | JSException | Zustand | BatchMetadata | PartitionedMessage | NetworkRequest | WSChannel | ResourceTiming | Incident | LongAnimationTask | InputChange | SelectionChange | MouseThrashing | UnbindNodes | ResourceTimingDeprecated | TabChange | TabData | CanvasNode | TagTrigger | Redux | SetPageLocation | GraphQL | WebVitals
type Message = Timestamp | SetPageLocationDeprecated | SetViewportSize | SetViewportScroll | CreateDocument | CreateElementNode | CreateTextNode | MoveNode | RemoveNode | SetNodeAttribute | RemoveNodeAttribute | SetNodeData | SetNodeScroll | SetInputTarget | SetInputValue | SetInputChecked | MouseMove | NetworkRequestDeprecated | ConsoleLog | PageLoadTiming | PageRenderTiming | CustomEvent | UserID | UserAnonymousID | Metadata | StringDictGlobal | SetNodeAttributeDictGlobal | NodeAnimationResult | CSSInsertRule | CSSDeleteRule | Fetch | Profiler | OTable | StateAction | ReduxDeprecated | Vuex | MobX | NgRx | GraphQLDeprecated | PerformanceTrack | StringDictDeprecated | SetNodeAttributeDictDeprecated | StringDict | SetNodeAttributeDict | ResourceTimingDeprecatedDeprecated | ConnectionInformation | SetPageVisibility | LoadFontFace | SetNodeFocus | LongTask | SetNodeAttributeURLBased | SetCSSDataURLBased | TechnicalInfo | CustomIssue | SetNodeSlot | CSSInsertRuleURLBased | MouseClick | MouseClickDeprecated | CreateIFrameDocument | AdoptedSSReplaceURLBased | AdoptedSSInsertRuleURLBased | AdoptedSSDeleteRule | AdoptedSSAddOwner | AdoptedSSRemoveOwner | JSException | Zustand | BatchMetadata | PartitionedMessage | NetworkRequest | WSChannel | ResourceTiming | Incident | LongAnimationTask | InputChange | SelectionChange | MouseThrashing | UnbindNodes | ResourceTimingDeprecated | TabChange | TabData | CanvasNode | TagTrigger | Redux | SetPageLocation | GraphQL | WebVitals
export default Message

View file

@ -45,6 +45,7 @@ type TagTypeMap = {
style: HTMLStyleElement | SVGStyleElement
link: HTMLLinkElement
canvas: HTMLCanvasElement
slot: HTMLSlotElement
}
export function hasTag<T extends keyof TagTypeMap>(
el: Node,

View file

@ -340,6 +340,17 @@ export function SetNodeAttributeDictGlobal(
]
}
export function NodeAnimationResult(
id: number,
styles: string,
): Messages.NodeAnimationResult {
return [
Messages.Type.NodeAnimationResult,
id,
styles,
]
}
export function CSSInsertRule(
id: number,
rule: string,
@ -686,6 +697,17 @@ export function CustomIssue(
]
}
export function SetNodeSlot(
id: number,
slotID: number,
): Messages.SetNodeSlot {
return [
Messages.Type.SetNodeSlot,
id,
slotID,
]
}
export function CSSInsertRuleURLBased(
id: number,
rule: string,

View file

@ -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,27 @@ 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)
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))
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) {

View file

@ -29,9 +29,11 @@ import ConstructedStyleSheets from './modules/constructedStyleSheets.js'
import Selection from './modules/selection.js'
import Tabs from './modules/tabs.js'
import LongAnimationTask from "./modules/longAnimationTask.js";
import FeatureFlags, { IFeatureFlag } from './modules/featureFlags.js'
import WebAnimations from './modules/webAnimations.js'
import { IN_BROWSER, deprecationWarn, DOCS_HOST, inIframe } from './utils.js'
import FeatureFlags, { IFeatureFlag } from './modules/featureFlags.js'
import type { Options as AppOptions } from './app/index.js'
import type { Options as ConsoleOptions } from './modules/console.js'
import type { Options as ExceptionOptions } from './modules/exception.js'
@ -43,6 +45,7 @@ import type { MouseHandlerOptions } from './modules/mouse.js'
import type { SessionInfo } from './app/session.js'
import type { CssRulesOptions } from './modules/cssrules.js'
import type { LATOptions } from './modules/longAnimationTask.js'
import type { Options as WapOptions } from './modules/webAnimations.js'
import type { StartOptions } from './app/index.js'
//TODO: unique options init
@ -71,6 +74,7 @@ export type Options = Partial<
// dev only
__DISABLE_SECURE_MODE?: boolean
css: CssRulesOptions
webAnimations?: WapOptions
}
const DOCS_SETUP = '/en/sdk'
@ -217,6 +221,7 @@ export default class API {
Network(app, options.network)
}
Selection(app)
WebAnimations(app, options.webAnimations)
;(window as any).__OPENREPLAY__ = this
if (options.flags && options.flags.onFlagsLoad) {

View file

@ -0,0 +1,69 @@
import type App from '../app/index.js'
import { NodeAnimationResult } from '../app/messages.gen.js'
/**
* this will only work for custom elements by default (because of ionic)
*/
export interface Options {
allElements?: boolean
}
const toIgnore = ["composite", "computedOffset", "easing", "offset"]
function webAnimations(app: App, options: Options = {}) {
const { allElements = false } = options
let listening = new WeakSet<Node>()
let handled = new WeakSet()
function wire(anim, el, nodeId) {
if (handled.has(anim)) return
handled.add(anim)
anim.addEventListener(
'finish',
() => {
const lastKF = anim.effect.getKeyframes().at(-1)
const computedStyle = getComputedStyle(el)
const keys = Object.keys(lastKF).filter((p) => !toIgnore.includes(p))
// @ts-ignore
const finalStyle = {}
keys.forEach((key) => {
finalStyle[key] = computedStyle[key]
})
app.send(NodeAnimationResult(nodeId, JSON.stringify(finalStyle)))
},
{ once: true },
)
}
function scanElement(el, nodeId) {
el.getAnimations({ subtree: false }).forEach((anim) => wire(anim, el, nodeId))
}
app.nodes.attachNodeCallback((node) => {
if ((allElements || node.nodeName.includes('-')) && 'getAnimations' in node) {
const animations = (node as Element).getAnimations({ subtree: false })
const id = app.nodes.getID(node)
if (animations.length > 0 && !listening.has(node) && id) {
listening.add(node)
scanElement(node, id)
node.addEventListener('animationstart', () => scanElement(node, id))
}
}
})
const origAnimate = Element.prototype.animate
Element.prototype.animate = function (...args) {
const anim = origAnimate.apply(this, args)
wire(anim, this)
return anim
}
app.attachStopCallback(() => {
Element.prototype.animate = origAnimate // Restore original animate method
listening = new WeakSet<Node>()
handled = new WeakSet()
})
}
export default webAnimations

View file

@ -118,6 +118,10 @@ export default class MessageEncoder extends PrimitiveEncoder {
return this.uint(msg[1]) && this.uint(msg[2]) && this.uint(msg[3])
break
case Messages.Type.NodeAnimationResult:
return this.uint(msg[1]) && this.string(msg[2])
break
case Messages.Type.CSSInsertRule:
return this.uint(msg[1]) && this.string(msg[2]) && this.uint(msg[3])
break
@ -222,6 +226,10 @@ export default class MessageEncoder extends PrimitiveEncoder {
return this.string(msg[1]) && this.string(msg[2])
break
case Messages.Type.SetNodeSlot:
return this.uint(msg[1]) && this.uint(msg[2])
break
case Messages.Type.CSSInsertRuleURLBased:
return this.uint(msg[1]) && this.string(msg[2]) && this.uint(msg[3]) && this.string(msg[4])
break