Skip to content

Commit

Permalink
satisfy tsc.
Browse files Browse the repository at this point in the history
  • Loading branch information
botandrose-machine committed Jan 14, 2025
1 parent 1f858a9 commit 29e4995
Show file tree
Hide file tree
Showing 3 changed files with 70 additions and 8 deletions.
26 changes: 18 additions & 8 deletions src/idiomorph.js
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,7 @@
* @property {'outerHTML' | 'innerHTML'} morphStyle
* @property {boolean} [ignoreActive]
* @property {boolean} [ignoreActiveValue]
* @property {boolean} [restoreFocus]
* @property {ConfigCallbacksInternal} callbacks
* @property {ConfigHeadInternal} head
*/
Expand Down Expand Up @@ -180,28 +181,37 @@ var Idiomorph = (function () {
});
}

/**
* @param {MorphContext} ctx
* @param {Function} fn
* @returns {Promise<Node[]> | Node[]}
*/
function saveAndRestoreFocus(ctx, fn) {
if (!ctx.config.restoreFocus) return fn();

let activeElement = document.activeElement;
let activeElementId, selectionStart, selectionEnd;

// don't bother if the active element is not an input or textarea
if (
activeElement &&
["INPUT", "TEXTAREA"].includes(activeElement.tagName)
!(
activeElement instanceof HTMLInputElement ||
activeElement instanceof HTMLTextAreaElement
)
) {
activeElementId = activeElement.id;
selectionStart = activeElement.selectionStart;
selectionEnd = activeElement.selectionEnd;
return fn();
}

const { id: activeElementId, selectionStart, selectionEnd } = activeElement;

const results = fn();

if (activeElementId && activeElementId !== document.activeElement?.id) {
activeElement = ctx.target.querySelector(`#${activeElementId}`);
activeElement.focus();
// @ts-ignore we can assume this is focusable
activeElement?.focus();
}
if(selectionStart, selectionEnd) {
if (activeElement && selectionStart && selectionEnd) {
// @ts-ignore we know this is an input element
activeElement.setSelectionRange(selectionStart, selectionEnd);
}

Expand Down
4 changes: 4 additions & 0 deletions test/lib/utilities.js
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,10 @@ function setFocusAndSelection(elementId, selectedText) {
element.setSelectionRange(index, index + selectedText.length);
}

function setFocus(elementId) {
document.getElementById(elementId).focus();
}

function assertFocusAndSelection(elementId, selectedText) {
assertFocus(elementId);
const activeElement = document.activeElement;
Expand Down
48 changes: 48 additions & 0 deletions test/restore-focus.js
Original file line number Diff line number Diff line change
Expand Up @@ -230,4 +230,52 @@ describe("Option to forcibly restore focus after morph", function () {
getWorkArea().innerHTML.should.equal(finalSrc);
assertFocusAndSelection("focused", "b");
});

it("restores focus and selection state with a textarea", function () {
getWorkArea().innerHTML = `
<div>
<textarea id="focused">abc</textarea>
<textarea id="other"></textarea>
</div>
`;
setFocusAndSelection("focused", "b");

let finalSrc = `
<div>
<textarea id="other"></textarea>
<textarea id="focused">abc</textarea>
</div>
`;
Idiomorph.morph(getWorkArea(), finalSrc, {
morphStyle: "innerHTML",
restoreFocus: true,
});

getWorkArea().innerHTML.should.equal(finalSrc);
assertFocusAndSelection("focused", "b");
});

it("does nothing if a non input/textarea el is focused", function () {
getWorkArea().innerHTML = `
<div>
<p id="focused"></p>
<p id="other"></p>
</div>
`;
setFocus("focused");

let finalSrc = `
<div>
<p id="other"></p>
<p id="focused"></p>
</div>
`;
Idiomorph.morph(getWorkArea(), finalSrc, {
morphStyle: "innerHTML",
restoreFocus: true,
});

getWorkArea().innerHTML.should.equal(finalSrc);
assertNoFocus();
});
});

0 comments on commit 29e4995

Please sign in to comment.