Merge branch 'next' of https://github.com/lhorie/mithril.js into test-fix
This commit is contained in:
commit
199da9c21b
19 changed files with 4732 additions and 2868 deletions
|
|
@ -68,7 +68,7 @@ window.templateConverter = (function () {
|
|||
|
||||
if (el.attrs.class) {
|
||||
virtual += "." + el.attrs.class.replace(/\s+/g, ".")
|
||||
el.attrs.class = undefined
|
||||
delete el.attrs.class
|
||||
}
|
||||
|
||||
each(Object.keys(el.attrs).sort(), function (attrName) {
|
||||
|
|
|
|||
|
|
@ -165,8 +165,8 @@ var MyComponent = {
|
|||
|
||||
m.render(document.body, [
|
||||
//the two lines below are equivalent
|
||||
m(component, {data: "world"}),
|
||||
m.component(component, {data: "world"})
|
||||
m(MyComponent, {data: "world"}),
|
||||
m.component(MyComponent, {data: "world"})
|
||||
])
|
||||
```
|
||||
|
||||
|
|
@ -362,7 +362,7 @@ var MyComponent = {
|
|||
},
|
||||
view: function(ctrl) {
|
||||
return m("ul", [
|
||||
ctrl.things().map(function(name) {
|
||||
ctrl.things().map(function(thing) {
|
||||
return m("li", thing.name)
|
||||
})
|
||||
]);
|
||||
|
|
@ -590,7 +590,7 @@ where:
|
|||
|
||||
- **Component component**
|
||||
|
||||
A component is supposed to be an Object with two keys: `controller` and `view`. Each of these should point to a Javascript function. If a contoller is not specified, Mithril will automatically create an empty controller function.
|
||||
A component is supposed to be an Object with two keys: `controller` and `view`. Each of these should point to a Javascript function. If a controller is not specified, Mithril will automatically create an empty controller function.
|
||||
|
||||
- **Object attributes**
|
||||
|
||||
|
|
|
|||
|
|
@ -10,7 +10,7 @@
|
|||
|
||||
---
|
||||
|
||||
Redraws the view for the currently active component. Use [`m.mount()`](mithril.mount.md) or [`m.route()`](mithril.route.md) to activate a component.
|
||||
Redraws the view. Use [`m.mount()`](mithril.mount.md) or [`m.route()`](mithril.route.md) to activate a component.
|
||||
|
||||
Calling `m.redraw` triggers a redraw regardless of whether AJAX requests (and other asynchronous services) are completed. Therefore, you should ensure that templates have null checks in place to account for the possibility of variables being uninitialized when the forced redraw occurs.
|
||||
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@
|
|||
|
||||
If you already have your HTML written and want to convert it into a Mithril template, you can use the tool below for one-off manual conversion.
|
||||
|
||||
[Template Converter](tools/template-converter.html)
|
||||
[Template Converter](http://arthurclemens.github.io/mithril-template-converter/index.html)
|
||||
|
||||
---
|
||||
|
||||
|
|
|
|||
19
mithril.d.ts
vendored
19
mithril.d.ts
vendored
|
|
@ -27,7 +27,7 @@ declare module _mithril {
|
|||
MithrilVirtualElement<T> |
|
||||
MithrilComponent<T>>
|
||||
): MithrilVirtualElement<T>;
|
||||
|
||||
|
||||
/**
|
||||
* Initializes a component for use with m.render, m.mount, etc.
|
||||
*
|
||||
|
|
@ -127,6 +127,19 @@ declare module _mithril {
|
|||
callbackThis: any
|
||||
): (e: Event) => any;
|
||||
|
||||
/**
|
||||
* Returns a event handler that can be bound to an element, firing with
|
||||
* the specified property.
|
||||
*
|
||||
* @param attributeName Name of the element's attribute to bind to.
|
||||
* @param property The property to bind.
|
||||
* @return A function suitable for listening to an event.
|
||||
*/
|
||||
withAttr<T>(
|
||||
attributeName: string,
|
||||
property: MithrilBasicProperty<T>
|
||||
) : (e: Event) => any;
|
||||
|
||||
/**
|
||||
* @deprecated Use m.mount instead
|
||||
*/
|
||||
|
|
@ -561,7 +574,7 @@ declare module _mithril {
|
|||
* @see MithrilControllerConstructor
|
||||
*/
|
||||
interface MithrilControllerFunction<T extends MithrilController> {
|
||||
(): T;
|
||||
(opts?: any): T;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -603,7 +616,7 @@ declare module _mithril {
|
|||
*
|
||||
* @see m.component
|
||||
*/
|
||||
view(ctrl: T): MithrilVirtualElement<T>;
|
||||
view(ctrl?: T, opts?: any): MithrilVirtualElement<T>;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
|||
2677
mithril.js
2677
mithril.js
File diff suppressed because it is too large
Load diff
4
mithril.min.js
vendored
4
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
|
|
@ -47,6 +47,9 @@ window.mock = (function () {
|
|||
"use strict"
|
||||
|
||||
var window = {}
|
||||
|
||||
window.window = window
|
||||
|
||||
var document = window.document = {
|
||||
// FIXME: add document.createRange().createContextualFragment()
|
||||
|
||||
|
|
@ -138,7 +141,7 @@ window.mock = (function () {
|
|||
name = name.toLowerCase()
|
||||
var out = []
|
||||
|
||||
function traverse(node){
|
||||
function traverse(node) {
|
||||
if (node.childNodes && node.childNodes.length > 0) {
|
||||
node.childNodes.forEach(function (curr) {
|
||||
if (curr.nodeName.toLowerCase() === name) {
|
||||
|
|
@ -158,7 +161,7 @@ window.mock = (function () {
|
|||
|
||||
window.scrollTo = function () {}
|
||||
|
||||
;(function (window) {
|
||||
;(function () {
|
||||
// This is an actual conforming implementation of the
|
||||
// requestAnimationFrame spec, with the nonstandard extension of
|
||||
// rAF.$resolve for running the callbacks. It works in Node and the
|
||||
|
|
@ -214,7 +217,7 @@ window.mock = (function () {
|
|||
}
|
||||
|
||||
window.requestAnimationFrame = requestAnimationFrame
|
||||
})(window)
|
||||
})()
|
||||
|
||||
window.XMLHttpRequest = (function () {
|
||||
function Request() {
|
||||
|
|
|
|||
8
test/isolation-test.html
Normal file
8
test/isolation-test.html
Normal file
|
|
@ -0,0 +1,8 @@
|
|||
<!doctype html>
|
||||
<!--<script src="https://cdnjs.cloudflare.com/ajax/libs/es5-shim/4.0.3/es5-shim.min.js"></script>-->
|
||||
<script src="test.js"></script>
|
||||
<script src="mock.js"></script>
|
||||
<script src="../mithril.js"></script>
|
||||
|
||||
<p>Open the console to see the test report</p>
|
||||
<script src="./isolation-test.js"></script>
|
||||
159
test/isolation-test.js
Normal file
159
test/isolation-test.js
Normal file
|
|
@ -0,0 +1,159 @@
|
|||
/* global m, test, mock */
|
||||
(function () {
|
||||
"use strict"
|
||||
|
||||
m.deps(mock.window)
|
||||
|
||||
test(function () { // eslint-disable-line max-statements
|
||||
var root = mock.document.createElement("div")
|
||||
var retain = false
|
||||
var flag = true
|
||||
var loaded1 = null
|
||||
var loaded2 = null
|
||||
var loaded1a = null
|
||||
var loaded2a = null
|
||||
|
||||
var Comp1 = {
|
||||
controller: function () {
|
||||
loaded1 = true
|
||||
this.onunload = function () {
|
||||
loaded1 = false
|
||||
}
|
||||
},
|
||||
view: function () {
|
||||
if (retain) {
|
||||
return {subtree: "retain"}
|
||||
} else {
|
||||
return m("a", {
|
||||
config: function (el, init, ctx) {
|
||||
if (!init) {
|
||||
loaded1a = true
|
||||
ctx.onunload = function () {
|
||||
loaded1a = false
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var Comp2 = {
|
||||
controller: function () {
|
||||
loaded2 = true
|
||||
this.onunload = function () {
|
||||
loaded2 = false
|
||||
}
|
||||
},
|
||||
view: function () {
|
||||
if (retain) {
|
||||
return {subtree: "retain"}
|
||||
} else {
|
||||
return m("b", {
|
||||
config: function (el, init, ctx) {
|
||||
if (!init) {
|
||||
loaded2a = true
|
||||
ctx.onunload = function () {
|
||||
loaded2a = false
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var Root = {
|
||||
view: function () {
|
||||
return flag ? Comp1 : Comp2
|
||||
}
|
||||
}
|
||||
|
||||
m.mount(root, Root)
|
||||
|
||||
mock.requestAnimationFrame.$resolve()
|
||||
|
||||
// loaded 1
|
||||
var result1 = loaded1 === true &&
|
||||
loaded2 === null &&
|
||||
loaded1a === true &&
|
||||
loaded2a === null
|
||||
|
||||
retain = true
|
||||
m.redraw(true)
|
||||
mock.requestAnimationFrame.$resolve()
|
||||
|
||||
// retained
|
||||
var result2 = loaded1 === true &&
|
||||
loaded2 === null &&
|
||||
loaded1a === true &&
|
||||
loaded2a === null
|
||||
|
||||
flag = false
|
||||
m.redraw(true)
|
||||
mock.requestAnimationFrame.$resolve()
|
||||
|
||||
// loaded 2 while retained: both controllers are alive at the same time
|
||||
// because dom element is retained
|
||||
var result3 = loaded1 === true &&
|
||||
loaded2 === true &&
|
||||
loaded1a === true &&
|
||||
loaded2a === null
|
||||
|
||||
retain = false
|
||||
m.redraw(true)
|
||||
mock.requestAnimationFrame.$resolve()
|
||||
|
||||
// unretained, i.e. 2 is now dynamic
|
||||
var result4 = loaded1 === false &&
|
||||
loaded2 === true &&
|
||||
loaded1a === false &&
|
||||
loaded2a === true
|
||||
|
||||
flag = true
|
||||
m.redraw(true)
|
||||
mock.requestAnimationFrame.$resolve()
|
||||
|
||||
// loaded 1 while dynamic
|
||||
var result5 = loaded1 === true &&
|
||||
loaded2 === false &&
|
||||
loaded1a === true &&
|
||||
loaded2a === false
|
||||
|
||||
return result1 && result2 && result3 && result4 && result5
|
||||
})
|
||||
|
||||
/*
|
||||
test(function() {
|
||||
var root = mock.document.createElement("div")
|
||||
var redraws = 0, data
|
||||
var Root = {
|
||||
view: function() {
|
||||
return Comp
|
||||
}
|
||||
}
|
||||
|
||||
var Comp = {
|
||||
controller: function() {
|
||||
this.foo = m.request({method: "GET", url: "/foo"})
|
||||
},
|
||||
view: function(ctrl) {
|
||||
redraws++
|
||||
data = ctrl.foo()
|
||||
return m("div")
|
||||
}
|
||||
}
|
||||
|
||||
m.mount(root, Root)
|
||||
|
||||
mock.requestAnimationFrame.$resolve()
|
||||
mock.XMLHttpRequest.$instances.pop().onreadystatechange()
|
||||
|
||||
return redraws == 1 && data.url == "/foo"
|
||||
})
|
||||
*/
|
||||
|
||||
test.print(function (value) {
|
||||
console.log(value) // eslint-disable-line no-console
|
||||
})
|
||||
})()
|
||||
|
|
@ -5,4 +5,4 @@
|
|||
<script src="../mithril.js"></script>
|
||||
<script src="mithril-tests.js"></script>
|
||||
|
||||
<p>Open the console to see the test report</p>
|
||||
<p>Open the console to see the test report</p>
|
||||
|
|
|
|||
|
|
@ -1,48 +0,0 @@
|
|||
<p>Typing in the fields below should not move the cursor to the end of the input. Especially in Chrome</p>
|
||||
<p>All inputs should update with the same value</p>
|
||||
<p>Typing in an input should not prevent it from being updated by other inputs</p>
|
||||
<div id="test"></div>
|
||||
<script src="../mithril.js"></script>
|
||||
<script>
|
||||
var app = {}
|
||||
|
||||
app.controller = function() {
|
||||
this.title = m.prop("hello world");
|
||||
}
|
||||
|
||||
app.view = function(ctrl) {
|
||||
return m("body", [
|
||||
m("h1", ["Title: ", ctrl.title()]),
|
||||
m("input[list=data]", {
|
||||
onkeyup: m.withAttr("value", ctrl.title),
|
||||
value: ctrl.title()
|
||||
}),
|
||||
m("datalist#data", [
|
||||
m("option", "John"),
|
||||
m("option", "Bob"),
|
||||
m("option", "Mary")
|
||||
]),
|
||||
m("br"),
|
||||
m("textarea", {
|
||||
onkeyup: m.withAttr("value", ctrl.title),
|
||||
value: ctrl.title()
|
||||
}),
|
||||
m("br"),
|
||||
m("textarea", {
|
||||
onkeyup: m.withAttr("value", ctrl.title)
|
||||
}, ctrl.title()),
|
||||
m("br"),
|
||||
m("div[contenteditable]", {
|
||||
style: {border: "1px solid #888"},
|
||||
onkeyup: m.withAttr("innerHTML", ctrl.title)
|
||||
}, ctrl.title()),
|
||||
m("br"),
|
||||
m("div[contenteditable]", {
|
||||
style: {border: "1px solid #888"},
|
||||
onkeyup: m.withAttr("innerHTML", ctrl.title)
|
||||
}, m.trust(ctrl.title())),
|
||||
]);
|
||||
}
|
||||
|
||||
m.module(document.getElementById("test"), app);
|
||||
</script>
|
||||
|
|
@ -1,135 +0,0 @@
|
|||
<!doctype html>
|
||||
<!--<script src="https://cdnjs.cloudflare.com/ajax/libs/es5-shim/4.0.3/es5-shim.min.js"></script>-->
|
||||
<script src="test.js"></script>
|
||||
<script src="mock.js"></script>
|
||||
<script src="../mithril.js"></script>
|
||||
|
||||
<p>Open the console to see the test report</p>
|
||||
<script>
|
||||
function testMithril(mock) {
|
||||
m.deps(mock)
|
||||
|
||||
test(function() {
|
||||
var root = mock.document.createElement("div")
|
||||
var retain = false
|
||||
var flag = true
|
||||
var loaded1 = null, loaded2 = null, loaded1a = null, loaded2a = null
|
||||
|
||||
var Root = {
|
||||
view: function() {
|
||||
return flag ? Comp1 : Comp2
|
||||
}
|
||||
}
|
||||
|
||||
var Comp1 = {
|
||||
controller: function() {
|
||||
loaded1 = true
|
||||
this.onunload = function() {
|
||||
loaded1 = false
|
||||
}
|
||||
},
|
||||
view: function(ctrl) {
|
||||
return retain ? {subtree: "retain"} : m("a", {config: function(el, init, ctx) {
|
||||
if (!init) {
|
||||
loaded1a = true
|
||||
ctx.onunload = function() {
|
||||
loaded1a = false
|
||||
}
|
||||
}
|
||||
}})
|
||||
}
|
||||
}
|
||||
var Comp2 = {
|
||||
controller: function() {
|
||||
loaded2 = true
|
||||
this.onunload = function() {
|
||||
loaded2 = false
|
||||
}
|
||||
},
|
||||
view: function(ctrl) {
|
||||
return retain ? {subtree: "retain"} : m("b", {config: function(el, init, ctx) {
|
||||
if (!init) {
|
||||
loaded2a = true
|
||||
ctx.onunload = function() {
|
||||
loaded2a = false
|
||||
}
|
||||
}
|
||||
}})
|
||||
}
|
||||
}
|
||||
|
||||
m.mount(root, Root)
|
||||
|
||||
mock.requestAnimationFrame.$resolve()
|
||||
|
||||
//loaded 1
|
||||
var result1 = loaded1 === true && loaded2 === null && loaded1a === true && loaded2a === null
|
||||
|
||||
retain = true
|
||||
m.redraw(true)
|
||||
mock.requestAnimationFrame.$resolve()
|
||||
|
||||
//retained
|
||||
var result2 = loaded1 === true && loaded2 === null && loaded1a === true && loaded2a === null
|
||||
|
||||
flag = false
|
||||
m.redraw(true)
|
||||
mock.requestAnimationFrame.$resolve()
|
||||
|
||||
//loaded 2 while retained: both controllers are alive at the same time because dom element is retained
|
||||
var result3 = loaded1 === true && loaded2 === true && loaded1a === true && loaded2a === null
|
||||
|
||||
retain = false
|
||||
m.redraw(true)
|
||||
mock.requestAnimationFrame.$resolve()
|
||||
|
||||
//unretained, i.e. 2 is now dynamic
|
||||
var result4 = loaded1 === false && loaded2 === true && loaded1a === false && loaded2a === true
|
||||
|
||||
flag = true
|
||||
m.redraw(true)
|
||||
mock.requestAnimationFrame.$resolve()
|
||||
|
||||
//loaded 1 while dynamic
|
||||
var result5 = loaded1 === true && loaded2 === false && loaded1a === true && loaded2a === false
|
||||
|
||||
return result1 && result2 && result3 && result4 && result5
|
||||
})
|
||||
|
||||
|
||||
/*
|
||||
test(function() {
|
||||
var root = mock.document.createElement("div")
|
||||
var redraws = 0, data
|
||||
var Root = {
|
||||
view: function() {
|
||||
return Comp
|
||||
}
|
||||
}
|
||||
|
||||
var Comp = {
|
||||
controller: function() {
|
||||
this.foo = m.request({method: "GET", url: "/foo"})
|
||||
},
|
||||
view: function(ctrl) {
|
||||
redraws++
|
||||
data = ctrl.foo()
|
||||
return m("div")
|
||||
}
|
||||
}
|
||||
|
||||
m.mount(root, Root)
|
||||
|
||||
mock.requestAnimationFrame.$resolve()
|
||||
mock.XMLHttpRequest.$instances.pop().onreadystatechange()
|
||||
|
||||
return redraws == 1 && data.url == "/foo"
|
||||
})
|
||||
*/
|
||||
}
|
||||
|
||||
//mocks
|
||||
testMithril(mock.window)
|
||||
|
||||
test.print(function(value) {console.log(value)})
|
||||
</script>
|
||||
File diff suppressed because it is too large
Load diff
135
tests/mock.js
135
tests/mock.js
|
|
@ -1,40 +1,49 @@
|
|||
if (!Array.prototype.indexOf) {
|
||||
Array.prototype.indexOf = function (item) {
|
||||
for (var i = 0; i < this.length; i++) {
|
||||
if (this[i] === item) return i
|
||||
}
|
||||
return -1
|
||||
}
|
||||
}
|
||||
if (!Array.prototype.map) {
|
||||
Array.prototype.map = function (callback) {
|
||||
var results = []
|
||||
for (var i = 0; i < this.length; i++) {
|
||||
results[i] = callback(this[i], i, this)
|
||||
}
|
||||
return results
|
||||
}
|
||||
}
|
||||
if (!Array.prototype.filter) {
|
||||
Array.prototype.filter = function (callback) {
|
||||
var results = []
|
||||
for (var i = 0; i < this.length; i++) {
|
||||
if (callback(this[i], i, this)) results.push(this[i])
|
||||
}
|
||||
return results
|
||||
}
|
||||
}
|
||||
if (!Object.keys) {
|
||||
Object.keys = function () {
|
||||
var keys = []
|
||||
for (var i in this) keys.push(i)
|
||||
return keys
|
||||
}
|
||||
}
|
||||
(function (global) { // eslint-disable-line max-statements
|
||||
"use strict"
|
||||
|
||||
var mock = {}
|
||||
mock.window = (function () {
|
||||
var window = {}
|
||||
/* eslint-disable no-extend-native */
|
||||
if (!Array.prototype.indexOf) {
|
||||
Array.prototype.indexOf = function (item) {
|
||||
for (var i = 0; i < this.length; i++) {
|
||||
if (this[i] === item) return i
|
||||
}
|
||||
return -1
|
||||
}
|
||||
}
|
||||
|
||||
if (!Array.prototype.map) {
|
||||
Array.prototype.map = function (callback) {
|
||||
var results = []
|
||||
for (var i = 0; i < this.length; i++) {
|
||||
results[i] = callback(this[i], i, this)
|
||||
}
|
||||
return results
|
||||
}
|
||||
}
|
||||
|
||||
if (!Array.prototype.filter) {
|
||||
Array.prototype.filter = function (callback) {
|
||||
var results = []
|
||||
for (var i = 0; i < this.length; i++) {
|
||||
if (callback(this[i], i, this)) results.push(this[i])
|
||||
}
|
||||
return results
|
||||
}
|
||||
}
|
||||
|
||||
if (!Object.keys) {
|
||||
Object.keys = function () {
|
||||
var keys = []
|
||||
for (var i in this) if ({}.hasOwnProperty.call(this, i)) {
|
||||
keys.push(i)
|
||||
}
|
||||
return keys
|
||||
}
|
||||
}
|
||||
/* eslint-enable no-extend-native */
|
||||
|
||||
var window = global.mock = {window: window}
|
||||
window.window = window
|
||||
window.document = {}
|
||||
window.document.childNodes = []
|
||||
window.document.createElement = function (tag) {
|
||||
|
|
@ -46,6 +55,7 @@ mock.window = (function () {
|
|||
appendChild: window.document.appendChild,
|
||||
removeChild: window.document.removeChild,
|
||||
replaceChild: window.document.replaceChild,
|
||||
|
||||
insertBefore: function (node, reference) {
|
||||
node.parentNode = this
|
||||
var referenceIndex = this.childNodes.indexOf(reference)
|
||||
|
|
@ -54,15 +64,18 @@ mock.window = (function () {
|
|||
if (referenceIndex < 0) this.childNodes.push(node)
|
||||
else this.childNodes.splice(referenceIndex, 0, node)
|
||||
},
|
||||
|
||||
insertAdjacentHTML: function (position, html) {
|
||||
//todo: accept markup
|
||||
// todo: accept markup
|
||||
if (position === "beforebegin") {
|
||||
this.parentNode.insertBefore(window.document.createTextNode(html), this)
|
||||
}
|
||||
else if (position === "beforeend") {
|
||||
this.parentNode.insertBefore(
|
||||
window.document.createTextNode(html),
|
||||
this)
|
||||
} else if (position === "beforeend") {
|
||||
this.appendChild(window.document.createTextNode(html))
|
||||
}
|
||||
},
|
||||
|
||||
setAttribute: function (name, value) {
|
||||
this[name] = value.toString()
|
||||
},
|
||||
|
|
@ -70,7 +83,7 @@ mock.window = (function () {
|
|||
this.namespaceURI = namespace
|
||||
this[name] = value.toString()
|
||||
},
|
||||
getAttribute: function (name, value) {
|
||||
getAttribute: function (name) {
|
||||
return this[name]
|
||||
},
|
||||
addEventListener: function () {},
|
||||
|
|
@ -104,16 +117,18 @@ mock.window = (function () {
|
|||
this.childNodes.splice(index, 1)
|
||||
child.parentNode = null
|
||||
}
|
||||
//getElementsByTagName is only used by JSONP tests, it's not required by Mithril
|
||||
// getElementsByTagName is only used by JSONP tests, it's not required by
|
||||
// Mithril
|
||||
window.document.getElementsByTagName = function (name){
|
||||
name = name.toLowerCase()
|
||||
var out = []
|
||||
|
||||
var traverse = function (node){
|
||||
function traverse(node) {
|
||||
if (node.childNodes && node.childNodes.length > 0){
|
||||
node.childNodes.map(function (curr){
|
||||
if (curr.nodeName.toLowerCase() === name)
|
||||
if (curr.nodeName.toLowerCase() === name) {
|
||||
out.push(curr)
|
||||
}
|
||||
traverse(curr)
|
||||
})
|
||||
}
|
||||
|
|
@ -136,8 +151,9 @@ mock.window = (function () {
|
|||
callback()
|
||||
}
|
||||
}
|
||||
|
||||
window.XMLHttpRequest = (function () {
|
||||
var request = function () {
|
||||
function XMLHttpRequest() {
|
||||
this.$headers = {}
|
||||
this.setRequestHeader = function (key, value) {
|
||||
this.$headers[key] = value
|
||||
|
|
@ -150,21 +166,28 @@ mock.window = (function () {
|
|||
this.responseText = JSON.stringify(this)
|
||||
this.readyState = 4
|
||||
this.status = 200
|
||||
request.$instances.push(this)
|
||||
XMLHttpRequest.$instances.push(this)
|
||||
}
|
||||
}
|
||||
request.$instances = []
|
||||
return request
|
||||
}())
|
||||
window.location = {search: "", pathname: "", hash: ""},
|
||||
XMLHttpRequest.$instances = []
|
||||
return XMLHttpRequest
|
||||
})()
|
||||
|
||||
window.location = {search: "", pathname: "", hash: ""}
|
||||
|
||||
window.history = {}
|
||||
window.history.$$length = 0
|
||||
|
||||
window.history.pushState = function (data, title, url) {
|
||||
window.history.$$length++
|
||||
window.location.pathname = window.location.search = window.location.hash = url
|
||||
},
|
||||
window.history.replaceState = function (data, title, url) {
|
||||
window.location.pathname = window.location.search = window.location.hash = url
|
||||
window.location.pathname =
|
||||
window.location.search =
|
||||
window.location.hash = url
|
||||
}
|
||||
return window
|
||||
}())
|
||||
|
||||
window.history.replaceState = function (data, title, url) {
|
||||
window.location.pathname =
|
||||
window.location.search =
|
||||
window.location.hash = url
|
||||
}
|
||||
})(this)
|
||||
|
|
|
|||
|
|
@ -1,97 +0,0 @@
|
|||
<!doctype html>
|
||||
<html>
|
||||
<head>
|
||||
<title>SVG test</title>
|
||||
<style>
|
||||
.path {
|
||||
stroke-dasharray: 1000;
|
||||
stroke-dashoffset: 1000;
|
||||
animation: dash 5s linear alternate infinite;
|
||||
-webkit-animation: dash 5s linear alternate infinite;
|
||||
}
|
||||
|
||||
@keyframes dash {
|
||||
from {
|
||||
stroke-dashoffset: 1000;
|
||||
}
|
||||
to {
|
||||
stroke-dashoffset: 0;
|
||||
}
|
||||
}
|
||||
@-webkit-keyframes dash {
|
||||
from {
|
||||
stroke-dashoffset: 1000;
|
||||
}
|
||||
to {
|
||||
stroke-dashoffset: 0;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
</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>This page should contain:</p>
|
||||
<ul>
|
||||
<li>an HTML link labeled "HTML link"</li>
|
||||
<li>an SVG link labeled "SVG link"</li>
|
||||
<li>a tilted blue square</li>
|
||||
<li>a cat picture</li>
|
||||
<li>an animated line drawing</li>
|
||||
<li>a clock with the current time</li>
|
||||
</ul>
|
||||
<p>The links should open in a new tab. All items should display title tooltips when hovered over.</p>
|
||||
|
||||
<div id="test"></div>
|
||||
<script src="../mithril.js"></script>
|
||||
<script>
|
||||
var svg = [
|
||||
m("a[href='http://google.com'][target='_blank'][title='HTML link']", "HTML link"),
|
||||
m("br"),
|
||||
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("svg[height='201px'][width='201px']", [
|
||||
m("image[href='http://placekitten.com/201/201'][height='200px'][width='200px'][title='Cat picture']")
|
||||
]),
|
||||
m("svg[enable-background='new 0 0 340 333'][height='333px'][viewBox='0 0 340 333'][width='340px'][x='0px'][y='0px'][title='Line drawings']", [
|
||||
m("path.path[d='M66.039,133.545c0,0-21-57,18-67s49-4,65,8s30,41,53,27s66,4,58,32s-5,44,18,57s22,46,0,45s-54-40-68-16s-40,88-83,48s11-61-11-80s-79-7-70-41C46.039,146.545,53.039,128.545,66.039,133.545z'][fill='#FFFFFF'][stroke='#000000'][stroke-miterlimit='10'][stroke-width='4']")
|
||||
]),
|
||||
m("svg[height='270px'][width='270px'][viewBox='0 0 270 270']", [
|
||||
m("g[transform='translate(150,150)'][title='Clock']", [
|
||||
m("g", [
|
||||
m("circle[r='108'][fill='none'][stroke-width='4'][stroke='gray']"),
|
||||
m("circle[r='97'][fill='none'][stroke-width='11'][stroke='black'][stroke-dasharray='4,46.789082'][transform='rotate(-1.5)']"),
|
||||
m("circle[r='100'][fill='none'][stroke-width='5'][stroke='black'][stroke-dasharray='2,8.471976'][transform='rotate(-.873)']"),
|
||||
]),
|
||||
m("g[transform='rotate(180)']", [
|
||||
m("g[id='hour']", [
|
||||
m("line[stroke-width='5'][y2='75'][stroke-linecap='round'][stroke='blue'][opacity='.5']"),
|
||||
m("animateTransform[attributeName='transform'][type='rotate'][repeatCount='indefinite'][dur='12h'][by='360']"),
|
||||
m("circle[r='7']")
|
||||
]),
|
||||
m("g[id='minute']", [
|
||||
m("line[stroke-width='4'][y2='93'][stroke-linecap='round'][stroke='green'][opacity='.9']"),
|
||||
m("animateTransform[attributeName='transform'][type='rotate'][repeatCount='indefinite'][dur='60min'][by='360']"),
|
||||
m("circle[r='6'][fill='red']")
|
||||
]),
|
||||
m("g[id='second']", [
|
||||
m("line[stroke-width='2'][y1='-20'][y2=102][stroke-linecap='round'][stroke='red']"),
|
||||
m("animateTransform[attributeName='transform'][type='rotate'][repeatCount='indefinite'][dur='60s'][by='360']"),
|
||||
m("circle[r='4'][fill='blue']")
|
||||
])
|
||||
])
|
||||
]),
|
||||
m("script", 'var a=new Date,b=parseInt(a.getHours());b=b>12?b-12:b;var c=parseInt(a.getMinutes()),d=parseInt(a.getSeconds()),e=6*d,f=6*(c+d/60),g=30*(b+c/60+d/3600),h=document.getElementById("hour"),i=document.getElementById("minute"),j=document.getElementById("second");h.setAttribute("transform","rotate("+g.toString()+")"),i.setAttribute("transform","rotate("+f.toString()+")"),j.setAttribute("transform","rotate("+e.toString()+")")'),
|
||||
]),
|
||||
m("svg[height='200px'][width='200px']", [
|
||||
m("foreignObject[x=0][y=0][width='100px'][height='100px'][transform='translate(0,0)']", m('div', {xmlns: "http://www.w3.org/1999/xhtml"}, m.trust('this is a piece of html rendered as <a href="http://www.w3.org/TR/SVG11/extend.html">SVG foreignObject</strong>')))
|
||||
])
|
||||
]
|
||||
|
||||
m.render(document.getElementById("test"), svg)
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
|
|
@ -1,28 +1,38 @@
|
|||
if (!this.console) {
|
||||
var log = function (value) { document.write("<pre>" + value + "</pre>") }
|
||||
this.console = {log: log, error: log}
|
||||
}
|
||||
/* eslint-env browser */
|
||||
|
||||
function test(condition) {
|
||||
test.total++
|
||||
(function (global) {
|
||||
"use strict"
|
||||
|
||||
try {
|
||||
if (!condition()) throw new Error("failed")
|
||||
function log(value) {
|
||||
document.write("<pre>" + value + "</pre>")
|
||||
}
|
||||
catch (e) {
|
||||
console.error(e)
|
||||
test.failures.push(condition)
|
||||
}
|
||||
}
|
||||
test.total = 0
|
||||
test.failures = []
|
||||
test.print = function (print) {
|
||||
for (var i = 0; i < test.failures.length; i++) {
|
||||
print(test.failures[i].toString())
|
||||
}
|
||||
print("tests: " + test.total + "\nfailures: " + test.failures.length)
|
||||
|
||||
if (test.failures.length > 0) {
|
||||
throw new Error(test.failures.length + " tests did not pass")
|
||||
if (!global.console) {
|
||||
global.console = {log: log, error: log}
|
||||
}
|
||||
}
|
||||
|
||||
global.test = test
|
||||
function test(condition) {
|
||||
test.total++
|
||||
|
||||
try {
|
||||
if (!condition()) throw new Error("failed")
|
||||
} catch (e) {
|
||||
console.error(e) // eslint-disable-line no-console
|
||||
test.failures.push(condition)
|
||||
}
|
||||
}
|
||||
test.total = 0
|
||||
test.failures = []
|
||||
test.print = function (print) {
|
||||
for (var i = 0; i < test.failures.length; i++) {
|
||||
print(test.failures[i].toString())
|
||||
}
|
||||
|
||||
print("tests: " + test.total + "\nfailures: " + test.failures.length)
|
||||
|
||||
if (test.failures.length > 0) {
|
||||
throw new Error(test.failures.length + " tests did not pass")
|
||||
}
|
||||
}
|
||||
})(this)
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue