Skip to content

Commit 7d76372

Browse files
committed
fix textarea diffing, fixes #119
1 parent 7f713f4 commit 7d76372

File tree

8 files changed

+42
-21
lines changed

8 files changed

+42
-21
lines changed

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.

package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,7 @@
4949
"prettier": "^2.7.1",
5050
"rollup": "^3.10.0",
5151
"rollup-plugin-dts": "^5.1.1",
52+
"tslib": "^2.5.0",
5253
"updates": "^13.1.13"
5354
}
5455
}

src/diffDOM/dom/apply.ts

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -90,6 +90,9 @@ export function applyDiff(
9090
diff[options._const.oldValue] as string,
9191
diff[options._const.newValue] as string
9292
)
93+
if (node.parentNode instanceof HTMLTextAreaElement) {
94+
node.parentNode.value = diff[options._const.newValue] as string
95+
}
9396
break
9497
case options._const.modifyValue:
9598
if (!node || typeof node.value === "undefined") {
@@ -168,12 +171,17 @@ export function applyDiff(
168171
)
169172
break
170173
}
171-
case options._const.removeTextElement:
174+
case options._const.removeTextElement: {
172175
if (!node || node.nodeType !== 3) {
173176
return false
174177
}
175-
node.parentNode.removeChild(node)
178+
const parentNode = node.parentNode
179+
parentNode.removeChild(node)
180+
if (parentNode instanceof HTMLTextAreaElement) {
181+
parentNode.value = ""
182+
}
176183
break
184+
}
177185
case options._const.addTextElement: {
178186
const parentRoute = route.slice()
179187
const c: number = parentRoute.splice(parentRoute.length - 1, 1)[0]
@@ -185,6 +193,9 @@ export function applyDiff(
185193
return false
186194
}
187195
node.insertBefore(newNode, node.childNodes[c] || null)
196+
if (node.parentNode instanceof HTMLTextAreaElement) {
197+
node.parentNode.value = diff[options._const.value] as string
198+
}
188199
break
189200
}
190201
default:

src/diffDOM/virtual/apply.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -101,6 +101,9 @@ function applyVirtualDiff(
101101
break
102102
case options._const.modifyTextElement:
103103
node.data = diff[options._const.newValue]
104+
if (parentNode.nodeName === "TEXTAREA") {
105+
parentNode.value = diff[options._const.newValue]
106+
}
104107
break
105108
case options._const.modifyValue:
106109
node.value = diff[options._const.newValue]

src/diffDOM/virtual/fromDOM.ts

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -18,16 +18,17 @@ export function nodeToObj(
1818
(objNode.attributes[attribute.name] = attribute.value)
1919
)
2020
}
21-
if (aNode instanceof HTMLTextAreaElement) {
22-
objNode.value = aNode.value
23-
} else if (aNode.childNodes && aNode.childNodes.length > 0) {
21+
if (aNode.childNodes && aNode.childNodes.length > 0) {
2422
objNode.childNodes = []
2523
const nodeArray = Array.prototype.slice.call(aNode.childNodes)
2624
nodeArray.forEach((childNode) =>
2725
objNode.childNodes.push(nodeToObj(childNode, options))
2826
)
2927
}
3028
if (options.valueDiffing) {
29+
if (aNode instanceof HTMLTextAreaElement) {
30+
objNode.value = aNode.value
31+
}
3132
if (
3233
aNode instanceof HTMLInputElement &&
3334
["radio", "checkbox"].includes(aNode.type.toLowerCase()) &&

src/diffDOM/virtual/fromString.ts

Lines changed: 15 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,10 @@
1-
import { nodeType } from "../types"
1+
import { DiffDOMOptionsPartial, nodeType } from "../types"
22

33
// from html-parse-stringify (MIT)
44

55
const tagRE =
66
/<\s*\/*[a-zA-Z:_][a-zA-Z0-9:_\-.]*\s*(?:"[^"]*"['"]*|'[^']*'['"]*|[^'"/>])*\/*\s*>|<!--(?:.|\n|\r)*?-->/g
77

8-
// re-used obj for quick lookups of components
9-
const empty = Object.create ? Object.create(null) : {}
108
const attrRE = /\s([^'"/\s><]+?)[\s/>]|([^\s=]+)=\s?(".*?"|'.*?')/g
119

1210
function unescape(string: string) {
@@ -97,7 +95,10 @@ const parseTag = (tag: string) => {
9795
}
9896
}
9997

100-
export const stringToObj = (html: string, options = { components: empty }) => {
98+
export const stringToObj = (
99+
html: string,
100+
options: DiffDOMOptionsPartial = { valueDiffing: true }
101+
) => {
101102
const result: nodeType[] = []
102103
let current: { type: string; node: nodeType; voidElement: boolean }
103104
let level = -1
@@ -147,13 +148,6 @@ export const stringToObj = (html: string, options = { components: empty }) => {
147148
if (isOpen) {
148149
current = parseTag(tag)
149150
level++
150-
if (
151-
current.type === "tag" &&
152-
options.components[current.node.nodeName]
153-
) {
154-
current.type = "component"
155-
inComponent = true
156-
}
157151
if (
158152
!current.voidElement &&
159153
!inComponent &&
@@ -163,10 +157,19 @@ export const stringToObj = (html: string, options = { components: empty }) => {
163157
if (!current.node.childNodes) {
164158
current.node.childNodes = []
165159
}
160+
const data = unescape(
161+
html.slice(start, html.indexOf("<", start))
162+
)
166163
current.node.childNodes.push({
167164
nodeName: "#text",
168-
data: unescape(html.slice(start, html.indexOf("<", start))),
165+
data,
169166
})
167+
if (
168+
options.valueDiffing &&
169+
current.node.nodeName === "TEXTAREA"
170+
) {
171+
current.node.value = data
172+
}
170173
}
171174
// if we're at root, push new base node
172175
if (level === 0 && current.node.nodeName) {

tests/form.test.js

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -67,14 +67,16 @@ describe("form", () => {
6767
expect(diff4).toHaveLength(1)
6868

6969
const diff5 = dd.diff(first, second)
70-
expect(diff5).toHaveLength(1)
70+
expect(diff5).toHaveLength(2)
7171

72-
second.innerText = "Some text"
72+
second.innerHTML = "Some text"
7373
const diff6 = dd.diff(first, second)
7474
dd.apply(first, diff6)
75+
expect(first.innerHTML).toBe(second.innerHTML)
7576
const diff7 = dd.diff(first, third)
7677
dd.apply(first, diff7)
7778
expect(first.value).toBe(third.value)
79+
expect(first.innerHTML).toBe(third.innerHTML)
7880
})
7981

8082
it("can diff input type = text", () => {

0 commit comments

Comments
 (0)