fix(player): fix and centralize CSS pseudoclasses rewriting
This commit is contained in:
parent
f65487ca17
commit
e2c4e048ea
9 changed files with 44 additions and 49 deletions
|
|
@ -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()
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
})
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
})
|
||||
|
|
|
|||
2
frontend/app/player/web/messages/rewriter/constants.ts
Normal file
2
frontend/app/player/web/messages/rewriter/constants.ts
Normal file
|
|
@ -0,0 +1,2 @@
|
|||
export const HOVER_CLASSNAME = "-openreplay-hover"
|
||||
export const FOCUS_CLASSNAME = "-openreplay-focus"
|
||||
|
|
@ -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
|
||||
}
|
||||
Loading…
Add table
Reference in a new issue