Precise DOM morphing
morphing typescript dom
0
fork

Configure Feed

Select the types of activity you want to include in your feed.

Simplify wasDirty checks

+47 -8
+27 -8
src/morphlex.ts
··· 210 210 } 211 211 212 212 function flagDirtyInputs(node: ParentNode): void { 213 + if (node.nodeType === ELEMENT_NODE_TYPE) { 214 + const element = node as Element 215 + if (isInputElement(element)) { 216 + if (element.value !== element.defaultValue || element.checked !== element.defaultChecked) { 217 + element.setAttribute("morphlex-dirty", "") 218 + } 219 + } else if (isOptionElement(element)) { 220 + if (element.selected !== element.defaultSelected) { 221 + element.setAttribute("morphlex-dirty", "") 222 + } 223 + } else if (element.localName === "textarea") { 224 + const textarea = element as HTMLTextAreaElement 225 + if (textarea.value !== textarea.defaultValue) { 226 + textarea.setAttribute("morphlex-dirty", "") 227 + } 228 + } 229 + } 230 + 213 231 for (const input of node.querySelectorAll("input")) { 214 - if ((input.name && input.value !== input.defaultValue) || input.checked !== input.defaultChecked) { 232 + if (input.value !== input.defaultValue || input.checked !== input.defaultChecked) { 215 233 input.setAttribute("morphlex-dirty", "") 216 234 } 217 235 } 218 236 219 237 for (const element of node.querySelectorAll("option")) { 220 - if (element.value && element.selected !== element.defaultSelected) { 238 + if (element.selected !== element.defaultSelected) { 221 239 element.setAttribute("morphlex-dirty", "") 222 240 } 223 241 } ··· 373 391 } 374 392 375 393 #visitAttributes(from: Element, to: Element): void { 376 - if (from.hasAttribute("morphlex-dirty")) { 394 + const wasDirty = from.hasAttribute("morphlex-dirty") 395 + if (wasDirty) { 377 396 from.removeAttribute("morphlex-dirty") 378 397 } 379 398 ··· 381 400 for (const { name, value } of to.attributes) { 382 401 if (name === "value") { 383 402 if (isInputElement(from) && from.value !== value) { 384 - if (from !== this.#skipValuePropertyUpdateFor && (!this.#options.preserveChanges || from.value === from.defaultValue)) { 403 + if (from !== this.#skipValuePropertyUpdateFor && (!this.#options.preserveChanges || !wasDirty)) { 385 404 from.value = value 386 405 } 387 406 } ··· 389 408 390 409 if (name === "selected") { 391 410 if (isOptionElement(from) && !from.selected) { 392 - if (!this.#options.preserveChanges || from.selected === from.defaultSelected) { 411 + if (!this.#options.preserveChanges || !wasDirty) { 393 412 from.selected = true 394 413 } 395 414 } ··· 397 416 398 417 if (name === "checked") { 399 418 if (isInputElement(from) && !from.checked) { 400 - if (!this.#options.preserveChanges || from.checked === from.defaultChecked) { 419 + if (!this.#options.preserveChanges || !wasDirty) { 401 420 from.checked = true 402 421 } 403 422 } ··· 416 435 if (!to.hasAttribute(name)) { 417 436 if (name === "selected") { 418 437 if (isOptionElement(from) && from.selected) { 419 - if (!this.#options.preserveChanges || from.selected === from.defaultSelected) { 438 + if (!this.#options.preserveChanges || !wasDirty) { 420 439 from.selected = false 421 440 } 422 441 } ··· 424 443 425 444 if (name === "checked") { 426 445 if (isInputElement(from) && from.checked) { 427 - if (!this.#options.preserveChanges || from.checked === from.defaultChecked) { 446 + if (!this.#options.preserveChanges || !wasDirty) { 428 447 from.checked = false 429 448 } 430 449 }
+20
test/new/inputs.browser.test.ts
··· 72 72 expect(second.defaultValue).toBe("a") 73 73 expect(second.getAttribute("value")).toBe("a") 74 74 }) 75 + 76 + test("morphing updates default while dirty and updates value once clean again", () => { 77 + const input = dom(`<input type="text" value="a">`) as HTMLInputElement 78 + 79 + input.value = "b" 80 + expect(input.value).toBe("b") 81 + expect(input.defaultValue).toBe("a") 82 + 83 + morph(input, dom(`<input type="text" value="c">`), { preserveChanges: true }) 84 + expect(input.value).toBe("b") 85 + expect(input.defaultValue).toBe("c") 86 + 87 + input.value = "c" 88 + expect(input.value).toBe("c") 89 + expect(input.defaultValue).toBe("c") 90 + 91 + morph(input, dom(`<input type="text" value="d">`), { preserveChanges: true }) 92 + expect(input.value).toBe("d") 93 + expect(input.defaultValue).toBe("d") 94 + }) 75 95 }) 76 96 77 97 describe("checkbox", () => {