mirror of
https://github.com/chenasraf/clarity.git
synced 2026-05-17 17:48:05 +00:00
add time to style events based on original dom event
This commit is contained in:
@@ -23,8 +23,8 @@ async function discover(): Promise<void> {
|
||||
|
||||
let timer: Timer = { id: id(), cost: Metric.LayoutCost };
|
||||
task.start(timer);
|
||||
await traverse(document, timer, Source.Discover);
|
||||
checkDocumentStyles(document);
|
||||
await traverse(document, timer, Source.Discover, ts);
|
||||
checkDocumentStyles(document, ts);
|
||||
await encode(Event.Discover, timer, ts);
|
||||
task.stop(timer);
|
||||
}
|
||||
|
||||
@@ -129,19 +129,19 @@ async function process(): Promise<void> {
|
||||
if (state === Task.Wait) { state = await task.suspend(timer); }
|
||||
if (state === Task.Stop) { break; }
|
||||
let target = mutation.target;
|
||||
let type = track(mutation, timer, instance);
|
||||
let type = track(mutation, timer, instance, record.time);
|
||||
if (type && target && target.ownerDocument) { dom.parse(target.ownerDocument); }
|
||||
if (type && target && target.nodeType == Node.DOCUMENT_FRAGMENT_NODE && (target as ShadowRoot).host) { dom.parse(target as ShadowRoot); }
|
||||
switch (type) {
|
||||
case Constant.Attributes:
|
||||
processNode(target, Source.Attributes);
|
||||
processNode(target, Source.Attributes, record.time);
|
||||
break;
|
||||
case Constant.CharacterData:
|
||||
processNode(target, Source.CharacterData);
|
||||
processNode(target, Source.CharacterData, record.time);
|
||||
break;
|
||||
case Constant.ChildList:
|
||||
processNodeList(mutation.addedNodes, Source.ChildListAdd, timer);
|
||||
processNodeList(mutation.removedNodes, Source.ChildListRemove, timer);
|
||||
processNodeList(mutation.addedNodes, Source.ChildListAdd, timer, record.time);
|
||||
processNodeList(mutation.removedNodes, Source.ChildListRemove, timer, record.time);
|
||||
break;
|
||||
case Constant.Suspend:
|
||||
let value = dom.get(target);
|
||||
@@ -156,7 +156,7 @@ async function process(): Promise<void> {
|
||||
task.stop(timer);
|
||||
}
|
||||
|
||||
function track(m: MutationRecord, timer: Timer, instance: number): string {
|
||||
function track(m: MutationRecord, timer: Timer, instance: number, timestamp: number): string {
|
||||
let value = m.target ? dom.get(m.target.parentNode) : null;
|
||||
// Check if the parent is already discovered and that the parent is not the document root
|
||||
if (value && value.data.tag !== Constant.HTML) {
|
||||
@@ -172,7 +172,7 @@ function track(m: MutationRecord, timer: Timer, instance: number): string {
|
||||
history[key] = key in history ? history[key] : [0, instance];
|
||||
let h = history[key];
|
||||
// Lookup any pending nodes queued up for removal, and process them now if we suspended a mutation before
|
||||
if (inactive === false && h[0] >= Setting.MutationSuspendThreshold) { processNodeList(h[2], Source.ChildListRemove, timer); }
|
||||
if (inactive === false && h[0] >= Setting.MutationSuspendThreshold) { processNodeList(h[2], Source.ChildListRemove, timer, timestamp); }
|
||||
// Update the counter
|
||||
h[0] = inactive ? (h[1] === instance ? h[0] : h[0] + 1) : 1;
|
||||
h[1] = instance;
|
||||
@@ -195,16 +195,16 @@ function names(nodes: NodeList): string {
|
||||
return output.join();
|
||||
}
|
||||
|
||||
async function processNodeList(list: NodeList, source: Source, timer: Timer): Promise<void> {
|
||||
async function processNodeList(list: NodeList, source: Source, timer: Timer, timestamp: number): Promise<void> {
|
||||
let length = list ? list.length : 0;
|
||||
for (let i = 0; i < length; i++) {
|
||||
if (source === Source.ChildListAdd) {
|
||||
traverse(list[i], timer, source);
|
||||
traverse(list[i], timer, source, timestamp);
|
||||
} else {
|
||||
let state = task.state(timer);
|
||||
if (state === Task.Wait) { state = await task.suspend(timer); }
|
||||
if (state === Task.Stop) { break; }
|
||||
processNode(list[i], source);
|
||||
processNode(list[i], source, timestamp);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -12,7 +12,7 @@ import { electron } from "@src/data/metadata";
|
||||
const IGNORE_ATTRIBUTES = ["title", "alt", "onload", "onfocus", "onerror", "data-drupal-form-submit-last"];
|
||||
const newlineRegex = /[\r\n]+/g;
|
||||
|
||||
export default function (node: Node, source: Source): Node {
|
||||
export default function (node: Node, source: Source, timestamp: number): Node {
|
||||
let child: Node = null;
|
||||
|
||||
// Do not track this change if we are attempting to remove a node before discovering it
|
||||
@@ -43,7 +43,7 @@ export default function (node: Node, source: Source): Node {
|
||||
// We check for regions in the beginning when discovering document and
|
||||
// later whenever there are new additions or modifications to DOM (mutations)
|
||||
if (node === document) dom.parse(document);
|
||||
checkDocumentStyles(node as Document);
|
||||
checkDocumentStyles(node as Document, timestamp);
|
||||
observe(node);
|
||||
break;
|
||||
case Node.DOCUMENT_FRAGMENT_NODE:
|
||||
@@ -67,7 +67,7 @@ export default function (node: Node, source: Source): Node {
|
||||
// the same way we observe real shadow DOM nodes (encapsulation provided by the browser).
|
||||
dom[call](node, shadowRoot.host, { tag: Constant.PolyfillShadowDomTag, attributes: {} }, source);
|
||||
}
|
||||
checkDocumentStyles(node as Document);
|
||||
checkDocumentStyles(node as Document, timestamp);
|
||||
}
|
||||
break;
|
||||
case Node.TEXT_NODE:
|
||||
|
||||
@@ -14,6 +14,7 @@ let replaceSync: (text?: string) => void = null;
|
||||
const styleSheetId = 'claritySheetId';
|
||||
const styleSheetPageNum = 'claritySheetNum';
|
||||
let styleSheetMap = {};
|
||||
let styleTimeMap: {[key: string]: number} = {};
|
||||
|
||||
export function start(): void {
|
||||
reset();
|
||||
@@ -56,7 +57,8 @@ function bootStrapStyleSheet(styleSheet: CSSStyleSheet): void {
|
||||
}
|
||||
}
|
||||
|
||||
export function checkDocumentStyles(documentNode: Document): void {
|
||||
export function checkDocumentStyles(documentNode: Document, timestamp: number): void {
|
||||
timestamp = timestamp || time();
|
||||
if (!documentNode?.adoptedStyleSheets) {
|
||||
// if we don't have adoptedStyledSheets on the Node passed to us, we can short circuit.
|
||||
return;
|
||||
@@ -69,8 +71,8 @@ export function checkDocumentStyles(documentNode: Document): void {
|
||||
if (styleSheet[styleSheetPageNum] !== pageNum) {
|
||||
styleSheet[styleSheetPageNum] = pageNum;
|
||||
styleSheet[styleSheetId] = shortid();
|
||||
trackStyleChange(time(), styleSheet[styleSheetId], StyleSheetOperation.Create);
|
||||
trackStyleChange(time(), styleSheet[styleSheetId], StyleSheetOperation.ReplaceSync, getCssRules(styleSheet));
|
||||
trackStyleChange(timestamp, styleSheet[styleSheetId], StyleSheetOperation.Create);
|
||||
trackStyleChange(timestamp, styleSheet[styleSheetId], StyleSheetOperation.ReplaceSync, getCssRules(styleSheet));
|
||||
}
|
||||
currentStyleSheets.push(styleSheet[styleSheetId]);
|
||||
}
|
||||
@@ -81,14 +83,16 @@ export function checkDocumentStyles(documentNode: Document): void {
|
||||
}
|
||||
if (!arraysEqual(currentStyleSheets, styleSheetMap[documentId])) {
|
||||
// Using -1 to signify the root document node as we don't track that as part of our nodeMap
|
||||
trackStyleAdoption(time(), documentNode == document ? -1 : getId(documentNode), StyleSheetOperation.SetAdoptedStyles, currentStyleSheets);
|
||||
trackStyleAdoption(timestamp, documentNode == document ? -1 : getId(documentNode), StyleSheetOperation.SetAdoptedStyles, currentStyleSheets);
|
||||
styleSheetMap[documentId] = currentStyleSheets;
|
||||
styleTimeMap[documentId] = timestamp;
|
||||
}
|
||||
}
|
||||
|
||||
export function compute(): void {
|
||||
checkDocumentStyles(document);
|
||||
Object.keys(styleSheetMap).forEach((x) => checkDocumentStyles(getNode(parseInt(x, 10)) as Document));
|
||||
let ts = -1 in styleTimeMap ? styleTimeMap[-1] : null;
|
||||
checkDocumentStyles(document, ts);
|
||||
Object.keys(styleSheetMap).forEach((x) => checkDocumentStyles(getNode(parseInt(x, 10)) as Document, styleTimeMap[x]));
|
||||
}
|
||||
|
||||
export function reset(): void {
|
||||
@@ -97,6 +101,7 @@ export function reset(): void {
|
||||
|
||||
export function stop(): void {
|
||||
styleSheetMap = {};
|
||||
styleTimeMap = {};
|
||||
reset();
|
||||
}
|
||||
|
||||
|
||||
@@ -3,7 +3,7 @@ import { Source } from "@clarity-types/layout";
|
||||
import * as task from "@src/core/task";
|
||||
import node from "@src/layout/node";
|
||||
|
||||
export default async function(root: Node, timer: Timer, source: Source): Promise<void> {
|
||||
export default async function(root: Node, timer: Timer, source: Source, timestamp: number): Promise<void> {
|
||||
let queue = [root];
|
||||
while (queue.length > 0) {
|
||||
let entry = queue.shift();
|
||||
@@ -22,7 +22,7 @@ export default async function(root: Node, timer: Timer, source: Source): Promise
|
||||
// Check if processing a node gives us a pointer to one of its sub nodes for traversal
|
||||
// E.g. an element node may give us a pointer to traverse shadowDom if shadowRoot property is set
|
||||
// Or, an iframe from the same origin could give a pointer to it's document for traversing contents of iframe.
|
||||
let subnode = node(entry, source);
|
||||
let subnode = node(entry, source, timestamp);
|
||||
if (subnode) { queue.push(subnode); }
|
||||
}
|
||||
}
|
||||
@@ -185,6 +185,7 @@ export class Visualizer implements VisualizerType {
|
||||
case Data.Event.StyleSheetAdoption:
|
||||
case Data.Event.StyleSheetUpdate:
|
||||
this.layout.styleChange(entry as Layout.StyleSheetEvent);
|
||||
break;
|
||||
case Data.Event.Animation:
|
||||
this.layout.animateChange(entry as Layout.AnimationEvent);
|
||||
break;
|
||||
|
||||
Reference in New Issue
Block a user