Skip to content

Read ownerDocument off the Node prototype - #163

Closed
myabc wants to merge 3 commits into
bigskysoftware:mainfrom
myabc:fix/owner-document-shadowing
Closed

Read ownerDocument off the Node prototype#163
myabc wants to merge 3 commits into
bigskysoftware:mainfrom
myabc:fix/owner-document-shadowing

Conversation

@myabc

@myabc myabc commented Sep 1, 2026

Copy link
Copy Markdown
Contributor

Note

This and #164 are pre-emptive fixes to possible issues that I found when reviewing @lizarusi's #156

A form control named ownerDocument shadows the form's DOM property, causing morphing to fail when creating the pantry in the target document.

Resolve ctx.doc through the native Node getter. Cache it on first use so importing the module does not require a DOM.

Tests cover focus and selection restoration on a shadowing form and loading without DOM constructors.

`saveAndRestoreFocus` resolves the document that owns the focus by
reading `ctx.target.ownerDocument`. `<form>` is [LegacyOverrideBuiltIns],
so a named control such as `<input name="ownerDocument">` installs an own
property on the form that shadows `Node.prototype.ownerDocument`.

When the morph target is such a form, `doc` is an `HTMLInputElement`,
`doc.activeElement` is `undefined`, and the function early-returns, so
focus and selection restoration silently stop happening.

Add an `ownerDocumentOf` helper that reads through the prototype getter,
caching the descriptor once at module scope. The getter is also
realm-safe: it brand-checks the internal slot rather than the realm.
@myabc
myabc force-pushed the fix/owner-document-shadowing branch from 61be01e to f66723a Compare September 5, 2026 15:09
@myabc
myabc marked this pull request as ready for review September 5, 2026 16:15
Copilot AI lite review requested due to automatic review settings September 5, 2026 16:15
@myabc myabc changed the title read ownerDocument off the Node prototype Read ownerDocument off the Node prototype Sep 5, 2026

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟢 Approval recommended

The fix is narrowly scoped, aligns with the documented root cause, and is supported by targeted regression tests.

Pull request overview

This PR fixes a morphing failure caused by <form> elements that shadow the ownerDocument property (via [LegacyOverrideBuiltIns]), by resolving ctx.doc through the native Node.prototype.ownerDocument getter and caching that getter lazily to avoid requiring DOM constructors at import time.

Changes:

  • Switch morph context document resolution from oldNode.ownerDocument to a new ownerDocumentOf(oldNode) helper.
  • Add a regression test covering focus/selection restoration when a target <form> shadows ownerDocument.
  • Add a test ensuring src/idiomorph.js can be evaluated even when DOM constructors are unavailable.
File summaries
File Description
test/restore-focus.js Adds coverage for focus/selection restoration when a form shadows ownerDocument.
test/core.js Verifies the library source can be loaded/evaluated without DOM constructors.
src/idiomorph.js Introduces ownerDocumentOf and uses it when creating the morph context.
Review details
  • Files reviewed: 3/3 changed files
  • Comments generated: 1
  • Review effort level: Lite

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Comment thread src/idiomorph.js Outdated
@myabc

myabc commented Sep 5, 2026

Copy link
Copy Markdown
Contributor Author

@botandrose @lizarusi apologies that these patches didn't make the cut for v0.8.0 (although tbf I don't think they are critical). I had Claude also take a look at #156, but sat on the findings until I could verify.

Would be grateful for your feedback!

@botandrose

Copy link
Copy Markdown
Collaborator

@myabc Hi Alex, thank you for exploring this one!

While this is indeed a bug, its such an extreme corner-case, that I think the juice on this one is just not worth the squeeze. It seems to me that someone has to essentially try to hit this, and its not easy to hit! They have to have a very unlikely setup with a form element named ownerDocument, be morphing the form specifically. And then even if this happens, the actual breakage is simply the focus restoration, which itself is only needed for non-moveBefore browsers like Safari, and only as a backup if the nature of the morph happens to re-parent the focused element.

So I would bet this bug has probably literally never happened in the real world, and the consequences are minor anyways.

Furthermore, the upcoming Safari 26.6 / 27.0 is supposed to support moveBefore, at which point I'm going to rip out this entire focus-save-and-restore mechanism anyways, because it'll no longer be needed.

So I'm going to close this one. Let me know if you disagree!

@botandrose botandrose closed this Sep 6, 2026
@myabc

myabc commented Sep 7, 2026

Copy link
Copy Markdown
Contributor Author

@botandrose I understand the trade-off between covering all edge cases vs. keeping a solution clean and easy to reason about, so 👍🏻 from me for closing these two PRs.

While we have hit occasional issues with form DOM properties colliding method names at @opf, this particular edge case hasn't caused us issues.

Furthermore, the upcoming Safari 26.6 / 27.0 is supposed to support moveBefore, at which point I'm going to rip out this entire focus-save-and-restore mechanism anyways, because it'll no longer be needed.

Nice!

@lizarusi

lizarusi commented Sep 7, 2026

Copy link
Copy Markdown
Contributor

@myabc thanks for looking into this! Yeah, very interesting findings, I agree that even though these are real bugs, you'd almost have to be trying to break it to hit these cases.

Let's see if anyone hits them in the wild!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants