Remove dependance on global window and document (#2897)
* 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
This commit is contained in:
parent
5488953436
commit
8e7ef427e0
2 changed files with 22 additions and 17 deletions
|
|
@ -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 = "<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
|
||||
|
|
@ -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
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue