diff --git a/LICENSE b/LICENSE new file mode 100644 index 00000000..2aae0f1e --- /dev/null +++ b/LICENSE @@ -0,0 +1,21 @@ +The MIT License (MIT) + +Copyright (c) 2017 Leo Horie + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/README.md b/README.md index 353976cf..9100b1f9 100644 --- a/README.md +++ b/README.md @@ -28,7 +28,7 @@ It's small (< 8kb gzip), fast and provides routing and XHR utilities out of the
-
Performance
+
Rendering Time
Mithril (6.4ms)
Vue (9.8ms) @@ -223,7 +223,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`. 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) +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 `withCredentials` means to enable cookies (a requirement for the REM API to work) ```javascript var count = 0 @@ -232,7 +232,7 @@ var increment = function() { method: "PUT", url: "http://rem-rest-api.herokuapp.com/api/tutorial/1", data: {count: count + 1}, - useCredentials: true, + withCredentials: true, }) .then(function(data) { count = parseInt(data.count) diff --git a/docs/animation.md b/docs/animation.md index 0d45614f..de9d2bea 100644 --- a/docs/animation.md +++ b/docs/animation.md @@ -102,4 +102,4 @@ Note that the `onbeforeremove` hook only fires on the element that loses its `pa When creating animations, it's recommended that you only use the `opacity` and `transform` CSS rules, since these can be hardware-accelerated by modern browsers and yield better performance than animating `top`, `left`, `width`, and `height`. -It's also recommended that you avoid the `box-shadow` rule and selectors like `:nth-child`, since these are also resource intensive options. Other things that can be expensive include large or dynamically scaled images and overlapping elements with different `position` values (e.g. an absolute postioned element over a fixed element). +It's also recommended that you avoid the `box-shadow` rule and selectors like `:nth-child`, since these are also resource intensive options. If you want to animate a `box-shadow`, consider [putting the `box-shadow` rule on a pseudo element, and animate that element's opacity instead](http://tobiasahlin.com/blog/how-to-animate-box-shadow/). Other things that can be expensive include large or dynamically scaled images and overlapping elements with different `position` values (e.g. an absolute postioned element over a fixed element). diff --git a/docs/autoredraw.md b/docs/autoredraw.md index a3a1360a..eb1f093f 100644 --- a/docs/autoredraw.md +++ b/docs/autoredraw.md @@ -89,7 +89,7 @@ m.route(document.body, "/", { ### When Mithril does not redraw -Mithril does not redraw after `setTimeout`, `setInterval`, `requestAnimationFrame` and 3rd party library event handlers (e.g. Socket.io callbacks). In those cases, you must manually call [`m.redraw()`](redraw.md). +Mithril does not redraw after `setTimeout`, `setInterval`, `requestAnimationFrame`, raw `Promise` resolutions and 3rd party library event handlers (e.g. Socket.io callbacks). In those cases, you must manually call [`m.redraw()`](redraw.md). Mithril also does not redraw after lifecycle methods. Parts of the UI may be redrawn after an `oninit` handler, but other parts of the UI may already have been redrawn when a given `oninit` handler fires. Handlers like `oncreate` and `onupdate` fire after the UI has been redrawn. diff --git a/docs/index.md b/docs/index.md index b0f22448..9cbc1016 100644 --- a/docs/index.md +++ b/docs/index.md @@ -53,13 +53,14 @@ The easiest way to try out Mithril is to include it from a CDN, and follow this Let's create an HTML file to follow along: ```markup - - - + + // your code goes here! + + ``` --- diff --git a/docs/keys.md b/docs/keys.md index 9fd87814..0149418c 100644 --- a/docs/keys.md +++ b/docs/keys.md @@ -106,9 +106,11 @@ var Button = { return m("button", {key: vnode.attrs.id}, u.name) } } + +// PREFER users.map(function(u) { return m("div", [ - m(Button, {id: u.id}, u.name) // key should be here, not in component + m(Button, {key: u.id}, u.name) // key should be here, not in component ]) }) ``` diff --git a/docs/simple-application.md b/docs/simple-application.md index 91bf0a8e..134e11c6 100644 --- a/docs/simple-application.md +++ b/docs/simple-application.md @@ -601,7 +601,7 @@ We replaced each component with a [RouteResolver](route.md#routeresolver) (basic The interesting thing to pay attention to is how components can be used instead of a selector string in a `m()` call. Here, in the `/list` route, we have `m(Layout, m(UserList))`. This means there's a root vnode that represents an instance of `Layout`, which has a `UserList` vnode as its only child. -In the `/edit/:id` route, there's also a `vnode` argument that carries the route parameters into the `UserForm` component. So if the URL is `/edit/1`, then `vnode.attrs` in this case is `{id: 1}`, and this `m(UserForm, vnode.attrs)` is equivalent to `m(UserForm, {id: 1})`. The equivalent JSX code would be ``. +In the `/edit/:id` route, there's also a `vnode` argument that carries the route parameters into the `UserForm` component. So if the URL is `/edit/1`, then `vnode.attrs` in this case is `{id: 1}`, and this `m(UserForm, vnode.attrs)` is equivalent to `m(UserForm, {id: 1})`. The equivalent JSX code would be ``. Refresh the page in the browser and now you'll see the global navigation on every page in the app. diff --git a/docs/style.css b/docs/style.css index 9053365b..afd99f62 100644 --- a/docs/style.css +++ b/docs/style.css @@ -1,3 +1,4 @@ +body {-webkit-text-size-adjust: 100%;} body,table,h5 {font:normal 16px 'Open Sans';} header,main {margin:auto;max-width:1000px;} header section {position:absolute;width:250px;} diff --git a/docs/vnodes.md b/docs/vnodes.md index 190105a7..e8df0199 100644 --- a/docs/vnodes.md +++ b/docs/vnodes.md @@ -11,11 +11,11 @@ ### What is virtual DOM -A virtual DOM tree is a Javascript data structure that describes a DOM tree. It consists of nested virtual DOM nodes, also known *vnodes*. +A virtual DOM tree is a Javascript data structure that describes a DOM tree. It consists of nested virtual DOM nodes, also known as *vnodes*. The first time a virtual DOM tree is rendered, it is used as a blueprint to create a DOM tree that matches its structure. -Typically, Virtual DOM trees are then recreated every render cycle, which normally occurs in response to event handlers or to data changes. Mithril *diffs* a vnode tree against its previous version and only modifies DOM elements in spots where there are changes. +Typically, virtual DOM trees are then recreated every render cycle, which normally occurs in response to event handlers or to data changes. Mithril *diffs* a vnode tree against its previous version and only modifies DOM elements in spots where there are changes. It may seem wasteful to recreate vnodes so frequently, but as it turns out, modern Javascript engines can create hundreds of thousands of objects in less than a millisecond. On the other hand, modifying the DOM is several orders of magnitude more expensive than creating vnodes. @@ -23,7 +23,7 @@ For that reason, Mithril uses a sophisticated and highly optimized virtual DOM d The reason Mithril goes to such great lengths to support a rendering model that recreates the entire virtual DOM tree on every render is to provide [retained mode rendering](https://en.wikipedia.org/wiki/Retained_mode), a style of rendering that makes it drastically easier to manage UI complexity. -To illustrate why retained mode is so important, consider the DOM API and HTML. The DOM API is an [immediate mode](https://en.wikipedia.org/wiki/Immediate_mode_(computer_graphics)) rendering system and requires writing out exact instructions to assemble a DOM tree procedurally. The imperative nature of the DOM API means you have many opportunities to micro-optimize your code, but it also means that you have more chances for introducing bugs and more chances to make code harder to understand. +To illustrate why retained mode is so important, consider the DOM API and HTML. The DOM API is an [immediate mode](https://en.wikipedia.org/wiki/Immediate_mode_(computer_graphics)) rendering system and requires writing out exact instructions to assemble a DOM tree procedurally. The imperative nature of the DOM API means you have many opportunities to micro-optimize your code, but it also means that you have more chances of introducing bugs and more chances to make code harder to understand. In contrast, HTML is a retained mode rendering system. With HTML, you can write a DOM tree in a far more natural and readable way, without worrying about forgetting to append a child to a parent, running into stack overflows when rendering extremely deep trees, etc. @@ -35,13 +35,13 @@ Virtual DOM goes one step further than HTML by allowing you to write *dynamic* D Virtual DOM nodes, or *vnodes*, are javascript objects that represent DOM elements (or parts of the DOM). Mithril's virtual DOM engine consumes a tree of vnodes to produce a DOM tree. -Vnodes can be created via the [`m()`](hyperscript.md) hyperscript utility: +Vnodes are created via the [`m()`](hyperscript.md) hyperscript utility: ```javascript m("div", {id: "test"}, "hello") ``` -Vnodes can also consume [components](components.md): +Hyperscript can also consume [components](components.md): ```javascript // define a component @@ -70,8 +70,8 @@ Property | Type | Description `key` | `String?` | The value used to map a DOM element to its respective item in a array of data. `attrs` | `Object?` | A hashmap of [DOM attributes](hyperscript.md#dom-attributes), [events](hyperscript.md#events), [properties](hyperscript.md#properties) and [lifecycle methods](hyperscript.md#lifecycle-methods). `children` | `(Array|String|Number|Boolean)?` | In most vnode types, the `children` property is an array of vnodes. For text and trusted HTML vnodes, The `children` property is either a string, a number or a boolean. -`text` | `(String|Number|Boolean)?` | This is used instead of `children` if a vnode contains a text node as its only child. This is done for performance reasons. Component vnodes never use the `text` property even if they have a text node as its only child. -`dom` | `Element?` | Points to the element that corresponds to the vnode. This property is `undefined` in the `oninit` lifecycle method. In fragment and trusted HTML vnodes, `dom` points to the first element in the range. +`text` | `(String|Number|Boolean)?` | This is used instead of `children` if a vnode contains a text node as its only child. This is done for performance reasons. Component vnodes never use the `text` property even if they have a text node as their only child. +`dom` | `Element?` | Points to the element that corresponds to the vnode. This property is `undefined` in the `oninit` lifecycle method. In fragments and trusted HTML vnodes, `dom` points to the first element in the range. `domSize` | `Number?` | This is only set in fragment and trusted HTML vnodes, and it's `undefined` in all other vnode types. It defines the number of DOM elements that the vnode represents (starting from the element referenced by the `dom` property). `state` | `Object` | An object that is persisted between redraws. In component vnodes, `state` is a shallow clone of the component object. `events` | `Object?` | An object that is persisted between redraws and that stores event handlers so that they can be removed using the DOM API. The `events` property is `undefined` if there are no event handlers defined. This property is only used internally by Mithril, do not use it. @@ -110,4 +110,4 @@ When creating libraries that emit vnodes, you should use this module instead of Vnodes are supposed to represent the state of the DOM at a certain point in time. Mithril's rendering engine assumes a reused vnode is unchanged, so modifying a vnode that was used in a previous render will result in undefined behavior. -It is possible to reuse vnodes to prevent a diff, but it's preferable to use the `onbeforeupdate` hook to make your intent clear to other developers (or your future self). \ No newline at end of file +It is possible to reuse vnodes to prevent a diff, but it's preferable to use the `onbeforeupdate` hook to make your intent clear to other developers (or your future self).