Add support for StylesheetRule in document fragment (#293)
* add failing test * add stylesheet to dom to manipulate the rules * cleanup
This commit is contained in:
@@ -746,6 +746,22 @@ export class Replayer {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const styleEl = (target as Node) as HTMLStyleElement;
|
const styleEl = (target as Node) as HTMLStyleElement;
|
||||||
|
const parent = ((target.parentNode as unknown) as INode);
|
||||||
|
const usingVirtualParent = this.fragmentParentMap.has(parent);
|
||||||
|
let placeholderNode;
|
||||||
|
|
||||||
|
if (usingVirtualParent) {
|
||||||
|
/**
|
||||||
|
* styleEl.sheet is only accessible if the styleEl is part of the
|
||||||
|
* dom. This doesn't work on DocumentFragments so we have to re-add
|
||||||
|
* it to the dom temporarily.
|
||||||
|
*/
|
||||||
|
const domParent = this.fragmentParentMap.get((target.parentNode as unknown) as INode);
|
||||||
|
placeholderNode = document.createTextNode('');
|
||||||
|
parent.replaceChild(placeholderNode, target);
|
||||||
|
domParent!.appendChild(target);
|
||||||
|
}
|
||||||
|
|
||||||
const styleSheet = <CSSStyleSheet>styleEl.sheet;
|
const styleSheet = <CSSStyleSheet>styleEl.sheet;
|
||||||
|
|
||||||
if (d.adds) {
|
if (d.adds) {
|
||||||
@@ -776,6 +792,11 @@ export class Replayer {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (usingVirtualParent && placeholderNode) {
|
||||||
|
parent.replaceChild(target, placeholderNode);
|
||||||
|
}
|
||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case IncrementalSource.CanvasMutation: {
|
case IncrementalSource.CanvasMutation: {
|
||||||
|
|||||||
94
test/events/style-sheet-rule-events.ts
Normal file
94
test/events/style-sheet-rule-events.ts
Normal file
@@ -0,0 +1,94 @@
|
|||||||
|
import {
|
||||||
|
EventType,
|
||||||
|
eventWithTime,
|
||||||
|
IncrementalSource
|
||||||
|
} from '../../src/types';
|
||||||
|
|
||||||
|
const now = Date.now();
|
||||||
|
const events: eventWithTime[] = [
|
||||||
|
{
|
||||||
|
type: EventType.DomContentLoaded,
|
||||||
|
data: {},
|
||||||
|
timestamp: now,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: EventType.Load,
|
||||||
|
data: {},
|
||||||
|
timestamp: now + 100,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: EventType.Meta,
|
||||||
|
data: {
|
||||||
|
href: 'http://localhost',
|
||||||
|
width: 1000,
|
||||||
|
height: 800,
|
||||||
|
},
|
||||||
|
timestamp: now + 100,
|
||||||
|
},
|
||||||
|
// full snapshot:
|
||||||
|
{
|
||||||
|
"data": {
|
||||||
|
"node": {
|
||||||
|
"id": 1, "type": 0, "childNodes": [{ "id": 2, "name": "html", "type": 1, "publicId": "", "systemId": "" }, {
|
||||||
|
"id": 3, "type": 2, "tagName": "html", "attributes": { "lang": "en" }, "childNodes": [{
|
||||||
|
"id": 4, "type": 2, "tagName": "head", "attributes": {}, "childNodes": [
|
||||||
|
{
|
||||||
|
"id": 101, "type": 2, "tagName": "style", "attributes": { "data-jss": "", "data-meta": "sk, Unthemed, Static" }, "childNodes": [{ "id": 102, "type": 3, "isStyle": true, "textContent": "\n.c01x {\n opacity: 1;\n transform: translateX(0);\n}\n" }]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": 105, "type": 2, "tagName": "style", "attributes":
|
||||||
|
{ "_cssText": ".css-1uxxxx3 { position: fixed; top: 0px; right: 0px; left: 4rem; z-index: 15; flex-shrink: 0; height: 0.25rem; overflow: hidden; background-color: rgb(17, 171, 209); }.css-1c9xxxx { height: 0.25rem; background-color: rgb(190, 232, 242); opacity: 0; transition: opacity 0.5s ease 0s; }.css-lsxxx { padding-left: 4rem; }", "data-emotion": "css" }, "childNodes": [{ "id": 106, "type": 3, "isStyle": true, "textContent": "" }]
|
||||||
|
}]
|
||||||
|
}, {
|
||||||
|
"id": 107, "type": 2, "tagName": "body", "attributes": {}, "childNodes": []
|
||||||
|
}]
|
||||||
|
}]
|
||||||
|
}, "initialOffset": { "top": 0, "left": 0 }
|
||||||
|
},
|
||||||
|
"type": EventType.FullSnapshot,
|
||||||
|
"timestamp": now + 100
|
||||||
|
},
|
||||||
|
// mutation that adds stylesheet
|
||||||
|
{
|
||||||
|
"data": {
|
||||||
|
"adds": [
|
||||||
|
{
|
||||||
|
"node": {
|
||||||
|
"id": 255, "type": 2, "tagName": "style", "attributes": { "data-jss": "", "data-meta": "Col, Themed, Dynamic" }, "childNodes": []
|
||||||
|
},
|
||||||
|
"nextId": 101,
|
||||||
|
"parentId": 4
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"node": {
|
||||||
|
"id": 256, "type": 3, "isStyle": true, "textContent": "\n.c011xx {\n padding: 1.3125rem;\n flex: none;\n width: 100%;\n}\n"
|
||||||
|
},
|
||||||
|
"nextId": null,
|
||||||
|
"parentId": 255
|
||||||
|
},
|
||||||
|
],
|
||||||
|
"texts": [],
|
||||||
|
"source": IncrementalSource.Mutation,
|
||||||
|
"removes": [],
|
||||||
|
"attributes": []
|
||||||
|
},
|
||||||
|
"type": EventType.IncrementalSnapshot,
|
||||||
|
"timestamp": now + 500
|
||||||
|
},
|
||||||
|
// adds StyleSheetRule
|
||||||
|
{
|
||||||
|
"data": {
|
||||||
|
"id": 105, "adds": [
|
||||||
|
{
|
||||||
|
"rule": ".css-1fbxx79{display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;-webkit-flex-direction:column;-ms-flex-direction:column;flex-direction:column;min-width:60rem;min-height:100vh;}",
|
||||||
|
"index": 2
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"source": IncrementalSource.StyleSheetRule
|
||||||
|
},
|
||||||
|
"type": EventType.IncrementalSnapshot,
|
||||||
|
"timestamp": now + 1000
|
||||||
|
}
|
||||||
|
];
|
||||||
|
|
||||||
|
export default events;
|
||||||
@@ -10,6 +10,7 @@ import {
|
|||||||
sampleEvents as events,
|
sampleEvents as events,
|
||||||
sampleStyleSheetRemoveEvents as stylesheetRemoveEvents
|
sampleStyleSheetRemoveEvents as stylesheetRemoveEvents
|
||||||
} from './utils';
|
} from './utils';
|
||||||
|
import styleSheetRuleEvents from './events/style-sheet-rule-events';
|
||||||
|
|
||||||
interface ISuite extends Suite {
|
interface ISuite extends Suite {
|
||||||
code: string;
|
code: string;
|
||||||
@@ -135,6 +136,19 @@ describe('replayer', function (this: ISuite) {
|
|||||||
expect(currentState).to.equal('paused');
|
expect(currentState).to.equal('paused');
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('can fast forward past StyleSheetRule changes on virtual elements', async () => {
|
||||||
|
await this.page.evaluate(`events = ${JSON.stringify(styleSheetRuleEvents)}`);
|
||||||
|
const actionLength = await this.page.evaluate(`
|
||||||
|
const { Replayer } = rrweb;
|
||||||
|
const replayer = new Replayer(events);
|
||||||
|
replayer.play(1500);
|
||||||
|
replayer['timer']['actions'].length;
|
||||||
|
`);
|
||||||
|
expect(actionLength).to.equal(
|
||||||
|
styleSheetRuleEvents.filter((e) => e.timestamp - styleSheetRuleEvents[0].timestamp >= 1500).length,
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
it('can handle removing style elements', async () => {
|
it('can handle removing style elements', async () => {
|
||||||
await this.page.evaluate(`events = ${JSON.stringify(stylesheetRemoveEvents)}`);
|
await this.page.evaluate(`events = ${JSON.stringify(stylesheetRemoveEvents)}`);
|
||||||
const actionLength = await this.page.evaluate(`
|
const actionLength = await this.page.evaluate(`
|
||||||
|
|||||||
Reference in New Issue
Block a user