small tweaks to docs

This commit is contained in:
Leo Horie 2016-12-01 01:49:19 -05:00
parent c5c18f9231
commit 87dcbbf5c7
19 changed files with 308 additions and 75 deletions

View file

@ -1,11 +1,11 @@
# buildQueryString(object)
- [API](#api)
- [Signature](#signature)
- [How it works](#how-it-works)
---
### API
### Signature
`querystring = m.buildQueryString(object)`

View file

@ -1,13 +1,13 @@
# fragment(html)
# fragment(attrs, children)
- [API](#api)
- [Signature](#signature)
- [How it works](#how-it-works)
---
### API
### Signature
Generates a trusted HTML [vnode](vnodes.md)
Generates a fragment [vnode](vnodes.md)
`vnode = m.fragment(attrs, children)`

View file

@ -1,6 +1,6 @@
# m(selector, attributes, children)
- [API](#api)
- [Signature](#signature)
- [How it works](#how-it-works)
- [Flexibility](#flexibility)
- [CSS selectors](#css-selectors)
@ -17,13 +17,13 @@
---
### API
### Signature
`vnode = m(selector, attributes, children)`
Argument | Type | Required | Description
------------ | ------------------------------------------ | -------- | ---
`selector` | `String|Object` | Yes | A CSS selector or a [component](https://github.com/lhorie/mithril.js/blob/rewrite/docs/components.md)
`selector` | `String|Object` | Yes | A CSS selector or a [component](components.md)
`attributes` | `Object` | No | HTML attributes or element properties
`children` | `Array<Vnode>|String|Number|Boolean` | No | Child [vnodes](vnodes.md#structure). Can be written as [splat arguments](signatures.md#splats)
**returns** | `Vnode` | | A [vnode](vnodes.md#structure)

View file

@ -4,7 +4,7 @@
If you're new to Javascript or just want a very simple setup to get your feet wet, you can get Mithril from a [CDN](https://en.wikipedia.org/wiki/Content_delivery_network):
```
```markup
<script src="http://cdn.rawgit.com/lhorie/mithril.js/rewrite/mithril.js"></script>
```
@ -14,7 +14,7 @@ If you're new to Javascript or just want a very simple setup to get your feet we
#### Quick start
```
```bash
# 1) install
npm install mithril@rewrite --save
@ -37,14 +37,14 @@ NPM (Node package manager) is the default package manager that is bundled w/ Nod
To use Mithril via NPM, go to your project folder, and run `npm init --yes` from the command line. This will create a file called `package.json`.
```
```bash
npm init --yes
# creates a file called package.json
```
Then, run `npm install mithril@rewrite --save` to install Mithril. This will create a folder called `node_modules`, and a `mithril` folder inside of it. It will also add an entry under `dependencies` in the `package.json` file
```
```bash
npm install mithril@rewrite --save
```
@ -149,13 +149,6 @@ webpack --watch
If you don't have the ability to run a bundler script due to company security policies, there's an options to not use a module system at all:
```javascript
// index.js
// if a CommonJS environment is not detected, Mithril will be created in the global scope
m.render(document.body, "hello world")
```
```markup
<html>
<head>
@ -167,3 +160,10 @@ m.render(document.body, "hello world")
</body>
</html>
```
```javascript
// index.js
// if a CommonJS environment is not detected, Mithril will be created in the global scope
m.render(document.body, "hello world")
```

226
docs/introduction.md Normal file
View file

@ -0,0 +1,226 @@
# Introduction
- [What is Mithril?](#what-is-mithril)
- [Getting started](#getting-started)
- [Hello world](#hello-world)
- [DOM elements](#dom-elements)
- [Components](#components)
- [Routing](#routing)
- [XHR](#xhr)
---
### What is Mithril?
Mithril is a framework for developing Javascript-based Single Page Applications. It's designed to be fast, small and economical.
---
### 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.
Let's create an HTML file to follow along:
```markup
<div id="root"></div>
<script src="http://cdn.rawgit.com/lhorie/mithril.js/rewrite/mithril.js"></script>
<script>
var root = document.getElementById("root")
// your code goes here!
</script>
```
---
### Hello world
Let's start as small as well can: render some text on screen. Copy the code below into your file (and by copy, I mean type it out - you'll learn better)
```javascript
m.render(root, "Hello world")
```
Now, let's change the text to something else. Add this line of code under the previous one:
```javascript
m.render(root, "My first app")
```
As you can see, you use the same code to both create and update HTML. Mithril automatically figures out the most efficient way of updating the text, rather than blindly recreating it from scratch.
---
### DOM elements
Let's wrap our text in an `<h1>` tag.
```javascript
m.render(root, m("h1", "My first app"))
```
The `m()` function can be used to describe any HTML structure you want. So if you to add a class to the `<h1>`:
```javascript
m("h1", {class: "title"}, "My first app")
```
If you want to have multiple elements:
```javascript
[
m("h1", {class: "title"}, "My first app"),
m("button", "A button"),
]
```
And so on:
```javascript
m("main", [
m("h1", {class: "title"}, "My first app"),
m("button", "A button"),
])
```
---
### Components
A Mithril component is just an object with a `view` function. Here's the code above as a component:
```javascript
var Hello = {
view: function() {
return m("main", [
m("h1", {class: "title"}, "My first app"),
m("button", "A button"),
])
}
}
```
To activate the component, we use `m.mount`.
```javascript
m.mount(root, Hello)
```
As you would expect, doing so creates this markup:
```markup
<main>
<h1 class="title">My first app</h1>
<button>A button</button>
</main>
```
The `m.mount` function is similar to `m.render`, but instead of rendering some HTML only once, it activates Mithril's auto-redrawing system. To understand what that means, let's add some events:
```javascript
var count = 0 // added a variable
var Hello = {
view: function() {
return m("main", [
m("h1", {class: "title"}, "My first app"),
m("button", {onclick: function() {count++}}, count + " clicks"), // changed this line
])
}
}
m.mount(root, Hello)
```
We defined an `onclick` event on the button, which increments a variable `count` (which was declared at the top). We are now also rendering the value of that variable in the button label.
You can now update the label of the button by clicking the button. Since we used `m.mount`, you don't need to manually call `m.render` to apply the changes in the `count` variable to the HTML; Mithril does it for you.
If you're wondering about performance, it turns out Mithril is very fast at rendering updates, because it only touches the parts of the DOM it absolutely needs to. So in our example above, when you click the button, the text in it is the only part of the DOM Mithril actually updates.
---
### Routing
Routing just means going from one screen to another in an application with several screens.
Let's add a splash page that appears before our click counter. First we create a component for it:
```javascript
var Splash = {
view: function() {
return m("a", {href: "#!/hello"}, "Enter!")
}
}
```
As you can see, this component simply renders a link to `#!/hello`. The `#!` part is known as a hashbang, and it's a common convention used in Single Page Applications to indicate that the stuff after it (the `/hello` part) is a route path.
Now that we going to have more than one screen, we use `m.route` instead of `m.mount`.
```javascript
m.route(root, "/splash", {
"/splash": Splash,
"/hello": Hello,
})
```
The `m.route` function still has the same auto-redrawing functionality that `m.mount` does, and it also enables URL awareness; in other words, it lets Mithril know what to do when it sees a `#!` in the URL.
The `"/splash"` right after `root` means that's the default route, i.e. if the hashbang in the URL doesn't point to one of the defined routes (`/splash` and `/hello`, in our case), then Mithril redirects to the default route. So if you open the page in a browser and your URL is `http://localhost`, then you get redirected to `http://localhost/#!/splash`.
Also, as you would expect, clicking on the link on the splash page takes you to the click counter screen we created earlier. Notice that now your URL will point to `http://localhost/#!/hello`. You can navigate back and forth to the splash page using the browser's back and next button.
---
### XHR
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`.
```javascript
var count = 0
var increment = function() {
m.request({
method: "PUT",
url: "http://rem-rest-api.herokuapp.com/api/tutorial/1",
data: {count: count + 1},
useCredentials: true,
})
.then(function(data) {
count = parseInt(data.count)
})
}
```
Calling the increment function [upserts](https://en.wiktionary.org/wiki/upsert) an object `{count: 1}` to the `/api/tutorial/1` endpoint. This endpoint returns an object with the same `count` value that was sent to it. Notice that the `count` variable is only updated after the request completes, and it's updated with the response value from the server now.
Let's replace the event handler in the component to call the `increment` function instead of incrementing the `count` variable directly:
```javascript
var Hello = {
view: function() {
return m("main", [
m("h1", {class: "title"}, "My first app"),
m("button", {onclick: increment}, count + " clicks"),
])
}
}
```
Clicking the button should now update the count.
---
We covered how to create and update HTML, how to create components, routes for a Single Page Application, and interacted with a server via XHR.
This should be enough to get you started writing the frontend for a real application. Now that you are comfortable with the basics of the Mithril API, [be sure to check out the simple application tutorial](simple-application.md), which walks you through building a realistic application.

View file

@ -1,19 +1,19 @@
# jsonp(options)
- [API](#api)
- [Signature](#signature)
- [How it works](#how-it-works)
- [Typical usage](#typical-usage)
---
### API
### Signature
`promise = m.jsonp(options)`
Argument | Type | Required | Description
---------------------- | --------------------------------- | -------- | ---
`options.url` | `String` | Yes | The URL to send the request to. The URL may be either absolute or relative, and it may contain [interpolations](#dynamic-urls).
`options.data` | `any` | No | The data to be interpolated into the URL and serialized into the querystring (for GET requests) or body (for other types of requests).
`options.data` | `any` | No | The data to be interpolated into the URL and serialized into the querystring.
`options.type` | `any = Function(any)` | No | A constructor to be applied to each object in the response. Defaults to the [identity function](https://en.wikipedia.org/wiki/Identity_function).
`options.callbackName` | `String` | No | The name of the function that will be called as the callback. Defaults to a randomized string (e.g. `_mithril_6888197422121285_0({a: 1})`
`options.callbackKey` | `String` | No | The name of the querystring parameter name that specifies the callback name. Defaults to `callback` (e.g. `/someapi?callback=_mithril_6888197422121285_0`)

View file

@ -86,6 +86,9 @@ function initMocks() {
"GET /api/v1/todos": function(request) {
return {status: 200, responseText: JSON.stringify([])}
},
"PUT /api/v1/users/1": function(request) {
return {status: 200, responseText: request.query.callback ? request.query.callback + "([])" : "[]"}
},
"POST /api/v1/upload": function(request) {
return {status: 200, responseText: JSON.stringify([])}
},

View file

@ -1,13 +1,13 @@
# mount(root, component)
- [API](#api)
- [Signature](#signature)
- [How it works](#how-it-works)
- [Performance considerations](#performance-considerations)
- [Differences from m.render](#differences-from-m-render)
---
### API
### Signature
`m.mount(element, component)`

View file

@ -1,11 +1,11 @@
# parseQueryString(string)
- [API](#api)
- [Signature](#signature)
- [How it works](#how-it-works)
---
### API
### Signature
`object = m.parseQueryString(string)`

View file

@ -1,14 +1,14 @@
# Promise(executor)
- [API](#api)
- [Static members](#static-members)
- [Promise.resolve](#promiseresolve)
- [Promise.reject](#promisereject)
- [Promise.all](#promiseall)
- [Promise.race](#promiserace)
- [Instance members](#static-members)
- [promise.then](#promisethen)
- [promise.catch](#promisecatch)
- [Signature](#signature)
- [Static members](#static-members)
- [Promise.resolve](#promiseresolve)
- [Promise.reject](#promisereject)
- [Promise.all](#promiseall)
- [Promise.race](#promiserace)
- [Instance members](#instance-members)
- [promise.then](#promisethen)
- [promise.catch](#promisecatch)
- [How it works](#how-it-works)
- [Promise chaining](#promise-chaining)
- [Promise absorption](#promise-absorption)
@ -18,7 +18,7 @@
---
### API
### Signature
`promise = new Promise(executor)`
@ -146,7 +146,7 @@ promise.then(function(value) {
})
```
Promises are useful for working with [asynchronous](https://en.wikipedia.org/wiki/Asynchrony_(computer_programming)) APIs, such as [`m.request`](request.md)
Promises are useful for working with asynchronous APIs, such as [`m.request`](request.md)
Asynchronous APIs are those which typically take a long time to run, and therefore would take too long to return a value using the `return` statement of a function. Instead, they do their work in the background, allowing other Javascript code to run in the meantime. When they are done, they call a function with their results.

View file

@ -1,11 +1,11 @@
# redraw()
- [API](#api)
- [Signature](#signature)
- [How it works](#how-it-works)
---
### API
### Signature
`m.redraw()`
@ -19,6 +19,6 @@ Argument | Type | Required | Description
When callbacks outside of Mithril run, you need to notify Mithril's rendering engine that a redraw is needed. External callbacks could be `setTimeout`/`setInterval`/`requestAnimationFrame` callbacks, web socket library callbacks, event handlers in jQuery plugins, third party XHR request callbacks, etc.
To trigger a redraw, call `m.redraw()`
To trigger a redraw, call `m.redraw()`. Note that `m.redraw` only works if you used `m.mount` or `m.route`. If you rendered via `m.render`, you should use `m.render` to redraw.
You should not call m.redraw from a [lifecycle method](lifecycle-methods.md). Doing so will result in undefined behavior.

View file

@ -1,6 +1,6 @@
# render(element, vnodes)
- [API](#api)
- [Signature](#signature)
- [How it works](#how-it-works)
- [Why Virtual DOM](#why-virtual-dom)
- [Differences from other API methods](#differences-from-other-api-methods)
@ -8,7 +8,7 @@
---
### API
### Signature
`m.render(element, vnodes)`
@ -52,6 +52,8 @@ Another difference is that `m.render` method expects a [vnode](vnodes.md) (or a
### Standalone usage
`var render = require("mithril/render")`
The `m.render` module is similar in scope to view libraries like Knockout, React and Vue. It is approximately 500 lines of code (3kb min+gzip) and implements a virtual DOM diffing engine with a modern search space reduction algorithm and DOM recycling, which translate to top-of-class performance, both in terms of initial page load and re-rendering. It has no dependencies on other parts of Mithril and can be used as a standalone library.
Despite being incredibly small, the render module is fully functional and self-suficient. It supports everything you might expect: SVG, custom elements, and all valid attributes and events - without any weird case-sensitive edge cases or exceptions. Of course, it also fully supports [components](components.md) and [lifecycle methods](lifecycle-methods.md).

View file

@ -1,6 +1,6 @@
# request(options)
- [API](#api)
- [Signature](#signature)
- [How it works](#how-it-works)
- [Typical usage](#typical-usage)
- [Loading icons and error messages](#loading-icons-and-error-messages)
@ -15,7 +15,7 @@
---
### API
### Signature
`promise = m.request([url,] options)`

View file

@ -1,14 +1,14 @@
# route(root, defaultRoute, routes)
- [API](#api)
- [Static members](#static-members)
- [route.set](#routeset)
- [route.get](#routeget)
- [route.prefix](#routeprefix)
- [route.link](#routelink)
- [RouteResolver](#routeresolver)
- [routeResolver.onmatch](#routeresolveronmatch)
- [routeResolver.render](#routeresolverrender)
- [Signature](#signature)
- [Static members](#static-members)
- [route.set](#routeset)
- [route.get](#routeget)
- [route.prefix](#routeprefix)
- [route.link](#routelink)
- [RouteResolver](#routeresolver)
- [routeResolver.onmatch](#routeresolveronmatch)
- [routeResolver.render](#routeresolverrender)
- [How it works](#how-it-works)
- [Typical usage](#typical-usage)
- [Navigating to different routes](#navigating-to-different-routes)
@ -21,7 +21,7 @@
---
### API
### Signature
`m.route(root, defaultRoute, routes)`

View file

@ -1,17 +1,17 @@
# stream()
- [API](#api)
- [Static members](#static-members)
- [stream.combine](#streamcombine)
- [stream.merge](#streammerge)
- [stream.HALT](#streamhalt)
- [stream["fantasy-land/of"]](#streamfantasy-landof)
- [Instance members](#static-members)
- [stream.map](#streammap)
- [stream.end](#streamend)
- [stream["fantasy-land/of"]](#streamfantasy-landof)
- [stream["fantasy-land/map"]](#streamfantasy-landmap)
- [stream["fantasy-land/ap"]](#streamfantasy-landap)
- [Signature](#signature)
- [Static members](#static-members)
- [stream.combine](#streamcombine)
- [stream.merge](#streammerge)
- [stream.HALT](#streamhalt)
- [stream["fantasy-land/of"]](#streamfantasy-landof)
- [Instance members](#static-members)
- [stream.map](#streammap)
- [stream.end](#streamend)
- [stream["fantasy-land/of"]](#streamfantasy-landof)
- [stream["fantasy-land/map"]](#streamfantasy-landmap)
- [stream["fantasy-land/ap"]](#streamfantasy-landap)
- [Basic usage](#basic-usage)
- [Streams as variables](#streams-as-variables)
- [Bidirectional bindings](#bidirectional-bindings)
@ -25,7 +25,7 @@
---
### API
### Signature
Creates a stream

View file

@ -1,6 +1,6 @@
# Testing
Mithril comes with a testing framework called [ospec](../ospec/README.md). What makes it different from most test frameworks is that it avoids all configurability for the sake of avoiding [yak shaving](http://catb.org/jargon/html/Y/yak-shaving.html) and [analysis paralysis](https://en.wikipedia.org/wiki/Analysis_paralysis).
Mithril comes with a testing framework called [ospec](https://github.com/lhorie/mithril.js/tree/rewrite/ospec). What makes it different from most test frameworks is that it avoids all configurability for the sake of avoiding [yak shaving](http://catb.org/jargon/html/Y/yak-shaving.html) and [analysis paralysis](https://en.wikipedia.org/wiki/Analysis_paralysis).
The easist way to setup the test runner is to create an NPM script for it. Open your project's `package.json` file and edit the `test` line under the `scripts` section:
@ -38,6 +38,8 @@ To run the test, use the command `npm test`. Ospec considers any Javascript file
npm test
```
---
### Good testing practices
Generally speaking, there are two ways to write tests: upfront and after the fact.

View file

@ -1,6 +1,6 @@
# trust(html)
- [API](#api)
- [Signature](#signature)
- [How it works](#how-it-works)
- [Security considerations](#security-considerations)
- [Scripts that do not run](#scripts-that-do-not-run)
@ -8,7 +8,7 @@
---
### API
### Signature
Generates a trusted HTML [vnode](vnodes.md)

View file

@ -1,11 +1,11 @@
# version
- [API](#api)
- [Signature](#signature)
- [How it works](#how-it-works)
---
### API
### Signature
`m.version`

View file

@ -1,13 +1,13 @@
# withAttr(attrName, callback)
- [API](#api)
- [Signature](#signature)
- [How to use](#how-to-use)
- [Predictable event target](#predictable-event-target)
- [Attributes and properties](#attributes-and-properties)
---
### API
### 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.