Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

2.0.2 #99

Merged
merged 4 commits into from
Jan 24, 2024
Merged
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
2 changes: 1 addition & 1 deletion src/cypress/e2e/searchreplace.cy.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ describe('Search Replace ', () => {
})
const hidden = copy.clonedElementRemoved.querySelectorAll('.hidden')
expect(hidden.length).to.equal(0)
expect(copy.clonedElementRemoved.children.length).to.be.eq(1)
expect(copy.clonedElementRemoved.children.length).to.be.eq(2)
})
})

Expand Down
15 changes: 6 additions & 9 deletions src/elements.ts
Original file line number Diff line number Diff line change
Expand Up @@ -58,17 +58,14 @@ export function isHidden(element: HTMLElement | Element, cloned = false) {

// clones are not visible so we can't use checkVisibility
if (!cloned && 'checkVisibility' in element && typeof element.checkVisibility === 'function') {
if (element.classList.contains('interface-complementary-area-header__small-title')) {
}
// use the relatively new checkVisibility method, which returns `true` if the element is visible
return !element.checkVisibility()
}

// This method is not as accurate as checkVisibility
// compute the style as its not immediately obvious if the element is hidden
const computedStyle = getComputedStyle(element)
if (element.classList.contains('interface-complementary-area-header__small-title')) {
}

if (computedStyle.display === 'none') {
return true
}
Expand Down Expand Up @@ -112,8 +109,8 @@ export function copyElementAndRemoveSelectedElements(
function removeSelectedElements(element: HTMLElement) {
if (element) {
const childNodes = <HTMLElement[]>Array.from(element.children)
// eslint-disable-next-line prefer-const
for (let [childIndex, child] of childNodes.entries()) {

for (const child of childNodes) {
if (child.isEqualNode(element)) {
continue
}
Expand All @@ -127,9 +124,9 @@ export function copyElementAndRemoveSelectedElements(
}
} else {
// Recursively process visible child elements
child = removeSelectedElements(child as HTMLElement)
if (element.children[childIndex] && !child.isEqualNode(element.children[childIndex])) {
element.replaceChild(child, element.children[childIndex])
const newChild = removeSelectedElements(child as HTMLElement)
if (element.contains(child) && !newChild.isEqualNode(child)) {
element.replaceChild(newChild, child)
}
}
}
Expand Down
23 changes: 16 additions & 7 deletions src/searchreplace.ts
Original file line number Diff line number Diff line change
Expand Up @@ -124,10 +124,14 @@ function containsAncestor(element: Element, results: Map<Element, SearchReplaceR
}

function countOccurrences(el: HTMLElement, config: SearchReplaceConfig): number {
let matches = el[config.searchTarget].match(config.globalSearchPattern) || []
let target = el[config.searchTarget]

if (config.hiddenContent && config.searchTarget === 'innerText' && 'textContent' in el) {
matches = (el as HTMLElement).textContent?.match(config.globalSearchPattern) || []
// textContent contains text of visible and hidden elements
target = (el as HTMLElement).textContent
}

const matches = target.match(config.globalSearchPattern) || []
return matches.length
}

Expand Down Expand Up @@ -178,18 +182,21 @@ function getElementFromNode(node: Node): Element {

function isIgnored(ignoredElements: Set<Element>, node: Node, hiddenContent: boolean, elementFilter: RegExp): number {
const toCheck = getElementFromNode(node)
// if a script or an iframe that is not a blob iframe, reject
if (toCheck.tagName.match(elementFilter) && !isBlobIframe(toCheck)) {
return NodeFilter.FILTER_REJECT
}

// if an ignored element, reject
if (ignoredElements.has(toCheck)) {
return NodeFilter.FILTER_REJECT
}

// if the equivalent of an ignored element (e.g. ignored are clones), reject
if (equivalentInIgnoredElements(ignoredElements, toCheck)) {
return NodeFilter.FILTER_REJECT
}

// if we're not checking hidden content and the element is hidden, reject
if (!hiddenContent) {
if (!elementIsVisible(toCheck as HTMLElement)) {
return NodeFilter.FILTER_REJECT
Expand Down Expand Up @@ -396,6 +403,7 @@ function equivalentInIgnoredElements(ignoredElements: Set<Element>, element: Ele
return true
}
}

return false
}

Expand All @@ -407,7 +415,6 @@ function replaceInHTML(
elementsChecked: Map<Element, SearchReplaceResult>
): ReplaceFunctionReturnType {
for (const [originalIndex, originalElement] of originalElements.entries()) {
let ignoredElements = new Set<Element>()
let clonedElement = originalElement.cloneNode(true) as HTMLElement

const { clonedElementRemoved, removedSet } = copyElementAndRemoveSelectedElements(
Expand All @@ -417,13 +424,16 @@ function replaceInHTML(
false
)
clonedElement = clonedElementRemoved as HTMLElement
ignoredElements = removedSet
let ignoredElements = removedSet
if (!config.hiddenContent) {
// We have to check the visibility of the original elements as the cloned ones are all invisible
if (!elementIsVisible(originalElements[originalIndex])) {
continue
}
ignoredElements = new Set([...ignoredElements, ...getHiddenElements(originalElement, config)])
ignoredElements = new Set([
...ignoredElements,
...(getHiddenElements(originalElement, config) as Set<HTMLElement>),
])
// the above works if an ancestor of the element is hidden, but not if the element contains descendants that
// are hidden. To check for this, we need to check the relatives of the element to see if they are hidden
// and if so, create a copy of the element with the hidden elements removed, storing a map of the hidden
Expand Down Expand Up @@ -519,7 +529,6 @@ export async function searchReplace(
usesKnockout: usesKnockout(window.document),
searchTarget,
}
console.log('Search replace config', config)

// we check other places if text was not replaced in a text editor
let result: ReplaceFunctionReturnType
Expand Down
7 changes: 4 additions & 3 deletions tests/test.html
Original file line number Diff line number Diff line change
Expand Up @@ -48,16 +48,17 @@ <h2>7 Hidden Nested Div</h2>
<div class="hidden">This is a test!!! ¹² - hidden</div>
</div>
</div>
<script type="text/javascript">
console.log("This is a test!!! ¹²")
</script>
<div>
<h2>8 Plain old div</h2>
<div>This is a test!!! ¹²</div>
</div>
<iframe src="iframe.html"></iframe>
<script type="text/javascript">
console.log("This is a test!!! ¹²")
</script>
</div>
<div style="display: none;" class="hidden">Hidden Sibling</div>
<style></style>
<div style="display: none;">
<div>
<div class="hidden">Hidden Nested Sibling</div>
Expand Down
4 changes: 2 additions & 2 deletions webpack/webpack.prod.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,12 @@ const TerserPlugin = require('terser-webpack-plugin')
module.exports = merge(common, {
mode: 'production',
optimization: {
minimize: false,
minimize: true,
minimizer: [
new TerserPlugin({
terserOptions: {
compress: {
drop_console: false,
drop_console: true,
},
},
}),
Expand Down
Loading