fix svg across component boundaries
This commit is contained in:
parent
7b268c6ee8
commit
ca784a684e
6 changed files with 64 additions and 75 deletions
55
mithril.js
55
mithril.js
|
|
@ -96,7 +96,7 @@ if (typeof Promise === "undefined") {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
function Node(tag, key, attrs, children, text, dom) {
|
function Node(tag, key, attrs, children, text, dom) {
|
||||||
return {tag: tag, key: key, attrs: attrs, children: children, text: text, dom: dom, domSize: undefined, state: {}, events: undefined}
|
return {tag: tag, key: key, attrs: attrs, children: children, text: text, dom: dom, domSize: undefined, state: {}, events: undefined, instance: undefined}
|
||||||
}
|
}
|
||||||
Node.normalize = function(node) {
|
Node.normalize = function(node) {
|
||||||
if (node instanceof Array) return Node("[", undefined, undefined, Node.normalizeChildren(node), undefined, undefined)
|
if (node instanceof Array) return Node("[", undefined, undefined, Node.normalizeChildren(node), undefined, undefined)
|
||||||
|
|
@ -147,12 +147,7 @@ function hyperscript(selector) {
|
||||||
if (children instanceof Array && children.length == 1 && children[0] != null && children[0].tag === "#") text = children[0].children
|
if (children instanceof Array && children.length == 1 && children[0] != null && children[0].tag === "#") text = children[0].children
|
||||||
else childList = children
|
else childList = children
|
||||||
|
|
||||||
var vnode = Node(tag || "div", attrs.key, hasAttrs ? attrs : undefined, childList, text, undefined)
|
return Node(tag || "div", attrs.key, hasAttrs ? attrs : undefined, childList, text, undefined)
|
||||||
switch (vnode.tag) {
|
|
||||||
case "svg": changeNS("http://www.w3.org/2000/svg", vnode); break
|
|
||||||
case "math": changeNS("http://www.w3.org/1998/Math/MathML", vnode); break
|
|
||||||
}
|
|
||||||
return vnode
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -174,12 +169,6 @@ function hyperscript(selector) {
|
||||||
|
|
||||||
return Node(selector, attrs && attrs.key, attrs || {}, Node.normalizeChildren(children), undefined, undefined)
|
return Node(selector, attrs && attrs.key, attrs || {}, Node.normalizeChildren(children), undefined, undefined)
|
||||||
}
|
}
|
||||||
function changeNS(ns, vnode) {
|
|
||||||
vnode.ns = ns
|
|
||||||
if (vnode.children != null) {
|
|
||||||
for (var i = 0; i < vnode.children.length; i++) changeNS(ns, vnode.children[i])
|
|
||||||
}
|
|
||||||
}
|
|
||||||
var m = hyperscript
|
var m = hyperscript
|
||||||
var renderService = function($window) {
|
var renderService = function($window) {
|
||||||
var $doc = $window.document
|
var $doc = $window.document
|
||||||
|
|
@ -188,26 +177,26 @@ var renderService = function($window) {
|
||||||
function setEventCallback(callback) {return onevent = callback}
|
function setEventCallback(callback) {return onevent = callback}
|
||||||
|
|
||||||
//create
|
//create
|
||||||
function createNodes(parent, vnodes, start, end, hooks, nextSibling) {
|
function createNodes(parent, vnodes, start, end, hooks, nextSibling, ns) {
|
||||||
for (var i = start; i < end; i++) {
|
for (var i = start; i < end; i++) {
|
||||||
var vnode = vnodes[i]
|
var vnode = vnodes[i]
|
||||||
if (vnode != null) {
|
if (vnode != null) {
|
||||||
insertNode(parent, createNode(vnode, hooks), nextSibling)
|
insertNode(parent, createNode(vnode, hooks, ns), nextSibling)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
function createNode(vnode, hooks) {
|
function createNode(vnode, hooks, ns) {
|
||||||
var tag = vnode.tag
|
var tag = vnode.tag
|
||||||
if (vnode.attrs != null) initLifecycle(vnode.attrs, vnode, hooks)
|
if (vnode.attrs != null) initLifecycle(vnode.attrs, vnode, hooks)
|
||||||
if (typeof tag === "string") {
|
if (typeof tag === "string") {
|
||||||
switch (tag) {
|
switch (tag) {
|
||||||
case "#": return createText(vnode)
|
case "#": return createText(vnode)
|
||||||
case "<": return createHTML(vnode)
|
case "<": return createHTML(vnode)
|
||||||
case "[": return createFragment(vnode, hooks)
|
case "[": return createFragment(vnode, hooks, ns)
|
||||||
default: return createElement(vnode, hooks)
|
default: return createElement(vnode, hooks, ns)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else return createComponent(vnode, hooks)
|
else return createComponent(vnode, hooks, ns)
|
||||||
}
|
}
|
||||||
function createText(vnode) {
|
function createText(vnode) {
|
||||||
return vnode.dom = $doc.createTextNode(vnode.children)
|
return vnode.dom = $doc.createTextNode(vnode.children)
|
||||||
|
|
@ -227,19 +216,22 @@ var renderService = function($window) {
|
||||||
}
|
}
|
||||||
return fragment
|
return fragment
|
||||||
}
|
}
|
||||||
function createFragment(vnode, hooks) {
|
function createFragment(vnode, hooks, ns) {
|
||||||
var fragment = $doc.createDocumentFragment()
|
var fragment = $doc.createDocumentFragment()
|
||||||
if (vnode.children != null) {
|
if (vnode.children != null) {
|
||||||
var children = vnode.children
|
var children = vnode.children
|
||||||
createNodes(fragment, children, 0, children.length, hooks, null)
|
createNodes(fragment, children, 0, children.length, hooks, null, ns)
|
||||||
}
|
}
|
||||||
vnode.dom = fragment.firstChild
|
vnode.dom = fragment.firstChild
|
||||||
vnode.domSize = fragment.childNodes.length
|
vnode.domSize = fragment.childNodes.length
|
||||||
return fragment
|
return fragment
|
||||||
}
|
}
|
||||||
function createElement(vnode, hooks) {
|
function createElement(vnode, hooks, ns) {
|
||||||
var tag = vnode.tag
|
var tag = vnode.tag
|
||||||
var ns = vnode.ns
|
switch (vnode.tag) {
|
||||||
|
case "svg": ns = "http://www.w3.org/2000/svg"; break
|
||||||
|
case "math": ns = "http://www.w3.org/1998/Math/MathML"; break
|
||||||
|
}
|
||||||
|
|
||||||
var attrs = vnode.attrs
|
var attrs = vnode.attrs
|
||||||
var is = attrs && attrs.is
|
var is = attrs && attrs.is
|
||||||
|
|
@ -260,18 +252,18 @@ var renderService = function($window) {
|
||||||
|
|
||||||
if (vnode.children != null) {
|
if (vnode.children != null) {
|
||||||
var children = vnode.children
|
var children = vnode.children
|
||||||
createNodes(element, children, 0, children.length, hooks, null)
|
createNodes(element, children, 0, children.length, hooks, null, ns)
|
||||||
setLateAttrs(vnode)
|
setLateAttrs(vnode)
|
||||||
}
|
}
|
||||||
return element
|
return element
|
||||||
}
|
}
|
||||||
function createComponent(vnode, hooks) {
|
function createComponent(vnode, hooks, ns) {
|
||||||
vnode.state = copy(vnode.tag)
|
vnode.state = copy(vnode.tag)
|
||||||
|
|
||||||
initLifecycle(vnode.tag, vnode, hooks)
|
initLifecycle(vnode.tag, vnode, hooks)
|
||||||
vnode.instance = Node.normalize(vnode.tag.view.call(vnode.state, vnode))
|
vnode.instance = Node.normalize(vnode.tag.view.call(vnode.state, vnode))
|
||||||
if (vnode.instance != null) {
|
if (vnode.instance != null) {
|
||||||
var element = createNode(vnode.instance, hooks)
|
var element = createNode(vnode.instance, hooks, ns)
|
||||||
vnode.dom = vnode.instance.dom
|
vnode.dom = vnode.instance.dom
|
||||||
vnode.domSize = vnode.instance.domSize
|
vnode.domSize = vnode.instance.domSize
|
||||||
return element
|
return element
|
||||||
|
|
@ -500,7 +492,7 @@ var renderService = function($window) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (vnode.dom.parentNode != null) parent.removeChild(vnode.dom)
|
if (vnode.dom.parentNode != null) parent.removeChild(vnode.dom)
|
||||||
if (context != null && vnode.domSize == null && !hasIntegrationMethods(vnode)) { //TODO test custom elements
|
if (context != null && vnode.domSize == null && !hasIntegrationMethods(vnode.attrs) && !(typeof vnode.tag !== "string" && hasIntegrationMethods(vnode.tag))) { //TODO test custom elements
|
||||||
if (!context.pool) context.pool = [vnode]
|
if (!context.pool) context.pool = [vnode]
|
||||||
else context.pool.push(vnode)
|
else context.pool.push(vnode)
|
||||||
}
|
}
|
||||||
|
|
@ -526,7 +518,7 @@ var renderService = function($window) {
|
||||||
}
|
}
|
||||||
function setAttr(vnode, key, old, value) {
|
function setAttr(vnode, key, old, value) {
|
||||||
var element = vnode.dom
|
var element = vnode.dom
|
||||||
if (key === "key" || (old === value && !isFormAttribute(vnode, key)) || typeof value === "undefined" || isLifecycleMethod(key)) return
|
if (key === "key" || (old === value && !isFormAttribute(vnode, key)) && typeof value !== "object" || typeof value === "undefined" || isLifecycleMethod(key)) return
|
||||||
var nsLastIndex = key.indexOf(":")
|
var nsLastIndex = key.indexOf(":")
|
||||||
if (nsLastIndex > -1 && key.substr(0, nsLastIndex) === "xlink") {
|
if (nsLastIndex > -1 && key.substr(0, nsLastIndex) === "xlink") {
|
||||||
element.setAttributeNS("http://www.w3.org/1999/xlink", key.slice(nsLastIndex + 1), value)
|
element.setAttributeNS("http://www.w3.org/1999/xlink", key.slice(nsLastIndex + 1), value)
|
||||||
|
|
@ -576,12 +568,13 @@ var renderService = function($window) {
|
||||||
function isAttribute(attr) {
|
function isAttribute(attr) {
|
||||||
return attr === "href" || attr === "list" || attr === "form"// || attr === "type" || attr === "width" || attr === "height"
|
return attr === "href" || attr === "list" || attr === "form"// || attr === "type" || attr === "width" || attr === "height"
|
||||||
}
|
}
|
||||||
function hasIntegrationMethods(vnode) {
|
function hasIntegrationMethods(source) {
|
||||||
return vnode.attrs != null && (vnode.attrs.oncreate || vnode.attrs.onupdate || vnode.attrs.onbeforeremove || vnode.attrs.onremove)
|
return source != null && (source.oncreate || source.onupdate || source.onbeforeremove || source.onremove)
|
||||||
}
|
}
|
||||||
|
|
||||||
//style
|
//style
|
||||||
function updateStyle(element, old, style) {
|
function updateStyle(element, old, style) {
|
||||||
|
if (old === style) element.style = "", old = null
|
||||||
if (style == null) element.style = ""
|
if (style == null) element.style = ""
|
||||||
else if (typeof style === "string") element.style = style
|
else if (typeof style === "string") element.style = style
|
||||||
else {
|
else {
|
||||||
|
|
@ -992,6 +985,8 @@ m.route = function($window, renderer, pubsub) {
|
||||||
}
|
}
|
||||||
route.link = router.link
|
route.link = router.link
|
||||||
route.prefix = router.setPrefix
|
route.prefix = router.setPrefix
|
||||||
|
route.setPath = router.setPath
|
||||||
|
route.getPath = router.getPath
|
||||||
|
|
||||||
return route
|
return route
|
||||||
}(window, renderService, redrawService)
|
}(window, renderService, redrawService)
|
||||||
|
|
|
||||||
|
|
@ -40,12 +40,7 @@ function hyperscript(selector) {
|
||||||
if (children instanceof Array && children.length == 1 && children[0] != null && children[0].tag === "#") text = children[0].children
|
if (children instanceof Array && children.length == 1 && children[0] != null && children[0].tag === "#") text = children[0].children
|
||||||
else childList = children
|
else childList = children
|
||||||
|
|
||||||
var vnode = Node(tag || "div", attrs.key, hasAttrs ? attrs : undefined, childList, text, undefined)
|
return Node(tag || "div", attrs.key, hasAttrs ? attrs : undefined, childList, text, undefined)
|
||||||
switch (vnode.tag) {
|
|
||||||
case "svg": changeNS("http://www.w3.org/2000/svg", vnode); break
|
|
||||||
case "math": changeNS("http://www.w3.org/1998/Math/MathML", vnode); break
|
|
||||||
}
|
|
||||||
return vnode
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -68,11 +63,4 @@ function hyperscript(selector) {
|
||||||
return Node(selector, attrs && attrs.key, attrs || {}, Node.normalizeChildren(children), undefined, undefined)
|
return Node(selector, attrs && attrs.key, attrs || {}, Node.normalizeChildren(children), undefined, undefined)
|
||||||
}
|
}
|
||||||
|
|
||||||
function changeNS(ns, vnode) {
|
|
||||||
vnode.ns = ns
|
|
||||||
if (vnode.children != null) {
|
|
||||||
for (var i = 0; i < vnode.children.length; i++) changeNS(ns, vnode.children[i])
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
module.exports = hyperscript
|
module.exports = hyperscript
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
function Node(tag, key, attrs, children, text, dom) {
|
function Node(tag, key, attrs, children, text, dom) {
|
||||||
return {tag: tag, key: key, attrs: attrs, children: children, text: text, dom: dom, domSize: undefined, state: {}, events: undefined, ns: undefined, instance: undefined}
|
return {tag: tag, key: key, attrs: attrs, children: children, text: text, dom: dom, domSize: undefined, state: {}, events: undefined, instance: undefined}
|
||||||
}
|
}
|
||||||
Node.normalize = function(node) {
|
Node.normalize = function(node) {
|
||||||
if (node instanceof Array) return Node("[", undefined, undefined, Node.normalizeChildren(node), undefined, undefined)
|
if (node instanceof Array) return Node("[", undefined, undefined, Node.normalizeChildren(node), undefined, undefined)
|
||||||
|
|
|
||||||
|
|
@ -10,26 +10,26 @@ module.exports = function($window) {
|
||||||
function setEventCallback(callback) {return onevent = callback}
|
function setEventCallback(callback) {return onevent = callback}
|
||||||
|
|
||||||
//create
|
//create
|
||||||
function createNodes(parent, vnodes, start, end, hooks, nextSibling) {
|
function createNodes(parent, vnodes, start, end, hooks, nextSibling, ns) {
|
||||||
for (var i = start; i < end; i++) {
|
for (var i = start; i < end; i++) {
|
||||||
var vnode = vnodes[i]
|
var vnode = vnodes[i]
|
||||||
if (vnode != null) {
|
if (vnode != null) {
|
||||||
insertNode(parent, createNode(vnode, hooks), nextSibling)
|
insertNode(parent, createNode(vnode, hooks, ns), nextSibling)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
function createNode(vnode, hooks) {
|
function createNode(vnode, hooks, ns) {
|
||||||
var tag = vnode.tag
|
var tag = vnode.tag
|
||||||
if (vnode.attrs != null) initLifecycle(vnode.attrs, vnode, hooks)
|
if (vnode.attrs != null) initLifecycle(vnode.attrs, vnode, hooks)
|
||||||
if (typeof tag === "string") {
|
if (typeof tag === "string") {
|
||||||
switch (tag) {
|
switch (tag) {
|
||||||
case "#": return createText(vnode)
|
case "#": return createText(vnode)
|
||||||
case "<": return createHTML(vnode)
|
case "<": return createHTML(vnode)
|
||||||
case "[": return createFragment(vnode, hooks)
|
case "[": return createFragment(vnode, hooks, ns)
|
||||||
default: return createElement(vnode, hooks)
|
default: return createElement(vnode, hooks, ns)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else return createComponent(vnode, hooks)
|
else return createComponent(vnode, hooks, ns)
|
||||||
}
|
}
|
||||||
function createText(vnode) {
|
function createText(vnode) {
|
||||||
return vnode.dom = $doc.createTextNode(vnode.children)
|
return vnode.dom = $doc.createTextNode(vnode.children)
|
||||||
|
|
@ -49,19 +49,22 @@ module.exports = function($window) {
|
||||||
}
|
}
|
||||||
return fragment
|
return fragment
|
||||||
}
|
}
|
||||||
function createFragment(vnode, hooks) {
|
function createFragment(vnode, hooks, ns) {
|
||||||
var fragment = $doc.createDocumentFragment()
|
var fragment = $doc.createDocumentFragment()
|
||||||
if (vnode.children != null) {
|
if (vnode.children != null) {
|
||||||
var children = vnode.children
|
var children = vnode.children
|
||||||
createNodes(fragment, children, 0, children.length, hooks, null)
|
createNodes(fragment, children, 0, children.length, hooks, null, ns)
|
||||||
}
|
}
|
||||||
vnode.dom = fragment.firstChild
|
vnode.dom = fragment.firstChild
|
||||||
vnode.domSize = fragment.childNodes.length
|
vnode.domSize = fragment.childNodes.length
|
||||||
return fragment
|
return fragment
|
||||||
}
|
}
|
||||||
function createElement(vnode, hooks) {
|
function createElement(vnode, hooks, ns) {
|
||||||
var tag = vnode.tag
|
var tag = vnode.tag
|
||||||
var ns = vnode.ns
|
switch (vnode.tag) {
|
||||||
|
case "svg": ns = "http://www.w3.org/2000/svg"; break
|
||||||
|
case "math": ns = "http://www.w3.org/1998/Math/MathML"; break
|
||||||
|
}
|
||||||
|
|
||||||
var attrs = vnode.attrs
|
var attrs = vnode.attrs
|
||||||
var is = attrs && attrs.is
|
var is = attrs && attrs.is
|
||||||
|
|
@ -82,18 +85,18 @@ module.exports = function($window) {
|
||||||
|
|
||||||
if (vnode.children != null) {
|
if (vnode.children != null) {
|
||||||
var children = vnode.children
|
var children = vnode.children
|
||||||
createNodes(element, children, 0, children.length, hooks, null)
|
createNodes(element, children, 0, children.length, hooks, null, ns)
|
||||||
setLateAttrs(vnode)
|
setLateAttrs(vnode)
|
||||||
}
|
}
|
||||||
return element
|
return element
|
||||||
}
|
}
|
||||||
function createComponent(vnode, hooks) {
|
function createComponent(vnode, hooks, ns) {
|
||||||
vnode.state = copy(vnode.tag)
|
vnode.state = copy(vnode.tag)
|
||||||
|
|
||||||
initLifecycle(vnode.tag, vnode, hooks)
|
initLifecycle(vnode.tag, vnode, hooks)
|
||||||
vnode.instance = Node.normalize(vnode.tag.view.call(vnode.state, vnode))
|
vnode.instance = Node.normalize(vnode.tag.view.call(vnode.state, vnode))
|
||||||
if (vnode.instance != null) {
|
if (vnode.instance != null) {
|
||||||
var element = createNode(vnode.instance, hooks)
|
var element = createNode(vnode.instance, hooks, ns)
|
||||||
vnode.dom = vnode.instance.dom
|
vnode.dom = vnode.instance.dom
|
||||||
vnode.domSize = vnode.instance.domSize
|
vnode.domSize = vnode.instance.domSize
|
||||||
return element
|
return element
|
||||||
|
|
|
||||||
|
|
@ -67,6 +67,27 @@ o.spec("component", function() {
|
||||||
o(root.childNodes.length).equals(1)
|
o(root.childNodes.length).equals(1)
|
||||||
o(root.firstChild).equals(div.dom)
|
o(root.firstChild).equals(div.dom)
|
||||||
})
|
})
|
||||||
|
o("svg works when creating across component boundary", function() {
|
||||||
|
var component = {
|
||||||
|
view: function(vnode) {
|
||||||
|
return {tag: "g"}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
render(root, [{tag: "svg", children: [{tag: component}]}])
|
||||||
|
|
||||||
|
o(root.firstChild.firstChild.namespaceURI).equals("http://www.w3.org/2000/svg")
|
||||||
|
})
|
||||||
|
o("svg works when updating across component boundary", function() {
|
||||||
|
var component = {
|
||||||
|
view: function(vnode) {
|
||||||
|
return {tag: "g"}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
render(root, [{tag: "svg", children: [{tag: component}]}])
|
||||||
|
render(root, [{tag: "svg", children: [{tag: component}]}])
|
||||||
|
|
||||||
|
o(root.firstChild.firstChild.namespaceURI).equals("http://www.w3.org/2000/svg")
|
||||||
|
})
|
||||||
})
|
})
|
||||||
o.spec("return value", function() {
|
o.spec("return value", function() {
|
||||||
o("can return fragments", function() {
|
o("can return fragments", function() {
|
||||||
|
|
|
||||||
|
|
@ -394,24 +394,6 @@ o.spec("hyperscript", function() {
|
||||||
o(vnode.children[0].children[0].children[1].tag).equals("s")
|
o(vnode.children[0].children[0].children[1].tag).equals("s")
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
o.spec("namespaced", function() {
|
|
||||||
o("handles svg ns", function() {
|
|
||||||
var vnode = m("svg", m("g"))
|
|
||||||
|
|
||||||
o(vnode.tag).equals("svg")
|
|
||||||
o(vnode.ns).equals("http://www.w3.org/2000/svg")
|
|
||||||
o(vnode.children[0].tag).equals("g")
|
|
||||||
o(vnode.children[0].ns).equals("http://www.w3.org/2000/svg")
|
|
||||||
})
|
|
||||||
o("handles mathml ns", function() {
|
|
||||||
var vnode = m("math", m("mrow"))
|
|
||||||
|
|
||||||
o(vnode.tag).equals("math")
|
|
||||||
o(vnode.ns).equals("http://www.w3.org/1998/Math/MathML")
|
|
||||||
o(vnode.children[0].tag).equals("mrow")
|
|
||||||
o(vnode.children[0].ns).equals("http://www.w3.org/1998/Math/MathML")
|
|
||||||
})
|
|
||||||
})
|
|
||||||
o.spec("components", function() {
|
o.spec("components", function() {
|
||||||
o("works", function() {
|
o("works", function() {
|
||||||
var component = {
|
var component = {
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue