Skip to content
Open
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
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,7 @@ Idiomorph supports the following options:
| `morphStyle` | The style of morphing to use, either `innerHTML` or `outerHTML` | `Idiomorph.morph(..., {morphStyle:'innerHTML'})` |
| `ignoreActive` | If set to `true`, idiomorph will skip the active element | `Idiomorph.morph(..., {ignoreActive:true})` |
| `ignoreActiveValue` | If set to `true`, idiomorph will not update the active element's value | `Idiomorph.morph(..., {ignoreActiveValue:true})` |
| `ignoreValue` | If set to `true`, idiomorph will not update any element's value including inputs, checkboxes and textarea | `Idiomorph.morph(..., {ignoreValue:true})` |
| `restoreFocus` | If set to `true`, idiomorph will attempt to restore any lost focus and selection state after the morph. | `Idiomorph.morph(..., {restoreFocus:true})` |
| `head` | Allows you to control how the `head` tag is merged. See the [head](#the-head-tag) section for more details | `Idiomorph.morph(..., {head:{style:merge}})` |
| `callbacks` | Allows you to insert callbacks when events occur in the morph life cycle, see the callback table below | `Idiomorph.morph(..., {callbacks:{beforeNodeAdded:function(node){...}})` |
Expand Down
14 changes: 9 additions & 5 deletions src/idiomorph.js
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@
* @property {'outerHTML' | 'innerHTML'} [morphStyle]
* @property {boolean} [ignoreActive]
* @property {boolean} [ignoreActiveValue]
* @property {boolean} [ignoreValue]
* @property {boolean} [restoreFocus]
* @property {ConfigCallbacks} [callbacks]
* @property {ConfigHead} [head]
Expand Down Expand Up @@ -69,6 +70,7 @@
* @property {'outerHTML' | 'innerHTML'} morphStyle
* @property {boolean} [ignoreActive]
* @property {boolean} [ignoreActiveValue]
* @property {boolean} [ignoreValue]
* @property {boolean} [restoreFocus]
* @property {ConfigCallbacksInternal} callbacks
* @property {ConfigHeadInternal} head
Expand Down Expand Up @@ -106,6 +108,7 @@ var Idiomorph = (function () {
* @property {ConfigInternal['morphStyle']} morphStyle
* @property {ConfigInternal['ignoreActive']} ignoreActive
* @property {ConfigInternal['ignoreActiveValue']} ignoreActiveValue
* @property {ConfigInternal['ignoreValue']} ignoreValue
* @property {ConfigInternal['restoreFocus']} restoreFocus
* @property {Map<Node, Set<string>>} idMap
* @property {Set<string>} persistentIds
Expand Down Expand Up @@ -601,7 +604,8 @@ var Idiomorph = (function () {
);
} else {
morphAttributes(oldNode, newContent, ctx);
if (!ignoreValueOfActiveElement(oldNode, ctx)) {
if (!ignoreValueOfActiveElement(oldNode, ctx) &&
(!ctx.ignoreValue || !(oldNode instanceof HTMLTextAreaElement))) {
// @ts-ignore newContent can be a node here because .firstChild will be null
morphChildren(ctx, oldNode, newContent);
}
Expand Down Expand Up @@ -653,7 +657,7 @@ var Idiomorph = (function () {
}
}

if (!ignoreValueOfActiveElement(oldElt, ctx)) {
if (!ctx.ignoreValue && !ignoreValueOfActiveElement(oldElt, ctx)) {
syncInputValue(oldElt, newElt, ctx);
}
}
Expand Down Expand Up @@ -774,9 +778,8 @@ var Idiomorph = (function () {
*/
function ignoreAttribute(attr, element, updateType, ctx) {
if (
attr === "value" &&
ctx.ignoreActiveValue &&
element === document.activeElement
attr === "value" && (ctx.ignoreValue ||
(ctx.ignoreActiveValue && element === document.activeElement))
) {
return true;
}
Expand Down Expand Up @@ -962,6 +965,7 @@ var Idiomorph = (function () {
morphStyle: morphStyle,
ignoreActive: mergedConfig.ignoreActive,
ignoreActiveValue: mergedConfig.ignoreActiveValue,
ignoreValue: mergedConfig.ignoreValue,
restoreFocus: mergedConfig.restoreFocus,
idMap: idMap,
persistentIds: persistentIds,
Expand Down
109 changes: 109 additions & 0 deletions test/core.js
Original file line number Diff line number Diff line change
Expand Up @@ -366,6 +366,51 @@ describe("Core morphing tests", function () {
document.body.removeChild(parent);
});

it("ignore input value change when ignoreValue is true", function () {
let parent = make("<div><input value='foo'></div>");
document.body.append(parent);

let initial = parent.querySelector("input");

// morph
let finalSrc = '<input value="bar">';
Idiomorph.morph(initial, finalSrc, { morphStyle: "outerHTML" });
initial.outerHTML.should.equal('<input value="bar">');

document.activeElement.should.equal(document.body);

let finalSrc2 = '<input class="foo" value="doh">';
Idiomorph.morph(initial, finalSrc2, {
morphStyle: "outerHTML",
ignoreValue: true,
});
initial.value.should.equal("bar");
initial.classList.value.should.equal("foo");

document.body.removeChild(parent);
});

it("ignores textarea value when ignoreValue is true", function () {
let parent = make("<div><textarea>foo</textarea></div>");
document.body.append(parent);
let initial = parent.querySelector("textarea");

let finalSrc = "<textarea>bar</textarea>";
Idiomorph.morph(initial, finalSrc, { morphStyle: "outerHTML" });
initial.outerHTML.should.equal("<textarea>bar</textarea>");

document.activeElement.should.equal(document.body);

let finalSrc2 = '<textarea class="foo">doh</textarea>';
Idiomorph.morph(initial, finalSrc2, {
morphStyle: "outerHTML",
ignoreValue: true,
});
initial.outerHTML.should.equal('<textarea class="foo">bar</textarea>');

document.body.removeChild(parent);
});

it("can morph input value properly because value property is special and doesnt reflect", function () {
let initial = make('<div><input value="foo"></div>');
let final = make('<input value="foo">');
Expand Down Expand Up @@ -419,6 +464,70 @@ describe("Core morphing tests", function () {
document.body.removeChild(parent);
});

it("morph does not remove input checked with ignoreValue set", function () {
let parent = make('<div><input type="checkbox"></div>');
document.body.append(parent);
let initial = parent.querySelector("input");
initial.checked = true;

let finalSrc = '<input type="checkbox">';
Idiomorph.morph(initial, finalSrc, { morphStyle: "outerHTML", ignoreValue: true });
initial.outerHTML.should.equal('<input type="checkbox">');
initial.checked.should.equal(true);
document.body.removeChild(parent);
});

it("morph does not reset input checked with ignoreValue set", function () {
let parent = make('<div><input type="checkbox" checked></div>');
document.body.append(parent);
let initial = parent.querySelector("input");
initial.checked = false;

let finalSrc = '<input type="checkbox" checked>';
Idiomorph.morph(initial, finalSrc, { morphStyle: "outerHTML", ignoreValue: true });
initial.outerHTML.should.equal('<input type="checkbox" checked="">');
initial.checked.should.equal(false);
document.body.removeChild(parent);
});

it("morph does still set input checked when checked attribute added even with ignoreValue set", function () {
let parent = make('<div><input type="checkbox" checked></div>');
document.body.append(parent);
let initial = parent.querySelector("input");

let MiddleSrc = '<input type="checkbox">';
Idiomorph.morph(initial, MiddleSrc, { morphStyle: "outerHTML"});

initial.outerHTML.should.equal('<input type="checkbox">');
initial.checked.should.equal(false);

let finalSrc = '<input type="checkbox" checked>';

Idiomorph.morph(initial, finalSrc, { morphStyle: "outerHTML", ignoreValue: true});
initial.outerHTML.should.equal('<input type="checkbox" checked="">');
initial.checked.should.equal(true);
document.body.removeChild(parent);
});

it("morph does still remove input checked when checked attribute removed even with ignoreValue set", function () {
let parent = make('<div><input type="checkbox"></div>');
document.body.append(parent);
let initial = parent.querySelector("input");

let MiddleSrc = '<input type="checkbox" checked>';
Idiomorph.morph(initial, MiddleSrc, { morphStyle: "outerHTML"});

initial.outerHTML.should.equal('<input type="checkbox" checked="">');
initial.checked.should.equal(true);

let finalSrc = '<input type="checkbox">';

Idiomorph.morph(initial, finalSrc, { morphStyle: "outerHTML", ignoreValue: true});
initial.outerHTML.should.equal('<input type="checkbox">');
initial.checked.should.equal(false);
document.body.removeChild(parent);
});

it("can morph input checked properly, set checked property to true", function () {
let parent = make('<div><input type="checkbox" checked></div>');
document.body.append(parent);
Expand Down