fix(player): fix and centralize CSS pseudoclasses rewriting

This commit is contained in:
Alex Kaminskii 2023-04-01 00:43:35 +02:00
parent f65487ca17
commit e2c4e048ea
9 changed files with 44 additions and 49 deletions

View file

@ -4,7 +4,7 @@ import type Screen from '../../Screen/Screen';
import type { Message, SetNodeScroll } from '../../messages';
import { MType } from '../../messages';
import ListWalker from '../../../common/ListWalker';
import StylesManager, { rewriteNodeStyleSheet } from './StylesManager';
import StylesManager from './StylesManager';
import FocusManager from './FocusManager';
import SelectionManager from './SelectionManager';
import type { StyleElement } from './VirtualDOM';
@ -289,11 +289,6 @@ export default class DOMManager extends ListWalker<Message> {
vn = this.vTexts.get(msg.id)
if (!vn) { logger.error("SetCssData: Node not found", msg); return }
vn.setData(msg.data)
if (vn.node instanceof HTMLStyleElement) {
doc = this.screen.document
// TODO: move to message parsing
doc && rewriteNodeStyleSheet(doc, vn.node)
}
if (msg.tp === MType.SetCssData) { // Styles in priority (do we need inlines as well?)
vn.applyChanges()
}

View file

@ -2,8 +2,7 @@ import logger from 'App/logger';
import type { SetNodeFocus } from '../../messages';
import type { VElement } from './VirtualDOM';
import ListWalker from '../../../common/ListWalker';
const FOCUS_CLASS = "-openreplay-focus"
import { FOCUS_CLASSNAME } from '../../messages/rewriter/constants'
export default class FocusManager extends ListWalker<SetNodeFocus> {
constructor(private readonly vElements: Map<number, VElement>) {super()}
@ -11,7 +10,7 @@ export default class FocusManager extends ListWalker<SetNodeFocus> {
move(t: number) {
const msg = this.moveGetLast(t)
if (!msg) {return}
this.focused?.classList.remove(FOCUS_CLASS)
this.focused?.classList.remove(FOCUS_CLASSNAME)
if (msg.id === -1) {
this.focused = null
return
@ -19,7 +18,7 @@ export default class FocusManager extends ListWalker<SetNodeFocus> {
const vn = this.vElements.get(msg.id)
if (!vn) { logger.error("Node not found", msg); return }
this.focused = vn.node
this.focused.classList.add(FOCUS_CLASS)
this.focused.classList.add(FOCUS_CLASSNAME)
}
}

View file

@ -1,19 +1,18 @@
import type Screen from '../../Screen/Screen';
import type { CssInsertRule, CssDeleteRule } from '../../messages';
import { replaceCSSPseudoclasses } from '../../messages/rewriter/rewriteMessage'
type CSSRuleMessage = CssInsertRule | CssDeleteRule;
const HOVER_CN = "-openreplay-hover";
const HOVER_SELECTOR = `.${HOVER_CN}`;
// Doesn't work with css files (hasOwnProperty)
export function rewriteNodeStyleSheet(doc: Document, node: HTMLLinkElement | HTMLStyleElement) {
// Doesn't work with css files (hasOwnProperty returns false)
// TODO: recheck and remove if true
function rewriteNodeStyleSheet(doc: Document, node: HTMLLinkElement | HTMLStyleElement) {
const ss = Object.values(doc.styleSheets).find(s => s.ownerNode === node);
if (!ss || !ss.hasOwnProperty('rules')) { return; }
for(let i = 0; i < ss.rules.length; i++){
const r = ss.rules[i]
if (r instanceof CSSStyleRule) {
r.selectorText = r.selectorText.replace('/\:hover/g', HOVER_SELECTOR)
r.selectorText = replaceCSSPseudoclasses(r.selectorText)
}
}
}
@ -29,7 +28,7 @@ export default class StylesManager {
this.linkLoadingCount = 0;
this.linkLoadPromises = [];
//cancel all promises? tothinkaboutit
//cancel all promises? thinkaboutit
}
setStyleHandlers(node: HTMLLinkElement, value: string): void {
@ -44,6 +43,7 @@ export default class StylesManager {
}
timeoutId = setTimeout(addSkipAndResolve, 4000);
// It would be better to make it more relyable with addEventListener
node.onload = () => {
const doc = this.screen.document;
doc && rewriteNodeStyleSheet(doc, node);

View file

@ -1,20 +1,14 @@
import type Screen from '../Screen/Screen'
import type { MouseMove } from "../messages";
import { HOVER_CLASSNAME } from '../messages/rewriter/constants'
import ListWalker from '../../common/ListWalker'
const HOVER_CLASS = "-openreplay-hover";
const HOVER_CLASS_DEPR = "-asayer-hover";
export default class MouseMoveManager extends ListWalker<MouseMove> {
private hoverElements: Array<Element> = []
constructor(private screen: Screen) {super()}
// private getCursorTarget() {
// return this.screen.getElementFromInternalPoint(this.current)
// }
private getCursorTargets() {
return this.screen.getElementsFromInternalPoint(this.current)
}
@ -25,12 +19,10 @@ export default class MouseMoveManager extends ListWalker<MouseMove> {
const diffRemove = this.hoverElements.filter(elem => !curHoverElements.includes(elem))
this.hoverElements = curHoverElements
diffAdd.forEach(elem => {
elem.classList.add(HOVER_CLASS)
elem.classList.add(HOVER_CLASS_DEPR)
elem.classList.add(HOVER_CLASSNAME)
})
diffRemove.forEach(elem => {
elem.classList.remove(HOVER_CLASS)
elem.classList.remove(HOVER_CLASS_DEPR)
elem.classList.remove(HOVER_CLASSNAME)
})
}

View file

@ -2,7 +2,7 @@ import type { RawMessage } from './raw.gen'
import type { TrackerMessage } from './tracker.gen'
import translate from './tracker.gen'
import { TP_MAP } from './tracker-legacy.gen'
import resolveURL from './urlBasedResolver'
import rewriteMessage from './rewriter/rewriteMessage'
function legacyTranslate(msg: any): RawMessage | null {
@ -30,7 +30,7 @@ export default class JSONRawMessageReader {
if (!rawMsg) {
return this.readMessage()
}
return resolveURL(rawMsg)
return rewriteMessage(rawMsg)
}
}

View file

@ -2,7 +2,7 @@ import type { Message } from './message.gen';
import type { RawMessage } from './raw.gen';
import { MType } from './raw.gen';
import RawMessageReader from './RawMessageReader.gen';
import resolveURL from './urlBasedResolver'
import rewriteMessage from './rewriter/rewriteMessage'
import Logger from 'App/logger'
// TODO: composition instead of inheritance
@ -77,7 +77,7 @@ export default class MFileReader extends RawMessageReader {
}
const index = this.getLastMessageID()
const msg = Object.assign(resolveURL(rMsg), {
const msg = Object.assign(rewriteMessage(rMsg), {
time: this.currentTime,
_index: index,
})

View file

@ -0,0 +1,2 @@
export const HOVER_CLASSNAME = "-openreplay-hover"
export const FOCUS_CLASSNAME = "-openreplay-focus"

View file

@ -10,24 +10,31 @@ import type {
RawAdoptedSsInsertRule,
RawAdoptedSsReplaceURLBased,
RawAdoptedSsReplace,
} from './raw.gen'
import { MType } from './raw.gen'
} from '../raw.gen'
import { MType } from '../raw.gen'
import { resolveURL, resolveCSS } from './urlResolve'
import { HOVER_CLASSNAME, FOCUS_CLASSNAME } from './constants'
// type PickMessage<T extends MType> = Extract<RawMessage, { tp: T }>;
// type ResolversMap = {
// [Key in MType]: (event: PickMessage<Key>) => RawMessage
// }
const HOVER_SELECTOR = `.${HOVER_CLASSNAME}`
const FOCUS_SELECTOR = `.${FOCUS_CLASSNAME}`
export function replaceCSSPseudoclasses(cssText: string): string {
return cssText
.replace('/\:hover/g', HOVER_SELECTOR)
.replace('/\:focus/g', FOCUS_SELECTOR)
}
function rewriteCSS(baseURL: string, cssText: string): string {
return replaceCSSPseudoclasses(resolveCSS(baseURL, cssText))
}
// TODO: commonURLBased logic for feilds
const resolvers = {
// TODO: common logic for URL fields in all the ...URLBased messages
const REWRITERS = {
[MType.SetNodeAttributeURLBased]: (msg: RawSetNodeAttributeURLBased): RawSetNodeAttribute =>
({
...msg,
value: msg.name === 'src' || msg.name === 'href'
? resolveURL(msg.baseURL, msg.value)
: (msg.name === 'style'
? resolveCSS(msg.baseURL, msg.value)
? rewriteCSS(msg.baseURL, msg.value)
: msg.value
),
tp: MType.SetNodeAttribute,
@ -35,35 +42,35 @@ const resolvers = {
[MType.SetCssDataURLBased]: (msg: RawSetCssDataURLBased): RawSetCssData =>
({
...msg,
data: resolveCSS(msg.baseURL, msg.data),
data: rewriteCSS(msg.baseURL, msg.data),
tp: MType.SetCssData,
}),
[MType.CssInsertRuleURLBased]: (msg: RawCssInsertRuleURLBased): RawCssInsertRule =>
({
...msg,
rule: resolveCSS(msg.baseURL, msg.rule),
rule: rewriteCSS(msg.baseURL, msg.rule),
tp: MType.CssInsertRule,
}),
[MType.AdoptedSsInsertRuleURLBased]: (msg: RawAdoptedSsInsertRuleURLBased): RawAdoptedSsInsertRule =>
({
...msg,
rule: resolveCSS(msg.baseURL, msg.rule),
rule: rewriteCSS(msg.baseURL, msg.rule),
tp: MType.AdoptedSsInsertRule,
}),
[MType.AdoptedSsReplaceURLBased]: (msg: RawAdoptedSsReplaceURLBased): RawAdoptedSsReplace =>
({
...msg,
text: resolveCSS(msg.baseURL, msg.text),
text: rewriteCSS(msg.baseURL, msg.text),
tp: MType.AdoptedSsReplace,
}),
} as const
export default function resolve(msg: RawMessage): RawMessage {
// @ts-ignore --- any idea?
if (resolvers[msg.tp]) {
export default function rewriteMessage(msg: RawMessage): RawMessage {
// @ts-ignore --- any idea for correct typing?
if (REWRITERS[msg.tp]) {
// @ts-ignore
return resolvers[msg.tp](msg)
return REWRITERS[msg.tp](msg)
}
return msg
}