Skip to content

Commit

Permalink
Only require specification of case sensitivity when diffing inside of…
Browse files Browse the repository at this point in the history
… SVGs
  • Loading branch information
johanneswilm committed Nov 3, 2023
1 parent d007c7b commit fef8e0a
Show file tree
Hide file tree
Showing 5 changed files with 70 additions and 11 deletions.
2 changes: 2 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -220,3 +220,5 @@ dd = new diffDOM.DiffDOM({
caseSensitive: true,
})
```

**NOTE!** If there is an SVG inside of the HTML in the string, diffDOM can automatically determine that it should switch to case sensitivity. It is only if the diff happens entirely within an SVG that it is required to specify this.
2 changes: 1 addition & 1 deletion browser/diffDOM.js

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion browser/diffDOM.js.map

Large diffs are not rendered by default.

12 changes: 9 additions & 3 deletions src/diffDOM/virtual/fromString.ts
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ const parseTag = (tag: string, caseSensitive: boolean) => {

let tagMatch = tag.match(/<\/?([^\s]+?)[/\s>]/)
if (tagMatch) {
res.nodeName = caseSensitive ? tagMatch[1] : tagMatch[1].toUpperCase()
res.nodeName = (caseSensitive || tagMatch[1] === "svg") ? tagMatch[1] : tagMatch[1].toUpperCase()
if (lookup[tagMatch[1]] || tag.charAt(tag.length - 2) === "/") {
voidElement = true
}
Expand Down Expand Up @@ -103,7 +103,7 @@ export const stringToObj = (
let current: { type: string; node: nodeType; voidElement: boolean }
let level = -1
const arr: { type: string; node: nodeType; voidElement: boolean }[] = []
let inComponent = false
let inComponent = false, insideSvg = false

// handle text at top level
if (html.indexOf("<") !== 0) {
Expand Down Expand Up @@ -146,7 +146,10 @@ export const stringToObj = (
}

if (isOpen) {
current = parseTag(tag, options.caseSensitive)
current = parseTag(tag, options.caseSensitive || insideSvg)
if (current.node.nodeName==="svg") {
insideSvg = true
}
level++
if (
!current.voidElement &&
Expand Down Expand Up @@ -197,6 +200,9 @@ export const stringToObj = (
level--
// move current up a level to match the end tag
if (level > -1) {
if (current.node.nodeName==="svg") {
insideSvg = false
}
current = arr[level]
}
}
Expand Down
63 changes: 57 additions & 6 deletions tests/xmlString.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@

import { DiffDOM, nodeToObj, stringToObj } from "../dist/index"

const strings = [
const stringsIncludingSVGs = [
`<svg height=50 width=50>
<defs>
<clipPath id="clipPath">
Expand Down Expand Up @@ -32,20 +32,28 @@ const strings = [
</svg>`,
]

const stringsInsideSVGs = [
`<defs><clipPath id="clipPath"><rect x="15" y="15" width="40" height="40" /></clipPath></defs>`,
`<defs></defs>`,

`<defs></defs>`,
`<defs><clipPath id="clipPath"><rect x="15" y="15" width="40" height="40" /></clipPath></defs>`,
]

describe("string", () => {
it("can diff and patch case sensitive xml strings", () => {
const dd = new DiffDOM({
debug: true,
diffcap: 500,
caseSensitive: true,
caseSensitive: false,
})

for (let i = 0; i < strings.length; i += 2) {
for (let i = 0; i < stringsIncludingSVGs.length; i += 2) {
const el1Outer = document.createElement("div")
const el2Outer = document.createElement("div")
el1Outer.innerHTML = strings[i]
el2Outer.innerHTML = strings[i + 1]
const diffs = dd.diff(strings[i], strings[i + 1])
el1Outer.innerHTML = stringsIncludingSVGs[i]
el2Outer.innerHTML = stringsIncludingSVGs[i + 1]
const diffs = dd.diff(stringsIncludingSVGs[i], stringsIncludingSVGs[i + 1])
expect(diffs).not.toHaveLength(0)
const el1 = el1Outer.firstElementChild
const el2 = el2Outer.firstElementChild
Expand All @@ -59,5 +67,48 @@ describe("string", () => {
el1a.innerHTML
).toEqual(el1.innerHTML)
}

const ddCaseSensitive = new DiffDOM({
debug: true,
diffcap: 500,
caseSensitive: true,
})

for (let i = 0; i < stringsInsideSVGs.length; i += 2) {
const el1Outer = document.createElementNS('http://www.w3.org/2000/svg', 'svg')
const el2Outer = document.createElementNS('http://www.w3.org/2000/svg', 'svg')
el1Outer.innerHTML = stringsInsideSVGs[i]
el2Outer.innerHTML = stringsInsideSVGs[i + 1]
const diffsCaseSensitive = ddCaseSensitive.diff(stringsInsideSVGs[i], stringsInsideSVGs[i + 1])
const diffs = dd.diff(stringsInsideSVGs[i], stringsInsideSVGs[i + 1])
expect(diffsCaseSensitive).not.toHaveLength(0)
expect(diffs).not.toHaveLength(0)
const el1 = el1Outer.firstElementChild
const el2 = el2Outer.firstElementChild
const el1a = el1.cloneNode(true)
const el1b = el1.cloneNode(true)
ddCaseSensitive.apply(el1a, diffsCaseSensitive)
expect(
el1a.innerHTML
).toEqual(el2.innerHTML)
// Trying to do the same without case sensitivity should not work.
dd.apply(el1b, diffs)
if (el1b.innerHTML.length || el2.innerHTML.length) {
expect(
el1b.innerHTML
).not.toEqual(el2.innerHTML)
}
ddCaseSensitive.undo(el1a, diffsCaseSensitive)
expect(
el1a.innerHTML
).toEqual(el1.innerHTML)
// Trying to do the same without case sensitivity should not work.
dd.undo(el1b, diffs)
if (el1b.innerHTML.length || el1.innerHTML.length) {
expect(
el1b.innerHTML
).not.toEqual(el1.innerHTML)
}
}
})
})

0 comments on commit fef8e0a

Please sign in to comment.