update docs, add descriptions for api methods

This commit is contained in:
Leo Horie 2016-12-02 17:51:07 -05:00
parent d56c30cc4a
commit cdb9017a72
25 changed files with 613 additions and 40 deletions

View file

@ -1,22 +1,174 @@
# API
- [m](hyperscript.md)
- [m.render](render.md)
- [m.mount](mount.md)
- [m.route](route.md)
- [m.route.set](route.md#routeset)
- [m.route.get](route.md#routeget)
- [m.route.prefix](route.md#routeprefix)
- [m.route.link](route.md#routelink)
- [m.request](request.md)
- [m.jsonp](jsonp.md)
- [m.parseQueryString](parseQueryString.md)
- [m.buildQueryString](buildQueryString.md)
- [m.withAttr](withAttr.md)
- [m.trust](trust.md)
- [m.fragment](fragment.md)
- [m.redraw](redraw.md)
- [m.version](version.md)
### Cheatsheet
Here are examples for the most commonly used methods. If a method is not listed below, it's meant for advanced usage.
#### m(selector, attrs, children) - [docs](hyperscript.md)
```javascript
m("div.class#id", {title: "title"}, ["children"])
```
---
#### m.mount(element, component) - [docs](mount.md)
```javascript
var state = {
count: 0,
inc: function() {state.count++}
}
var Counter = {
view: function() {
return m("div", {onclick: state.inc}, state.count)
}
}
m.mount(document.body, Counter)
```
---
#### m.route(root, defaultRoute, routes) - [docs](route.md)
```javascript
var Home = {
view: function() {
return "Welcome"
}
}
m.route(document.body, "/home", {
"/home": Home, // defines `http://localhost/#!/home`
})
```
#### m.route.set(path) - [docs](route.md#routeset)
```javascript
m.route.set("/home")
```
#### m.route.get() - [docs](route.md#routeget)
```javascript
var currentRoute = m.route.get()
```
#### m.route.prefix(prefix) - [docs](route.md#routeprefix)
Call this before `m.route()`
```javascript
m.route.prefix("#!")
```
#### m.route.link() - [docs](route.md#routelink)
```javascript
m("a[href='/Home']", {oncreate: m.route.link}, "Go to home page")
```
---
#### m.request(options) - [docs](request.md)
```javascript
m.request({
method: "PUT",
url: "/api/v1/users/:id",
data: {id: 1, name: "test"}
})
.then(function(result) {
console.log(result)
})
```
---
#### m.jsonp(options) - [docs](jsonp.md)
```javascript
m.jsonp({
url: "/api/v1/users/:id",
data: {id: 1},
callbackKey: "callback",
})
.then(function(result) {
console.log(result)
})
```
---
#### m.parseQueryString(querystring) - [docs](parseQueryString.md)
```javascript
var object = m.parseQueryString("a=1&b=2")
// {a: "1", b: "2"}
```
---
#### m.buildQueryString(object) - [docs](buildQueryString.md)
```javascript
var querystring = m.buildQueryString({a: "1", b: "2"})
// "a=1&b=2"
```
---
#### m.withAttr(attrName, callback) - [docs](withAttr.md)
```javascript
var state: {
value = ""
setValue: function(v) {value = v}
}
var Component = {
view: function() {
return m("input", {
oninput: m.withAttr("value", state.setValue),
value: state.value,
})
}
}
m.mount(document.body, Component)
```
---
#### m.trust(htmlString) - [docs](trust.md)
```javascript
m.render(document.body, m.trust("<h1>Hello</h1>"))
```
---
#### m.redraw() - [docs](redraw.md)
```javascript
var count = 0
function inc() {
setInterval(function() {
count++
m.redraw()
}, 1000)
}
var Counter = {
oninit: inc,
view: function() {
return m("div", count)
}
}
m.mount(document.body, Counter)
```
- [Promise](promise.md)
- [Stream](stream.md)

View file

@ -1,10 +1,22 @@
# buildQueryString(object)
- [Description](#description)
- [Signature](#signature)
- [How it works](#how-it-works)
---
### Description
Turns an object into a string of form `a=1&b=2`
```javascript
var querystring = m.buildQueryString({a: "1", b: "2"})
// "a=1&b=2"
```
---
### Signature
`querystring = m.buildQueryString(object)`

View file

@ -1,8 +1,11 @@
# Examples
Here are some examples of Mithril in action
- [Animation](http://cdn.rawgit.com/lhorie/mithril.js/rewrite/examples/animation/mosaic.html)
- [DBMonster](http://cdn.rawgit.com/lhorie/mithril.js/rewrite/examples/dbmonster/mithril/index.html)
- [Markdown Editor](http://cdn.rawgit.com/lhorie/mithril.js/rewrite/examples/editor/index.html)
- SVG: [Clock](http://cdn.rawgit.com/lhorie/mithril.js/rewrite/examples/svg/clock.html), [Ring](http://cdn.rawgit.com/lhorie/mithril.js/rewrite/examples/svg/ring.html), [Tiger](http://cdn.rawgit.com/lhorie/mithril.js/rewrite/examples/svg/tiger.html)
- [ThreadItJS](http://cdn.rawgit.com/lhorie/mithril.js/rewrite/examples/threaditjs/index.html)
- [TodoMVC](http://cdn.rawgit.com/lhorie/mithril.js/rewrite/examples/todomvc/index.html)
- [TodoMVC](http://cdn.rawgit.com/lhorie/mithril.js/rewrite/examples/todomvc/index.html)

View file

@ -1,10 +1,17 @@
# fragment(attrs, children)
- [Description](#description)
- [Signature](#signature)
- [How it works](#how-it-works)
---
### Description
Allows attaching lifecycle methods to a fragment [vnode](vnodes.md)
---
### Signature
Generates a fragment [vnode](vnodes.md)

52
docs/generate.js Normal file
View file

@ -0,0 +1,52 @@
var fs = require("fs")
var path = require("path")
var marked = require("marked")
var layout = fs.readFileSync("./docs/layout.html", "utf-8")
var version = JSON.parse(fs.readFileSync("./package.json", "utf-8")).version
try {fs.mkdirSync("docs/archive/" + version)} catch (e) {}
try {fs.mkdirSync("docs/archive/" + version + "/lib")} catch (e) {}
try {fs.mkdirSync("docs/archive/" + version + "/lib/prism")} catch (e) {}
var guides = fs.readFileSync("docs/guides.md", "utf-8")
var methods = fs.readFileSync("docs/methods.md", "utf-8")
generate("docs")
function generate(pathname) {
if (fs.lstatSync(pathname).isDirectory()) {
fs.readdirSync(pathname).forEach(function(filename) {
generate(pathname + "/" + filename)
})
}
else if (!pathname.match(/tutorials|archive/)) {
if (pathname.match(/\.md$/)) {
var outputFilename = pathname.replace(/\.md$/, ".html")
var markdown = fs.readFileSync(pathname, "utf-8")
var fixed = markdown
.replace(/(`[^`]+?)<(.*`)/gim, "$1&lt;$2") // fix generic syntax
.replace(/`((?:\S| -> |, )+)(\|)(\S+)`/gim, function(match, a, b, c) { // fix pipes in code tags
return "<code>" + (a + b + c).replace(/\|/g, "&#124;") + "</code>"
})
.replace(/(^# .+?(?:\r?\n){2,}?)(?:(-(?:.|\r|\n)+?)((?:\r?\n){2,})|)/m, function(match, title, nav, space) { // inject menu
var file = path.basename(pathname)
var link = new RegExp("([ \t]*)(- )(\\[.+?\\]\\(" + file + "\\))")
var replace = function(match, space, li, link) {
return space + li + "**" + link + "**" + (nav ? "\n" + nav.replace(/(^|\n)/g, "$1\t" + space) : "")
}
var modified = guides.match(link) ? guides.replace(link, replace) : methods.replace(link, replace)
return title + modified + "\n\n"
})
.replace(/\.md/gim, ".html") // fix links
var html = layout
.replace(/\[body\]/, marked(fixed))
.replace(/<h5 id="([^"]+?)">([^<]+?)<\/h5>/gim, function(match, id, text) { // fix anchors
return "<h5 id=\"" + text.toLowerCase().replace(/\.|\[|\]|&quot;|\//g, "") + "\">" + text + "</h5>"
})
fs.writeFileSync("docs/archive/" + version + "/" + outputFilename.replace(/^docs\//, ""), html, "utf-8")
}
else {
fs.writeFileSync("docs/archive/" + version + "/" + pathname.replace(/^docs\//, ""), fs.readFileSync(pathname, "utf-8"), "utf-8")
}
}
}

16
docs/guides.md Normal file
View file

@ -0,0 +1,16 @@
- Tutorials
- [Installation](installation.md)
- [Introduction](introduction.md)
- [Tutorial](tutorial.md)
- [Testing](testing.md)
- [Examples](examples.md)
- Key concepts
- [Vnodes](vnodes.md)
- [Components](components.md)
- [Lifecycle methods](lifecycle-methods.md)
- [Keys](keys.md)
- Migration
- [Migrating from 0.2.x](migration.md)
- Meta
- [Chat room](https://gitter.im/lhorie/mithril.js)
- [Credits](credits.md)

View file

@ -1,5 +1,6 @@
# m(selector, attributes, children)
- [Description](#description)
- [Signature](#signature)
- [How it works](#how-it-works)
- [Flexibility](#flexibility)
@ -17,6 +18,24 @@
---
### Description
Represents an HTML element in a Mithril view
```javascript
m("div", {class: "foo"}, "hello")
// represents <div class="foo">hello</div>
```
You can also [use HTML syntax](https://babeljs.io/repl/#?code=%2F**%20%40jsx%20m%20*%2F%0A%3Ch1%3EMy%20first%20app%3C%2Fh1%3E) via a Babel plugin.
```markup
/** jsx m */
<div class="foo">hello</div>
```
---
### Signature
`vnode = m(selector, attributes, children)`

View file

@ -12,13 +12,13 @@
### What is Mithril?
Mithril is a framework for developing Javascript-based Single Page Applications. It's designed to be fast, small and economical.
Mithril is a framework for building Single Page Applications. It's small but batteries-included.
---
### Getting started
The easiest way to try out Mithril is to include it from a CDN, and follow this tutorial. It'll only take 10 minutes.
The easiest way to try out Mithril is to include it from a CDN, and follow this tutorial. It'll cover the majority of the API surface but it'll only take 10 minutes.
Let's create an HTML file to follow along:
@ -84,6 +84,8 @@ m("main", [
])
```
Note: If you would rather use `<html>` syntax, [you can do so by using Babel](https://babeljs.io/repl/#?code=%2F**%20%40jsx%20m%20*%2F%0A%3Ch1%3EMy%20first%20app%3C%2Fh1%3E).
---
### Components
@ -180,7 +182,7 @@ Basically, XHR is just a way to talk to a server.
Let's change our click counter to make it save data on a server. For the server, we'll use [REM](http://rem-rest-api.herokuapp.com), a mock REST API designed for toy apps like this tutorial.
First we create a function that calls `m.request`.
First we create a function that calls `m.request`. The `url` specifies an endpoint that represents a resource, the `method` specifies the type of action we're taking (typically the `PUT` method [upserts](https://en.wiktionary.org/wiki/upsert)), `data` is the payload that we're sending to the endpoint and `useCredentials` means to enable cookies (a requirement for the REM API to work)
```javascript
var count = 0

View file

@ -1,11 +1,29 @@
# jsonp(options)
- [Description](#description)
- [Signature](#signature)
- [How it works](#how-it-works)
- [Typical usage](#typical-usage)
---
### Description
Makes JSON-P requests. Typically, it's useful to interact with servers that allow JSON-P but that don't have CORS enabled.
```javascript
m.jsonp({
url: "/api/v1/users/:id",
data: {id: 1},
callbackKey: "callback",
})
.then(function(result) {
console.log(result)
})
```
---
### Signature
`promise = m.jsonp(options)`

29
docs/layout.html Normal file
View file

@ -0,0 +1,29 @@
<html>
<head>
<meta charset="UTF-8" />
<title>Mithril.js</title>
<link href='https://fonts.googleapis.com/css?family=Open+Sans' rel='stylesheet' type='text/css' />
<link href="lib/prism/prism.css" rel="stylesheet" />
<link href="style.css" rel="stylesheet" />
</head>
<body>
<header>
<section>
<h1>Mithril</h1>
<nav>
<a href="introduction.html">Guide</a>
<a href="api.html">API</a>
<a href="https://github.com/lhorie/mithril.js">Github</a>
</nav>
</section>
</header>
<main>
<section>
[body]
<hr />
<small>License: MIT. &copy; Leo Horie.</small>
</section>
</main>
<script src="lib/prism/prism.js"></script>
</body>
</html

6
docs/lib/prism/prism.css Normal file
View file

@ -0,0 +1,6 @@
.token.comment,.token.prolog,.token.doctype,.token.cdata {color:#888;}
.token.property,.token.tag,.token.boolean,.token.number,.token.constant,.token.symbol {color:#905;}
.token.selector,.token.attr-name,.token.string,.token.builtin {color:#690;}
.token.atrule,.token.attr-value,.token.punctuation,.token.keyword {color:#1e5799;}
.token.regex,.token.important {color:#e90;}

9
docs/lib/prism/prism.js Normal file
View file

@ -0,0 +1,9 @@
/**
* Prism: Lightweight, robust, elegant syntax highlighting
* MIT license http://www.opensource.org/licenses/mit-license.php/
* @author Lea Verou http://lea.verou.me
*/(function(){var e=/\blang(?:uage)?-(?!\*)(\w+)\b/i,t=self.Prism={util:{type:function(e){return Object.prototype.toString.call(e).match(/\[object (\w+)\]/)[1]},clone:function(e){var n=t.util.type(e);switch(n){case"Object":var r={};for(var i in e)e.hasOwnProperty(i)&&(r[i]=t.util.clone(e[i]));return r;case"Array":return e.slice()}return e}},languages:{extend:function(e,n){var r=t.util.clone(t.languages[e]);for(var i in n)r[i]=n[i];return r},insertBefore:function(e,n,r,i){i=i||t.languages;var s=i[e],o={};for(var u in s)if(s.hasOwnProperty(u)){if(u==n)for(var a in r)r.hasOwnProperty(a)&&(o[a]=r[a]);o[u]=s[u]}return i[e]=o},DFS:function(e,n){for(var r in e){n.call(e,r,e[r]);t.util.type(e)==="Object"&&t.languages.DFS(e[r],n)}}},highlightAll:function(e,n){var r=document.querySelectorAll('code[class*="language-"], [class*="language-"] code, code[class*="lang-"], [class*="lang-"] code');for(var i=0,s;s=r[i++];)t.highlightElement(s,e===!0,n)},highlightElement:function(r,i,s){var o,u,a=r;while(a&&!e.test(a.className))a=a.parentNode;if(a){o=(a.className.match(e)||[,""])[1];u=t.languages[o]}if(!u)return;r.className=r.className.replace(e,"").replace(/\s+/g," ")+" language-"+o;a=r.parentNode;/pre/i.test(a.nodeName)&&(a.className=a.className.replace(e,"").replace(/\s+/g," ")+" language-"+o);var f=r.textContent;if(!f)return;f=f.replace(/&/g,"&amp;").replace(/</g,"&lt;").replace(/\u00a0/g," ");var l={element:r,language:o,grammar:u,code:f};t.hooks.run("before-highlight",l);if(i&&self.Worker){var c=new Worker(t.filename);c.onmessage=function(e){l.highlightedCode=n.stringify(JSON.parse(e.data),o);t.hooks.run("before-insert",l);l.element.innerHTML=l.highlightedCode;s&&s.call(l.element);t.hooks.run("after-highlight",l)};c.postMessage(JSON.stringify({language:l.language,code:l.code}))}else{l.highlightedCode=t.highlight(l.code,l.grammar,l.language);t.hooks.run("before-insert",l);l.element.innerHTML=l.highlightedCode;s&&s.call(r);t.hooks.run("after-highlight",l)}},highlight:function(e,r,i){return n.stringify(t.tokenize(e,r),i)},tokenize:function(e,n,r){var i=t.Token,s=[e],o=n.rest;if(o){for(var u in o)n[u]=o[u];delete n.rest}e:for(var u in n){if(!n.hasOwnProperty(u)||!n[u])continue;var a=n[u],f=a.inside,l=!!a.lookbehind,c=0;a=a.pattern||a;for(var h=0;h<s.length;h++){var p=s[h];if(s.length>e.length)break e;if(p instanceof i)continue;a.lastIndex=0;var d=a.exec(p);if(d){l&&(c=d[1].length);var v=d.index-1+c,d=d[0].slice(c),m=d.length,g=v+m,y=p.slice(0,v+1),b=p.slice(g+1),w=[h,1];y&&w.push(y);var E=new i(u,f?t.tokenize(d,f):d);w.push(E);b&&w.push(b);Array.prototype.splice.apply(s,w)}}}return s},hooks:{all:{},add:function(e,n){var r=t.hooks.all;r[e]=r[e]||[];r[e].push(n)},run:function(e,n){var r=t.hooks.all[e];if(!r||!r.length)return;for(var i=0,s;s=r[i++];)s(n)}}},n=t.Token=function(e,t){this.type=e;this.content=t};n.stringify=function(e,r,i){if(typeof e=="string")return e;if(Object.prototype.toString.call(e)=="[object Array]")return e.map(function(t){return n.stringify(t,r,e)}).join("");var s={type:e.type,content:n.stringify(e.content,r,i),tag:"span",classes:["token",e.type],attributes:{},language:r,parent:i};s.type=="comment"&&(s.attributes.spellcheck="true");t.hooks.run("wrap",s);var o="";for(var u in s.attributes)o+=u+'="'+(s.attributes[u]||"")+'"';return"<"+s.tag+' class="'+s.classes.join(" ")+'" '+o+">"+s.content+"</"+s.tag+">"};if(!self.document){self.addEventListener("message",function(e){var n=JSON.parse(e.data),r=n.language,i=n.code;self.postMessage(JSON.stringify(t.tokenize(i,t.languages[r])));self.close()},!1);return}var r=document.getElementsByTagName("script");r=r[r.length-1];if(r){t.filename=r.src;document.addEventListener&&!r.hasAttribute("data-manual")&&document.addEventListener("DOMContentLoaded",t.highlightAll)}})();;
Prism.languages.markup={comment:/&lt;!--[\w\W]*?-->/g,prolog:/&lt;\?.+?\?>/,doctype:/&lt;!DOCTYPE.+?>/,cdata:/&lt;!\[CDATA\[[\w\W]*?]]>/i,tag:{pattern:/&lt;\/?[\w:-]+\s*(?:\s+[\w:-]+(?:=(?:("|')(\\?[\w\W])*?\1|\w+))?\s*)*\/?>/gi,inside:{tag:{pattern:/^&lt;\/?[\w:-]+/i,inside:{punctuation:/^&lt;\/?/,namespace:/^[\w-]+?:/}},"attr-value":{pattern:/=(?:('|")[\w\W]*?(\1)|[^\s>]+)/gi,inside:{punctuation:/=|>|"/g}},punctuation:/\/?>/g,"attr-name":{pattern:/[\w:-]+/g,inside:{namespace:/^[\w-]+?:/}}}},entity:/&amp;#?[\da-z]{1,8};/gi};Prism.hooks.add("wrap",function(e){e.type==="entity"&&(e.attributes.title=e.content.replace(/&amp;/,"&"))});;
Prism.languages.clike={comment:{pattern:/(^|[^\\])(\/\*[\w\W]*?\*\/|(^|[^:])\/\/.*?(\r?\n|$))/g,lookbehind:!0},string:/("|')(\\?.)*?\1/g,"class-name":{pattern:/((?:(?:class|interface|extends|implements|trait|instanceof|new)\s+)|(?:catch\s+\())[a-z0-9_\.\\]+/ig,lookbehind:!0,inside:{punctuation:/(\.|\\)/}},keyword:/\b(if|else|while|do|for|return|in|instanceof|function|new|try|throw|catch|finally|null|break|continue)\b/g,"boolean":/\b(true|false)\b/g,"function":{pattern:/[a-z0-9_]+\(/ig,inside:{punctuation:/\(/}}, number:/\b-?(0x[\dA-Fa-f]+|\d*\.?\d+([Ee]-?\d+)?)\b/g,operator:/[-+]{1,2}|!|&lt;=?|>=?|={1,3}|(&amp;){1,2}|\|?\||\?|\*|\/|\~|\^|\%/g,ignore:/&(lt|gt|amp);/gi,punctuation:/[{}[\];(),.:]/g};
;
Prism.languages.javascript=Prism.languages.extend("clike",{keyword:/\b(var|let|if|else|while|do|for|return|in|instanceof|function|get|set|new|with|typeof|try|throw|catch|finally|null|break|continue)\b/g,number:/\b-?(0x[\dA-Fa-f]+|\d*\.?\d+([Ee]-?\d+)?|NaN|-?Infinity)\b/g});Prism.languages.insertBefore("javascript","keyword",{regex:{pattern:/(^|[^/])\/(?!\/)(\[.+?]|\\.|[^/\r\n])+\/[gim]{0,3}(?=\s*($|[\r\n,.;})]))/g,lookbehind:!0}});Prism.languages.markup&&Prism.languages.insertBefore("markup","tag",{script:{pattern:/(&lt;|<)script[\w\W]*?(>|&gt;)[\w\W]*?(&lt;|<)\/script(>|&gt;)/ig,inside:{tag:{pattern:/(&lt;|<)script[\w\W]*?(>|&gt;)|(&lt;|<)\/script(>|&gt;)/ig,inside:Prism.languages.markup.tag.inside},rest:Prism.languages.javascript}}});;

20
docs/methods.md Normal file
View file

@ -0,0 +1,20 @@
- Core
- [m](hyperscript.md)
- [m.render](render.md)
- [m.mount](mount.md)
- [m.route](route.md)
- [m.request](request.md)
- [m.jsonp](jsonp.md)
- [m.parseQueryString](parseQueryString.md)
- [m.buildQueryString](buildQueryString.md)
- [m.withAttr](withAttr.md)
- [m.trust](trust.md)
- [m.fragment](fragment.md)
- [m.redraw](redraw.md)
- [m.version](version.md)
- [Promise](promise.md)
- Optional
- [Stream](stream.md)
- Tooling
- [Bundler](bundler.md)
- [Ospec](ospec.md)

View file

@ -1,5 +1,6 @@
# mount(root, component)
- [Description](#description)
- [Signature](#signature)
- [How it works](#how-it-works)
- [Performance considerations](#performance-considerations)
@ -7,6 +8,27 @@
---
### Description
Activates a component, enabling it to autoredraw on user events
```javascript
var state = {
count: 0,
inc: function() {state.count++}
}
var Counter = {
view: function() {
return m("div", {onclick: state.inc}, state.count)
}
}
m.mount(document.body, Counter)
```
---
### Signature
`m.mount(element, component)`

View file

@ -1,10 +1,22 @@
# parseQueryString(string)
- [Description](#description)
- [Signature](#signature)
- [How it works](#how-it-works)
---
### Description
Turns a string of the form `?a=1&b=2` to an object
```javascript
var object = m.parseQueryString("a=1&b=2")
// {a: "1", b: "2"}
```
---
### Signature
`object = m.parseQueryString(string)`

View file

@ -1,5 +1,6 @@
# Promise(executor)
- [Description](#description)
- [Signature](#signature)
- [Static members](#static-members)
- [Promise.resolve](#promiseresolve)
@ -14,7 +15,16 @@
- [Promise absorption](#promise-absorption)
- [Error handling](#error-handling)
- [Shorthands](#shorthands)
- [Waiting for multiple promises](#waiting-for-multiple-promises)
- [Multiple promises](#multiple-promises)
- [Why not callbacks](#why-not-callbacks)
---
### Description
A [ES6 Promise](https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Global_Objects/Promise) polyfill.
A Promise is a mechanism for working with asynchronous computations.
---
@ -262,7 +272,7 @@ promise
---
### Waiting for multiple promises
### Multiple promises
In some occasions, you may need to make HTTP requests in parallel, and run code after all requests complete. This can be accomplished by `Promise.all`
@ -287,3 +297,13 @@ Promise.all([
In the example above, there are two user searches happening in parallel. Once they both complete, we take the names of all the users and alert them.
This example also illustrates another benefit of smaller functions: we reused the `getUserNames` function we had created above.
---
### Why not callbacks
Callbacks are another mechanism for working with asynchrounous computations, and are indeed more adequate to use if an asynchronous computation may occur more than one time (for example, an `onscroll` event handler).
However, for asynchronous computations that only occur once in response to an action, promises can be refactored more effectively, reducing code smells known as pyramids of doom (deeply nested series of callbacks with unmanaged state being used across several closure levels).
In addition, promises can considerably reduce boilerplate related to error handling.

View file

@ -1,10 +1,21 @@
# redraw()
- [Description](#description)
- [Signature](#signature)
- [How it works](#how-it-works)
---
### Description
Updates the DOM after a change in the application data layer.
You DON'T need to call it if data is modified within the execution context of an event handler defined in a Mithril view, or after request completion when using `m.request`/`m.jsonp`.
You DO need to call it in `setTimeout`/`setInterval`/`requestAnimationFrame` callbacks, or callbacks from 3rd party libraries.
---
### Signature
`m.redraw()`

View file

@ -1,5 +1,6 @@
# render(element, vnodes)
- [Description](#description)
- [Signature](#signature)
- [How it works](#how-it-works)
- [Why Virtual DOM](#why-virtual-dom)
@ -8,6 +9,17 @@
---
### Description
Renders a template to the DOM
```javascript
m.render(document.body, "hello")
// <body>hello</body>
```
---
### Signature
`m.render(element, vnodes)`

View file

@ -1,5 +1,6 @@
# request(options)
- [Description](#description)
- [Signature](#signature)
- [How it works](#how-it-works)
- [Typical usage](#typical-usage)
@ -12,7 +13,25 @@
- [Non-JSON responses](#non-json-responses)
- [Retrieving response details](#retrieving-response-details)
- [Why JSON instead of HTML](#why-json-instead-of-html)
- [Why XMLHttpRequest instead of fetch](#why-xmlhttprequest-instead-of-fetch)
- [Why XHR instead of fetch](#why-xhr-instead-of-fetch)
- [Avoid anti-patterns](#avoid-anti-patterns)
---
### Description
Makes XHR (aka AJAX) requests, and returns a [promise](promise.md)
```javascript
m.request({
method: "PUT",
url: "/api/v1/users/:id",
data: {id: 1, name: "test"}
})
.then(function(result) {
console.log(result)
})
```
---
@ -422,7 +441,7 @@ Data services may be organized in many different ways depending on the nature of
---
### Why XMLHttpRequest instead of fetch
### Why XHR instead of fetch
[`fetch()`](https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API) is a newer Web API for fetching resources from servers, similar to `XMLHttpRequest`.
@ -431,11 +450,13 @@ Mithril's `m.request` uses `XMLHttpRequest` instead of `fetch()` for a number of
- `fetch` is not fully standardized yet, and may be subject to specification changes.
- `XMLHttpRequest` calls can be aborted before they resolve (e.g. to avoid race conditions in for instant search UIs).
- `XMLHttpRequest` provides hooks for progress listeners for long running requests (e.g. file uploads).
- `XMLHttpRequest` is supported by all browsers, whereas `fetch()` is not supported by Internet Explorer and Safari.
- `XMLHttpRequest` is supported by all browsers, whereas `fetch()` is not supported by Internet Explorer, Safari and Android (non-Chromium).
Currently, due to lack of browser support, `fetch()` typically requires a [polyfill](https://github.com/github/fetch), which is over 11kb uncompressed - nearly three times larger than Mithril's `m.request`.
Currently, due to lack of browser support, `fetch()` typically requires a [polyfill](https://github.com/github/fetch), which is over 11kb uncompressed - nearly three times larger than Mithril's XHR module.
Despite being much smaller, `m.request` supports many important and not-so-trivial-to-implement features like [URL interpolation](#dynamic-urls), querystring serialization and [JSON-P requests](jsonp.md). The `fetch` polyfill does not support any of those.
Despite being much smaller, Mithril's XHR module supports many important and not-so-trivial-to-implement features like [URL interpolation](#dynamic-urls), querystring serialization and [JSON-P requests](jsonp.md), in addition to its ability to integrate seamlessly to Mithril's autoredrawing subsystem. The `fetch` polyfill does not support any of those, and requires extra libraries and boilerplates to achieve the same level of functionality.
In addition, Mithril's XHR module is optimized for JSON-based endpoints and makes that most common case appropriately terse - i.e. `m.request(url)` - whereas `fetch` requires an additional explicit step to parse the response data as JSON: `fetch(url).then(function(response) {return response.json()})`
The `fetch()` API does have a few technical advantages over `XMLHttpRequest` in a few uncommon cases:
@ -443,3 +464,24 @@ The `fetch()` API does have a few technical advantages over `XMLHttpRequest` in
- it integrates to the [Service Worker API](https://developer.mozilla.org/en-US/docs/Web/API/Service_Worker_API), which provides an extra layer of control over how and when network requests happen. This API also allows access to push notifications and background synchronization features.
In typical scenarios, streaming won't provide noticeable performance benefits because it's generally not advisable to download megabytes of data to begin with. Also, the memory gains from repeatedly reusing small buffers may be offset or nullified if they result in excessive browser repaints. For those reasons, choosing `fetch()` streaming instead of `m.request` is only recommended for extremely resource intensive applications.
---
### Avoid anti-patterns
#### Promises are not the response data
The `m.request` method returns a [Promise](promise.md), not the response data itself. It cannot return that data directly because an HTTP request may take a long time to complete (due to network latency), and if Javascript waited for it, it would freeze the application until the data was available.
```javascript
// AVOID
var users = m.request("/api/v1/users")
console.log("list of users:", users)
// `users` is NOT a list of users, it's a promise
// PREFER
m.request("/api/v1/users").then(function(users) {
console.log("list of users:", users)
})
```

View file

@ -1,5 +1,6 @@
# route(root, defaultRoute, routes)
- [Description](#description)
- [Signature](#signature)
- [Static members](#static-members)
- [route.set](#routeset)
@ -21,6 +22,24 @@
---
### Description
Navigate between "pages" within an application
```javascript
var Home = {
view: function() {
return "Welcome"
}
}
m.route(document.body, "/home", {
"/home": Home, // defines `http://localhost/#!/home`
})
```
---
### Signature
`m.route(root, defaultRoute, routes)`

View file

@ -1,5 +1,6 @@
# stream()
- [Description](#description)
- [Signature](#signature)
- [Static members](#static-members)
- [stream.combine](#streamcombine)
@ -25,6 +26,16 @@
---
### Description
A Stream is a reactive data structure, similar to cells in spreadsheet applications.
For example, in a spreadsheet, if `A1 = B1 + C1`, then changing the value of `B1` or `C1` automatically changes the value of `A1`.
Similarly, you can make a stream depend on other streams so that changing the value of one automatically updates the other. This is useful when you have very expensive computations and want to only run them when necessary, as opposed to, say, on every redraw.
---
### Signature
Creates a stream

45
docs/style.css Normal file
View file

@ -0,0 +1,45 @@
body,table,h5 {font:normal 16px 'Open Sans';}
header,main {margin:auto;max-width:1000px;}
header section {position:absolute;width:250px;}
nav a {border-left:1px solid #ddd;padding:0 10px;}
nav a:first-child {border:0;padding-left:0;}
main {margin-bottom:100px;}
main section {margin-left:270px;}
h1 {margin:0 0 15px;}
h5 {font-style:italic;}
pre,code {background:#eee;font-family:monospace;}
pre {border-left:3px solid #1e5799;overflow:auto;padding:10px 20px;}
code {border:1px solid #ddd;display:inline-block;margin:0 0 1px;padding:3px;white-space:pre;}
pre code {border:0;margin:0;padding:0;}
table {border-collapse:collapse;width:100%;}
tbody tr:nth-child(odd) {background:#fafafa;}
thead tr,tbody tr:nth-child(even) {background:#f3f3f3;}
th {text-align:left;}
th,td {padding:3px 10px;vertical-align:top;}
a {color:#1e5799;display:inline-block;text-decoration:none;}
a:hover {text-decoration:underline;}
hr {border:0;border-bottom:1px solid #ddd;margin:30px 0;}
#signature + p code {padding:3px 10px;}
h1 + ul {margin:40px 0 0 -270px;padding:0;position:absolute;width:250px;}
h1 + ul + hr {display:none;}
h1 + ul li {border-bottom:1px solid #eee;list-style:none;margin:0;padding:0;}
h1 + ul li:last-child {border-bottom:0;}
h1 + ul ul {margin:0 0 10px;padding:0 0 0 15px;}
h1 + ul ul li {border:0;}
@media (max-width: 767px) {
main section {margin:0;}
h1 + ul + hr {display:block;}
header section,h1 + ul {margin:0 0 20px;position:static;width:auto;}
}
@media (max-width: 1024px) {
#signature + p + table,#signature + p + table tbody,#signature + p + table tr,#signature + p + table th,#signature + p + table td {display:block;}
#signature + p + table thead {display:none;}
#signature + p + table td:before {display:inline-block;font-style:italic;padding:0 10px 0 0;width:100px;}
#signature + p + table tr:not(:last-child) td:nth-child(1):before {content:"Argument:";}
#signature + p + table td:nth-child(2):before {content:"Type:";}
#signature + p + table td:nth-child(3):before {content:"Required:";}
#signature + p + table td:nth-child(4):before {content:"Description:";}
#signature + p + table tr:last-child td:nth-child(3) {display:none;}
}

View file

@ -1,5 +1,6 @@
# trust(html)
- [Description](#description)
- [Signature](#signature)
- [How it works](#how-it-works)
- [Security considerations](#security-considerations)
@ -8,9 +9,15 @@
---
### Signature
### Description
Generates a trusted HTML [vnode](vnodes.md)
Turns an HTML string into unescaped HTML. **Do not use `m.trust` on unsanitized user input.**
Always try to use an [alternative method](#avoid-trusting-html) first, before considering using `m.trust`.
---
### Signature
`vnode = m.trust(html)`

View file

@ -1,18 +1,39 @@
# withAttr(attrName, callback)
- [Description](#description)
- [Signature](#signature)
- [How to use](#how-to-use)
- [How it works](#how-it-works)
- [Predictable event target](#predictable-event-target)
- [Attributes and properties](#attributes-and-properties)
---
### Description
Returns an event handler that runs `callback` with the value of the specified DOM attribute
```javascript
var state: {
value = ""
setValue: function(v) {value = v}
}
var Component = {
view: function() {
return m("input", {
oninput: m.withAttr("value", state.setValue),
value: state.value,
})
}
}
m.mount(document.body, Component)
```
---
### Signature
Creates an event handler. The event handler takes the value of a DOM element's property and calls a function with it as the argument.
This helper function is provided to help decouple the browser's event model from application code.
`m.withAttr(attrName, callback, thisArg?)`
Argument | Type | Required | Description
@ -26,7 +47,11 @@ Argument | Type | Required | Description
---
### How to use
### How it works
The `m.withAttr` method creates an event handler. The event handler takes the value of a DOM element's property and calls a function with it as the argument.
This helper function is provided to help decouple the browser's event model from application code.
```javascript
// standalone usage

View file

@ -1,6 +1,6 @@
{
"name": "mithril",
"version": "1.0.0-rc.5",
"version": "1.0.0-rc.6",
"description": "A framework for building brilliant applications",
"author": "Leo Horie",
"license": "MIT",
@ -12,13 +12,15 @@
"build-browser": "node bundler/cli browser.js -o mithril.js",
"build-min": "node bundler/cli browser.js -o mithril.min.js -m",
"lintdocs": "node docs/lint",
"gendocs": "node docs/generate",
"lint": "eslint .",
"test": "node ospec/bin/ospec",
"cover": "istanbul cover --print both ospec/bin/ospec"
},
"devDependencies": {
"eslint": "^2.10.2",
"istanbul": "^0.4.3"
"istanbul": "^0.4.3",
"marked": "^0.3.6"
},
"publishConfig": {
"tag": "rewrite"