Merge branch 'next' of github.com:lhorie/mithril.js into next

Conflicts:
	docs/mithril.request.md
	mithril.js
This commit is contained in:
Barney 2014-12-10 10:34:55 +00:00
commit 0f2b7dad4d
271 changed files with 44112 additions and 182 deletions

View file

@ -1,7 +1,44 @@
## Change Log
[v0.1.26](/mithril/archive/v0.1.26) - maintenance
### Bug Fixes:
- make sure input[type] is CSS-targetable [#364](https://github.com/lhorie/mithril.js/issues/364)
- throw error if m.route.param is called before initializing routes [#361](https://github.com/lhorie/mithril.js/issues/361)
---
[v0.1.25](/mithril/archive/v0.1.25) - maintenance
### Bug Fixes:
- fixed input cursor jumping regression
- fixed interop bug when QUnit and AMD are used at the same time [#355](https://github.com/lhorie/mithril.js/issues/355)
- fixed route arg duplication in edge case [#352](https://github.com/lhorie/mithril.js/issues/352)
- prevented meaningless error in Chrome edge case [#358](https://github.com/lhorie/mithril.js/issues/358)
---
[v0.1.24](/mithril/archive/v0.1.24) - maintenance
### Bug Fixes:
- Prevent rogue `is` attribute from being created in Chrome
- Fix `data` regression in `m.request`
---
[v0.1.23](/mithril/archive/v0.1.23) - maintenance
### News:
- There's now support for extended custom elements (e.g. `m("button[is=my-button]")`)
- `m.request` now supports a `initialValue` option to help prevent type errors in views when using the `background` option
### Bug Fixes:
- docs now have anchor links for easier navigation
- fixed a bunch of IE8 issues [#298](https://github.com/lhorie/mithril.js/issues/298)
- fixed handling of `method` option in JSONP mode [#292](https://github.com/lhorie/mithril.js/issues/292)
- fixed source map files
@ -9,6 +46,7 @@
- fixed template compiler edge case [#286](https://github.com/lhorie/mithril.js/issues/286)
- fixed pathname bug in m.route [#290](https://github.com/lhorie/mithril.js/issues/290)
- fixed pathname querystring bug in routed links [#304](https://github.com/lhorie/mithril.js/issues/304)
- fixed handling of value in inputs when model value is not in sync with input value [#336](https://github.com/lhorie/mithril.js/issues/336)
---

View file

@ -1,6 +1,6 @@
## How is Mithril Different from Other Frameworks
There are a lot of different Javascript MVC frameworks and evaluating their merits and shortcomings can be a daunting task.
There are a lot of different Javascript frameworks and evaluating their merits and shortcomings can be a daunting task.
This page aims to provide a comparison between Mithril and some of the most widely used frameworks, as well as some of the younger, but relevant ones.
@ -104,7 +104,7 @@ Ember is also more opinionated in terms of how application architecture should l
### React
React is a templating engine developed by Facebook. It's relevant for comparison because it uses the same architecture as Mithril's templating engine: i.e. it acknowledges that DOM operations are the bottleneck of templating systems, and implements a virtual DOM tree which keeps track of changes and only applies diffs to the real DOM where needed.
React is a component engine developed by Facebook. It's relevant for comparison because it uses the same architecture as Mithril's templating engine: i.e. it acknowledges that DOM operations are the bottleneck of templating systems, and implements a virtual DOM tree which keeps track of changes and only applies diffs to the real DOM where needed.
The most visible difference between React and Mithril is that React's *JSX* syntax does not run natively in the browser, whereas Mithril's uncompiled templates do. Both can be compiled, but React's compiled code still has function calls for each virtual DOM element; Mithril templates compile into static Javascript data structures.

View file

@ -136,7 +136,7 @@ myApp.users.index.view = function() {
There's no rule for how you should organize code, and given that namespacing is often achieved with simple javascript, you can use simple javascript patterns to alias a long namespace and reduce the amount of typing:
```javascript
new function() {
!function() {
var module = myApp.users.index = {}
module.vm = {/*...*/}
@ -148,7 +148,7 @@ new function() {
return vm.something
}
}
}()
```
---

View file

@ -130,7 +130,7 @@ In the case of our todo application, the view-model needs a few things: it needs
```javascript
//define the view-model
todo.vm = new function() {
todo.vm = (function() {
var vm = {}
vm.init = function() {
//a running list of todos
@ -148,7 +148,7 @@ todo.vm = new function() {
};
}
return vm
}
}())
```
The code above defines a view-model object called `vm`. It is simply a javascript object that has a `init` function. This function initializes the `vm` object with three members: `list`, which is simply an array, `description`, which is an `m.prop` getter-setter function with an empty string as the initial value, and `add`, which is a method that adds a new Todo instance to `list` if an input description getter-setter is not an empty string.
@ -334,10 +334,10 @@ vm.add = function() {
vm.list.push(new todo.Todo({description: vm.description()}));
vm.description("");
}
}.bind(this);
};
```
The difference with the modified version is that `add` no longer takes an argument, and we call `.bind(this)` at the end to lock the scoping of `this` inside of the `add` method.
The difference with the modified version is that `add` no longer takes an argument.
With this, we can make the `onclick` binding on the template *much* simpler:
@ -447,7 +447,7 @@ todo.TodoList = Array;
//stores a description for new todos before they are created
//and takes care of the logic surrounding when adding is permitted
//and clearing the input after adding a todo to the list
todo.vm = new function() {
todo.vm = (function() {
var vm = {}
vm.init = function() {
//a running list of todos
@ -465,7 +465,7 @@ todo.vm = new function() {
};
}
return vm
}
}())
//the controller defines what part of the model is relevant for the current page
//in our case, there's only one view-model that handles everything

1
docs/layout/ghbtns.html Normal file

File diff suppressed because one or more lines are too long

View file

@ -30,7 +30,7 @@
<a class="button" href="mithril.min.zip">Download v$version</a>
</p>
<iframe src="http://ghbtns.com/github-btn.html?user=lhorie&repo=mithril.js&type=watch&count=true" allowtransparency="true" frameborder="0" scrolling="0" width="100" height="20"></iframe>
<iframe src="ghbtns.html?user=lhorie&repo=mithril.js&type=watch&count=true" allowtransparency="true" frameborder="0" scrolling="0" width="100" height="20"></iframe>
<a href="https://twitter.com/share" class="twitter-share-button" data-url="http://lhorie.github.io/mithril" data-via="LeoHorie">Tweet</a>
<script>!function(d,s,id){var js,fjs=d.getElementsByTagName(s)[0],p=/^http:/.test(d.location)?'http':'https';if(!d.getElementById(id)){js=d.createElement(s);js.id=id;js.src=p+'://platform.twitter.com/widgets.js';fjs.parentNode.insertBefore(js,fjs);}}(document, 'script', 'twitter-wjs');</script>
@ -77,19 +77,22 @@
<h2>Sample code</h2>
<pre><code class="language-javascript">//namespace
var app = {};
//model
var PageList = function() {
app.PageList = function() {
return m.request({method: "GET", url: "pages.json"});
};
//controller
var app = {};
app.controller = function() {
this.pages = app.PageList();
this.rotate = function() {
this.pages().push(this.pages().shift())
}.bind(this)
var pages = app.PageList();
return {
pages: pages,
rotate: function() {
pages().push(pages().shift());
}
}
};
//view
@ -98,7 +101,7 @@ app.view = function(ctrl) {
ctrl.pages().map(function(page) {
return m("a", {href: page.url}, page.title);
}),
m("a", {onclick: ctrl.rotate}, "Rotate links")
m("button", {onclick: ctrl.rotate}, "Rotate links")
];
};
@ -121,11 +124,13 @@ app.PageList = function() {
//controller
app.controller = function() {
this.pages = app.PageList();
this.rotate = function() {
this.pages().push(this.pages().shift())
}.bind(this)
var pages = app.PageList();
return {
pages: pages,
rotate: function() {
pages().push(pages().shift());
}
}
};
//view
@ -246,7 +251,7 @@ m.module(document.getElementById("example"), app);
<blockquote class="twitter-tweet" lang="en"><p>Mithril: The newest JavaScript MVC library 3Kb. <a href="http://twitter.com/LeoHorie">@LeoHorie</a> got it right: It's all about good guides/docs: <a href="http://lhorie.github.io/mithril/comparison.html">lhorie.github.io/mithril/comparison.html</a></p> &mdash; David Corbacho (@dcorbacho) <a href="https://twitter.com/dcorbacho/status/446926407843991552">March 21, 2014</a></blockquote>
<script async src="http://platform.twitter.com/widgets.js"></script>
<script async src="https://platform.twitter.com/widgets.js"></script>
</div>
</div>
</section>

View file

@ -6,7 +6,7 @@ Installation: npm install -g sweet.js
Usage: sjs --module /template-compiler.sjs --output <output-filename>.js <input-filename>.js
*/
macro m {
macro m_impl {
case { _ ($selector, $dynAttrs ..., $children ...) } => {
var selectorSyntax = #{$selector};
var selector = unwrapSyntax(selectorSyntax);
@ -47,7 +47,7 @@ macro m {
return #{ ({tag: $tag, attrs: $attrs , children: $children ...}) };
}
catch (e) {
return #{ m($tag, {}, [$dynAttrs ..., $children ...]) }
return #{ m_impl($tag, {}, [$dynAttrs ..., $children ...]) }
}
}
case { _ ($selector, $partial ...) } => {
@ -55,17 +55,29 @@ macro m {
try {
var partial = unwrapSyntax(partialSyntax);
var isTag = partial.inner && partial.inner.length > 2 && (partial.inner[0].token.value == "tag" && partial.inner[1].token.value == ":")
return !isTag ? #{m($selector, $partial ..., [])} : #{m($selector, {}, $partial ...)};
return !isTag ? #{m_impl($selector, $partial ..., [])} : #{m_impl($selector, {}, $partial ...)};
}
catch (e) {
return #{m($selector, {}, $partial ...)}
return #{m_impl($selector, {}, $partial ...)}
}
}
case { _ ($selector) } => {
return #{m($selector, {}, [])};
return #{m_impl($selector, {}, [])};
}
}
let m = macro {
case { _ ($selector, $dynAttrs ..., $children ...) } => {
return #{m_impl($selector, $dynAttrs ..., $children ...)}
}
case { _ ($selector, $partial ...) } => {
return #{m_impl($selector, $partial ...)}
}
case { _ ($selector) } => {
return #{m_impl($selector, {}, [])};
}
case { _ } => {
return #{Mithril};
return #{m};
}
}

View file

@ -2,7 +2,7 @@
---
- [How auto-redrawing-works](#how-auto-redrawing-works)
- [How auto-redrawing works](#how-auto-redrawing-works)
- [Integrating multiple execution threads](#integrating-multiple-execution-threads)
- [Integrating to legacy code](#integrating-to-legacy-code)
- [Signature](#signature)
@ -242,4 +242,4 @@ void startComputation()
```clike
void endComputation()
```
```

View file

@ -64,17 +64,17 @@ The example below shows how to use a SubtreeDirective object to create a static
var app = {}
//here's an example plugin that determines whether data has changes.
//in this case, it simply assume data has changed the first time, and never changes after that.
app.bindOnce = new function() {
//in this case, it simply assumes data has changed the first time, and never changes after that.
app.bindOnce = (function() {
var cache = {}
function(view) {
return function(view) {
if (!cache[view.toString()]) {
cache[view.toString()] = true
return view()
}
else return {subtree: "retain"}
}
}
}())
//here's the view
app.view = function() {

View file

@ -18,7 +18,7 @@ Because Mithril encourages all entity logic to be done in the model layer, it's
Models are also responsible for centralizing tasks such as filtering of entity lists and validation routines, so that access to these methods is available across the application.
DOM manipulation should be done in the view via [`m()` and `config`](mithril). Controllers may explicitly call [`m.redraw`](mithril.redraw.md), but, if possible, it's preferable to abstract this into a service which integrates with Mithril's auto-redrawing system (see [`m.startComputation` / `m.endComputation`](mithril.computation.md)).
DOM manipulation should be done in the view via [`m()` and `config`](mithril). Controllers may explicitly call [`m.redraw`](mithril.redraw.md), but, if possible, it's preferable to abstract this into a service which integrates with Mithril's auto-redrawing system (see [`m.startComputation` / `m.endComputation`](mithril.computation.md)). You should avoid instantiating controller classes from views.
---
@ -68,39 +68,13 @@ That organization pattern needlessly ties unrelated aspects of the application t
---
## Global Namespace Hygiene
For developer convenience, Mithril uses the global `m` variable as a namespace, much like jQuery uses `$`.
If you want to ensure global namespace hygiene, you can wrap your code in "islands" like this:
```javascript
new function(m) {
//your code goes here
}(Mithril);
```
If you are creating components to be used by 3rd parties, it's recommended that you always use this idiom.
In the unlikely case that you have another global variable called `m` in your page, you should consider renaming it to make it more descriptive, or use the idiom below to keep it intact.
```markup
<script>_temp = m</script>
<script src="mithril.js"></script>
<script>m = _temp</script>
```
---
## Usage of m.redraw
`m.redraw` is a method that allows you to render a template outside the scope of Mithril's auto-redrawing system.
Calling this method while using `m.module` or `m.route` should only be done if you have recurring asynchronous view updates (i.e. something that uses setInterval).
If you're integrating other non-recurring services (e.g. calling setTimeout), you should use [`m.startComputation` / `m.emdComputation`](mithril.computation.md) instead.
If you're integrating other non-recurring services (e.g. calling setTimeout), you should use [`m.startComputation` / `m.endComputation`](mithril.computation.md) instead.
This is the most potentially expensive method in Mithril and should not be used at a rate faster than the rate at which the native `requestAnimationFrame` method fires (i.e. the rate at which browsers are comfortable calling recurring rendering-intensive code). Typically, this rate is around 60 calls per second.

View file

@ -62,7 +62,7 @@ Mithril relies on some Ecmascript 5 features, namely: `Array::indexOf`, `Array::
The easiest way to polyfill these features is to include this script:
```javascript
<script src="https://polyfill.io/"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/es5-shim/4.0.3/es5-shim.min.js"></script>
```
This will provide all the polyfills required for the browser. You can alternatively include only specific polyfills: