From 0550079bfc95dad8546609956e0b14fb26a918c5 Mon Sep 17 00:00:00 2001 From: Leo Horie Date: Tue, 27 May 2014 08:51:34 -0400 Subject: [PATCH] editorial --- archive/v0.1.14/auto-redrawing.html | 6 +-- archive/v0.1.14/benchmarks.html | 4 +- archive/v0.1.14/comparison.html | 22 +++++----- archive/v0.1.14/compiling-templates.html | 2 +- archive/v0.1.14/components.html | 4 +- archive/v0.1.14/getting-started.html | 42 ++++++++++---------- archive/v0.1.14/how-to-read-signatures.html | 8 ++-- archive/v0.1.14/index.html | 4 +- archive/v0.1.14/installation.html | 8 ++-- archive/v0.1.14/integration.html | 2 +- archive/v0.1.14/mithril.html | 6 +-- archive/v0.1.14/mithril.min.zip | Bin 46051 -> 46051 bytes archive/v0.1.14/mithril.module.html | 4 +- archive/v0.1.14/mithril.request.html | 6 +-- archive/v0.1.14/mithril.route.html | 6 +-- archive/v0.1.14/mithril.trust.html | 6 +-- archive/v0.1.14/practices.html | 12 +++--- archive/v0.1.14/routing.html | 22 +++++----- archive/v0.1.14/web-services.html | 20 +++++----- 19 files changed, 93 insertions(+), 91 deletions(-) diff --git a/archive/v0.1.14/auto-redrawing.html b/archive/v0.1.14/auto-redrawing.html index 93a7fe55..15c6c8a6 100644 --- a/archive/v0.1.14/auto-redrawing.html +++ b/archive/v0.1.14/auto-redrawing.html @@ -71,9 +71,9 @@ var doStuff = function() {

Integrating multiple execution threads

When integrating with third party libraries, you might find that you need to call asynchronous methods from outside of Mithril's API.

-

In order to integrate non-trivial asynchronous code to Mithril's auto-redrawing system, you need to ensure all execution threads call m.startComputation / m.endComputation.

+

In order to integrate non-trivial asynchronous code with Mithril's auto-redrawing system, you need to ensure all execution threads call m.startComputation / m.endComputation.

An execution thread is basically any amount of code that runs before other asynchronous threads start to run.

-

Integrating multiple execution threads can be done in a two different ways: in a layered fashion or in comprehensive fashion

+

Integrating multiple execution threads can be done in two different ways: in a layered fashion or in comprehensive fashion.

Layered integration

Layered integration is recommended for modular code where many different APIs may be put together at the application level.

Below is an example where various methods implemented with a third party library can be integrated in layered fashion: any of the methods can be used in isolation or in combination.

@@ -105,7 +105,7 @@ var doBoth = function(callback) { }) };

Comprehensive integration

-

Comprehensive integration is recommended if integrating a monolithic series of asynchronous operations. In contrast to layered integration, it minimizes the number of m.startComputation / m.endComputation to avoid clutter.

+

Comprehensive integration is recommended if integrating a monolithic series of asynchronous operations. In contrast to layered integration, it minimizes the number of m.startComputation / m.endComputation calls to avoid clutter.

The example below shows a convoluted series of AJAX requests implemented with a third party library.

var doSomething = function(callback) {
     m.startComputation(); //call `startComputation` before everything else
diff --git a/archive/v0.1.14/benchmarks.html b/archive/v0.1.14/benchmarks.html
index c6bc8afb..02df5b85 100644
--- a/archive/v0.1.14/benchmarks.html
+++ b/archive/v0.1.14/benchmarks.html
@@ -45,10 +45,10 @@
 						
 						

Benchmarks

-

These benchmarks were designed to measure Javascript running time for Mithril in comparison with other popular Javascript MVC frameworks. Javascript running time is significant because the gzipped size of a framework can be misleading in terms of how much code actually runs on page loads. In my experience, page loads happen far more commonly than one would expect in single page applications: power users open multiple tabs, and mobile users are open and close the browser very frequently. And as far as templating engines go, the initial page load represents the worst case for the rendering algorithm since there are very little room for performance optimization tricks. It's arguably also one of the most important metric when it comes to performance.

+

These benchmarks were designed to measure Javascript running time for Mithril in comparison with other popular Javascript MVC frameworks. Javascript running time is significant because the gzipped size of a framework can be misleading in terms of how much code actually runs on page loads. In my experience, page loads happen far more commonly than one would expect in single page applications: power users open multiple tabs, and mobile users open and close the browser very frequently. And as far as templating engines go, the initial page load represents the worst case for the rendering algorithm since there is very little room for performance optimization tricks. It's arguably also one of the most important metrics when it comes to performance.

The numbers shown here are best-run results for all frameworks, except for Mithril's case, for which I'm taking the worst-run result. The numbers aren't statistically rigorous (e.g. I didn't bother to calculate standard deviation), but they should be enough to give a rough idea of what is faster than what.

Generally speaking, these tests are making a deliberate effort to be biased in favor of other frameworks: for example, I don't load "optional-but-usually-used-in-real-life" things like the router module for Angular, or Marionette in Backbone's case, and I load the entirety of Mithril. In addition, this test deliberately avoids triggering requestAnimationFrame-based performance optimizations for Mithril, since this optimization does not exist in many frameworks and severely skews numbers in Mithril's favor in CPU-intensive situations like parallax sites. I'm also NOT using the Mithril template compiler, which would also skew the benchmark in Mithril's favor.

-

To run the execution time tests below, click on their respective links, run the profiler from your desired browser's developer tools and measure the running time of a page refresh (Lower is better).

+

To run the execution time tests below, click on their respective links, run the profiler from your desired browser's developer tools and measure the running time of a page refresh (lower is better).

diff --git a/archive/v0.1.14/comparison.html b/archive/v0.1.14/comparison.html index a608cd3a..5b9c0760 100644 --- a/archive/v0.1.14/comparison.html +++ b/archive/v0.1.14/comparison.html @@ -50,13 +50,13 @@

Code Size

One of the most obvious differences between Mithril and most frameworks is in file size: Mithril is around 4kb gzipped and has no dependencies on other libraries.

Note that while a small gzipped size can look appealing, that number is often used to "hide the weight" of the uncompressed code: remember that the decompressed Javascript still needs to be parsed and evaluated on every page load, and this cost (which can be in the dozens of milliseconds range for some frameworks in some browsers) cannot be cached.

-

This cost might be less of a concern in single page apps, but not necessarily if the app is typically opened simultaneously in multiple tabs, or in less powerful devices.

+

This cost might be less of a concern in single page apps, but not necessarily if the app is typically opened simultaneously in multiple tabs, or run on less powerful devices.

The performance tests in the homepage show execution times for parsing and evaluation of Mithril's code, compared to some popular frameworks. As you can see, it paints a much less flattering picture for some frameworks than when we look at gzipped size alone.

Documentation

Another point of comparison is documentation. Most of the popular frameworks have at least a bare minimum amount of documentation nowadays, but many leave a bit to be desired: some lack usage examples, and some frameworks' communities need to rely heavily on third party sites for explanations of more advanced topics, and sometimes even for learning the basics.

This is a problem particularly for frameworks that had breaking changes in the past: It's common to find answers in StackOverflow that are out-of-date and no longer work with the latest version of said frameworks.

-

Mithril has more documentation in this site than the amount of code in the framework, and none of the documentation is auto-generated.

-

All API points are explained in prose, and have code examples. Because the entire documentation is hand-crafted, you get the benefit of actually having explanations for things that documentation generator tools don't support well (for example, interfaces and callback parameter documentation).

+

Mithril has more documentation in its Github repo than source code, and none of the documentation is auto-generated.

+

All API points are explained in prose, and have code examples. Because the entire documentation is hand-crafted, you get the benefit of actually having explanations for things that documentation-generator tools don't support well (for example, interfaces and callback parameter documentation).

In addition, this guide section covers topics related to how to fit all the pieces together.

From the get-go, Mithril's build system produces archived versions of the code and documentation so that you'll never be stuck without docs for out-of-date versions.

Given how young Mithril is, hopefully you can appreciate the level of commitment for providing good documentation.

@@ -81,24 +81,24 @@

Backbone

Backbone was originally designed as a way to structure jQuery-based applications. One of its selling points is that it allows developers to leverage their existing jQuery knowledge, while providing some "walls" to organize the code in a more structured manner.

As with jQuery, Mithril differs from Backbone by enforcing view code to be written in a declarative style.

-

Another marking difference is that Backbone is workflow agnostic, that is, there's no one idiomatic way to organize applications. This is good for framework adoption, but not necessarily ideal for team scalability and codebase discoverability.

-

In contrast, Mithril encourages that applications be developed using the patterns found throughout this guide. This discourages "bastardized" MVC pattern variations and architecturing style fragmentation.

-

One technical aspect that is also different is that Backbone is heavily event-oriented. Mithril, on the other hand, purposely avoids the observer pattern in an attempt to abolish "come-from hell", i.e. a class of debugging problems where you don't know what triggers some code because of a long chain of events triggering other events.

+

Another marking difference is that Backbone is workflow agnostic, providing no idiomatic way to organize applications. This is good for framework adoption, but not necessarily ideal for team scalability and codebase discoverability.

+

In contrast, Mithril encourages you to develop applications using the patterns found throughout this guide, and discourages the use of "bastardized" MVC pattern variations.

+

One technical aspect that is also different is that Backbone is heavily event-oriented. Mithril, on the other hand, purposely avoids the observer pattern in an attempt to abolish "come-from hell", a class of debugging problems where you don't know what triggers some code because of a long chain of events triggering other events.

A particularly nasty instance of this problem that sometimes occurs in "real-time" applications is when event triggering chains become circular due to a conditional statement bug, causing infinite loops and browser crashes.

Another significant difference between Backbone and Mithril is in their approach to familiarity: Backbone appeals to people familiar w/ jQuery; Mithril is designed to be familiar to people with server-side MVC framework experience.

Angular

Angular is an MVC framework maintained by Google, and it provides a declarative view layer and an emphasis on testability. It leverages developer experience with server-side MVC frameworks, and in many ways, is very similar in scope to Mithril.

The main difference between Angular templates and Mithril templates is that Angular templates follow the tradition of being defined in HTML. This has the benefit of cleaner syntax for writing static text, but it comes with the disadvantage of features getting awkwardly tied to HTML syntax, as well as providing poor debugging support.

-

One thing you may have noticed in the homepage is that, out of the box, Angular is not as performant as other frameworks. Steep performance degradation is a notoriously common issue in non-trivial Angular applications and there are several third party libraries which attempt to get around performance problems. Speaking from experience, it's generally difficult to reason about performance in Angular.

+

One thing you may have noticed on the Mithril homepage is that, out of the box, Angular is not as performant as other frameworks. Steep performance degradation is a notoriously common issue in non-trivial Angular applications and there are several third party libraries which attempt to get around performance problems. Speaking from experience, it's generally difficult to reason about performance in Angular.

Mithril takes some learnings from that and implements a templating redrawing system that renders less aggressively, is less complex and is easier to profile.

-

A noteworthy difference between Angular and Mithril is in framework complexity: Angular implements several subsystems that would seem more logical in programming language implementations (e.g. a parser, a dynamic scoping mechanism, decorators, etc). Mithril, on the other hand, tries to provide only features to support a more classic MVC paradigm.

+

A noteworthy difference between Angular and Mithril is in framework complexity: Angular implements several subsystems that would seem more logical in programming language implementations (e.g. a parser, a dynamic scoping mechanism, decorators, etc). Mithril, on the other hand, tries to provide only features that support a more classic MVC paradigm.

Ember

Ember is a highly comprehensive MVC framework, providing a large API that covers not only traditional MVC patterns, but also a vast range of helper utilities as well.

-

The biggest difference between Ember and Mithril is summarized in the Architecture section above: Ember's comprehensiveness come at a cost of a steep learning curve, and a high degree of vendor lock-in.

+

The biggest difference between Ember and Mithril is summarized in the Architecture section above: Ember's comprehensiveness comes at the cost of a steep learning curve and a high degree of vendor lock-in.

Ember is also more opinionated in terms of how application architecture should look, and as a result, tends to be less transparent in terms of what is actually happening under the hood.

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.

-

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.

+

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.

Another difference is that Mithril, being an MVC framework, rather than a templating engine, provides an auto-redrawing system that is aware of network asynchrony and that can render views efficiently without cluttering application code with redraw calls, and without letting the developer unintentionally bleed out of the MVC pattern.

Note also that, despite having a bigger scope, Mithril has a smaller file size than React.

Knockout

@@ -107,7 +107,7 @@

Generally speaking, Knockout applications tend to be more tightly coupled than Mithril since Knockout doesn't provide an equivalent to Mithril's modules and components.

As with Angular, Knockout templates are written in HTML, and therefore have the same pros and cons as Angular templates.

Vue

-

Vue is a relatively new and unknown templating engine, but it boasts impressive results in its performance benchmark.

+

Vue is a relatively new templating engine, but it boasts impressive results in its performance benchmark.

It is not a full MVC framework, but it is similar to Angular templates, and uses the same terminology for its features (e.g. directives and filters).

The most relevant difference is that Vue uses browser features that don't work (and cannot be made to work) in Internet Explorer 8. Mithril allows developers to support browsers all the way back to IE6 and Blackberry.

Vue's implementation cleverly hijacks array methods, but it should be noted that Javascript Arrays cannot be truly subclassed and as such, Vue suffers from abstraction leaks.

diff --git a/archive/v0.1.14/compiling-templates.html b/archive/v0.1.14/compiling-templates.html index 4d5dc799..6eb39a5b 100644 --- a/archive/v0.1.14/compiling-templates.html +++ b/archive/v0.1.14/compiling-templates.html @@ -47,7 +47,7 @@

Compiling Templates

You can optionally pre-compile templates that use m() by running the template-compiler.sjs macro with Sweet.js. This step isn't required in order to use Mithril, but it's an easy way to squeeze a little bit more performance out of an application, without the need for code changes.

Compiling a template transforms the nested function calls of a template into a raw virtual DOM tree (which is merely a collection of native Javascript objects that is ready to be rendered via m.render). This means that compiled templates don't need to parse the string in m("div#foo") and they don't incur the cost of the function call.

-

It's worth mentioning that Mithril has built-in mechanisms elsewhere that take care of real bottlenecks like browser repaint management and DOM updating. This optional compilation tool is merely "icing on the cake" that speeds up the javascript run-time of templates (which is already fast even without compilation - see performance test in the homepage).

+

It's worth mentioning that Mithril has built-in mechanisms elsewhere that take care of real bottlenecks like browser repaint management and DOM updating. This optional compilation tool is merely "icing on the cake" that speeds up the Javascript run-time of templates (which is already fast, even without compilation - see the performance section on the homepage).

The macro takes regular Mithril templates like the one below:

var view = function() {
     return m("a", {href: "http://google.com"}, "test");
diff --git a/archive/v0.1.14/components.html b/archive/v0.1.14/components.html
index 45b28f25..9553e8cc 100644
--- a/archive/v0.1.14/components.html
+++ b/archive/v0.1.14/components.html
@@ -103,8 +103,8 @@ projectList.view = function(ctrl) {
 
 //initialize
 m.module(document.body, dashboard);
-

As you can see, components look exactly like regular modules - it's turtles all the way down! Remember that modules are simply dumb containers for controller and view classes.

-

This means components are decoupled both horizontally and vertically. It's possible to refactor each component as a isolated unit of logic (which itself follows the MVC pattern). And we can do so without touching the rest of the application (as long as the component API stays the same).

+

As you can see, components look exactly like regular modules - it's turtles all the way down! Remember that modules are simply dumb containers for controller and view classes.

+

This means components are decoupled both horizontally and vertically. It's possible to refactor each component as an isolated unit of logic (which itself follows the MVC pattern). And we can do so without touching the rest of the application (as long as the component API stays the same).

Similarly, it's possible to mix and match different classes to make mix-in anonymous components (e.g. it's straightforward to build several views - for, say, a mobile app - that use the same controller).

It's also possible to keep references to parent and even sibling components. This is useful, for example, when implementing notification badges in a navigation component, which are triggered and managed by other components in the system.


diff --git a/archive/v0.1.14/getting-started.html b/archive/v0.1.14/getting-started.html index eb6f73ed..aa7acb48 100644 --- a/archive/v0.1.14/getting-started.html +++ b/archive/v0.1.14/getting-started.html @@ -46,7 +46,7 @@

Getting Started

What is Mithril?

-

Mithril is a client-side Javascript MVC framework, i.e. it's a tool to make application code divided into a data layer (called "Model"), a UI layer (called View), and a glue layer (called Controller)

+

Mithril is a client-side Javascript MVC framework, i.e. it's a tool to make application code divided into a data layer (called Model), a UI layer (called View), and a glue layer (called Controller)

Mithril is around 4kb gzipped thanks to its small, focused, API. It provides a templating engine with a virtual DOM diff implementation for performant rendering, utilities for high-level modelling via functional composition, as well as support for routing and componentization.

The goal of the framework is to make application code discoverable, readable and maintainable, and hopefully help you become an even better developer.

Unlike some frameworks, Mithril tries very hard to avoid locking you into a web of dependencies: you can use as little of the framework as you need.

@@ -62,7 +62,7 @@

Yes, this is valid HTML 5! According to the specs, the <html>, <head> and <body> tags can be omitted, but their respective DOM elements will still be there implicitly when a browser renders that markup.


Model

-

In Mithril, typically an application lives in an namespace and contains modules. Modules are merely structures that represent a viewable "page" or component.

+

In Mithril, an application typically lives in a namespace and contains modules. Modules are merely structures that represent a viewable "page" or component.

For simplicity, our application will have only one module, and we're going to use it as the namespace for our application:

<script>
 //this application only has one module: todo
@@ -113,7 +113,7 @@ list.length; //0

Controller

Our next step is to write a controller that will use our model classes.

-
//the controller uses 3 model-level entities, of which one is a custom defined class:
+
//the controller uses three model-level entities, of which one is a custom defined class:
 //`Todo` is the central class in this application
 //`list` is merely a generic array, with standard array methods
 //`description` is a temporary storage box that holds a string
@@ -184,7 +184,7 @@ m.render(document, todo.view(ctrl));
</html>

Data Bindings

-

Let's implement a data binding on the text input. Data bindings connect a DOM element to a javascript variable so that updating one updates the other.

+

Let's implement a data binding on the text input. Data bindings connect a DOM element to a Javascript variable so that updating one updates the other.

m("input")
 
 //becomes
@@ -196,7 +196,7 @@ m.render(todo.view(ctrl)); // input is empty
 ctrl.description("Write code"); //set the description in the controller
 m.render(todo.view(ctrl)); // input now says "Write code"

Note that calling the todo.view method multiple times does not re-render the entire template.

-

Mithril internally keeps a virtual representation of the DOM in cache, scans for changes, and then only modifies the minimum required to apply the change.

+

Internally, Mithril keeps a virtual representation of the DOM in cache, scans for changes, and then only modifies the minimum required to apply the change.

In this case, Mithril only touches the value attribute of the input.


Bindings can also be bi-directional: that is, they can be made such that, in addition to what we saw just now, a user typing on the input updates the description getter-setter.

@@ -210,7 +210,7 @@ m.render(todo.view(ctrl)); // input now says "Write code"
onchange: function(e) {
     ctrl.description(e.target["value"]);
 }
-

The difference, aside from the cosmetic avoidance of anonymous functions, is that the m.withAttr idiom also takes care of catching the correct event target and selecting the appropriate source of the data - i.e. whether it should come from a javascript property or from DOMElement::getAttribute()

+

The difference, aside from the cosmetic avoidance of anonymous functions, is that the m.withAttr idiom also takes care of catching the correct event target and selecting the appropriate source of the data - i.e. whether it should come from a Javascript property or from DOMElement::getAttribute()


In addition to bi-directional data binding, we can also bind parameterized functions to events:

m("button", {onclick: ctrl.add.bind(ctrl, ctrl.description)}, "Add")
@@ -271,22 +271,22 @@ m("table", [ };

Here are the highlights of the template above:


When running the classes in this application separately, you have full control and full responsibility for determining when to redraw the view.

-

However, Mithril does provide another utility to make this task automatic.

+

However, Mithril does provide another utility to make this task automatic: the Auto-Redrawing System.

In order to enable Mithril's auto-redrawing system, we run the code as a Mithril module:

m.module(document, todo);
-

Mithril's auto-redrawing system keeps track of controller stability, and only redraws the view once it detects that the controller has finished running all of its code, including asynchronous ajax payloads.

+

Mithril's auto-redrawing system keeps track of controller stability, and only redraws the view once it detects that the controller has finished running all of its code, including asynchronous AJAX payloads.

Also note that this mechanism itself is not asynchronous if it doesn't need to be: Mithril does not need to wait for the next browser repaint frame to redraw - it doesn't even need to wait for the document ready event on the first redraw - it will redraw immediately upon script completion, if able to.


Summary

@@ -308,7 +308,7 @@ todo.Todo = function(data) { //the TodoList class is a list of Todo's todo.TodoList = Array; -//the controller uses 3 model-level entities, of which one is a custom defined class: +//the controller uses three model-level entities, of which one is a custom defined class: //`Todo` is the central class in this application //`list` is merely a generic array, with standard array methods //`description` is a temporary storage box that holds a string @@ -355,9 +355,9 @@ m.module(document, todo);

Model

Idiomatic Mithril code is meant to apply good programming conventions and be easy to refactor.

In the application above, notice how the Todo class can easily be moved to a different module if code re-organization is required.

-

Todos are self-contained and their data aren't tied to the DOM like in typical jQuery based code. The Todo class API is reusable and unit-test friendly, and in addition, it's a plain-vanilla Javascript class which requires almost no framework-specific learning curve.

+

Todos are self-contained and their data aren't tied to the DOM like in typical jQuery based code. The Todo class API is reusable and unit-test friendly, and in addition, it's a plain-vanilla Javascript class, and so has almost no framework-specific learning curve.

m.prop is a simple but surprisingly versatile tool: it's composable, it enables uniform data access and allows a higher degree of decoupling when major refactoring is required.

-

When said refactoring is unavoidable, the developer can simply replace the m.prop call with an appropriate getter-setter implementation, instead of having to grep for API usage across the entire application.

+

When refactoring is unavoidable, the developer can simply replace the m.prop call with an appropriate getter-setter implementation, instead of having to grep for API usage across the entire application.

For example, if todo descriptions needed to always be uppercased, one could simply change the description getter-setter:

this.description = m.prop(data.description)

becomes:

@@ -370,7 +370,7 @@ this.description = function(value) { return description; }

According to Mithril's philosophy, list and description are also considered model-level entities. This is a subtle but important point: model entities don't need to be full-blown custom classes.

-

Native javascript classes are quite appropriate for storing primitive and structured data. Since in this case they are indeed being used to store data - even if temporarily - they are model entities!

+

Native Javascript classes are quite appropriate for storing primitive and structured data. Since in this case they are indeed being used to store data - even if temporarily - they are model entities!

Be aware that by using the native Array class for a list, we're making an implicit statement that we are going to support all of the standard Array methods as part of our API.

While this decision allows better API discoverability, the trade-off is that we're largely giving up on custom constraints and behavior. For example, if we wanted to change the application to make the list be persisted, a native Array would most certainly not be a suitable class to use.

In order to deal with that type of refactoring, one can explicitly decide to support only a subset of the Array API, and implement another class with the same interface as this subset API.

@@ -411,14 +411,14 @@ this.description = function(value) {
  • You get the ability to automate linting, unit testing and minifying of the entire view layer - and you are even able to use Closure Compiler's Advanced Mode without needing extensive annotations.

  • -
  • It provides full Turing completeness: full control over evaluation eagerness/lazyness and caching in templates. You can even build components that take other components as first-class-citizen parameters!

    +
  • It provides full Turing completeness: full control over evaluation eagerness/laziness and caching in templates. You can even build components that take other components as first-class-citizen parameters!

  • -
  • Turtles all the way down: you don't need write custom data binding code in jQuery for every possible user interaction, and you don't need to support a complicated "directive" layer to be able to fit some types of components into the system.

    +
  • Turtles all the way down: you don't need write custom data binding code in jQuery for every possible user interaction, and you don't need to support a complicated "directive" layer to be able to fit some types of components into the system.

  • Views in Mithril use a virtual DOM diff implementation, which sidesteps performance problems related to opaque dirty-checking and excessive browser repaint that are present in some frameworks.

    Another feature - the optional m() utility - allows writing terse templates in a declarative style using CSS shorthands, similar to popular HTML preprocessors from server-side MVC frameworks.

    -

    And because Mithril views are javascript, the developer has full freedom to abstract common patterns - from bidirectional binding helpers to full blown components - using standard javascript refactoring techniques.

    +

    And because Mithril views are Javascript, the developer has full freedom to abstract common patterns - from bidirectional binding helpers to full blown components - using standard Javascript refactoring techniques.

    Mithril templates are also more collision-proof than other component systems since there's no way to pollute the HTML tag namespace by defining ad-hoc tag names.

    A more intellectually interesting aspect of the framework is that event handling is encouraged to be done via functional composition (i.e. by using tools like m.withAttr, m.prop and the native .bind() method for partial application).

    If you've been interested in learning or using Functional Programming in the real world, Mithril provides very pragmatic opportunities to get into it.

    @@ -438,6 +438,8 @@ this.description = function(value) {

    Misc

    diff --git a/archive/v0.1.14/how-to-read-signatures.html b/archive/v0.1.14/how-to-read-signatures.html index ef150b6e..1b97757f 100644 --- a/archive/v0.1.14/how-to-read-signatures.html +++ b/archive/v0.1.14/how-to-read-signatures.html @@ -61,8 +61,8 @@

    How to Read Signatures

    -

    Rather than providing concrete classes like other frameworks, Mithril provides methods that operate on plain old javascript objects (POJOs) that match given signatures.

    -

    A signature is a description of its static type. For functions, it shows what are the parameters of the function, its return value and their expected types. For objects and arrays, it shows the expected data structure and the expected types of their members.

    +

    Rather than providing concrete classes like other frameworks, Mithril provides methods that operate on plain old Javascript objects (POJOs) that match given signatures.

    +

    A signature is a description of its static type. For functions, it shows the parameters of the function, its return value and their expected types. For objects and arrays, it shows the expected data structure and the expected types of their members.

    Method signatures in this documentation follow a syntax similar to Java syntax, with some extra additions:

    ReturnType methodName(ParameterType1 param1, ParameterType2 param2)

    Optional Parameters

    @@ -121,7 +121,7 @@ var a = aComplexTypeValue typeof a == "function" // true "label" in a // true a.label = "first" -

    Polimorphic Types

    +

    Polymorphic Types

    When multiple (but not all) types are accepted, the pipe | is used to delimit the list of valid types

    void test(Children children, Value value)
     
    @@ -132,7 +132,7 @@ where:
     test(["test", 2], "second")
     test([1, 2, 3], "second")
     test([1, "test", 3], 2)
    -

    Pipe syntax within Object curly brace syntax means that for a specific key name has specific type requirements.

    +

    Pipe syntax within Object curly brace syntax means that, for a specific key, name has specific type requirements.

    In the example below, the value parameter should be a key-value map. This map may contain a key called config, whose value should be a function.

    void test(Object { any | void config(DOMElement) } value)
    //example of a valid function call
    diff --git a/archive/v0.1.14/index.html b/archive/v0.1.14/index.html
    index 4b89589a..fa4c1888 100644
    --- a/archive/v0.1.14/index.html
    +++ b/archive/v0.1.14/index.html
    @@ -148,7 +148,7 @@ m.module(document.getElementById("example"), app);
     
     			
    -

    Performance

    +

    Performance

    To run the execution time tests below, click on their respective links, run the profiler from your desired browser's developer tools and measure the running time of a page refresh (Lower is better). Read more

    @@ -242,4 +242,4 @@ m.module(document.getElementById("example"), app); - \ No newline at end of file + diff --git a/archive/v0.1.14/installation.html b/archive/v0.1.14/installation.html index 6a99b659..bb98ebe0 100644 --- a/archive/v0.1.14/installation.html +++ b/archive/v0.1.14/installation.html @@ -49,16 +49,16 @@

    Direct download

    You can download a zip of the latest version version here.

    -

    Links to older versions can be found in the change log

    +

    Links to older versions can be found in the change log.

    In order to use Mithril, extract it from the zip file and point a script tag to the .js file:

    <script src="mithril.min.js"></script>

    CDNs (Content Delivery Networks)

    -

    You can also find Mithril in cdnjs and jsdelivr

    +

    You can also find Mithril in cdnjs and jsDelivr.

    Content delivery networks allow the library to be cached across different websites that use the same version of the framework, and help reduce latency by serving the files from a server that is physically near the user's location.

    -

    CdnJs

    +

    cdnjs

    <script src="//cdnjs.cloudflare.com/ajax/libs/mithril/0.1.14/mithril.min.js"></script>
    -

    JsDelivr

    +

    jsDelivr

    <script src="//cdn.jsdelivr.net/mithril/0.1.14/mithril.min.js"></script>

    NPM

    diff --git a/archive/v0.1.14/integration.html b/archive/v0.1.14/integration.html index 94a88a4a..a4b16a37 100644 --- a/archive/v0.1.14/integration.html +++ b/archive/v0.1.14/integration.html @@ -127,7 +127,7 @@ m.module(document.body, dashboard);

    This can be done by simply calling m.startComputation at the beginning, and m.endComputation at the end of the function. You must add a pair of these calls for each asynchronous execution thread, unless the thread is already integrated.

    For example, if you were to call a web service using m.request, you would not need to add more calls to m.startComputation / m.endComputation (you would still need the first pair in the event handler, though).

    On the other hand, if you were to call a web service using jQuery, then you would be responsible for adding a m.startComputation call before the jQuery ajax call, and for adding a m.endComputation call at the end of the completion callback, in addition to the calls within the change event handler. Refer to the auto-redrawing guide for an example.

    -

    One important note about the config method is that you should avoid calling m.redraw, m.startComputation and m.endComputation in the config function's execution thread. (An execution thread is basically any amount of code that runs before other asynchronous threads start to run)

    +

    One important note about the config method is that you should avoid calling m.redraw, m.startComputation and m.endComputation in the config function's execution thread. (An execution thread is basically any amount of code that runs before other asynchronous threads start to run.)

    While Mithril technically does support this use case, relying on multiple redraw passes degrades performance and makes it possible to code yourself into an infinite execution loop situation, which is extremely difficult to debug.

    The dashboard module in the example shows how a developer would consume the select2 component.

    You should always document integration components so that others can find out what attribute parameters can be used to initialize the component.

    diff --git a/archive/v0.1.14/mithril.html b/archive/v0.1.14/mithril.html index e85b01d1..b99655fa 100644 --- a/archive/v0.1.14/mithril.html +++ b/archive/v0.1.14/mithril.html @@ -83,7 +83,7 @@ m("a[name=top]"); //yields <a name="top"></a> m("[contenteditable]"); //yields <div contenteditable></div> m("a#google.external[href='http://google.com']", "Google"); //yields <a id="google" class="external" href="http://google.com">Google</a> -

    Each m() call creates a virtual DOM element, that is, a javascript object that represents a DOM element, and which is eventually converted into one.

    +

    Each m() call creates a virtual DOM element, that is, a Javascript object that represents a DOM element, and which is eventually converted into one.

    You can, of course, nest virtual elements:

    m("ul", [
         m("li", "item 1"),
    @@ -132,7 +132,7 @@ m.render(document.body, [
     </body>

    As you can see, flow control is done with vanilla Javascript. This allows the developer to abstract away any aspect of the template at will.


    -

    Note that you can use both javascript property names and HTML attribute names to set values in the attributes argument, but you should pass a value of appropriate type. If an attribute has the same name in Javascript and in HTML, then Mithril assumes you're setting the Javascript property.

    +

    Note that you can use both Javascript property names and HTML attribute names to set values in the attributes argument, but you should pass a value of appropriate type. If an attribute has the same name in Javascript and in HTML, then Mithril assumes you're setting the Javascript property.

    m("div", {class: "widget"}); //yields <div class="widget"></div>
     
     m("div", {className: "widget"}); //yields <div class="widget"></div>
    @@ -278,7 +278,7 @@ m("a[href='/dashboard']", {config: m.route}, "Dashboard&q
     

    If it's a SubtreeDirective with the value "retain", it will retain the existing DOM tree in place, if any. See subtree directives for more information.

  • returns VirtualElement

    -

    The returned VirtualElement is a javascript data structure that represents the DOM element to be rendered by m.render

    +

    The returned VirtualElement is a Javascript data structure that represents the DOM element to be rendered by m.render

  • diff --git a/archive/v0.1.14/mithril.min.zip b/archive/v0.1.14/mithril.min.zip index 8d0d5d9595f261910c65ba63e2715de3feebc427..bd837d12d4b163960906d07a1a05fe65c56a53f3 100644 GIT binary patch delta 65 zcmaF-oaym%Cf)#VW)?065J+&_y^*&CTnlD1k>r8t-$n> G&GrBpHyS_y diff --git a/archive/v0.1.14/mithril.module.html b/archive/v0.1.14/mithril.module.html index 8ed90158..f3ef6f42 100644 --- a/archive/v0.1.14/mithril.module.html +++ b/archive/v0.1.14/mithril.module.html @@ -176,8 +176,8 @@ where:

    The controller class is instantiated immediately upon calling m.module.

    Once the controller code finishes executing (and this may include waiting for AJAX requests to complete), the view class is instantiated, and the instance of the controller is passed as an argument to the view's constructor.

    Note that controllers can manually instantiate child controllers (since they are simply Javascript constructors), and likewise, views can instantiate child views and manually pass the child controller instances down the the child view constructors.

    -

    This "turtles all the way down" approach is the heart of Mithril's component system.

    -

    Components are nothing more than decoupled classes that can be dynamically brought together as required. This permits the swapping of implementations at a routing level (for example, if implementing widgetized versions of existing components) and class dependency hierarchies can be structurally organized to provide uniform interfaces (for unit tests, for example).

    +

    This "turtles all the way down" approach is the heart of Mithril's component system.

    +

    Components are nothing more than decoupled classes that can be dynamically brought together as required. This permits the swapping of implementations at a routing level (for example, if implementing widgetized versions of existing components), and class dependency hierarchies can be structurally organized to provide uniform interfaces (for unit tests, for example).

    diff --git a/archive/v0.1.14/mithril.request.html b/archive/v0.1.14/mithril.request.html index e35d40a9..a71505b2 100644 --- a/archive/v0.1.14/mithril.request.html +++ b/archive/v0.1.14/mithril.request.html @@ -94,7 +94,7 @@ var doSomething = function() { /*...*/ } m.request({method: "GET", url: "/user"}).then(users).then(doSomething)

    While both basic assignment syntax and thennable syntax can be used to the same effect, typically it's recommended that you use the assignment syntax whenever possible, as it's easier to read.

    -

    The thennable mechanism is intended to be used in 3 ways:

    +

    The thennable mechanism is intended to be used in three ways:

    -

    In the example below, we take advantage of queuing to debug the ajax response data prior to doing further processing on the user list

    +

    In the example below, we take advantage of queuing to debug the AJAX response data prior to doing further processing on the user list

    var users = m.request({method: "GET", url: "/user"})
         .then(console.log);
         .then(function(users) {
    @@ -165,7 +165,7 @@ var controller = function() {
     //i.e. users() //[{name: "John"}, {name: "Mary"}, {name: "Jane"}]

    Casting the Response Data to a Class

    -

    It's possible to auto-cast a JSON response to a class. This is useful when we want to control access to certain properties in an object, as opposed to exposing all the fields in POJOs (plain old javascript objects) for arbitrary processing.

    +

    It's possible to auto-cast a JSON response to a class. This is useful when we want to control access to certain properties in an object, as opposed to exposing all the fields in POJOs (plain old Javascript objects) for arbitrary processing.

    In the example below, User.list returns a list of User instances.

    var User = function(data) {
         this.name = m.prop(data.name);
    diff --git a/archive/v0.1.14/mithril.route.html b/archive/v0.1.14/mithril.route.html
    index 295bb811..972a4970 100644
    --- a/archive/v0.1.14/mithril.route.html
    +++ b/archive/v0.1.14/mithril.route.html
    @@ -63,7 +63,7 @@
     							

    m.route

    Routing is a system that allows creating Single-Page-Applications (SPA), i.e. applications that can go from a page to another without causing a full browser refresh.

    It enables seamless navigability while preserving the ability to bookmark each page individually, and the ability to navigate the application via the browser's history mechanism.

    -

    This method overloads 4 different units of functionality:

    +

    This method overloads four different units of functionality:

    • m.route(rootElement, defaultRoute, routes) - defines the available URLs in an application, and their respective modules

    • @@ -80,7 +80,7 @@

      Defining routes

      Usage

      To define a list of routes, you need to specify a host DOM element, a default route and a key-value map of possible routes and respective modules to be rendered.

      -

      The example below defines 3 routes, to be rendered in <body>. home, login and dashboard are modules. We'll see how to define a module in a bit.

      +

      The example below defines three routes, to be rendered in <body>. home, login and dashboard are modules. We'll see how to define a module in a bit.

      m.route(document.body, "/", {
           "/": home,
           "/login": login,
      @@ -109,7 +109,7 @@ m.route.mode = "hash";
      <body>johndoe</body>

      Above, dashboard is a module. It contains a controller and a view properties. When the URL matches a route, the respective module's controller is instantiated and passed as a parameter to the view.

      In this case, since there's only route, the app redirects to the default route "/dashboard/johndoe".

      -

      The string johndoe is bound to the :userID parameter, which can be retrived programmatically in the controller via m.route.param("userID").

      +

      The string johndoe is bound to the :userID parameter, which can be retrieved programmatically in the controller via m.route.param("userID").

      The m.route.mode defines which part of the URL to use for routing.


      Variadic routes

      diff --git a/archive/v0.1.14/mithril.trust.html b/archive/v0.1.14/mithril.trust.html index b383bfb3..64ae4e68 100644 --- a/archive/v0.1.14/mithril.trust.html +++ b/archive/v0.1.14/mithril.trust.html @@ -63,7 +63,7 @@

      m.trust

      If you're writing a template for a view, use m() instead.

      This method flags a string as trusted HTML.

      -

      Trusted HTML is allowed to render arbitrary, potentially invalid markup, as well as run arbitrary javascript, and therefore the developer is responsible for either:

      +

      Trusted HTML is allowed to render arbitrary, potentially invalid markup, as well as run arbitrary Javascript, and therefore the developer is responsible for either:

      • sanitizing the markup contained in the string, or

      • @@ -73,7 +73,7 @@

        Note that browsers ignore <script> tags that have been inserted into the DOM via innerHTML. They do this because once the element is ready (and thus, has an accessible innerHTML property), their rendering engines cannot backtrack to the parsing-stage if the script calls something like document.write("</body>").

        For this reason, m.trust will not auto-run <script> tags from trusted strings.

        Browsers do, however, allow scripts to be run asynchronously via a number of execution points, such as the onload or onerror attributes in <img> and <iframe>.

        -

        IE also allows running of javascript via CSS behaviors in <link>/<style> tags and style attributes.

        +

        IE also allows running of Javascript via CSS behaviors in <link>/<style> tags and style attributes.

        It's worth noting that the execution points listed above are commonly used for security attacks in combination with malformed markup, e.g. strings with mismatched attribute quotes like " onload="alert(1).

        Mithril templates are defended against these attacks by default, except when markup is injected via m.trust.

        It is the developer's responsibility to ensure the input to m.trust cannot be maliciously modified by user-entered data.

        @@ -100,7 +100,7 @@ m.render("body", [

        A string containing HTML markup

      • returns String trustedHtml

        -

        The returned string is a String object instance (as opposed to a string primitive) containing the same html content, and exposing a flag property for internal use within Mithril. Do not create or manipulate trust flags manually.

        +

        The returned string is a String object instance (as opposed to a string primitive) containing the same HTML content, and exposing a flag property for internal use within Mithril. Do not create or manipulate trust flags manually.

        Also note that concatenating or splitting a trusted string removes the trust flag. If doing such operations, the final string needs to be flagged as trusted.

      diff --git a/archive/v0.1.14/practices.html b/archive/v0.1.14/practices.html index 2a8a5361..8a7dbda0 100644 --- a/archive/v0.1.14/practices.html +++ b/archive/v0.1.14/practices.html @@ -50,11 +50,11 @@

      Data manipulation should be done in model classes, such that controllers never have entities lying around in temporarily invalid states.

      Mithril's design strongly encourages all entity logic to be handled in atomic model layer methods (in the sense of entity state stability).

      In fact, unavoidable abstraction leaks (such as network-bound asynchrony) are laid out in such a way as to make idiomatic code organization elegant, and conversely, to make it so that the abstraction leak problems themselves discourage attempts to misplace entity logic in the controller.

      -

      This design decision comes from experience with DRY and "bus factor" of large, highly relational model layers.

      -

      This is in stark contrast to the ActiveRecord pattern of other frameworks, where model entities are largely object representations of database entities and these entities are manipulated in controllers in an ad-hoc field-by-field fashion, and the "committed" via a save method.

      -

      Because Mithril encourages all entity logic to be done in the model layer, it's idiomatic to create modules with model-level classes that deal specifically with relationship between entities, when there isn't already a model entity that can logically hold the relational business logic.

      +

      This design decision comes from experience with DRY and the "bus factor" of large, highly relational model layers.

      +

      This is in stark contrast to the ActiveRecord pattern of other frameworks, where model entities are largely object representations of database entities and these entities are manipulated in controllers in an ad-hoc field-by-field fashion, and then "committed" via a save method.

      +

      Because Mithril encourages all entity logic to be done in the model layer, it's idiomatic to create modules with model-level classes that deal specifically with relationships between entities, when there isn't already a model entity that can logically hold the relational business logic.

      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. Controllers may explicitly call m.redraw, but, if possible, it's preferable to abstract this into a service which integrates w/ Mithril's auto-redrawing system (see. m.startComputation / m.endComputation)

      +

      DOM manipulation should be done in the view via m() and config. Controllers may explicitly call m.redraw, 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).


      File Separation

      The examples in this site usually conflate different MVC layers together for the sake of readability, but normally it's recommended that each layer on a module be in different files. For example:

      @@ -77,7 +77,7 @@ app.view = function(ctrl) {

      You can use task automation tools such as GruntJS to concatenate the files back together for production.

      Typically, when separating MVC layers, it's common that the namespace declaration be in the model layer, since this is usually the most used dependency for the other layers.

      You may choose to declare the namespace in a separate file or have the build system generate it on demand, instead.

      -

      You should avoid grouping classes by the MVC layer they belong to, i.e. don't create 3 files called model.js, controllers.js and views.js.

      +

      You should avoid grouping classes by the MVC layer they belong to, i.e. don't create three files called model.js, controllers.js and views.js.

      That organization pattern needlessly ties unrelated aspects of the application together and dilutes the clarity of modules.


      Global Namespace Hygiene

      @@ -96,7 +96,7 @@ app.view = function(ctrl) {

      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 of 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).

      +

      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 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.

      If you call this method more often than that, Mithril may ignore calls or defer them to the next browser repaint cycle.

      diff --git a/archive/v0.1.14/routing.html b/archive/v0.1.14/routing.html index fbff0fc3..1e1a4d81 100644 --- a/archive/v0.1.14/routing.html +++ b/archive/v0.1.14/routing.html @@ -45,7 +45,7 @@

    Routing

    -

    Routing is a system that allows creating Single-Page-Applications (SPA), i.e. applications that can go from a page to another without causing a full browser refresh.

    +

    Routing is a system that allows creating Single-Page-Applications (SPA), i.e. applications that can go from one page to another without causing a full browser refresh.

    It enables seamless navigability while preserving the ability to bookmark each page individually, and the ability to navigate the application via the browser's history mechanism.

    Mithril provides utilities to handle three different aspect of routing: