add experimental svg support
- supports nested svg elements - supports svg attributes - supports xlink
This commit is contained in:
parent
7e2136ba51
commit
48025dd16a
8 changed files with 87 additions and 18 deletions
|
|
@ -32,7 +32,7 @@ new function(window) {
|
|||
}
|
||||
return cell
|
||||
}
|
||||
function build(parent, data, cached) {
|
||||
function build(parent, data, cached, namespace) {
|
||||
if (data === null || data === undefined) return
|
||||
|
||||
var cachedType = type.call(cached), dataType = type.call(data)
|
||||
|
|
@ -45,7 +45,7 @@ new function(window) {
|
|||
if (dataType == "[object Array]") {
|
||||
var nodes = [], intact = cached.length === data.length
|
||||
for (var i = 0; i < data.length; i++) {
|
||||
var item = build(parent, data[i], cached[i])
|
||||
var item = build(parent, data[i], cached[i], namespace)
|
||||
if (item === undefined) continue
|
||||
if (!item.nodes.intact) intact = false
|
||||
cached[i] = item
|
||||
|
|
@ -63,15 +63,16 @@ new function(window) {
|
|||
if (data.tag != cached.tag || Object.keys(data.attrs).join() != Object.keys(cached.attrs).join()) clear(cached.nodes)
|
||||
|
||||
var node, isNew = cached.nodes.length === 0
|
||||
if (data.tag === "svg") namespace = "http://www.w3.org/2000/svg"
|
||||
if (isNew) {
|
||||
node = window.document.createElement(data.tag)
|
||||
cached = {tag: data.tag, attrs: setAttributes(node, data.attrs, {}), children: build(node, data.children, cached.children), nodes: [node]}
|
||||
node = namespace === undefined ? window.document.createElement(data.tag) : window.document.createElementNS(namespace, data.tag)
|
||||
cached = {tag: data.tag, attrs: setAttributes(node, data.attrs, {}, namespace), children: build(node, data.children, cached.children, namespace), nodes: [node]}
|
||||
parent.appendChild(node)
|
||||
}
|
||||
else {
|
||||
node = cached.nodes[0]
|
||||
setAttributes(node, data.attrs, cached.attrs)
|
||||
cached.children = build(node, data.children, cached.children)
|
||||
setAttributes(node, data.attrs, cached.attrs, namespace)
|
||||
cached.children = build(node, data.children, cached.children, namespace)
|
||||
cached.nodes.intact = true
|
||||
}
|
||||
if (type.call(data.attrs["config"]) == "[object Function]") data.attrs["config"](node, !isNew)
|
||||
|
|
@ -116,7 +117,7 @@ new function(window) {
|
|||
|
||||
return cached
|
||||
}
|
||||
function setAttributes(node, dataAttrs, cachedAttrs) {
|
||||
function setAttributes(node, dataAttrs, cachedAttrs, namespace) {
|
||||
for (var attrName in dataAttrs) {
|
||||
var dataAttr = dataAttrs[attrName]
|
||||
if (!(attrName in cachedAttrs) || (cachedAttrs[attrName] !== dataAttr)) {
|
||||
|
|
@ -124,7 +125,8 @@ new function(window) {
|
|||
if (attrName == "config") continue
|
||||
if (attrName.indexOf("on") == 0 && typeof dataAttr == "function") dataAttr = autoredraw(dataAttr, node)
|
||||
if (attrName == "style") for (var rule in dataAttr) node.style[rule] = dataAttr[rule]
|
||||
else if (attrName in node) node[attrName] = dataAttr
|
||||
else if (attrName in node && namespace === undefined) node[attrName] = dataAttr
|
||||
else if (namespace !== undefined && attrName === "href") node.setAttributeNS("http://www.w3.org/1999/xlink", "href", dataAttr)
|
||||
else node.setAttribute(attrName, dataAttr)
|
||||
}
|
||||
}
|
||||
|
|
@ -453,11 +455,17 @@ mock.window = new function() {
|
|||
setAttribute: function(name, value) {
|
||||
this[name] = value.toString()
|
||||
},
|
||||
setAttributeNS: function(namespace, name, value) {
|
||||
this[name] = value.toString()
|
||||
},
|
||||
getAttribute: function(name, value) {
|
||||
return this[name]
|
||||
},
|
||||
}
|
||||
}
|
||||
window.document.createElementNS = function(namespace, tag) {
|
||||
return window.document.createElement(tag)
|
||||
}
|
||||
window.document.createTextNode = function(text) {
|
||||
return {nodeValue: text.toString()}
|
||||
}
|
||||
|
|
@ -537,6 +545,8 @@ function testMithril(mock) {
|
|||
test(function() {return m("div", m("div")).attrs.tag === "div"}) //yes, this is expected behavior: see method signature
|
||||
test(function() {return m("div", [undefined]).tag === "div"})
|
||||
test(function() {return m("div", [{foo: "bar"}])}) //as long as it doesn't throw errors, it's fine
|
||||
test(function() {return m("svg", [m("g")])})
|
||||
test(function() {return m("svg", [m("a[href='http://google.com']")])})
|
||||
|
||||
//m.module
|
||||
test(function() {
|
||||
|
|
@ -621,6 +631,18 @@ function testMithril(mock) {
|
|||
m.render(root, m("div", [undefined]))
|
||||
return root.childNodes[0].childNodes.length === 0
|
||||
})
|
||||
test(function() {
|
||||
var root = mock.document.createElement("div")
|
||||
m.render(root, m("svg", [m("g")]))
|
||||
console.log(root.childNodes[0].childNodes[0])
|
||||
return root.childNodes[0].childNodes[0].nodeName === "G"
|
||||
})
|
||||
test(function() {
|
||||
var root = mock.document.createElement("div")
|
||||
m.render(root, m("svg", [m("a[href='http://google.com']")]))
|
||||
console.log(root.childNodes[0].childNodes[0])
|
||||
return root.childNodes[0].childNodes[0].nodeName === "A"
|
||||
})
|
||||
|
||||
//m.redraw
|
||||
test(function() {
|
||||
|
|
|
|||
2
archive/v0.1.2/mithril.min.js
vendored
2
archive/v0.1.2/mithril.min.js
vendored
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
Binary file not shown.
18
mithril.js
18
mithril.js
|
|
@ -32,7 +32,7 @@ new function(window) {
|
|||
}
|
||||
return cell
|
||||
}
|
||||
function build(parent, data, cached) {
|
||||
function build(parent, data, cached, namespace) {
|
||||
if (data === null || data === undefined) return
|
||||
|
||||
var cachedType = type.call(cached), dataType = type.call(data)
|
||||
|
|
@ -45,7 +45,7 @@ new function(window) {
|
|||
if (dataType == "[object Array]") {
|
||||
var nodes = [], intact = cached.length === data.length
|
||||
for (var i = 0; i < data.length; i++) {
|
||||
var item = build(parent, data[i], cached[i])
|
||||
var item = build(parent, data[i], cached[i], namespace)
|
||||
if (item === undefined) continue
|
||||
if (!item.nodes.intact) intact = false
|
||||
cached[i] = item
|
||||
|
|
@ -63,15 +63,16 @@ new function(window) {
|
|||
if (data.tag != cached.tag || Object.keys(data.attrs).join() != Object.keys(cached.attrs).join()) clear(cached.nodes)
|
||||
|
||||
var node, isNew = cached.nodes.length === 0
|
||||
if (data.tag === "svg") namespace = "http://www.w3.org/2000/svg"
|
||||
if (isNew) {
|
||||
node = window.document.createElement(data.tag)
|
||||
cached = {tag: data.tag, attrs: setAttributes(node, data.attrs, {}), children: build(node, data.children, cached.children), nodes: [node]}
|
||||
node = namespace === undefined ? window.document.createElement(data.tag) : window.document.createElementNS(namespace, data.tag)
|
||||
cached = {tag: data.tag, attrs: setAttributes(node, data.attrs, {}, namespace), children: build(node, data.children, cached.children, namespace), nodes: [node]}
|
||||
parent.appendChild(node)
|
||||
}
|
||||
else {
|
||||
node = cached.nodes[0]
|
||||
setAttributes(node, data.attrs, cached.attrs)
|
||||
cached.children = build(node, data.children, cached.children)
|
||||
setAttributes(node, data.attrs, cached.attrs, namespace)
|
||||
cached.children = build(node, data.children, cached.children, namespace)
|
||||
cached.nodes.intact = true
|
||||
}
|
||||
if (type.call(data.attrs["config"]) == "[object Function]") data.attrs["config"](node, !isNew)
|
||||
|
|
@ -116,7 +117,7 @@ new function(window) {
|
|||
|
||||
return cached
|
||||
}
|
||||
function setAttributes(node, dataAttrs, cachedAttrs) {
|
||||
function setAttributes(node, dataAttrs, cachedAttrs, namespace) {
|
||||
for (var attrName in dataAttrs) {
|
||||
var dataAttr = dataAttrs[attrName]
|
||||
if (!(attrName in cachedAttrs) || (cachedAttrs[attrName] !== dataAttr)) {
|
||||
|
|
@ -124,7 +125,8 @@ new function(window) {
|
|||
if (attrName == "config") continue
|
||||
if (attrName.indexOf("on") == 0 && typeof dataAttr == "function") dataAttr = autoredraw(dataAttr, node)
|
||||
if (attrName == "style") for (var rule in dataAttr) node.style[rule] = dataAttr[rule]
|
||||
else if (attrName in node) node[attrName] = dataAttr
|
||||
else if (attrName in node && namespace === undefined) node[attrName] = dataAttr
|
||||
else if (namespace !== undefined && attrName === "href") node.setAttributeNS("http://www.w3.org/1999/xlink", "href", dataAttr)
|
||||
else node.setAttribute(attrName, dataAttr)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -21,6 +21,8 @@ function testMithril(mock) {
|
|||
test(function() {return m("div", m("div")).attrs.tag === "div"}) //yes, this is expected behavior: see method signature
|
||||
test(function() {return m("div", [undefined]).tag === "div"})
|
||||
test(function() {return m("div", [{foo: "bar"}])}) //as long as it doesn't throw errors, it's fine
|
||||
test(function() {return m("svg", [m("g")])})
|
||||
test(function() {return m("svg", [m("a[href='http://google.com']")])})
|
||||
|
||||
//m.module
|
||||
test(function() {
|
||||
|
|
@ -105,6 +107,18 @@ function testMithril(mock) {
|
|||
m.render(root, m("div", [undefined]))
|
||||
return root.childNodes[0].childNodes.length === 0
|
||||
})
|
||||
test(function() {
|
||||
var root = mock.document.createElement("div")
|
||||
m.render(root, m("svg", [m("g")]))
|
||||
console.log(root.childNodes[0].childNodes[0])
|
||||
return root.childNodes[0].childNodes[0].nodeName === "G"
|
||||
})
|
||||
test(function() {
|
||||
var root = mock.document.createElement("div")
|
||||
m.render(root, m("svg", [m("a[href='http://google.com']")]))
|
||||
console.log(root.childNodes[0].childNodes[0])
|
||||
return root.childNodes[0].childNodes[0].nodeName === "A"
|
||||
})
|
||||
|
||||
//m.redraw
|
||||
test(function() {
|
||||
|
|
|
|||
|
|
@ -13,11 +13,17 @@ mock.window = new function() {
|
|||
setAttribute: function(name, value) {
|
||||
this[name] = value.toString()
|
||||
},
|
||||
setAttributeNS: function(namespace, name, value) {
|
||||
this[name] = value.toString()
|
||||
},
|
||||
getAttribute: function(name, value) {
|
||||
return this[name]
|
||||
},
|
||||
}
|
||||
}
|
||||
window.document.createElementNS = function(namespace, tag) {
|
||||
return window.document.createElement(tag)
|
||||
}
|
||||
window.document.createTextNode = function(text) {
|
||||
return {nodeValue: text.toString()}
|
||||
}
|
||||
|
|
|
|||
25
tests/svg.html
Normal file
25
tests/svg.html
Normal file
|
|
@ -0,0 +1,25 @@
|
|||
<!doctype html>
|
||||
<html>
|
||||
<head></head>
|
||||
<body>
|
||||
<p>Since it's not possible to test SVG functionality from a NodeJS environment, this page can be used to test it in a browser.</p>
|
||||
<p>There should be an HTML link labeled "HTML link", a SVG link labeled "SVG link", and a tilted blue square. The links should open in a new tab. All three items should display title tooltips.</p>
|
||||
<div id="test"></div>
|
||||
<script src="../mithril.js"></script>
|
||||
<script>
|
||||
var svg = [
|
||||
m("p", [
|
||||
m("a[href='http://google.com'][target='_blank'][title='HTML link']", "HTML link")
|
||||
]),
|
||||
m("svg[width=180][height=200]", [
|
||||
m("rect[x=50][y=50][height=100][width=100][transform='translate(30) rotate(45 50 50)'][title='Square']", {style: {stroke: "#000", fill: "#0086b2"}}),
|
||||
m("a[href='http://google.com'][title='SVG link'][target=_new]", {style: {textDecoration: "underline"}}, [
|
||||
m("text[x=0][y=20]", "SVG Link")
|
||||
])
|
||||
])
|
||||
]
|
||||
|
||||
m.render(document.getElementById("test"), svg)
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
Loading…
Add table
Add a link
Reference in a new issue