Skip to content

Commit fef8e0a

Browse files
committed
Only require specification of case sensitivity when diffing inside of SVGs
1 parent d007c7b commit fef8e0a

File tree

5 files changed

+70
-11
lines changed

5 files changed

+70
-11
lines changed

README.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -220,3 +220,5 @@ dd = new diffDOM.DiffDOM({
220220
caseSensitive: true,
221221
})
222222
```
223+
224+
**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.

browser/diffDOM.js

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

browser/diffDOM.js.map

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/diffDOM/virtual/fromString.ts

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,7 @@ const parseTag = (tag: string, caseSensitive: boolean) => {
4646

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

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

148148
if (isOpen) {
149-
current = parseTag(tag, options.caseSensitive)
149+
current = parseTag(tag, options.caseSensitive || insideSvg)
150+
if (current.node.nodeName==="svg") {
151+
insideSvg = true
152+
}
150153
level++
151154
if (
152155
!current.voidElement &&
@@ -197,6 +200,9 @@ export const stringToObj = (
197200
level--
198201
// move current up a level to match the end tag
199202
if (level > -1) {
203+
if (current.node.nodeName==="svg") {
204+
insideSvg = false
205+
}
200206
current = arr[level]
201207
}
202208
}

tests/xmlString.test.js

Lines changed: 57 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44

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

7-
const strings = [
7+
const stringsIncludingSVGs = [
88
`<svg height=50 width=50>
99
<defs>
1010
<clipPath id="clipPath">
@@ -32,20 +32,28 @@ const strings = [
3232
</svg>`,
3333
]
3434

35+
const stringsInsideSVGs = [
36+
`<defs><clipPath id="clipPath"><rect x="15" y="15" width="40" height="40" /></clipPath></defs>`,
37+
`<defs></defs>`,
38+
39+
`<defs></defs>`,
40+
`<defs><clipPath id="clipPath"><rect x="15" y="15" width="40" height="40" /></clipPath></defs>`,
41+
]
42+
3543
describe("string", () => {
3644
it("can diff and patch case sensitive xml strings", () => {
3745
const dd = new DiffDOM({
3846
debug: true,
3947
diffcap: 500,
40-
caseSensitive: true,
48+
caseSensitive: false,
4149
})
4250

43-
for (let i = 0; i < strings.length; i += 2) {
51+
for (let i = 0; i < stringsIncludingSVGs.length; i += 2) {
4452
const el1Outer = document.createElement("div")
4553
const el2Outer = document.createElement("div")
46-
el1Outer.innerHTML = strings[i]
47-
el2Outer.innerHTML = strings[i + 1]
48-
const diffs = dd.diff(strings[i], strings[i + 1])
54+
el1Outer.innerHTML = stringsIncludingSVGs[i]
55+
el2Outer.innerHTML = stringsIncludingSVGs[i + 1]
56+
const diffs = dd.diff(stringsIncludingSVGs[i], stringsIncludingSVGs[i + 1])
4957
expect(diffs).not.toHaveLength(0)
5058
const el1 = el1Outer.firstElementChild
5159
const el2 = el2Outer.firstElementChild
@@ -59,5 +67,48 @@ describe("string", () => {
5967
el1a.innerHTML
6068
).toEqual(el1.innerHTML)
6169
}
70+
71+
const ddCaseSensitive = new DiffDOM({
72+
debug: true,
73+
diffcap: 500,
74+
caseSensitive: true,
75+
})
76+
77+
for (let i = 0; i < stringsInsideSVGs.length; i += 2) {
78+
const el1Outer = document.createElementNS('http://www.w3.org/2000/svg', 'svg')
79+
const el2Outer = document.createElementNS('http://www.w3.org/2000/svg', 'svg')
80+
el1Outer.innerHTML = stringsInsideSVGs[i]
81+
el2Outer.innerHTML = stringsInsideSVGs[i + 1]
82+
const diffsCaseSensitive = ddCaseSensitive.diff(stringsInsideSVGs[i], stringsInsideSVGs[i + 1])
83+
const diffs = dd.diff(stringsInsideSVGs[i], stringsInsideSVGs[i + 1])
84+
expect(diffsCaseSensitive).not.toHaveLength(0)
85+
expect(diffs).not.toHaveLength(0)
86+
const el1 = el1Outer.firstElementChild
87+
const el2 = el2Outer.firstElementChild
88+
const el1a = el1.cloneNode(true)
89+
const el1b = el1.cloneNode(true)
90+
ddCaseSensitive.apply(el1a, diffsCaseSensitive)
91+
expect(
92+
el1a.innerHTML
93+
).toEqual(el2.innerHTML)
94+
// Trying to do the same without case sensitivity should not work.
95+
dd.apply(el1b, diffs)
96+
if (el1b.innerHTML.length || el2.innerHTML.length) {
97+
expect(
98+
el1b.innerHTML
99+
).not.toEqual(el2.innerHTML)
100+
}
101+
ddCaseSensitive.undo(el1a, diffsCaseSensitive)
102+
expect(
103+
el1a.innerHTML
104+
).toEqual(el1.innerHTML)
105+
// Trying to do the same without case sensitivity should not work.
106+
dd.undo(el1b, diffs)
107+
if (el1b.innerHTML.length || el1.innerHTML.length) {
108+
expect(
109+
el1b.innerHTML
110+
).not.toEqual(el1.innerHTML)
111+
}
112+
}
62113
})
63114
})

0 commit comments

Comments
 (0)