initial release

This commit is contained in:
Leo Horie 2014-03-16 22:07:53 -04:00
parent 554e8358cf
commit 70b2489539
81 changed files with 6702 additions and 2 deletions

View file

@ -0,0 +1,2 @@
<script src="//cdnjs.cloudflare.com/ajax/libs/angular.js/1.2.10/angular.min.js"></script>
To run an execution time test on this page, run the profiler from your browser's developer tools and measure the running time of a page refresh. (Lower is better)

View file

@ -0,0 +1,14 @@
<html ng-app>
<head><script src="//cdnjs.cloudflare.com/ajax/libs/angular.js/1.2.10/angular.min.js"></script></head>
<body ng-controller="TestCtrl">
<p>To run an execution time test on this page, run the profiler from your browser's developer tools and measure the running time of a page refresh. (Lower is better)</p>
<div id="container">
<span ng-repeat="item in items"><input value="{{item.name}}"></span>
</div>
<script>
function TestCtrl($scope) {
$scope.items = [{name: "a"}, {name: "b"}, {name: "c"}, {name: "a"}, {name: "b"}, {name: "c"}, {name: "a"}, {name: "b"}, {name: "c"}, {name: "a"}, {name: "b"}, {name: "c"}, {name: "a"}, {name: "b"}, {name: "c"}, {name: "a"}, {name: "b"}, {name: "c"}, {name: "a"}, {name: "b"}, {name: "c"}, {name: "a"}, {name: "b"}, {name: "c"}, {name: "a"}, {name: "b"}, {name: "c"}, {name: "a"}, {name: "b"}, {name: "c"}, {name: "a"}, {name: "b"}, {name: "c"}, {name: "a"}, {name: "b"}, {name: "c"}, {name: "a"}, {name: "b"}, {name: "c"}, {name: "a"}, {name: "b"}, {name: "c"}, {name: "a"}, {name: "b"}, {name: "c"}, {name: "a"}, {name: "b"}, {name: "c"}, {name: "a"}, {name: "b"}, {name: "c"}, {name: "a"}, {name: "b"}, {name: "c"}, {name: "a"}, {name: "b"}, {name: "c"}, {name: "a"}, {name: "b"}, {name: "c"}, {name: "a"}, {name: "b"}, {name: "c"}, {name: "a"}, {name: "b"}, {name: "c"}, {name: "a"}, {name: "b"}, {name: "c"}, {name: "a"}, {name: "b"}, {name: "c"}, {name: "a"}, {name: "b"}, {name: "c"}, {name: "a"}, {name: "b"}, {name: "c"}, {name: "a"}, {name: "b"}, {name: "c"}, {name: "a"}, {name: "b"}, {name: "c"}, {name: "a"}, {name: "b"}, {name: "c"}, {name: "a"}, {name: "b"}, {name: "c"}, {name: "a"}, {name: "b"}, {name: "c"}, {name: "a"}, {name: "b"}, {name: "c"}, {name: "a"}, {name: "b"}, {name: "c"}, {name: "a"}, {name: "b"}, {name: "c"}, {name: "a"}, {name: "b"}, {name: "c"}, {name: "a"}, {name: "b"}, {name: "c"}, {name: "a"}, {name: "b"}, {name: "c"}, {name: "a"}, {name: "b"}, {name: "c"}, {name: "a"}, {name: "b"}, {name: "c"}, {name: "a"}, {name: "b"}, {name: "c"}, {name: "a"}, {name: "b"}, {name: "c"}, {name: "a"}, {name: "b"}, {name: "c"}, {name: "a"}, {name: "b"}, {name: "c"}, {name: "a"}, {name: "b"}, {name: "c"}, {name: "a"}, {name: "b"}, {name: "c"}, {name: "a"}, {name: "b"}, {name: "c"}, {name: "a"}, {name: "b"}, {name: "c"}, {name: "a"}, {name: "b"}, {name: "c"}, {name: "a"}, {name: "b"}, {name: "c"}, {name: "a"}, {name: "b"}, {name: "c"}];
}
</script>
</body>
</html>

View file

@ -0,0 +1,13 @@
<html ng-app>
<head><script src="//cdnjs.cloudflare.com/ajax/libs/angular.js/1.2.10/angular.min.js"></script></head>
<body ng-controller="TestCtrl">
<div id="container">
<span ng-repeat="item in items"><input value="{{item.name}}"></span>
</div>
<script>
function TestCtrl($scope) {
$scope.items = [{name: "a"}, {name: "b"}, {name: "c"}, {name: "a"}, {name: "b"}, {name: "c"}, {name: "a"}, {name: "b"}, {name: "c"}, {name: "a"}, {name: "b"}, {name: "c"}, {name: "a"}, {name: "b"}, {name: "c"}, {name: "a"}, {name: "b"}, {name: "c"}, {name: "a"}, {name: "b"}, {name: "c"}, {name: "a"}, {name: "b"}, {name: "c"}, {name: "a"}, {name: "b"}, {name: "c"}, {name: "a"}, {name: "b"}, {name: "c"}, {name: "a"}, {name: "b"}, {name: "c"}, {name: "a"}, {name: "b"}, {name: "c"}, {name: "a"}, {name: "b"}, {name: "c"}, {name: "a"}, {name: "b"}, {name: "c"}, {name: "a"}, {name: "b"}, {name: "c"}, {name: "a"}, {name: "b"}, {name: "c"}, {name: "a"}, {name: "b"}, {name: "c"}, {name: "a"}, {name: "b"}, {name: "c"}, {name: "a"}, {name: "b"}, {name: "c"}, {name: "a"}, {name: "b"}, {name: "c"}, {name: "a"}, {name: "b"}, {name: "c"}, {name: "a"}, {name: "b"}, {name: "c"}, {name: "a"}, {name: "b"}, {name: "c"}, {name: "a"}, {name: "b"}, {name: "c"}, {name: "a"}, {name: "b"}, {name: "c"}, {name: "a"}, {name: "b"}, {name: "c"}, {name: "a"}, {name: "b"}, {name: "c"}, {name: "a"}, {name: "b"}, {name: "c"}, {name: "a"}, {name: "b"}, {name: "c"}, {name: "a\"><img src='javascript:;' onerror=\"alert('alert box should not appear')\">"}, {name: "b"}, {name: "c"}, {name: "a"}, {name: "b"}, {name: "c"}, {name: "a"}, {name: "b"}, {name: "c"}, {name: "a"}, {name: "b"}, {name: "c"}, {name: "a"}, {name: "b"}, {name: "c"}, {name: "a"}, {name: "b"}, {name: "c"}, {name: "a"}, {name: "b"}, {name: "c"}, {name: "a"}, {name: "b"}, {name: "c"}, {name: "a"}, {name: "b"}, {name: "c"}, {name: "a"}, {name: "b"}, {name: "c"}, {name: "a"}, {name: "b"}, {name: "c"}, {name: "a"}, {name: "b"}, {name: "c"}, {name: "a"}, {name: "b"}, {name: "c"}, {name: "a"}, {name: "b"}, {name: "c"}, {name: "a"}, {name: "b"}, {name: "c"}, {name: "a"}, {name: "b"}, {name: "c"}, {name: "a"}, {name: "b"}, {name: "c"}, {name: "a"}, {name: "b"}, {name: "c"}, {name: "a"}, {name: "b"}, {name: "c"}, {name: "a"}, {name: "b"}, {name: "c"}, {name: "a"}, {name: "b"}, {name: "c"}];
}
</script>
</body>
</html>

View file

@ -0,0 +1,4 @@
<script src="//cdnjs.cloudflare.com/ajax/libs/jquery/2.1.0/jquery.min.js"></script>
<script src="//cdnjs.cloudflare.com/ajax/libs/underscore.js/1.5.2/underscore-min.js"></script>
<script src="//cdnjs.cloudflare.com/ajax/libs/backbone.js/1.1.0/backbone-min.js"></script>
To run an execution time test on this page, run the profiler from your browser's developer tools and measure the running time of a page refresh. (Lower is better)

View file

@ -0,0 +1,30 @@
<html>
<head>
<script src="//cdnjs.cloudflare.com/ajax/libs/jquery/2.1.0/jquery.min.js"></script>
<script src="//cdnjs.cloudflare.com/ajax/libs/underscore.js/1.5.2/underscore-min.js"></script>
<script src="//cdnjs.cloudflare.com/ajax/libs/backbone.js/1.1.0/backbone-min.js"></script>
</head>
<body>
<p>To run an execution time test on this page, run the profiler from your browser's developer tools and measure the running time of a page refresh. (Lower is better)</p>
<div id="container"></div>
<script type="text/template" id="template">
<% _.each(items, function( item ){ %><input value="<%= item.name %>" /><% })%>
</script>
<script>
var View = Backbone.View.extend({
el: $("#container"),
template: _.template(document.getElementById("template").innerHTML),
initialize: function() {
this.render()
},
render: function() {
this.$el.html(this.template({items: this.model}))
}
})
new View({
model: [{name: "a"}, {name: "b"}, {name: "c"}, {name: "a"}, {name: "b"}, {name: "c"}, {name: "a"}, {name: "b"}, {name: "c"}, {name: "a"}, {name: "b"}, {name: "c"}, {name: "a"}, {name: "b"}, {name: "c"}, {name: "a"}, {name: "b"}, {name: "c"}, {name: "a"}, {name: "b"}, {name: "c"}, {name: "a"}, {name: "b"}, {name: "c"}, {name: "a"}, {name: "b"}, {name: "c"}, {name: "a"}, {name: "b"}, {name: "c"}, {name: "a"}, {name: "b"}, {name: "c"}, {name: "a"}, {name: "b"}, {name: "c"}, {name: "a"}, {name: "b"}, {name: "c"}, {name: "a"}, {name: "b"}, {name: "c"}, {name: "a"}, {name: "b"}, {name: "c"}, {name: "a"}, {name: "b"}, {name: "c"}, {name: "a"}, {name: "b"}, {name: "c"}, {name: "a"}, {name: "b"}, {name: "c"}, {name: "a"}, {name: "b"}, {name: "c"}, {name: "a"}, {name: "b"}, {name: "c"}, {name: "a"}, {name: "b"}, {name: "c"}, {name: "a"}, {name: "b"}, {name: "c"}, {name: "a"}, {name: "b"}, {name: "c"}, {name: "a"}, {name: "b"}, {name: "c"}, {name: "a"}, {name: "b"}, {name: "c"}, {name: "a"}, {name: "b"}, {name: "c"}, {name: "a"}, {name: "b"}, {name: "c"}, {name: "a"}, {name: "b"}, {name: "c"}, {name: "a"}, {name: "b"}, {name: "c"}, {name: "a"}, {name: "b"}, {name: "c"}, {name: "a"}, {name: "b"}, {name: "c"}, {name: "a"}, {name: "b"}, {name: "c"}, {name: "a"}, {name: "b"}, {name: "c"}, {name: "a"}, {name: "b"}, {name: "c"}, {name: "a"}, {name: "b"}, {name: "c"}, {name: "a"}, {name: "b"}, {name: "c"}, {name: "a"}, {name: "b"}, {name: "c"}, {name: "a"}, {name: "b"}, {name: "c"}, {name: "a"}, {name: "b"}, {name: "c"}, {name: "a"}, {name: "b"}, {name: "c"}, {name: "a"}, {name: "b"}, {name: "c"}, {name: "a"}, {name: "b"}, {name: "c"}, {name: "a"}, {name: "b"}, {name: "c"}, {name: "a"}, {name: "b"}, {name: "c"}, {name: "a"}, {name: "b"}, {name: "c"}, {name: "a"}, {name: "b"}, {name: "c"}, {name: "a"}, {name: "b"}, {name: "c"}, {name: "a"}, {name: "b"}, {name: "c"}, {name: "a"}, {name: "b"}, {name: "c"}, {name: "a"}, {name: "b"}, {name: "c"}]
})
</script>
</body>
</html>

View file

@ -0,0 +1,29 @@
<html>
<head>
<script src="//cdnjs.cloudflare.com/ajax/libs/jquery/2.1.0/jquery.min.js"></script>
<script src="//cdnjs.cloudflare.com/ajax/libs/underscore.js/1.5.2/underscore-min.js"></script>
<script src="//cdnjs.cloudflare.com/ajax/libs/backbone.js/1.1.0/backbone-min.js"></script>
</head>
<body>
<div id="container"></div>
<script type="text/template" id="template">
<% _.each(items, function( item ){ %><input value="<%= item.name %>" /><% })%>
</script>
<script>
var View = Backbone.View.extend({
el: $("#container"),
template: _.template(document.getElementById("template").innerHTML),
initialize: function() {
this.render()
},
render: function() {
this.$el.html(this.template({items: this.model}))
}
})
new View({
model: [{name: "a"}, {name: "b"}, {name: "c"}, {name: "a"}, {name: "b"}, {name: "c"}, {name: "a"}, {name: "b"}, {name: "c"}, {name: "a"}, {name: "b"}, {name: "c"}, {name: "a"}, {name: "b"}, {name: "c"}, {name: "a"}, {name: "b"}, {name: "c"}, {name: "a"}, {name: "b"}, {name: "c"}, {name: "a"}, {name: "b"}, {name: "c"}, {name: "a"}, {name: "b"}, {name: "c"}, {name: "a"}, {name: "b"}, {name: "c"}, {name: "a"}, {name: "b"}, {name: "c"}, {name: "a"}, {name: "b"}, {name: "c"}, {name: "a"}, {name: "b"}, {name: "c"}, {name: "a"}, {name: "b"}, {name: "c"}, {name: "a"}, {name: "b"}, {name: "c"}, {name: "a"}, {name: "b"}, {name: "c"}, {name: "a"}, {name: "b"}, {name: "c"}, {name: "a"}, {name: "b"}, {name: "c"}, {name: "a"}, {name: "b"}, {name: "c"}, {name: "a"}, {name: "b"}, {name: "c"}, {name: "a"}, {name: "b"}, {name: "c"}, {name: "a"}, {name: "b"}, {name: "c"}, {name: "a"}, {name: "b"}, {name: "c"}, {name: "a"}, {name: "b"}, {name: "c"}, {name: "a"}, {name: "b"}, {name: "c"}, {name: "a"}, {name: "b"}, {name: "c"}, {name: "a"}, {name: "b"}, {name: "c"}, {name: "a"}, {name: "b"}, {name: "c"}, {name: "a"}, {name: "b"}, {name: "c"}, {name: "a\"><img src='javascript:;' onerror=\"alert('alert box should not appear')\">"}, {name: "b"}, {name: "c"}, {name: "a"}, {name: "b"}, {name: "c"}, {name: "a"}, {name: "b"}, {name: "c"}, {name: "a"}, {name: "b"}, {name: "c"}, {name: "a"}, {name: "b"}, {name: "c"}, {name: "a"}, {name: "b"}, {name: "c"}, {name: "a"}, {name: "b"}, {name: "c"}, {name: "a"}, {name: "b"}, {name: "c"}, {name: "a"}, {name: "b"}, {name: "c"}, {name: "a"}, {name: "b"}, {name: "c"}, {name: "a"}, {name: "b"}, {name: "c"}, {name: "a"}, {name: "b"}, {name: "c"}, {name: "a"}, {name: "b"}, {name: "c"}, {name: "a"}, {name: "b"}, {name: "c"}, {name: "a"}, {name: "b"}, {name: "c"}, {name: "a"}, {name: "b"}, {name: "c"}, {name: "a"}, {name: "b"}, {name: "c"}, {name: "a"}, {name: "b"}, {name: "c"}, {name: "a"}, {name: "b"}, {name: "c"}, {name: "a"}, {name: "b"}, {name: "c"}, {name: "a"}, {name: "b"}, {name: "c"}]
})
</script>
</body>
</html>

View file

@ -0,0 +1,2 @@
<script src="//cdnjs.cloudflare.com/ajax/libs/jquery/2.1.0/jquery.min.js"></script>
To run an execution time test on this page, run the profiler from your browser's developer tools and measure the running time of a page refresh. (Lower is better)

View file

@ -0,0 +1,17 @@
<html>
<head><script src="//cdnjs.cloudflare.com/ajax/libs/jquery/2.1.0/jquery.min.js"></script></head>
<body>
<p>To run an execution time test on this page, run the profiler from your browser's developer tools and measure the running time of a page refresh. (Lower is better)</p>
<div id="container"></div>
<script>
var items = [{name: "a"}, {name: "b"}, {name: "c"}, {name: "a"}, {name: "b"}, {name: "c"}, {name: "a"}, {name: "b"}, {name: "c"}, {name: "a"}, {name: "b"}, {name: "c"}, {name: "a"}, {name: "b"}, {name: "c"}, {name: "a"}, {name: "b"}, {name: "c"}, {name: "a"}, {name: "b"}, {name: "c"}, {name: "a"}, {name: "b"}, {name: "c"}, {name: "a"}, {name: "b"}, {name: "c"}, {name: "a"}, {name: "b"}, {name: "c"}, {name: "a"}, {name: "b"}, {name: "c"}, {name: "a"}, {name: "b"}, {name: "c"}, {name: "a"}, {name: "b"}, {name: "c"}, {name: "a"}, {name: "b"}, {name: "c"}, {name: "a"}, {name: "b"}, {name: "c"}, {name: "a"}, {name: "b"}, {name: "c"}, {name: "a"}, {name: "b"}, {name: "c"}, {name: "a"}, {name: "b"}, {name: "c"}, {name: "a"}, {name: "b"}, {name: "c"}, {name: "a"}, {name: "b"}, {name: "c"}, {name: "a"}, {name: "b"}, {name: "c"}, {name: "a"}, {name: "b"}, {name: "c"}, {name: "a"}, {name: "b"}, {name: "c"}, {name: "a"}, {name: "b"}, {name: "c"}, {name: "a"}, {name: "b"}, {name: "c"}, {name: "a"}, {name: "b"}, {name: "c"}, {name: "a"}, {name: "b"}, {name: "c"}, {name: "a"}, {name: "b"}, {name: "c"}, {name: "a"}, {name: "b"}, {name: "c"}, {name: "a"}, {name: "b"}, {name: "c"}, {name: "a"}, {name: "b"}, {name: "c"}, {name: "a"}, {name: "b"}, {name: "c"}, {name: "a"}, {name: "b"}, {name: "c"}, {name: "a"}, {name: "b"}, {name: "c"}, {name: "a"}, {name: "b"}, {name: "c"}, {name: "a"}, {name: "b"}, {name: "c"}, {name: "a"}, {name: "b"}, {name: "c"}, {name: "a"}, {name: "b"}, {name: "c"}, {name: "a"}, {name: "b"}, {name: "c"}, {name: "a"}, {name: "b"}, {name: "c"}, {name: "a"}, {name: "b"}, {name: "c"}, {name: "a"}, {name: "b"}, {name: "c"}, {name: "a"}, {name: "b"}, {name: "c"}, {name: "a"}, {name: "b"}, {name: "c"}, {name: "a"}, {name: "b"}, {name: "c"}, {name: "a"}, {name: "b"}, {name: "c"}, {name: "a"}, {name: "b"}, {name: "c"}, {name: "a"}, {name: "b"}, {name: "c"}, {name: "a"}, {name: "b"}, {name: "c"}, {name: "a"}, {name: "b"}, {name: "c"}];
var view = function() {
var container = $("#container").html("");
for (var i = 0; i < items.length; i++) {
container.append("<input value=\"" + items[i].name + "\" />");
}
}
$(view);
</script>
</body>
</html>

View file

@ -0,0 +1,16 @@
<html>
<head><script src="//cdnjs.cloudflare.com/ajax/libs/jquery/2.1.0/jquery.min.js"></script></head>
<body>
<div id="container"></div>
<script>
var items = [{name: "a"}, {name: "b"}, {name: "c"}, {name: "a"}, {name: "b"}, {name: "c"}, {name: "a"}, {name: "b"}, {name: "c"}, {name: "a"}, {name: "b"}, {name: "c"}, {name: "a"}, {name: "b"}, {name: "c"}, {name: "a"}, {name: "b"}, {name: "c"}, {name: "a"}, {name: "b"}, {name: "c"}, {name: "a"}, {name: "b"}, {name: "c"}, {name: "a"}, {name: "b"}, {name: "c"}, {name: "a"}, {name: "b"}, {name: "c"}, {name: "a"}, {name: "b"}, {name: "c"}, {name: "a"}, {name: "b"}, {name: "c"}, {name: "a"}, {name: "b"}, {name: "c"}, {name: "a"}, {name: "b"}, {name: "c"}, {name: "a"}, {name: "b"}, {name: "c"}, {name: "a"}, {name: "b"}, {name: "c"}, {name: "a"}, {name: "b"}, {name: "c"}, {name: "a"}, {name: "b"}, {name: "c"}, {name: "a"}, {name: "b"}, {name: "c"}, {name: "a"}, {name: "b"}, {name: "c"}, {name: "a"}, {name: "b"}, {name: "c"}, {name: "a"}, {name: "b"}, {name: "c"}, {name: "a"}, {name: "b"}, {name: "c"}, {name: "a"}, {name: "b"}, {name: "c"}, {name: "a"}, {name: "b"}, {name: "c"}, {name: "a"}, {name: "b"}, {name: "c"}, {name: "a"}, {name: "b"}, {name: "c"}, {name: "a"}, {name: "b"}, {name: "c"}, {name: "a"}, {name: "b"}, {name: "c"}, {name: "a\"><img src='javascript:;' onerror=\"alert('alert box should not appear')\">"}, {name: "b"}, {name: "c"}, {name: "a"}, {name: "b"}, {name: "c"}, {name: "a"}, {name: "b"}, {name: "c"}, {name: "a"}, {name: "b"}, {name: "c"}, {name: "a"}, {name: "b"}, {name: "c"}, {name: "a"}, {name: "b"}, {name: "c"}, {name: "a"}, {name: "b"}, {name: "c"}, {name: "a"}, {name: "b"}, {name: "c"}, {name: "a"}, {name: "b"}, {name: "c"}, {name: "a"}, {name: "b"}, {name: "c"}, {name: "a"}, {name: "b"}, {name: "c"}, {name: "a"}, {name: "b"}, {name: "c"}, {name: "a"}, {name: "b"}, {name: "c"}, {name: "a"}, {name: "b"}, {name: "c"}, {name: "a"}, {name: "b"}, {name: "c"}, {name: "a"}, {name: "b"}, {name: "c"}, {name: "a"}, {name: "b"}, {name: "c"}, {name: "a"}, {name: "b"}, {name: "c"}, {name: "a"}, {name: "b"}, {name: "c"}, {name: "a"}, {name: "b"}, {name: "c"}, {name: "a"}, {name: "b"}, {name: "c"}];
var view = function() {
var container = $("#container").html("");
for (var i = 0; i < items.length; i++) {
container.append("<input value=\"" + items[i].name + "\" />");
}
}
$(view);
</script>
</body>
</html>

View file

@ -0,0 +1,2 @@
<script src="../mithril.min.js"></script>
To run an execution time test on this page, run the profiler from your browser's developer tools and measure the running time of a page refresh. (Lower is better)

View file

@ -0,0 +1,20 @@
<html>
<head><script src="../mithril.min.js"></script></head>
<body>
<p>To run an execution time test on this page, run the profiler from your browser's developer tools and measure the running time of a page refresh. (Lower is better)</p>
<div id="container"></div>
<script>
var app = {}
app.controller = function() {
this.items = [{name: "a"}, {name: "b"}, {name: "c"}, {name: "a"}, {name: "b"}, {name: "c"}, {name: "a"}, {name: "b"}, {name: "c"}, {name: "a"}, {name: "b"}, {name: "c"}, {name: "a"}, {name: "b"}, {name: "c"}, {name: "a"}, {name: "b"}, {name: "c"}, {name: "a"}, {name: "b"}, {name: "c"}, {name: "a"}, {name: "b"}, {name: "c"}, {name: "a"}, {name: "b"}, {name: "c"}, {name: "a"}, {name: "b"}, {name: "c"}, {name: "a"}, {name: "b"}, {name: "c"}, {name: "a"}, {name: "b"}, {name: "c"}, {name: "a"}, {name: "b"}, {name: "c"}, {name: "a"}, {name: "b"}, {name: "c"}, {name: "a"}, {name: "b"}, {name: "c"}, {name: "a"}, {name: "b"}, {name: "c"}, {name: "a"}, {name: "b"}, {name: "c"}, {name: "a"}, {name: "b"}, {name: "c"}, {name: "a"}, {name: "b"}, {name: "c"}, {name: "a"}, {name: "b"}, {name: "c"}, {name: "a"}, {name: "b"}, {name: "c"}, {name: "a"}, {name: "b"}, {name: "c"}, {name: "a"}, {name: "b"}, {name: "c"}, {name: "a"}, {name: "b"}, {name: "c"}, {name: "a"}, {name: "b"}, {name: "c"}, {name: "a"}, {name: "b"}, {name: "c"}, {name: "a"}, {name: "b"}, {name: "c"}, {name: "a"}, {name: "b"}, {name: "c"}, {name: "a"}, {name: "b"}, {name: "c"}, {name: "a"}, {name: "b"}, {name: "c"}, {name: "a"}, {name: "b"}, {name: "c"}, {name: "a"}, {name: "b"}, {name: "c"}, {name: "a"}, {name: "b"}, {name: "c"}, {name: "a"}, {name: "b"}, {name: "c"}, {name: "a"}, {name: "b"}, {name: "c"}, {name: "a"}, {name: "b"}, {name: "c"}, {name: "a"}, {name: "b"}, {name: "c"}, {name: "a"}, {name: "b"}, {name: "c"}, {name: "a"}, {name: "b"}, {name: "c"}, {name: "a"}, {name: "b"}, {name: "c"}, {name: "a"}, {name: "b"}, {name: "c"}, {name: "a"}, {name: "b"}, {name: "c"}, {name: "a"}, {name: "b"}, {name: "c"}, {name: "a"}, {name: "b"}, {name: "c"}, {name: "a"}, {name: "b"}, {name: "c"}, {name: "a"}, {name: "b"}, {name: "c"}, {name: "a"}, {name: "b"}, {name: "c"}, {name: "a"}, {name: "b"}, {name: "c"}, {name: "a"}, {name: "b"}, {name: "c"}, {name: "a"}, {name: "b"}, {name: "c"}];
}
app.view = function(ctrl) {
return ctrl.items
.map(function(item) {
return m("input", {value: item.name})
});
}
m.module(document.getElementById("container"), app);
</script>
</body>
</html>

View file

@ -0,0 +1,19 @@
<html>
<head><script src="../mithril.min.js"></script></head>
<body>
<div id="container"></div>
<script>
var app = {}
app.controller = function() {
this.items = [{name: "a"}, {name: "b"}, {name: "c"}, {name: "a"}, {name: "b"}, {name: "c"}, {name: "a"}, {name: "b"}, {name: "c"}, {name: "a"}, {name: "b"}, {name: "c"}, {name: "a"}, {name: "b"}, {name: "c"}, {name: "a"}, {name: "b"}, {name: "c"}, {name: "a"}, {name: "b"}, {name: "c"}, {name: "a"}, {name: "b"}, {name: "c"}, {name: "a"}, {name: "b"}, {name: "c"}, {name: "a"}, {name: "b"}, {name: "c"}, {name: "a"}, {name: "b"}, {name: "c"}, {name: "a"}, {name: "b"}, {name: "c"}, {name: "a"}, {name: "b"}, {name: "c"}, {name: "a"}, {name: "b"}, {name: "c"}, {name: "a"}, {name: "b"}, {name: "c"}, {name: "a"}, {name: "b"}, {name: "c"}, {name: "a"}, {name: "b"}, {name: "c"}, {name: "a"}, {name: "b"}, {name: "c"}, {name: "a"}, {name: "b"}, {name: "c"}, {name: "a"}, {name: "b"}, {name: "c"}, {name: "a"}, {name: "b"}, {name: "c"}, {name: "a"}, {name: "b"}, {name: "c"}, {name: "a"}, {name: "b"}, {name: "c"}, {name: "a"}, {name: "b"}, {name: "c"}, {name: "a"}, {name: "b"}, {name: "c"}, {name: "a"}, {name: "b"}, {name: "c"}, {name: "a"}, {name: "b"}, {name: "c"}, {name: "a"}, {name: "b"}, {name: "c"}, {name: "a"}, {name: "b"}, {name: "c"}, {name: "a\"><img src='javascript:;' onerror=\"alert('alert box should not appear')\">"}, {name: "b"}, {name: "c"}, {name: "a"}, {name: "b"}, {name: "c"}, {name: "a"}, {name: "b"}, {name: "c"}, {name: "a"}, {name: "b"}, {name: "c"}, {name: "a"}, {name: "b"}, {name: "c"}, {name: "a"}, {name: "b"}, {name: "c"}, {name: "a"}, {name: "b"}, {name: "c"}, {name: "a"}, {name: "b"}, {name: "c"}, {name: "a"}, {name: "b"}, {name: "c"}, {name: "a"}, {name: "b"}, {name: "c"}, {name: "a"}, {name: "b"}, {name: "c"}, {name: "a"}, {name: "b"}, {name: "c"}, {name: "a"}, {name: "b"}, {name: "c"}, {name: "a"}, {name: "b"}, {name: "c"}, {name: "a"}, {name: "b"}, {name: "c"}, {name: "a"}, {name: "b"}, {name: "c"}, {name: "a"}, {name: "b"}, {name: "c"}, {name: "a"}, {name: "b"}, {name: "c"}, {name: "a"}, {name: "b"}, {name: "c"}, {name: "a"}, {name: "b"}, {name: "c"}, {name: "a"}, {name: "b"}, {name: "c"}];
}
app.view = function(ctrl) {
return ctrl.items
.map(function(item) {
return m("input", {value: item.name})
});
}
m.module(document.getElementById("container"), app);
</script>
</body>
</html>

196
archive/v0.1/index.html Normal file
View file

@ -0,0 +1,196 @@
<!doctype html>
<html>
<head>
<title>Mithril</title>
<link href="http://fonts.googleapis.com/css?family=Open+Sans:300italic" rel="stylesheet" />
<link href="lib/prism/prism.css" rel="stylesheet" />
<link href="style.css" rel="stylesheet" />
</head>
<body>
<header>
<nav class="container">
<a href="index.html" class="logo"><span>&#9675;</span> Mithril</a>
<a href="getting-started.html">Guide</a>
<a href="mithril.html">API</a>
<a href="mithril.min.zip">Download</a>
<a href="http://github.com/lhorie/mithril.js" target="_blank">Github</a>
</nav>
</header>
<main>
<section class="cta">
<div class="container">
<h1 class="logo"><span>&#9675;</span> Mithril</h1>
<p>A Javascript Framework for Building Brilliant Applications</p>
<a class="button" href="getting-started.html">Guide</a>
<a class="button" href="mithril.min.zip">Download v0.1</a>
</div>
</section>
<section class="features">
<div class="container row">
<div class="feature col(4,4,12)">
<h2>Light-weight</h2>
<ul>
<li>Only 3kb gzipped, no dependencies</li>
<li>Small API, small learning curve</li>
</ul>
</div>
<div class="feature col(4,4,12)">
<h2>Robust</h2>
<ul>
<li>Safe-by-default templates</li>
<li>Hierarchical MVC via components</li>
</ul>
</div>
<div class="feature col(4,4,12)">
<h2>Fast</h2>
<ul>
<li>Virtual DOM diffing and compilable templates</li>
<li>Intelligent auto-redrawing system</li>
</ul>
</div>
</div>
</section>
<section class="sample">
<div class="container">
<div class="col(8,8,12)">
<h2>Sample code</h2>
<pre><code class="language-javascript">//namespace
var app = {};
//model
app.PageList = function() {
return m.request({method: "GET", url: "pages.json"});
};
//controller
app.controller = function() {
this.pages = app.PageList();
};
//view
app.view = function(ctrl) {
return ctrl.pages().map(function(page) {
return m("a", {href: page.url}, page.title);
});
};
//initialize
m.module(document.getElementById("example"), app);</code></pre>
</div>
<div class="col(4,4,12)">
<h2>Output</h2>
<div id="example" class="example output">
<noscript>
<a href="getting-started.html">Getting Started</a>
<a href="mithril.html">Documentation</a></div>
</noscript>
<script src="mithril.min.js"></script>
<script>
//namespace
var app = {};
//model
app.PageList = function() {
return m.request({method: "GET", url: "pages.json"});
};
//controller
app.controller = function() {
this.pages = app.PageList();
};
//view
app.view = function(ctrl) {
return ctrl.pages().map(function(page) {
return m("a", {href: page.url}, page.title);
});
};
//initialize
m.module(document.getElementById("example"), app);
</script>
</div>
</div>
</div>
</section>
<section class="performance">
<div class="container">
<h2>Performance</h2>
<p>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)</p>
<div class="row">
<div class="col(4,4,6)">
<h3>Loading</h3>
<table>
<tr><td><a href="comparisons/mithril.parsing.html">Mithril</a></td><td><span class="bar" style="background:#161;width:1%;"></span> 0.28ms</td></tr>
<tr><td><a href="comparisons/jquery.parsing.html">jQuery</a></td><td><span class="bar" style="background:#66c;width:35%;"></span> 13.11ms</td></tr>
<tr><td><a href="comparisons/backbone.parsing.html">Backbone</a></td><td><span class="bar" style="background:#33c;width:50%;"></span> 18.54ms</td></tr>
<tr><td><a href="comparisons/angular.parsing.html">Angular</a></td><td><span class="bar" style="background:#c33;width:20%;"></span> 7.49ms</td></tr>
</table>
</div>
<div class="col(8,8,12)">
<h3>Rendering</h3>
<table>
<tr><td><a href="comparisons/mithril.rendering.html">Mithril</a></td><td><span class="bar" style="background:#161;width:4%;"></span> 9.44ms (uncompiled)</td></tr>
<tr><td><a href="comparisons/jquery.rendering.html">jQuery</a></td><td><span class="bar" style="background:#66c;width:17%;"></span> 40.27ms</td></tr>
<tr><td><a href="comparisons/backbone.rendering.html">Backbone</a></td><td><span class="bar" style="background:#33c;width:10%;"></span> 23.05ms</td></tr>
<tr><td><a href="comparisons/angular.rendering.html">Angular</a></td><td><span class="bar" style="background:#c33;width:50%;"></span> 118.63ms</td></tr>
</table>
</div>
</div>
</div>
</section>
<section class="security">
<div class="container">
<div class="row">
<div class="col(8,8,12)">
<h2>Safety</h2>
<p>Mithril templates are safe by default, i.e. you can't unintentionally create security holes.</p>
<p>To run the tests for each framework, click on the respective links. If you see an alert box, ensuring security with that framework is more work for you.</p>
</div>
<div class="col(4,4,12)">
<h3>Test Summary</h3>
<a href="comparisons/mithril.safety.html">Mithril</a> <em class="success">(pass) &#x2713;</em><br />
<a href="comparisons/jquery.safety.html">jQuery</a> <em class="error">(fail) &#x2717;</em><br />
<a href="comparisons/backbone.safety.html">Backbone</a> <em class="error">(fail) &#x2717;</em><br />
<a href="comparisons/angular.safety.html">Angular</a> <em class="success">(pass) &#x2713;</em><br />
</div>
</div>
</div>
</section>
<section class="more">
<div class="container row">
<div class="col(6,6,12)">
<h2>Guide</h2>
<p>Build a simple app, learn the ropes</p>
<p><a href="getting-started.html">Read Guide</a></p>
</div>
<div class="col(6,6,12)">
<h2>API</h2>
<p>Docs and code samples for your reference</p>
<p><a href="mithril.html">Read Docs</a></p>
</div>
</div>
</section>
</main>
<footer>
<div class="container">
Released under the <a href="http://opensource.org/licenses/MIT" target="_blank">MIT license</a><br />
&copy; 2014 Leo Horie
</div>
</footer>
<script src="lib/prism/prism.js"></script>
</body>
</html>

View file

@ -0,0 +1,126 @@
/**
* prism.js default theme for JavaScript, CSS and HTML
* Based on dabblet (http://dabblet.com)
* @author Lea Verou
*/
code[class*="language-"],
pre[class*="language-"] {
color: black;
text-shadow: 0 1px white;
font-family: Consolas, Monaco, 'Andale Mono', monospace;
direction: ltr;
text-align: left;
white-space: pre;
word-spacing: normal;
word-break: normal;
-moz-tab-size: 4;
-o-tab-size: 4;
tab-size: 4;
-webkit-hyphens: none;
-moz-hyphens: none;
-ms-hyphens: none;
hyphens: none;
}
pre[class*="language-"]::-moz-selection, pre[class*="language-"] ::-moz-selection,
code[class*="language-"]::-moz-selection, code[class*="language-"] ::-moz-selection {
text-shadow: none;
background: #b3d4fc;
}
pre[class*="language-"]::selection, pre[class*="language-"] ::selection,
code[class*="language-"]::selection, code[class*="language-"] ::selection {
text-shadow: none;
background: #b3d4fc;
}
@media print {
code[class*="language-"],
pre[class*="language-"] {
text-shadow: none;
}
}
/* Code blocks */
pre[class*="language-"] {
padding: 1em;
margin: .5em 0;
overflow: auto;
}
:not(pre) > code[class*="language-"],
pre[class*="language-"] {
background: #f5f2f0;
}
/* Inline code */
:not(pre) > code[class*="language-"] {
padding: .1em;
border-radius: .3em;
}
.token.comment,
.token.prolog,
.token.doctype,
.token.cdata {
color: slategray;
}
.token.punctuation {
color: #999;
}
.namespace {
opacity: .7;
}
.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.operator,
.token.entity,
.token.url,
.language-css .token.string,
.style .token.string,
.token.variable {
color: #a67f59;
background: hsla(0,0%,100%,.5);
}
.token.atrule,
.token.attr-value,
.token.keyword {
color: #07a;
}
.token.regex,
.token.important {
color: #e90;
}
.token.important {
font-weight: bold;
}
.token.entity {
cursor: help;
}

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}}});;

View file

@ -0,0 +1,725 @@
new function(window) {
var selectorCache = {}
var type = {}.toString
var parser = /(?:(^|#|\.)([^#\.\[\]]+))|(\[.+?\])/g, attrParser = /\[(.+?)(?:=("|'|)(.+?)\2)?\]/
Mithril = m = function() {
var args = arguments
var hasAttrs = type.call(args[1]) == "[object Object]"
var attrs = hasAttrs ? args[1] : {}
var classAttrName = "class" in attrs ? "class" : "className"
var cell = selectorCache[args[0]]
if (cell === undefined) {
selectorCache[args[0]] = cell = {tag: "div", attrs: {}}
var match, classes = []
while (match = parser.exec(args[0])) {
if (match[1] == "") cell.tag = match[2]
else if (match[1] == "#") cell.attrs.id = match[2]
else if (match[1] == ".") classes.push(match[2])
else if (match[3][0] == "[") {
var pair = attrParser.exec(match[3])
cell.attrs[pair[1]] = pair[3] || true
}
}
if (classes.length > 0) cell.attrs[classAttrName] = classes.join(" ")
}
cell = clone(cell)
cell.attrs = clone(cell.attrs)
cell.children = hasAttrs ? args[2] : args[1]
for (var attrName in attrs) {
if (attrName == classAttrName) cell.attrs[attrName] = (cell.attrs[attrName] || "") + " " + attrs[attrName]
else cell.attrs[attrName] = attrs[attrName]
}
return cell
}
function build(parent, data, cached) {
if (data === null || data === undefined) return
var cachedType = type.call(cached), dataType = type.call(data)
if (cachedType != dataType) {
if (cached !== null && cached !== undefined) clear(cached.nodes)
cached = new data.constructor
cached.nodes = []
}
if (dataType == "[object Array]") {
var nodes = [], intact = cached.length === data.length
for (var i = 0; i < data.length; i++) {
var item = build(parent, data[i], cached[i])
if (!item.nodes.intact) intact = false
cached[i] = item
}
if (!intact) {
for (var i = 0; i < data.length; i++) nodes = nodes.concat(cached[i].nodes)
for (var i = nodes.length, node; node = cached.nodes[i]; i++) if (node.parentNode !== null) node.parentNode.removeChild(node)
for (var i = cached.nodes.length, node; node = nodes[i]; i++) if (node.parentNode === null) parent.appendChild(node)
cached.length = data.length
cached.nodes = nodes
}
}
else if (dataType == "[object Object]") {
if (data.tag != cached.tag || Object.keys(data.attrs).join() != Object.keys(cached.attrs).join()) clear(cached.nodes)
var node, isNew = cached.nodes.length === 0
if (isNew) {
node = window.document.createElement(data.tag)
cached = {tag: data.tag, attrs: setAttributes(node, data.attrs, {}), children: build(node, data.children, cached.children), nodes: [node]}
parent.appendChild(node)
}
else {
node = cached.nodes[0]
setAttributes(node, data.attrs, cached.attrs)
cached.children = build(node, data.children, cached.children)
cached.nodes.intact = true
}
if (type.call(data.attrs["config"]) == "[object Function]") data.attrs["config"](node, !isNew)
}
else {
var node
if (cached.nodes.length === 0) {
if (data.$trusted) {
var lastChild = parent.lastChild
parent.insertAdjacentHTML("beforeend", data)
node = lastChild ? lastChild.nextSibling : parent.firstChild
}
else {
node = window.document.createTextNode(data)
parent.appendChild(node)
}
cached = "string number boolean".indexOf(typeof data) > -1 ? new data.constructor(data) : data
cached.nodes = [node]
}
else if (cached.valueOf() !== data.valueOf()) {
if (data.$trusted) {
var current = cached.nodes[0], nodes = [current]
if (current) {
while (current = current.nextSibling) nodes.push(current)
clear(nodes)
var lastChild = parent.lastChild
parent.insertAdjacentHTML("beforeend", data)
node = lastChild ? lastChild.nextSibling : parent.firstChild
}
else parent.innerHTML = data
}
else {
node = cached.nodes[0]
parent.appendChild(node)
node.nodeValue = data
}
cached = new data.constructor(data)
cached.nodes = [node]
}
else cached.nodes.intact = true
}
return cached
}
function setAttributes(node, dataAttrs, cachedAttrs) {
for (var attrName in dataAttrs) {
var dataAttr = dataAttrs[attrName]
if (!(attrName in cachedAttrs) || (cachedAttrs[attrName] !== dataAttr)) {
cachedAttrs[attrName] = dataAttr
if (attrName == "config") continue
if (attrName.indexOf("on") == 0 && typeof dataAttr == "function") dataAttr = autoredraw(dataAttr, node)
if (attrName == "style") for (var rule in dataAttr) node.style[rule] = dataAttr[rule]
else if (attrName in node) node[attrName] = dataAttr
else node.setAttribute(attrName, dataAttr)
}
}
return cachedAttrs
}
function clear(nodes) {
for (var i = 0; i < nodes.length; i++) nodes[i].parentNode.removeChild(nodes[i])
nodes.length = 0
}
function clone(object) {
var result = {}
for (var prop in object) result[prop] = object[prop]
return result
}
function autoredraw(callback, object) {
return function() {
m.startComputation()
var output = callback.apply(object || window, arguments)
m.endComputation()
return output
}
}
var html
var documentNode = {
insertAdjacentHTML: function(_, data) {
window.document.write(data)
window.document.close()
},
appendChild: function(node) {
if (html === undefined) html = window.document.createElement("html")
if (node.nodeName == "HTML") html = node
else html.appendChild(node)
if (window.document.documentElement !== html) {
window.document.replaceChild(html, window.document.documentElement)
}
}
}
var nodeCache = [], cellCache = {}
m.render = function(root, cell) {
var index = nodeCache.indexOf(root)
var id = index < 0 ? nodeCache.push(root) - 1 : index
var node = root == window.document || root == window.document.documentElement ? documentNode : root
cellCache[id] = build(node, cell, cellCache[id])
}
m.trust = function(value) {
value = new String(value)
value.$trusted = true
return value
}
var currentRoot, currentModule = {view: function() {}}, currentController = {}, now = 0, lastRedraw = 0, lastRedrawId = 0
m.module = function(root, module) {
m.startComputation()
currentRoot = root
currentModule = module
currentController = new module.controller
m.endComputation()
}
m.redraw = function() {
m.render(currentRoot || window.document, currentModule.view(currentController))
lastRedraw = now
}
function redraw() {
now = window.performance && window.performance.now ? window.performance.now() : new window.Date().getTime()
if (now - lastRedraw > 16) m.redraw()
else {
var cancel = window.cancelAnimationFrame || window.clearTimeout
var defer = window.requestAnimationFrame || window.setTimeout
cancel(lastRedrawId)
lastRedrawId = defer(m.redraw, 0)
}
}
var pendingRequests = 0, computePostRedrawHook = null
m.startComputation = function() {pendingRequests++}
m.endComputation = function() {
pendingRequests = Math.max(pendingRequests - 1, 0)
if (pendingRequests == 0) {
redraw()
if (computePostRedrawHook) {
computePostRedrawHook()
computePostRedrawHook = null
}
}
}
m.withAttr = function(prop, withAttrCallback) {
return function(e) {withAttrCallback(prop in e.currentTarget ? e.currentTarget[prop] : e.currentTarget.getAttribute(prop))}
}
//routing
var modes = {pathname: "", hash: "#", search: "?"}
var redirect = function() {}, routeParams = {}
m.route = function() {
if (arguments.length == 3) {
var root = arguments[0], defaultRoute = arguments[1], router = arguments[2]
redirect = function(source) {
var path = source.slice(modes[m.route.mode].length)
if (!routeByValue(root, router, path)) {
m.route(defaultRoute, true)
}
}
var listener = m.route.mode == "hash" ? "onhashchange" : "onpopstate"
window[listener] = function() {
redirect(window.location[m.route.mode])
}
computePostRedrawHook = scrollToHash
window[listener]()
}
else if (arguments[0].addEventListener) {
var element = arguments[0]
var isInitialized = arguments[1]
if (!isInitialized) {
element.removeEventListener("click", routeUnobtrusive)
element.addEventListener("click", routeUnobtrusive)
}
}
else if (typeof arguments[0] == "string") {
var route = arguments[0]
var shouldReplaceHistoryEntry = arguments[1] === true
if (window.history.pushState) {
computePostRedrawHook = function() {
window.history[shouldReplaceHistoryEntry ? "replaceState" : "pushState"](null, window.document.title, modes[m.route.mode] + route)
scrollToHash()
}
redirect(modes[m.route.mode] + route)
}
else window.location[m.route.mode] = route
}
}
m.route.param = function(key) {return routeParams[key]}
m.route.mode = "search"
function routeByValue(root, router, path) {
for (var route in router) {
if (route == path) return !void m.module(root, router[route])
var matcher = new RegExp("^" + route.replace(/:[^\/]+/g, "([^\\/]+)") + "$")
if (matcher.test(path)) {
return !void path.replace(matcher, function() {
var keys = route.match(/:[^\/]+/g)
var values = [].slice.call(arguments, 1, -2)
routeParams = {}
for (var i = 0; i < keys.length; i++) routeParams[keys[i].slice(1)] = values[i]
m.module(root, router[route])
})
}
}
}
function routeUnobtrusive(e) {
e.preventDefault()
m.route(e.currentTarget.getAttribute("href"))
}
function scrollToHash() {
if (m.route.mode != "hash" && window.location.hash) window.location.hash = window.location.hash
}
//model
m.prop = function(store) {
return function() {
if (arguments.length) store = arguments[0]
return store
}
}
m.deferred = function() {
var resolvers = [], rejecters = []
var object = {
resolve: function(value) {
for (var i = 0; i < resolvers.length; i++) resolvers[i](value)
},
reject: function(value) {
for (var i = 0; i < rejecters.length; i++) rejecters[i](value)
},
promise: m.prop()
}
object.promise.resolvers = resolvers
object.promise.then = function(success, error) {
var next = m.deferred()
if (!success) success = identity
if (!error) error = identity
resolvers.push(function(value) {
var result = success(value)
next.resolve(result !== undefined ? result : value)
})
rejecters.push(function(value) {
var result = error(value)
next.reject(result !== undefined ? result : value)
})
return next.promise
}
return object
}
m.sync = function(args) {
var method = "resolve"
function synchronizer(resolved) {
return function(value) {
results.push(value)
if (!resolved) method = "reject"
if (results.length == args.length) {
deferred.promise(results)
deferred[method](results)
}
return value
}
}
var deferred = m.deferred()
var results = []
for (var i = 0; i < args.length; i++) {
args[i].then(synchronizer(true), synchronizer(false))
}
return deferred.promise
}
function identity(value) {return value}
function ajax(options) {
var xhr = window.XDomainRequest ? new window.XDomainRequest : new window.XMLHttpRequest
xhr.open(options.method, options.url, true, options.user, options.password)
xhr.onload = typeof options.onload == "function" ? options.onload : function() {}
xhr.onerror = typeof options.onerror == "function" ? options.onerror : function() {}
xhr.withCredentials = true
if (typeof options.config == "function") options.config(xhr, options)
xhr.send(options.data)
return xhr
}
function querystring(object, prefix) {
var str = []
for(var prop in object) {
var key = prefix ? prefix + "[" + prop + "]" : prop, value = object[prop]
str.push(typeof value == "object" ? querystring(value, key) : encodeURIComponent(key) + "=" + encodeURIComponent(value))
}
return str.join("&")
}
function bindData(xhrOptions, data, serialize) {
if (data && Object.keys(data).length > 0) {
if (xhrOptions.method == "GET") {
xhrOptions.url = xhrOptions.url + (xhrOptions.url.indexOf("?") < 0 ? "?" : "&") + querystring(data)
}
else xhrOptions.data = serialize(data)
}
return xhrOptions
}
function parameterizeUrl(url, data) {
var tokens = url.match(/:\w+/g)
if (tokens && data) {
for (var i = 0; i < tokens.length; i++) {
var key = tokens[i].slice(1)
url = url.replace(tokens[i], data[key])
delete data[key]
}
}
return url
}
m.request = function(xhrOptions) {
m.startComputation()
var deferred = m.deferred()
var serialize = xhrOptions.serialize || JSON.stringify
var deserialize = xhrOptions.deserialize || JSON.parse
xhrOptions.url = parameterizeUrl(xhrOptions.url, xhrOptions.data)
xhrOptions = bindData(xhrOptions, xhrOptions.data, serialize)
xhrOptions.onload = xhrOptions.onerror = function(e) {
var unwrap = (e.type == "load" ? xhrOptions.unwrapSuccess : xhrOptions.unwrapError) || identity
var response = unwrap(deserialize(e.target.responseText))
if (response instanceof Array && xhrOptions.type) {
for (var i = 0; i < response.length; i++) response[i] = new xhrOptions.type(response[i])
}
else if (xhrOptions.type) response = new xhrOptions.type(response)
deferred.promise(response)
deferred[e.type == "load" ? "resolve" : "reject"](response)
m.endComputation()
}
ajax(xhrOptions)
deferred.promise.then = propBinder(deferred.promise)
return deferred.promise
}
function propBinder(promise) {
var bind = promise.then
return function(success, error) {
var next = bind(function(value) {return next(success(value))}, function(value) {return next(error(value))})
next.then = propBinder(next)
return next
}
}
//testing API
m.deps = function(mock) {return window = mock}
}(this)
function test(condition) {
try {if (!condition()) throw new Error}
catch (e) {test.failures.push(condition)}
test.total++
}
test.total = 0
test.failures = []
test.print = function(print) {
for (var i = 0; i < test.failures.length; i++) {
print(test.failures[i].toString())
}
print("tests: " + test.total + "\nfailures: " + test.failures.length)
}
var mock = {}
mock.window = new function() {
var window = {}
window.document = {}
window.document.childNodes = []
window.document.createElement = function(tag) {
return {
childNodes: [],
nodeName: tag.toUpperCase(),
appendChild: window.document.appendChild,
removeChild: window.document.removeChild,
replaceChild: window.document.replaceChild,
setAttribute: function(name, value) {
this[name] = value.toString()
},
getAttribute: function(name, value) {
return this[name]
},
}
}
window.document.createTextNode = function(text) {
return {nodeValue: text.toString()}
}
window.document.documentElement = null
window.document.replaceChild = function(newChild, oldChild) {
var index = this.childNodes.indexOf(oldChild)
if (index > -1) this.childNodes.splice(index, 1, newChild)
else this.childNodes.push(newChild)
newChild.parentNode = this
oldChild.parentNode = null
}
window.document.appendChild = function(child) {
this.childNodes.push(child)
child.parentNode = this
}
window.document.removeChild = function(child) {
var index = this.childNodes.indexOf(child)
this.childNodes.splice(index, 1)
child.parentNode = null
}
window.performance = new function () {
var timestamp = 50
this.$elapse = function(amount) {timestamp = amount}
this.now = function() {return timestamp}
}
window.cancelAnimationFrame = function() {}
window.requestAnimationFrame = function(callback) {callback()}
window.XMLHttpRequest = new function() {
var request = function() {
this.open = function(method, url) {
this.method = method
this.url = url
}
this.send = function() {
this.responseText = JSON.stringify(this)
request.$events.push({type: "load", target: this})
}
}
request.$events = []
return request
}
window.location = {search: "", pathname: "", hash: ""},
window.history = {}
window.history.pushState = function(data, title, url) {
window.location.pathname = window.location.search = window.location.hash = url
},
window.history.replaceState = function(data, title, url) {
window.location.pathname = window.location.search = window.location.hash = url
}
return window
}
function testMithril(mock) {
m.deps(mock)
//m
test(function() {return m("div").tag === "div"})
test(function() {return m(".foo").tag === "div"})
test(function() {return m(".foo").attrs.className === "foo"})
test(function() {return m("[title=bar]").tag === "div"})
test(function() {return m("[title=bar]").attrs.title === "bar"})
test(function() {return m("[title=\'bar\']").attrs.title === "bar"})
test(function() {return m("[title=\"bar\"]").attrs.title === "bar"})
test(function() {return m("div", "test").children === "test"})
test(function() {return m("div", ["test"]).children[0] === "test"})
test(function() {return m("div", {title: "bar"}, "test").attrs.title === "bar"})
test(function() {return m("div", {title: "bar"}, "test").children === "test"})
test(function() {return m("div", {title: "bar"}, ["test"]).children[0] === "test"})
test(function() {return m("div", {title: "bar"}, m("div")).children.tag === "div"})
test(function() {return m("div", {title: "bar"}, [m("div")]).children[0].tag === "div"})
test(function() {return m("div", ["a", "b"]).children.length === 2})
test(function() {return m("div", [m("div")]).children[0].tag === "div"})
test(function() {return m("div", m("div")).attrs.tag === "div"}) //yes, this is expected behavior: see method signature
//m.module
for (var i = 0; i < 2; i++) {
//first iteration tests immediate rendering
//second iteration tests deferred rendering
test(function() {
var root = mock.document.createElement("div")
m.module(root, {
controller: function() {this.value = "test"},
view: function(ctrl) {return ctrl.value}
})
return root.childNodes[0].nodeValue === "test"
})
}
//m.withAttr
test(function() {
var value
var handler = m.withAttr("test", function(data) {value = data})
handler({currentTarget: {test: "foo"}})
return value === "foo"
})
//m.trust
test(function() {return m.trust("test").valueOf() === "test"})
//m.render
test(function() {
var root = mock.document.createElement("div")
m.render(root, "test")
return root.childNodes[0].nodeValue === "test"
})
test(function() {
var root = mock.document.createElement("div")
m.render(root, m("div", {id: "a"}))
var elementBefore = root.childNodes[0]
m.render(root, m("div", {id: "b"}))
var elementAfter = root.childNodes[0]
return elementBefore === elementAfter
})
test(function() {
var root = mock.document.createElement("div")
m.render(root, m("#a"))
var elementBefore = root.childNodes[0]
m.render(root, m("#b"))
var elementAfter = root.childNodes[0]
return elementBefore === elementAfter
})
test(function() {
var root = mock.document.createElement("div")
m.render(root, m("div", {id: "a"}))
var elementBefore = root.childNodes[0]
m.render(root, m("div", {title: "b"}))
var elementAfter = root.childNodes[0]
return elementBefore !== elementAfter
})
test(function() {
var root = mock.document.createElement("div")
m.render(root, m("#a"))
var elementBefore = root.childNodes[0]
m.render(root, m("[title=b]"))
var elementAfter = root.childNodes[0]
return elementBefore !== elementAfter
})
test(function() {
var root = mock.document.createElement("div")
m.render(root, m("#a"))
var elementBefore = root.childNodes[0]
m.render(root, "test")
var elementAfter = root.childNodes[0]
return elementBefore !== elementAfter
})
//m.redraw
test(function() {
var controller
var root = mock.document.createElement("div")
m.module(root, {
controller: function() {controller = this},
view: function(ctrl) {return ctrl.value}
})
controller.value = "foo"
m.redraw()
return root.childNodes[0].nodeValue === "foo"
})
//m.route
test(function() {
var root = mock.document.createElement("div")
m.route.mode = "search"
m.route(root, "/test1", {
"/test1": {controller: function() {}, view: function() {return "foo"}}
})
return mock.location.search == "?/test1" && root.childNodes[0].nodeValue === "foo"
})
test(function() {
var root = mock.document.createElement("div")
m.route.mode = "pathname"
m.route(root, "/test2", {
"/test2": {controller: function() {}, view: function() {return "foo"}}
})
return mock.location.pathname == "/test2" && root.childNodes[0].nodeValue === "foo"
})
test(function() {
var root = mock.document.createElement("div")
m.route.mode = "hash"
m.route(root, "/test3", {
"/test3": {controller: function() {}, view: function() {return "foo"}}
})
return mock.location.hash == "#/test3" && root.childNodes[0].nodeValue === "foo"
})
test(function() {
var root = mock.document.createElement("div")
m.route.mode = "search"
m.route(root, "/test4/foo", {
"/test4/:test": {controller: function() {}, view: function() {return m.route.param("test")}}
})
return mock.location.search == "?/test4/foo" && root.childNodes[0].nodeValue === "foo"
})
//m.prop
test(function() {
var prop = m.prop("test")
return prop() === "test"
})
test(function() {
var prop = m.prop("test")
prop("foo")
return prop() == "foo"
})
//m.request
test(function() {
var prop = m.request({method: "GET", url: "test"})
var e = mock.XMLHttpRequest.$events.pop()
e.target.onload(e)
return prop().method === "GET" && prop().url === "test"
})
test(function() {
var prop = m.request({method: "GET", url: "test"}).then(function(value) {return "foo"})
var e = mock.XMLHttpRequest.$events.pop()
e.target.onload(e)
return prop() === "foo"
})
//m.deferred
test(function() {
var value
var deferred = m.deferred()
deferred.promise.then(function(data) {value = data})
deferred.resolve("test")
return value === "test"
})
test(function() {
var value
var deferred = m.deferred()
deferred.promise.then(function(value) {return "foo"}).then(function(data) {value = data})
deferred.resolve("test")
return value === "foo"
})
test(function() {
var value
var deferred = m.deferred()
deferred.promise.then(null, function(data) {value = data})
deferred.reject("test")
return value === "test"
})
test(function() {
var value
var deferred = m.deferred()
deferred.promise.then(null, function(value) {return "foo"}).then(null, function(data) {value = data})
deferred.reject("test")
return value === "foo"
})
//m.sync
test(function() {
var value
var deferred1 = m.deferred()
var deferred2 = m.deferred()
m.sync([deferred1.promise, deferred2.promise]).then(function(data) {value = data})
deferred1.resolve("test")
deferred2.resolve("foo")
return value[0] === "test" && value[1] === "foo"
})
//m.startComputation/m.endComputation
test(function() {
var controller
var root = mock.document.createElement("div")
m.module(root, {
controller: function() {controller = this},
view: function(ctrl) {return ctrl.value}
})
m.startComputation()
controller.value = "foo"
m.endComputation()
return root.childNodes[0].nodeValue === "foo"
})
}
//mocks
testMithril(mock.window)
test.print(console.log)

8
archive/v0.1/mithril.min.js vendored Normal file

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

Binary file not shown.

4
archive/v0.1/pages.json Normal file
View file

@ -0,0 +1,4 @@
[
{"title": "Getting Started", "url": "getting-started.html"},
{"title": "Documentation", "url": "mithril.html"}
]

86
archive/v0.1/style.css Normal file
View file

@ -0,0 +1,86 @@
.container {margin:auto;max-width:1000px;padding:0 20px;position:relative;}
.container:after,.row:after {content:"";display:table;clear:both;}
.container,.row,[class*='col('] {-moz-box-sizing:border-box;-webkit-box-sizing:border-box;box-sizing:border-box;}
[class*='col('] {float:left;}
[class*='(3,'] {width:25%;}
[class*='(4,'] {width:33.33333%;}
[class*='(6,'] {width:50%;}
[class*='(8,'] {width:66.66667%;}
[class*='(9,'] {width:75%;}
@media (max-width:1000px) {
[class*=',3,'] {width:25%;}
[class*=',4,'] {width:33.33333%;}
[class*=',6,'] {width:50%;}
[class*=',8,'] {width:66.66667%;}
[class*=',9,'] {width:75%;}
}
@media (max-width:750px) {
[class*=',6)'] {width:50%;}
[class*=',12)'] {width:100%;}
}
html {background:#999;color:#222;font:14px Helvetica;}
html,body {margin:0;padding:0;}
header,footer {background:#999;}
nav {text-align:right;}
nav a:first-child,nav a:first-child:visited {color:#fff;font-size:27px;float:left;line-height:1.3em;padding:0;text-decoration:none;}
nav a {color:#fff;display:inline-block;padding:10px;}
nav a:visited {color:#ddd;}
footer {text-align:center;padding:10px 0;}
footer,footer a,footer a:visited {color:#fff;}
h1,h2 {font-family:Palatino;margin:0 0 10px;}
h1 {font-size:3em;text-shadow:0.01em 0.01em #777, -0.01em -0.01em #fff;}
h1 span {animation:logo 2s;display:inline-block;}
h2 {color:#888;font-style:italic;}
h3 {margin:10px 0;}
p {margin:15px 0;}
ul {margin:15px 0;padding:0 0 0 1em;}
li {margin:0 0 10px;}
a {color:#161;}
a:visited {color:#383;}
a:hover {text-decoration:none;}
pre {background:#ffe;border:1px solid #ddd;overflow:auto;margin:0 0 15px;padding:5px 10px;white-space:pre;-webkit-overflow-scrolling:touch;}
pre[class*="language-"],code {background:#ffe;font:12px/15px Lucida Console,Monaco,monospace;}
hr {border-top:1px solid #ccc;border-width:1px 0 0;margin:20px 0;}
table {margin:0 0 10px;width:100%;}
.cta {padding:30px 0 20px;text-align:center;}
.cta {
background:
linear-gradient(27deg, #e5e5e5 5px, rgba(255,255,255,0) 5px) 0 5px,
linear-gradient(207deg, #e5e5e5 5px, rgba(255,255,255,0) 5px) 10px 0px,
linear-gradient(27deg, #f2f2f2 5px, rgba(255,255,255,0) 5px) 0px 10px,
linear-gradient(207deg, #f2f2f2 5px, rgba(255,255,255,0) 5px) 10px 5px,
linear-gradient(90deg, #ebebeb 10px, rgba(255,255,255,0) 10px),
linear-gradient(#ededed 25%, #eaeaea 25%, #eaeaea 50%, rgba(255,255,255,0) 50%, rgba(255,255,255,0) 75%, #f4f4f4 75%, #f4f4f4);
background-color: #e3e3e3;
background-size: 20px 20px;
}
.logo {color:#d3d3d3;font-family:Georgia;font-style:italic;}
.logo :before {content:"\25CB";position:absolute;margin:-0.17em 0 0 -0.10em;}
.logo :after {content:"\25CB";position:absolute;margin:-0.17em 0 0 -0.5em;}
.button,.button:visited {background:#5a5;border-radius:5px;box-shadow:1px 1px #777, -1px -1px #fff;color:#fff;display:inline-block;font:normal bold 16px Helvetica;margin:0 10px 10px;padding:10px 30px;text-decoration:none;}
.features {background:#fff;padding:30px 0 0;}
.feature {margin:0 0 30px;padding:0 20px 0 0;}
.sample {background:#f5f5f5;padding:30px 0 10px;}
.example {background:#ffe;border:1px solid #ddd;display:block;font:Courier New;margin-bottom:20px;padding:5px 10px;}
.example span {color:#383;font-weight:bold;}
.example small {color:#888;font-size:1em;}
.more {background:#ddd;padding:30px 0;}
.output a,.more a {display:block;margin:0 0 10px;}
.output a:after,.more a:after {content:" \bb";}
.performance {background:#fff;padding:30px 0;}
.performance td:first-child {text-align:right;width:1%;}
.bar {background:red;height:4px;float:left;margin:0.5em 1em 0 0;}
.security {background:#f5f5f5;padding:30px 0;}
.success {color:#383;}
.error {color:#f00;}
.content {background:#f5f5f5;padding:30px 0;}
@media (min-width:750px) {
.sample pre {margin-right:20px;}
}
@keyframes logo {
from {opacity:0;transform:scale(2) rotate(359deg);}
to {opacity:1;transform:scale(1) rotate(0deg);}
}

View file

@ -0,0 +1,64 @@
/*
Compiles Mithril templates
Requires sweet.js (https://github.com/mozilla/sweet.js)
Installation: npm install -g sweet.js
Usage: sjs --module /mithril.compile.sjs --output <output-filename>.js <input-filename>.js
*/
macro m {
case { _ ($selector) } => {
return #{m($selector, {}, [])};
}
case { _ ($selector, $partial) } => {
var partialSyntax = #{$partial};
var partial = unwrapSyntax(partialSyntax);
return partial.value == "{}" ? #{m($selector, $partial, [])} : #{m($selector, {}, partial)};
}
case { _ ($selector, $dynAttrs, $children) } => {
var selectorSyntax = #{$selector};
var selector = unwrapSyntax(selectorSyntax);
var dynAttrsSyntax = #{$dynAttrs};
var dynAttrs = unwrapSyntax(dynAttrsSyntax);
var parser = /(?:(^|#|\.)([^#\.\[\]]+))|(\[.+?\])/g;
var attrParser = /\[(.+?)=("|'|)(.+?)\2\]/;
var _match = null;
var classes = [];
var cell = {tag: "div", attrs: {}, children: []};
while (_match = parser.exec(selector)) {
if (_match[1] == "") cell.tag = _match[2];
else if (_match[1] == "#") cell.attrs.id = _match[2];
else if (_match[1] == ".") classes.push(_match[2]);
else if (_match[3][0] == "[") {
var pair = attrParser.exec(_match[3]);
cell.attrs[pair[1]] = pair[3];
}
}
if (classes.length > 0) cell.attrs["class"] = classes.join(" ");
var tag = makeValue(cell.tag, #{here});
var attrsBody = Object.keys(cell.attrs).reduce(function(memo, attrName) {
return memo.concat([
makeValue(attrName, #{here}),
makePunc(":", #{here}),
makeValue(cell.attrs[attrName], #{here}),
makePunc(",", #{here})
]);
}, []).concat(dynAttrs.inner);
var attrs = [makeDelim("{}", attrsBody, #{here})];
var children = cell.children.map(function(child) {
return makeValue(child, #{here});
})
letstx $tag = [tag], $attrs = attrs;
return #{ ({tag: $tag, attrs: $attrs , children: $children}) };
}
case { _ } => {
return #{Mithril};
}
}
export m;

View file

@ -0,0 +1,9 @@
<p>If you already have your HTML written and want to convert it into a Mithril template, paste the HTML below and press the "Convert" button.</p>
<div id="converter"></div>
<script src="../mithril.min.js"></script>
<script src="template-converter.js"></script>
<script>
m.module(document.getElementById("converter"), templateConverter);
</script>

View file

@ -0,0 +1,89 @@
var templateConverter = {};
templateConverter.DOMFragment = function(markup) {
if (markup.indexOf("<!doctype") > -1) return [new DOMParser().parseFromString(markup, "text/html").childNodes[1]]
var container = document.createElement("div");
container.insertAdjacentHTML("beforeend", markup);
return container.childNodes;
}
templateConverter.VirtualFragment = function recurse(domFragment) {
var virtualFragment = [];
for (var i = 0, el; el = domFragment[i]; i++) {
if (el.nodeType == 3) {
virtualFragment.push(el.nodeValue);
}
else {
var attrs = {};
for (var j = 0, attr; attr = el.attributes[j]; j++) {
attrs[attr.name] = attr.value;
}
virtualFragment.push({tag: el.tagName.toLowerCase(), attrs: attrs, children: recurse(el.childNodes)});
}
}
return virtualFragment;
}
templateConverter.Template = function recurse() {
if (Object.prototype.toString.call(arguments[0]) == "[object String]") {
return new recurse(new templateConverter.VirtualFragment(new templateConverter.DOMFragment(arguments[0])));
}
var virtualFragment = arguments[0], level = arguments[1]
if (!level) level = 1;
var tab = "\n" + new Array(level + 1).join("\t");
var virtuals = [];
for (var i = 0, el; el = virtualFragment[i]; i++) {
if (typeof el == "string") {
if (el.match(/\t| {2,}/g) && el.trim().length == 0) virtuals.indented = true;
else virtuals.push('"' + el.replace(/"/g, '\\"').replace(/\r/g, "\\r").replace(/\n/g, "\\n") + '"');
}
else {
var virtual = "";
if (el.tag != "div") virtual += el.tag;
if (el.attrs["class"]) {
virtual += "." + el.attrs["class"].replace(/\t+/g, " ").split(" ").join(".");
delete el.attrs["class"];
}
var attrNames = Object.keys(el.attrs).sort()
for (var j = 0, attrName; attrName = attrNames[j]; j++) {
if (attrName != "style") virtual += "[" + attrName + "='" + el.attrs[attrName].replace(/'/g, "\\'") + "']";
}
virtual = '"' + virtual + '"';
var style = ""
if (el.attrs.style) {
virtual += ", {style: " + ("{\"" + el.attrs.style.replace(/:/g, "\": \"").replace(/;/g, "\", \"") + "}").replace(/, "}|"}/, "}") + "}"
}
if (el.children.length > 0) {
virtual += ", " + recurse(el.children, level + 1);
}
virtual = "m(" + virtual + ")";
virtuals.push(virtual);
}
}
if (!virtuals.indented) tab = "";
var isInline = virtuals.length == 1 && virtuals[0].charAt(0) == '"';
var template = isInline ? virtuals.join(", ") : "[" + tab + virtuals.join("," + tab) + tab.slice(0, -1) + "]";
return new String(template);
}
templateConverter.controller = function() {
this.source = m.prop("");
this.output = m.prop("");
this.convert = function() {
return this.output(new templateConverter.Template(this.source()));
};
};
templateConverter.view = function(ctrl) {
return [
m("textarea", {autofocus: true, style: {width:"100%", height: "40%"}, onchange: m.withAttr("value", ctrl.source)}, ctrl.source()),
m("button", {onclick: ctrl.convert.bind(ctrl)}, "Convert"),
m("textarea", {style: {width:"100%", height: "40%"}}, ctrl.output())
];
};