Merge branch 'next' of https://github.com/lhorie/mithril.js into next
This commit is contained in:
commit
1ebb613e10
5 changed files with 148 additions and 56 deletions
|
|
@ -1,5 +1,6 @@
|
|||
# Change log
|
||||
|
||||
- [v1.1.1](#v111)
|
||||
- [v1.1.0](#v110)
|
||||
- [v1.0.1](#v101)
|
||||
- [Migrating from v0.2.x](#migrating-from-v02x)
|
||||
|
|
@ -7,12 +8,21 @@
|
|||
|
||||
---
|
||||
|
||||
### v1.1.1
|
||||
|
||||
#### Bug fixes
|
||||
|
||||
- hyperscript: Allow `0` as the second argument to `m()` - [#1752](https://github.com/lhorie/mithril.js/issues/#1752) / [#1753](https://github.com/lhorie/mithril.js/pull/#1753) ([@StephanHoyer](https://github.com/StephanHoyer))
|
||||
- hyperscript: remove `attrs.class` after normalizing to `attrs.className` - [#1764](https://github.com/lhorie/mithril.js/issues/#1764) / [#1769](https://github.com/lhorie/mithril.js/pull/#1769)
|
||||
- documentation improvements ([@JAForbes](https://github.com/JAForbes), [@smuemd](https://github.com/smuemd), [@hankeypancake](https://github.com/hankeypancake))
|
||||
|
||||
### v1.1.0
|
||||
|
||||
#### News
|
||||
|
||||
- support for ES6 class components
|
||||
- support for closure components
|
||||
- improvements in build and release automation
|
||||
|
||||
#### Bug fixes
|
||||
|
||||
|
|
|
|||
|
|
@ -203,7 +203,7 @@ Vue | Mithril
|
|||
|
||||
Vue is heavily inspired by Angular and has many things that Angular does (e.g. directives, filters, bi-directional bindings, `v-cloak`), but also has things inspired by React (e.g. components). As of Vue 2.0, it's also possible to write templates using hyperscript/JSX syntax (in addition to single-file components and the various webpack-based language transpilation plugins). Vue provides both bi-directional data binding and an optional Redux-like state management library, but unlike Angular, it provides no style guide. The many-ways-of-doing-one-thing approach can cause architectural fragmentation in long-lived projects.
|
||||
|
||||
Mithril has far less concepts and typically organizes applications in terms of components and a data layer. There are no different ways of defining components, and thus there's no need to install different sets of tools to make different flavors work.
|
||||
Mithril has far less concepts and typically organizes applications in terms of components and a data layer. All component creation styles in Mithril output the same vnode structure using native Javascript features only. The direct consequence of leaning on the language is less tooling and a simpler project setup.
|
||||
|
||||
#### Documentation
|
||||
|
||||
|
|
|
|||
16
docs/keys.md
16
docs/keys.md
|
|
@ -96,21 +96,21 @@ users.map(function(u) {
|
|||
|
||||
#### Avoid hiding keys in component root elements
|
||||
|
||||
If you refactor the code and put the button inside a component, the key must be moved out of the component and placed back where the component took the place of the button.
|
||||
If you refactor the code and make a user component, the key must be moved out of the component and put on the component itself, since it is now the immediate child of the array.
|
||||
|
||||
```javascript
|
||||
// AVOID
|
||||
var Button = {
|
||||
var User = {
|
||||
view: function(vnode) {
|
||||
return m("button", {key: vnode.attrs.id}, u.name)
|
||||
return m("div", { key: vnode.attrs.user.id }, [
|
||||
m(Button, vnode.attrs.user.name)
|
||||
])
|
||||
}
|
||||
}
|
||||
|
||||
// PREFER
|
||||
users.map(function(u) {
|
||||
return m("div", [
|
||||
m(Button, {key: u.id}, u.name) // key should be here, not in component
|
||||
])
|
||||
return m(User, { key: u.id, user: u }) // key should be here, not in component
|
||||
})
|
||||
```
|
||||
|
||||
|
|
@ -195,12 +195,12 @@ users[0].key = 'c'
|
|||
// AVOID
|
||||
users.map(function(user){
|
||||
// The component for John will be destroyed and recreated
|
||||
return m(UserComponent, user)
|
||||
return m(UserComponent, user)
|
||||
})
|
||||
|
||||
// PREFER
|
||||
users.map(function(user){
|
||||
// Key is specifically extracted: data model is given its own property
|
||||
return m(UserComponent, {key: user.id, model: user})
|
||||
return m(UserComponent, {key: user.id, model: user})
|
||||
})
|
||||
```
|
||||
|
|
|
|||
|
|
@ -1,6 +1,18 @@
|
|||
"use strict"
|
||||
|
||||
var parseURL = require("../test-utils/parseURL")
|
||||
var callAsync = require("../test-utils/callAsync.js")
|
||||
|
||||
function debouncedAsync(f) {
|
||||
var ref
|
||||
return function() {
|
||||
if (ref != null) return
|
||||
ref = callAsync(function(){
|
||||
ref = null
|
||||
f()
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = function(options) {
|
||||
if (options == null) options = {}
|
||||
|
|
@ -29,7 +41,9 @@ module.exports = function(options) {
|
|||
if (data.search != null && data.search !== search) search = data.search, isNew = true
|
||||
if (data.hash != null && data.hash !== hash) {
|
||||
hash = data.hash
|
||||
if (!isNew) hashchange()
|
||||
if (!isNew) {
|
||||
hashchange()
|
||||
}
|
||||
}
|
||||
return isNew
|
||||
}
|
||||
|
|
@ -38,9 +52,10 @@ module.exports = function(options) {
|
|||
if (value === "") return ""
|
||||
return (value.charAt(0) !== prefix ? prefix : "") + value
|
||||
}
|
||||
function hashchange() {
|
||||
function _hashchange() {
|
||||
if (typeof $window.onhashchange === "function") $window.onhashchange({type: "hashchange"})
|
||||
}
|
||||
var hashchange = debouncedAsync(_hashchange)
|
||||
function popstate() {
|
||||
if (typeof $window.onpopstate === "function") $window.onpopstate({type: "popstate", state: $window.history.state})
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
var o = require("../../ospec/ospec")
|
||||
var pushStateMock = require("../../test-utils/pushStateMock")
|
||||
|
||||
var callAsync = require("../../test-utils/callAsync")
|
||||
o.spec("pushStateMock", function() {
|
||||
|
||||
var $window
|
||||
|
|
@ -478,93 +478,160 @@ o.spec("pushStateMock", function() {
|
|||
})
|
||||
})
|
||||
o.spec("onhashchance", function() {
|
||||
o("onhashchange triggers on location.href change", function() {
|
||||
o("onhashchange triggers on location.href change", function(done) {
|
||||
$window.onhashchange = o.spy()
|
||||
$window.location.href = "http://localhost/#a"
|
||||
|
||||
o($window.onhashchange.callCount).equals(1)
|
||||
o($window.onhashchange.args[0].type).equals("hashchange")
|
||||
callAsync(function(){
|
||||
o($window.onhashchange.callCount).equals(1)
|
||||
o($window.onhashchange.args[0].type).equals("hashchange")
|
||||
done()
|
||||
})
|
||||
})
|
||||
o("onhashchange triggers on relative location.href change", function() {
|
||||
o("onhashchange triggers on relative location.href change", function(done) {
|
||||
$window.onhashchange = o.spy()
|
||||
$window.location.href = "#a"
|
||||
|
||||
o($window.onhashchange.callCount).equals(1)
|
||||
callAsync(function(){
|
||||
o($window.onhashchange.callCount).equals(1)
|
||||
done()
|
||||
})
|
||||
})
|
||||
o("onhashchange triggers on location.hash change", function() {
|
||||
o("onhashchange triggers on location.hash change", function(done) {
|
||||
$window.onhashchange = o.spy()
|
||||
$window.location.hash = "#a"
|
||||
|
||||
o($window.onhashchange.callCount).equals(1)
|
||||
callAsync(function(){
|
||||
o($window.onhashchange.callCount).equals(1)
|
||||
done()
|
||||
})
|
||||
})
|
||||
o("onhashchange does not trigger on page change", function() {
|
||||
o("onhashchange does not trigger on page change", function(done) {
|
||||
$window.onhashchange = o.spy()
|
||||
$window.location.href = "http://localhost/a"
|
||||
|
||||
o($window.onhashchange.callCount).equals(0)
|
||||
callAsync(function(){
|
||||
o($window.onhashchange.callCount).equals(0)
|
||||
done()
|
||||
})
|
||||
})
|
||||
o("onhashchange does not trigger on page change with different hash", function() {
|
||||
o("onhashchange does not trigger on page change with different hash", function(done) {
|
||||
$window.location.href = "http://localhost/#a"
|
||||
$window.onhashchange = o.spy()
|
||||
$window.location.href = "http://localhost/a#b"
|
||||
callAsync(function(){
|
||||
$window.onhashchange = o.spy()
|
||||
$window.location.href = "http://localhost/a#b"
|
||||
|
||||
o($window.onhashchange.callCount).equals(0)
|
||||
callAsync(function(){
|
||||
o($window.onhashchange.callCount).equals(0)
|
||||
done()
|
||||
})
|
||||
})
|
||||
})
|
||||
o("onhashchange does not trigger on page change with same hash", function() {
|
||||
o("onhashchange does not trigger on page change with same hash", function(done) {
|
||||
$window.location.href = "http://localhost/#b"
|
||||
$window.onhashchange = o.spy()
|
||||
$window.location.href = "http://localhost/a#b"
|
||||
callAsync(function(){
|
||||
$window.onhashchange = o.spy()
|
||||
$window.location.href = "http://localhost/a#b"
|
||||
|
||||
o($window.onhashchange.callCount).equals(0)
|
||||
callAsync(function(){
|
||||
o($window.onhashchange.callCount).equals(0)
|
||||
done()
|
||||
})
|
||||
})
|
||||
})
|
||||
o("onhashchange triggers on history.back()", function() {
|
||||
o("onhashchange triggers on history.back()", function(done) {
|
||||
$window.location.href = "#a"
|
||||
$window.onhashchange = o.spy()
|
||||
$window.history.back()
|
||||
callAsync(function(){
|
||||
$window.onhashchange = o.spy()
|
||||
$window.history.back()
|
||||
|
||||
o($window.onhashchange.callCount).equals(1)
|
||||
callAsync(function(){
|
||||
o($window.onhashchange.callCount).equals(1)
|
||||
done()
|
||||
})
|
||||
})
|
||||
})
|
||||
o("onhashchange triggers on history.forward()", function() {
|
||||
o("onhashchange triggers on history.forward()", function(done) {
|
||||
$window.location.href = "#a"
|
||||
$window.onhashchange = o.spy()
|
||||
$window.history.back()
|
||||
$window.history.forward()
|
||||
callAsync(function(){
|
||||
$window.onhashchange = o.spy()
|
||||
$window.history.back()
|
||||
callAsync(function(){
|
||||
$window.history.forward()
|
||||
|
||||
o($window.onhashchange.callCount).equals(2)
|
||||
callAsync(function(){
|
||||
o($window.onhashchange.callCount).equals(2)
|
||||
done()
|
||||
})
|
||||
})
|
||||
})
|
||||
})
|
||||
o("onhashchange does not trigger on history.back() that causes page change with different hash", function() {
|
||||
o("onhashchange triggers once when the hash changes twice in a single tick", function(done) {
|
||||
$window.location.href = "#a"
|
||||
callAsync(function(){
|
||||
$window.onhashchange = o.spy()
|
||||
$window.history.back()
|
||||
$window.history.forward()
|
||||
|
||||
callAsync(function(){
|
||||
o($window.onhashchange.callCount).equals(1)
|
||||
done()
|
||||
})
|
||||
})
|
||||
})
|
||||
o("onhashchange does not trigger on history.back() that causes page change with different hash", function(done) {
|
||||
$window.location.href = "#a"
|
||||
$window.location.href = "a#b"
|
||||
$window.onhashchange = o.spy()
|
||||
$window.history.back()
|
||||
callAsync(function(){
|
||||
$window.onhashchange = o.spy()
|
||||
$window.history.back()
|
||||
|
||||
o($window.onhashchange.callCount).equals(0)
|
||||
callAsync(function(){
|
||||
o($window.onhashchange.callCount).equals(0)
|
||||
done()
|
||||
})
|
||||
})
|
||||
})
|
||||
o("onhashchange does not trigger on history.back() that causes page change with same hash", function() {
|
||||
o("onhashchange does not trigger on history.back() that causes page change with same hash", function(done) {
|
||||
$window.location.href = "#a"
|
||||
$window.location.href = "a#a"
|
||||
$window.onhashchange = o.spy()
|
||||
$window.history.back()
|
||||
callAsync(function(){
|
||||
$window.onhashchange = o.spy()
|
||||
$window.history.back()
|
||||
|
||||
o($window.onhashchange.callCount).equals(0)
|
||||
callAsync(function(){
|
||||
o($window.onhashchange.callCount).equals(0)
|
||||
done()
|
||||
})
|
||||
})
|
||||
})
|
||||
o("onhashchange does not trigger on history.forward() that causes page change with different hash", function() {
|
||||
o("onhashchange does not trigger on history.forward() that causes page change with different hash", function(done) {
|
||||
$window.location.href = "#a"
|
||||
$window.location.href = "a#b"
|
||||
$window.onhashchange = o.spy()
|
||||
$window.history.back()
|
||||
$window.history.forward()
|
||||
callAsync(function(){
|
||||
$window.onhashchange = o.spy()
|
||||
$window.history.back()
|
||||
$window.history.forward()
|
||||
|
||||
o($window.onhashchange.callCount).equals(0)
|
||||
callAsync(function(){
|
||||
o($window.onhashchange.callCount).equals(0)
|
||||
done()
|
||||
})
|
||||
})
|
||||
})
|
||||
o("onhashchange does not trigger on history.forward() that causes page change with same hash", function() {
|
||||
o("onhashchange does not trigger on history.forward() that causes page change with same hash", function(done) {
|
||||
$window.location.href = "#a"
|
||||
$window.location.href = "a#b"
|
||||
$window.onhashchange = o.spy()
|
||||
$window.history.back()
|
||||
$window.history.forward()
|
||||
callAsync(function(){
|
||||
$window.onhashchange = o.spy()
|
||||
$window.history.back()
|
||||
$window.history.forward()
|
||||
|
||||
o($window.onhashchange.callCount).equals(0)
|
||||
callAsync(function(){
|
||||
o($window.onhashchange.callCount).equals(0)
|
||||
done()
|
||||
})
|
||||
})
|
||||
})
|
||||
})
|
||||
o.spec("onunload", function() {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue