feat(tracker): StyleSheet rules messages unifyied for Constructed and style-tag based cases

This commit is contained in:
Alex Kaminskii 2022-09-14 13:08:46 +02:00
parent 23240536b7
commit c29c29ab7c
6 changed files with 85 additions and 56 deletions

View file

@ -265,6 +265,8 @@ export default class DOMManager extends ListWalker<Message> {
vn.applyChanges()
}
return
// @depricated since 4.0.2 in favor of adopted_ss_insert/delete_rule + add_owner as being common case for StyleSheets
case "css_insert_rule":
vn = this.vElements.get(msg.id)
if (!vn) { logger.error("Node not found", msg); return }
@ -283,6 +285,8 @@ export default class DOMManager extends ListWalker<Message> {
}
vn.onStyleSheet(sheet => deleteRule(sheet, msg))
return
// end @depricated
case "create_i_frame_document":
vn = this.vElements.get(msg.frameID)
if (!vn) { logger.error("Node not found", msg); return }
@ -326,18 +330,7 @@ export default class DOMManager extends ListWalker<Message> {
}
deleteRule(styleSheet, msg)
return
case "replace_vcss":
styleSheet = this.styleSheets.get(msg.sheetID)
if (!styleSheet) {
logger.warn("No stylesheet was created for ", msg)
return
}
const toRemove = styleSheet.cssRules.length
for (let i = 0; i < toRemove; i++) {
styleSheet.deleteRule(i)
}
styleSheet.insertRule(msg.styles)
return
case "adopted_ss_replace":
styleSheet = this.styleSheets.get(msg.sheetID)
if (!styleSheet) {
@ -349,7 +342,14 @@ export default class DOMManager extends ListWalker<Message> {
return
case "adopted_ss_add_owner":
vn = this.vRoots.get(msg.id)
if (!vn) { logger.error("Node not found", msg); return }
if (!vn) {
// non-constructed case
vn = this.vElements.get(msg.id)
if (!vn) { logger.error("Node not found", msg); return }
if (!(vn instanceof VStyleElement)) { logger.error("Non-style owner", msg); return }
this.styleSheets.set(msg.sheetID, vn.node.sheet)
return
}
styleSheet = this.styleSheets.get(msg.sheetID)
if (!styleSheet) {
let context: typeof globalThis

View file

@ -238,15 +238,18 @@ message 36, 'CustomEvent', :tracker => false, :replayer => false do
string 'Name'
string 'Payload'
end
# depricated since 4.0.2 in favor of AdoptedSSInsertRule + AdoptedSSAddOwner
message 37, 'CSSInsertRule' do
uint 'ID'
string 'Rule'
uint 'Index'
end
# depricated since 4.0.2
message 38, 'CSSDeleteRule' do
uint 'ID'
uint 'Index'
end
message 39, 'Fetch' do
string 'Method'
string 'URL'
@ -421,6 +424,7 @@ message 70, 'CreateIFrameDocument' do
end
#Since 4.0.0 AdoptedStyleSheets etc
# TODO: rename to StyleSheets...
message 71, 'AdoptedSSReplaceURLBased' do
uint 'SheetID'
string 'Text'

View file

@ -291,6 +291,7 @@ export default abstract class Observer {
const width = el.clientWidth
const height = el.clientHeight
el = node.cloneNode() as Element
// TODO: use ResizeObserver
;(el as HTMLElement | SVGElement).style.width = width + 'px'
;(el as HTMLElement | SVGElement).style.height = height + 'px'
}

View file

@ -19,7 +19,7 @@ import Performance from './modules/performance.js'
import Scroll from './modules/scroll.js'
import Viewport from './modules/viewport.js'
import CSSRules from './modules/cssrules.js'
import AdoptedStyleSheets from './modules/adoptedStyleSheets.js'
import ConstructedStyleSheets from './modules/constructedStyleSheets.js'
import { IN_BROWSER, deprecationWarn, DOCS_HOST } from './utils.js'
import type { Options as AppOptions } from './app/index.js'
@ -112,7 +112,7 @@ export default class API {
if (app !== null) {
Viewport(app)
CSSRules(app)
AdoptedStyleSheets(app)
ConstructedStyleSheets(app)
Connection(app)
Console(app, options)
Exception(app, options)

View file

@ -19,6 +19,13 @@ function hasAdoptedSS(node: Node): node is StyleSheetOwner {
)
}
// TODO: incapsulate to be init-ed on-start and join with cssrules.ts under one folder
let _id = 0xf
export function nextID(): number {
return _id++
}
export const styleSheetIDMap: Map<CSSStyleSheet, number> = new Map()
export default function (app: App | null) {
if (app === null) {
return
@ -31,7 +38,6 @@ export default function (app: App | null) {
return
}
let nextID = 0xf
const styleSheetIDMap: Map<CSSStyleSheet, number> = new Map()
const adoptedStyleSheetsOwnings: Map<number, number[]> = new Map()
@ -53,7 +59,7 @@ export default function (app: App | null) {
let sheetID = styleSheetIDMap.get(s)
const init = !sheetID
if (!sheetID) {
sheetID = ++nextID
sheetID = nextID()
}
nowOwning.push(sheetID)
if (!pastOwning.includes(sheetID)) {

View file

@ -1,6 +1,12 @@
import type App from '../app/index.js'
import { CSSInsertRuleURLBased, CSSDeleteRule, TechnicalInfo } from '../app/messages.gen.js'
import {
AdoptedSSInsertRuleURLBased, // TODO: rename to common StyleSheet names
AdoptedSSDeleteRule,
AdoptedSSAddOwner,
TechnicalInfo,
} from '../app/messages.gen.js'
import { hasTag } from '../app/guards.js'
import { nextID, styleSheetIDMap } from './constructedStyleSheets.js'
export default function (app: App | null) {
if (app === null) {
@ -11,41 +17,43 @@ export default function (app: App | null) {
return
}
const processOperation = app.safe((stylesheet: CSSStyleSheet, index: number, rule?: string) => {
const sendMessage =
typeof rule === 'string'
? (nodeID: number) =>
app.send(CSSInsertRuleURLBased(nodeID, rule, index, app.getBaseHref()))
: (nodeID: number) => app.send(CSSDeleteRule(nodeID, index))
// TODO: Extend messages to maintain nested rules (CSSGroupingRule prototype, as well as CSSKeyframesRule)
if (!stylesheet.ownerNode) {
throw new Error('Owner Node not found')
}
const nodeID = app.nodes.getID(stylesheet.ownerNode)
if (nodeID !== undefined) {
sendMessage(nodeID)
} // else error?
})
const sendInserDeleteRule = app.safe(
(stylesheet: CSSStyleSheet, index: number, rule?: string) => {
const sheetID = styleSheetIDMap.get(stylesheet)
if (!sheetID) {
app.debug.warn('No sheedID found', stylesheet, styleSheetIDMap)
return
}
if (typeof rule === 'string') {
app.send(AdoptedSSInsertRuleURLBased(sheetID, rule, index, app.getBaseHref()))
} else {
app.send(AdoptedSSDeleteRule(sheetID, index))
}
},
)
const replaceGroupingRule = app.safe((ctx: CSSGroupingRule) => {
let topmostRule: CSSRule = ctx
// TODO: proper rule insertion/removal (how?)
const sendReplaceGroupingRule = app.safe((rule: CSSGroupingRule) => {
let topmostRule: CSSRule = rule
while (topmostRule.parentRule) {
topmostRule = topmostRule.parentRule
}
if (topmostRule.parentStyleSheet?.ownerNode) {
const entireStyle = topmostRule.cssText
const nodeID = app.nodes.getID(topmostRule.parentStyleSheet.ownerNode)
if (nodeID === undefined) {
return
}
const ruleList = topmostRule.parentStyleSheet.cssRules
const idx = Array.from(ruleList).indexOf(topmostRule)
if (idx >= 0) {
app.send(CSSDeleteRule(nodeID, idx))
app.send(CSSInsertRuleURLBased(nodeID, entireStyle, idx, app.getBaseHref()))
}
} else {
app.debug.error('Owner Node not found for the rule', topmostRule)
const sheet = topmostRule.parentStyleSheet
if (!sheet) {
app.debug.warn('No parent StyleSheet found for', topmostRule, rule)
return
}
const sheetID = styleSheetIDMap.get(sheet)
if (!sheetID) {
app.debug.warn('No sheedID found for', sheet, styleSheetIDMap)
return
}
const cssText = topmostRule.cssText
const ruleList = sheet.cssRules
const idx = Array.from(ruleList).indexOf(topmostRule)
if (idx >= 0) {
app.send(AdoptedSSInsertRuleURLBased(sheetID, cssText, idx, app.getBaseHref()))
app.send(AdoptedSSDeleteRule(sheetID, idx + 1)) // Remove previous clone
}
})
@ -55,22 +63,22 @@ export default function (app: App | null) {
context.CSSGroupingRule.prototype
context.CSSStyleSheet.prototype.insertRule = function (rule: string, index = 0) {
processOperation(this, index, rule)
sendInserDeleteRule(this, index, rule)
return insertRule.call(this, rule, index) as number
}
context.CSSStyleSheet.prototype.deleteRule = function (index: number) {
processOperation(this, index)
sendInserDeleteRule(this, index)
return deleteRule.call(this, index) as number
}
context.CSSGroupingRule.prototype.insertRule = function (rule: string, index = 0) {
const result = groupInsertRule.call(this, rule, index) as number
replaceGroupingRule(this)
sendReplaceGroupingRule(this)
return result
}
context.CSSGroupingRule.prototype.deleteRule = function (index = 0) {
const result = groupDeleteRule.call(this, index) as number
replaceGroupingRule(this)
sendReplaceGroupingRule(this)
return result
}
}
@ -83,11 +91,21 @@ export default function (app: App | null) {
return
}
if (node.textContent !== null && node.textContent.trim().length > 0) {
return // Only fully virtual sheets maintained so far
return // Non-virtual styles captured by the observer as a text
}
const rules = node.sheet.cssRules
const nodeID = app.nodes.getID(node)
if (!nodeID) {
return
}
const sheet = node.sheet
const sheetID = nextID()
styleSheetIDMap.set(sheet, sheetID)
app.send(AdoptedSSAddOwner(sheetID, nodeID))
const rules = sheet.cssRules
for (let i = 0; i < rules.length; i++) {
processOperation(node.sheet, i, rules[i].cssText)
sendInserDeleteRule(sheet, i, rules[i].cssText)
}
})
}