Skip to content

Commit

Permalink
Remove dependance on global window and document (#2897)
Browse files Browse the repository at this point in the history
* Remove dependance on global window and document

* Use any available document, prioritising parent.ownerDocument

* Fix mockDom for DocumentFragment, revert to better ownerDocument implementation

* Simplify activeElement usage
  • Loading branch information
KoryNunn authored Jul 29, 2024
1 parent 86f49b0 commit d436836
Show file tree
Hide file tree
Showing 2 changed files with 22 additions and 17 deletions.
36 changes: 19 additions & 17 deletions render/render.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,7 @@ var df = require("../render/domFor")
var delayedRemoval = df.delayedRemoval
var domFor = df.domFor

module.exports = function($window) {
var $doc = $window && $window.document

module.exports = function() {
var nameSpace = {
svg: "http://www.w3.org/2000/svg",
math: "http://www.w3.org/1998/Math/MathML"
Expand All @@ -16,6 +14,10 @@ module.exports = function($window) {
var currentRedraw
var currentRender

function getDocument(dom) {
return dom.ownerDocument;
}

function getNameSpace(vnode) {
return vnode.attrs && vnode.attrs.xmlns || nameSpace[vnode.tag]
}
Expand All @@ -40,9 +42,9 @@ module.exports = function($window) {

// IE11 (at least) throws an UnspecifiedError when accessing document.activeElement when
// inside an iframe. Catch and swallow this error, and heavy-handidly return null.
function activeElement() {
function activeElement(dom) {
try {
return $doc.activeElement
return getDocument(dom).activeElement
} catch (e) {
return null
}
Expand Down Expand Up @@ -71,7 +73,7 @@ module.exports = function($window) {
else createComponent(parent, vnode, hooks, ns, nextSibling)
}
function createText(parent, vnode, nextSibling) {
vnode.dom = $doc.createTextNode(vnode.children)
vnode.dom = getDocument(parent).createTextNode(vnode.children)
insertDOM(parent, vnode.dom, nextSibling)
}
var possibleParents = {caption: "table", thead: "table", tbody: "table", tfoot: "table", tr: "tbody", th: "tr", td: "tr", colgroup: "table", col: "colgroup"}
Expand All @@ -82,7 +84,7 @@ module.exports = function($window) {
// div.innerHTML = "<td>i</td><td>j</td>"
// console.log(div.innerHTML)
// --> "ij", no <td> in sight.
var temp = $doc.createElement(possibleParents[match[1]] || "div")
var temp = getDocument(parent).createElement(possibleParents[match[1]] || "div")
if (ns === "http://www.w3.org/2000/svg") {
temp.innerHTML = "<svg xmlns=\"http://www.w3.org/2000/svg\">" + vnode.children + "</svg>"
temp = temp.firstChild
Expand All @@ -92,15 +94,15 @@ module.exports = function($window) {
vnode.dom = temp.firstChild
vnode.domSize = temp.childNodes.length
// Capture nodes to remove, so we don't confuse them.
var fragment = $doc.createDocumentFragment()
var fragment = getDocument(parent).createDocumentFragment()
var child
while (child = temp.firstChild) {
fragment.appendChild(child)
}
insertDOM(parent, fragment, nextSibling)
}
function createFragment(parent, vnode, hooks, ns, nextSibling) {
var fragment = $doc.createDocumentFragment()
var fragment = getDocument(parent).createDocumentFragment()
if (vnode.children != null) {
var children = vnode.children
createNodes(fragment, children, 0, children.length, hooks, null, ns)
Expand All @@ -117,8 +119,8 @@ module.exports = function($window) {
ns = getNameSpace(vnode) || ns

var element = ns ?
is ? $doc.createElementNS(ns, tag, {is: is}) : $doc.createElementNS(ns, tag) :
is ? $doc.createElement(tag, {is: is}) : $doc.createElement(tag)
is ? getDocument(parent).createElementNS(ns, tag, {is: is}) : getDocument(parent).createElementNS(ns, tag) :
is ? getDocument(parent).createElement(tag, {is: is}) : getDocument(parent).createElement(tag)
vnode.dom = element

if (attrs != null) {
Expand Down Expand Up @@ -553,7 +555,7 @@ module.exports = function($window) {
// don't allocate for the common case
target = vnode.dom
} else {
target = $doc.createDocumentFragment()
target = getDocument(parent).createDocumentFragment()
for (var dom of domFor(vnode)) target.appendChild(dom)
}
insertDOM(parent, target, nextSibling)
Expand Down Expand Up @@ -693,7 +695,7 @@ module.exports = function($window) {
/* eslint-disable no-implicit-coercion */
//setting input[value] to same value by typing on focused element moves cursor to end in Chrome
//setting input[type=file][value] to same value causes an error to be generated if it's non-empty
if ((vnode.tag === "input" || vnode.tag === "textarea") && vnode.dom.value === "" + value && (isFileInput || vnode.dom === activeElement())) return
if ((vnode.tag === "input" || vnode.tag === "textarea") && vnode.dom.value === "" + value && (isFileInput || vnode.dom === activeElement(vnode.dom))) return
//setting select[value] to same value while having select open blinks select dropdown in Chrome
if (vnode.tag === "select" && old !== null && vnode.dom.value === "" + value) return
//setting option[value] to same value while having select open blinks select dropdown in Chrome
Expand Down Expand Up @@ -722,7 +724,7 @@ module.exports = function($window) {
&& key !== "title" // creates "null" as title
&& !(key === "value" && (
vnode.tag === "option"
|| vnode.tag === "select" && vnode.dom.selectedIndex === -1 && vnode.dom === activeElement()
|| vnode.tag === "select" && vnode.dom.selectedIndex === -1 && vnode.dom === activeElement(vnode.dom)
))
&& !(vnode.tag === "input" && key === "type")
) {
Expand Down Expand Up @@ -771,7 +773,7 @@ module.exports = function($window) {
}
}
function isFormAttribute(vnode, attr) {
return attr === "value" || attr === "checked" || attr === "selectedIndex" || attr === "selected" && vnode.dom === activeElement() || vnode.tag === "option" && vnode.dom.parentNode === $doc.activeElement
return attr === "value" || attr === "checked" || attr === "selectedIndex" || attr === "selected" && vnode.dom === activeElement(vnode.dom) || vnode.tag === "option" && vnode.dom.parentNode === activeElement(vnode.dom)
}
function isLifecycleMethod(attr) {
return attr === "oninit" || attr === "oncreate" || attr === "onupdate" || attr === "onremove" || attr === "onbeforeremove" || attr === "onbeforeupdate"
Expand Down Expand Up @@ -923,7 +925,7 @@ module.exports = function($window) {
var prevRedraw = currentRedraw
var prevDOM = currentDOM
var hooks = []
var active = activeElement()
var active = activeElement(dom)
var namespace = dom.namespaceURI

currentDOM = dom
Expand All @@ -936,7 +938,7 @@ module.exports = function($window) {
updateNodes(dom, dom.vnodes, vnodes, hooks, null, namespace === "http://www.w3.org/1999/xhtml" ? undefined : namespace)
dom.vnodes = vnodes
// `document.activeElement` can return null: https://html.spec.whatwg.org/multipage/interaction.html#dom-document-activeelement
if (active != null && activeElement() !== active && typeof active.focus === "function") active.focus()
if (active != null && activeElement(dom) !== active && typeof active.focus === "function") active.focus()
for (var i = 0; i < hooks.length; i++) hooks[i]()
} finally {
currentRedraw = prevRedraw
Expand Down
3 changes: 3 additions & 0 deletions test-utils/domMock.js
Original file line number Diff line number Diff line change
Expand Up @@ -307,6 +307,7 @@ module.exports = function(options) {
parentNode: null,
childNodes: [],
attributes: {},
ownerDocument: $window.document,
contains: function(child) {
while (child != null) {
if (child === this) return true
Expand Down Expand Up @@ -717,6 +718,7 @@ module.exports = function(options) {
},
createDocumentFragment: function() {
return {
ownerDocument: $window.document,
nodeType: 11,
nodeName: "#document-fragment",
appendChild: appendChild,
Expand All @@ -738,6 +740,7 @@ module.exports = function(options) {
get activeElement() {return activeElement},
},
}
$window.document.defaultView = $window
$window.document.documentElement = $window.document.createElement("html")
appendChild.call($window.document.documentElement, $window.document.createElement("head"))
$window.document.body = $window.document.createElement("body")
Expand Down

0 comments on commit d436836

Please sign in to comment.