diff --git a/render/render.js b/render/render.js
index 53031380..a9539671 100644
--- a/render/render.js
+++ b/render/render.js
@@ -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"
@@ -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]
}
@@ -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
}
@@ -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"}
@@ -82,7 +84,7 @@ module.exports = function($window) {
// div.innerHTML = "
i | j | "
// console.log(div.innerHTML)
// --> "ij", no 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 = ""
temp = temp.firstChild
@@ -92,7 +94,7 @@ 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)
@@ -100,7 +102,7 @@ module.exports = function($window) {
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)
@@ -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) {
@@ -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)
@@ -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
@@ -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")
) {
@@ -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"
@@ -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
@@ -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
diff --git a/test-utils/domMock.js b/test-utils/domMock.js
index 883b2cb1..5536b49f 100644
--- a/test-utils/domMock.js
+++ b/test-utils/domMock.js
@@ -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
@@ -717,6 +718,7 @@ module.exports = function(options) {
},
createDocumentFragment: function() {
return {
+ ownerDocument: $window.document,
nodeType: 11,
nodeName: "#document-fragment",
appendChild: appendChild,
@@ -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")
|