Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
108 changes: 106 additions & 2 deletions src/models/Monkey.js
Original file line number Diff line number Diff line change
Expand Up @@ -157,6 +157,8 @@ class Monkey {
'style'
)

this._applyOnShadowRoots(configuration, sum)

// Apply the text commands on the title element
this.addUndo(configuration.apply(this.scope.document, 'title', 'text'))

Expand All @@ -174,9 +176,10 @@ class Monkey {
})
}

_applyOnXpathGroup(configuration, xpath, groupName, key) {
_applyOnXpathGroup(configuration, xpath, groupName, key, contextNode) {
let text, i
const texts = this.scope.document.evaluate(xpath, this.scope.document, null, 6, null)
const ctx = contextNode || this.scope.document
const texts = this.scope.document.evaluate(xpath, ctx, null, 6, null)
for (i = 0; (text = texts.snapshotItem(i)) !== null; i += 1) {
this.addUndo(configuration.apply(text, key, groupName))
}
Expand Down Expand Up @@ -309,6 +312,107 @@ class Monkey {
this.addUndo(undos)
}

_collectOpenShadowRoots(root) {
const shadowRoots = []

// Prefer a TreeWalker-based traversal to avoid materializing a full NodeList
const ownerDocument = root.ownerDocument || root

if (ownerDocument && typeof ownerDocument.createTreeWalker === 'function') {
const walker = ownerDocument.createTreeWalker(root, NodeFilter.SHOW_ELEMENT, null, false)

let current = walker.currentNode
while (current) {
const el = current
if (el.shadowRoot && el.id !== 'dm-live-editor-host') {
Comment on lines +319 to +327
shadowRoots.push(el.shadowRoot)
shadowRoots.push(...this._collectOpenShadowRoots(el.shadowRoot))
}
current = walker.nextNode()
}

return shadowRoots
}

// Fallback for environments without TreeWalker support
Comment on lines +315 to +337
let elements

// Guard against invalid roots that do not support querySelectorAll
if (!root || typeof root.querySelectorAll !== 'function') {
if (logger && typeof logger.warn === 'function') {
logger.warn(
'Monkey._collectOpenShadowRoots: root does not support querySelectorAll; skipping shadow root collection.'
)
}
return shadowRoots
}

try {
elements = root.querySelectorAll('*')
} catch (e) {
Comment thread
svrnm marked this conversation as resolved.
if (logger && typeof logger.warn === 'function') {
logger.warn(
'Monkey._collectOpenShadowRoots: error while querying elements from root; skipping shadow root collection.',
e
)
}
return shadowRoots
}
Comment thread
svrnm marked this conversation as resolved.

for (const el of elements) {
if (el.shadowRoot && el.id !== 'dm-live-editor-host') {
shadowRoots.push(el.shadowRoot)
shadowRoots.push(...this._collectOpenShadowRoots(el.shadowRoot))
}
}
return shadowRoots
}

_applyOnShadowRoots(configuration, sum) {
const shadowRoots = this._collectOpenShadowRoots(this.scope.document)
for (const shadowRoot of shadowRoots) {
Comment on lines +364 to +373
sum.text += this._applyOnXpathGroup(
configuration,
'.//text()[ normalize-space(.) != ""]',
'text',
'data',
shadowRoot
)
configuration.getTextAttributes().forEach((attribute) => {
sum.text += this._applyOnXpathGroup(
configuration,
`.//*[@${attribute}]`,
'text',
attribute,
shadowRoot
)
})
sum.input += this._applyOnXpathGroup(configuration, './/input', 'input', 'value', shadowRoot)
sum.input += this._applyOnXpathGroup(
configuration,
'.//textarea',
'input',
'value',
shadowRoot
)
sum.image += this._applyOnXpathGroup(configuration, './/img', 'image', 'src', shadowRoot)
sum.image += this._applyOnXpathGroup(
configuration,
'.//div[contains(@ad-test-id, "dash-image-widget-renderer")]',
'image',
'style.backgroundImage',
shadowRoot
)
sum.image += this._applyOnXpathGroup(
configuration,
'.//dash-kit-image-widget2/div/ui-kit-card-v1/div/div/div',
'image',
'style.backgroundImage',
shadowRoot
)
}
Comment on lines +390 to +413

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@copilot apply changes based on this feedback

}

run(configuration) {
this.scope.setTimeout(() => {
this.applyOnce(configuration)
Expand Down
Loading
Loading