Do some local style modifications and profile.

1. Do some temporary style modifications to help make the code more readable
   for profiling (with help from ESLint).
2. Profile the code, and optimize accordingly.
This commit is contained in:
impinball 2015-07-09 16:14:08 -04:00
parent 83a30a4d3c
commit 9ae592ee4d
12 changed files with 4426 additions and 2695 deletions

5
.eslintignore Normal file
View file

@ -0,0 +1,5 @@
node_modules
**/*.min.js
docs/layout/lib/**/*.js
tests/e2e/libs/**
mithril.closure-compiler-externs.js

27
.eslintrc Normal file
View file

@ -0,0 +1,27 @@
{
"env": {
"browser": true
},
"rules": {
"no-cond-assign": [2, "except-parens"],
"no-shadow": 0,
"semi-spacing": 0,
"quotes": [2, "double", "avoid-escape"],
"curly": [2, "multi-line"],
"semi": [2, "never"],
"eqeqeq": [2, "allow-null"],
"no-throw-literal": 2,
"wrap-iife": 2,
"strict": [2, "function"],
"brace-style": [2, "1tbs", { "allowSingleLine": true }],
"linebreak-style": [1, "windows"],
"one-var": [2, {
"initialized": "never"
}],
"new-cap": 0,
"no-use-before-define": [2, "nofunc"],
"max-len": [2, 80, 4],
"dot-notation": 2,
"indent": [2, "tab"]
}
}

View file

@ -1,14 +1,15 @@
/* eslint-env node */
module.exports = function(grunt) {
_ = require('lodash');
"use strict"
var version = "0.2.0";
var _ = require("lodash")
var version = "0.4.0"
var inputFolder = "./docs";
var tempFolder = "./temp";
var archiveFolder = "./archive";
var outputFolder = "../mithril";
var inputFolder = "./docs"
var tempFolder = "./temp"
var archiveFolder = "./archive"
var outputFolder = "../mithril"
var guideLayout = "guide";
var guide = [
"auto-redrawing",
"benchmarks",
@ -24,8 +25,7 @@ module.exports = function(grunt) {
"routing",
"tools",
"web-services"
];
var apiLayout = "api";
]
var api = [
"change-log",
"roadmap",
@ -45,55 +45,68 @@ module.exports = function(grunt) {
"mithril.trust",
"mithril.withAttr",
"mithril.xhr"
];
]
var md2htmlTasks = {};
var md2htmlTasks = {}
var makeTasks = function(layout, pages) {
pages.map(function(name) {
var src = inputFolder + "/" + name + ".md";
var title = (grunt.file.exists(src)) ? grunt.file.read(src).split(/\n/)[0].substring(3) + ' - ' : '';
var src = inputFolder + "/" + name + ".md"
var title
if (grunt.file.exist(src)) {
title = grunt.file.read(src)
.split(/\n/)[0]
.substring(3) + " - "
} else {
title = ""
}
md2htmlTasks[name] = {
options: {layout: inputFolder + "/layout/" + layout + ".html", templateData: { "topic": title }},
options: {
layout: inputFolder + "/layout/" + layout + ".html",
templateData: { "topic": title }
},
files: [{src: [src], dest: tempFolder + "/" + name + ".html"}]
}
})
};
makeTasks("guide", guide);
makeTasks("api", api);
}
makeTasks("guide", guide)
makeTasks("api", api)
var sauceBrowsers =[
{ browserName: 'firefox', version: '19', platform: 'XP' },
var sauceBrowsers = [
{ browserName: "firefox", version: "19", platform: "XP" },
{ browserName: "internet explorer", platform: "XP", version: "6"},
{ browserName: "safari", platform: "OS X 10.9", version: "7"},
{ browserName: "iPad", platform: "OS X 10.9", version: "7.1"},
{ browserName: "opera", platform: "Linux", version: "12"},
{ browserName: "chrome", platform: "XP", version: "26"},
{ browserName: "chrome", platform: "Windows 8", version: "26"}
];
]
var sauceOnTestComplete = function(result, callback) {
var request = require('request');
var request = require("request")
var user = process.env.SAUCE_USERNAME;
var pass = process.env.SAUCE_ACCESS_KEY;
var user = process.env.SAUCE_USERNAME
var pass = process.env.SAUCE_ACCESS_KEY
request.put({
url: ['https://saucelabs.com/rest/v1', user, 'jobs', result.job_id].join('/'),
url: [
"https://saucelabs.com/rest/v1",
user,
"jobs",
result.job_id
].join("/"),
auth: { user: user, pass: pass },
json: { passed: result.passed }
}, function (error, response, body) {
}, function (error, response) {
if (error) {
callback(error);
callback(error)
} else if (response.statusCode !== 200) {
callback(new Error('Unexpected response status: '
+ response.statusCode + "\n "));
callback(new Error("Unexpected response status: "
+ response.statusCode + "\n "))
} else {
callback(null, result.passed);
callback(null, result.passed)
}
});
};
})
}
var sauceBaseOptions = {
username: process.env.SAUCE_USERNAME,
@ -102,74 +115,164 @@ module.exports = function(grunt) {
browsers: sauceBrowsers,
sauceConfig: {
"record-video": false,
"record-screenshots": false,
"record-screenshots": false
},
build: process.env.TRAVIS_JOB_ID,
onTestComplete: sauceOnTestComplete,
tunnelTimeout: 5,
};
tunnelTimeout: 5
}
var sauceCustomOptions = {
testname: "Mithril Custom Tests "+ new Date().toJSON(),
urls: ["http://127.0.0.1:8000/tests/index.html"],
};
_.assign(sauceCustomOptions, sauceBaseOptions);
testname: "Mithril Custom Tests " + new Date().toJSON(),
urls: ["http://127.0.0.1:8000/tests/index.html"]
}
_.assign(sauceCustomOptions, sauceBaseOptions)
var sauceQunitOptions = {
testname: "qUnit Tests "+ new Date().toJSON(),
urls: ["http://127.0.0.1:8000/tests/e2e/test.html"],
};
_.assign(sauceQunitOptions, sauceBaseOptions);
testname: "qUnit Tests " + new Date().toJSON(),
urls: ["http://127.0.0.1:8000/tests/e2e/test.html"]
}
_.assign(sauceQunitOptions, sauceBaseOptions)
var currentVersionArchiveFolder = archiveFolder + "/v" + version;
var currentVersionArchiveFolder = archiveFolder + "/v" + version
grunt.initConfig({
md2html: md2htmlTasks,
uglify: {
options: {banner: "/*\nMithril v" + version + "\nhttp://github.com/lhorie/mithril.js\n(c) Leo Horie\nLicense: MIT\n*/", sourceMap: true},
options: {
banner: [[
"/*",
"Mithril v" + version,
"http://github.com/lhorie/mithril.js",
"(c) Leo Horie",
"License: MIT",
"*/"
].join("\n")],
sourceMap: true
},
mithril: {src: "mithril.js", dest: "mithril.min.js"}
},
concat: {
test: {src: ["mithril.js", "./tests/test.js", "./tests/mock.js", "./tests/mithril-tests.js"], dest: currentVersionArchiveFolder + "/mithril-tests.js"}
test: {
src: [
"mithril.js",
"./tests/test.js",
"./tests/mock.js",
"./tests/mithril-tests.js"
],
dest: currentVersionArchiveFolder + "/mithril-tests.js"
}
},
zip: {
distribution: {
cwd: currentVersionArchiveFolder + "/",
src: [currentVersionArchiveFolder + "/mithril.min.js", currentVersionArchiveFolder + "/mithril.min.js.map", currentVersionArchiveFolder + "/mithril.js"],
src: [
currentVersionArchiveFolder + "/mithril.min.js",
currentVersionArchiveFolder + "/mithril.min.js.map",
currentVersionArchiveFolder + "/mithril.js"
],
dest: currentVersionArchiveFolder + "/mithril.min.zip"
}
},
replace: {
options: {force: true, patterns: [{match: /\.md/g, replacement: ".html"}, {match: /\$version/g, replacement: version}]},
links: {expand: true, flatten: true, src: [tempFolder + "/**/*.html"], dest: currentVersionArchiveFolder + "/"},
index: {src: inputFolder + "/layout/index.html", dest: currentVersionArchiveFolder + "/index.html"},
commonjs: {expand: true, flatten: true, src: [inputFolder + "/layout/*.json"], dest: currentVersionArchiveFolder},
cdnjs: {src: "deploy/cdnjs-package.json", dest: "../cdnjs/ajax/libs/mithril/package.json"}
options: {
force: true,
patterns: [
{match: /\.md/g, replacement: ".html"},
{match: /\$version/g, replacement: version}
]
},
links: {
expand: true,
flatten: true,
src: [tempFolder + "/**/*.html"],
dest: currentVersionArchiveFolder + "/"
},
index: {
src: inputFolder + "/layout/index.html",
dest: currentVersionArchiveFolder + "/index.html"
},
commonjs: {
expand: true,
flatten: true,
src: [inputFolder + "/layout/*.json"],
dest: currentVersionArchiveFolder
},
cdnjs: {
src: "deploy/cdnjs-package.json",
dest: "../cdnjs/ajax/libs/mithril/package.json"
}
},
copy: {
style: {src: inputFolder + "/layout/style.css", dest: currentVersionArchiveFolder + "/style.css"},
pages: {src: inputFolder + "/layout/pages.json", dest: currentVersionArchiveFolder + "/pages.json"},
lib: {expand: true, cwd: inputFolder + "/layout/lib/", src: "./**", dest: currentVersionArchiveFolder + "/lib/"},
tools: {expand: true, cwd: inputFolder + "/layout/tools/", src: "./**", dest: currentVersionArchiveFolder + "/tools/"},
comparisons: {expand: true, cwd: inputFolder + "/layout/comparisons/", src: "./**", dest: currentVersionArchiveFolder + "/comparisons/"},
unminified: {src: "mithril.js", dest: currentVersionArchiveFolder + "/mithril.js"},
minified: {src: "mithril.min.js", dest: currentVersionArchiveFolder + "/mithril.min.js"},
readme: {src: "README.md", dest: currentVersionArchiveFolder + "/README.md"},
map: {src: "mithril.min.js.map", dest: currentVersionArchiveFolder + "/mithril.min.js.map"},
typescript: {src: "mithril.d.ts", dest: currentVersionArchiveFolder + "/mithril.d.ts"},
publish: {expand: true, cwd: currentVersionArchiveFolder, src: "./**", dest: outputFolder},
archive: {expand: true, cwd: currentVersionArchiveFolder, src: "./**", dest: outputFolder + "/archive/v" + version},
style: {
src: inputFolder + "/layout/style.css",
dest: currentVersionArchiveFolder + "/style.css"
},
pages: {
src: inputFolder + "/layout/pages.json",
dest: currentVersionArchiveFolder + "/pages.json"
},
lib: {
expand: true,
cwd: inputFolder + "/layout/lib/",
src: "./**",
dest: currentVersionArchiveFolder + "/lib/"
},
tools: {
expand: true,
cwd: inputFolder + "/layout/tools/",
src: "./**",
dest: currentVersionArchiveFolder + "/tools/"
},
comparisons: {
expand: true,
cwd: inputFolder + "/layout/comparisons/",
src: "./**",
dest: currentVersionArchiveFolder + "/comparisons/"
},
unminified: {
src: "mithril.js",
dest: currentVersionArchiveFolder + "/mithril.js"
},
minified: {
src: "mithril.min.js",
dest: currentVersionArchiveFolder + "/mithril.min.js"
},
readme: {
src: "README.md",
dest: currentVersionArchiveFolder + "/README.md"
},
map: {
src: "mithril.min.js.map",
dest: currentVersionArchiveFolder + "/mithril.min.js.map"
},
typescript: {
src: "mithril.d.ts",
dest: currentVersionArchiveFolder + "/mithril.d.ts"
},
publish: {
expand: true,
cwd: currentVersionArchiveFolder,
src: "./**",
dest: outputFolder
},
archive: {
expand: true,
cwd: currentVersionArchiveFolder,
src: "./**",
dest: outputFolder + "/archive/v" + version
}
},
execute: {
tests: {src: [currentVersionArchiveFolder + "/mithril-tests.js"]}
},
qunit: {
all: ['tests/e2e/**/*.html']
all: ["tests/e2e/**/*.html"]
},
"saucelabs-custom": {
all:{
all: {
options: sauceCustomOptions
}
},
"saucelabs-qunit": {
all:{
all: {
options: sauceQunitOptions
}
},
@ -179,7 +282,7 @@ module.exports = function(grunt) {
server: {
options: {
port: 8888,
base: '.'
base: "."
}
}
},
@ -191,34 +294,45 @@ module.exports = function(grunt) {
default: {
files: [{
expand: true,
src: ['mithril.js'],
cwd: '.',
dest: '.'
src: ["mithril.js"],
cwd: ".",
dest: "."
}]
}
},
eslint: {
target: [
"**/*.js",
"!node_modules/**",
"!**/*.min.js",
"!docs/layout/lib/**/*.js"
]
}
});
})
grunt.loadNpmTasks("grunt-contrib-clean");
grunt.loadNpmTasks('grunt-contrib-concat');
grunt.loadNpmTasks("grunt-contrib-copy");
grunt.loadNpmTasks("grunt-contrib-uglify");
grunt.loadNpmTasks('grunt-execute');
grunt.loadNpmTasks("grunt-md2html");
grunt.loadNpmTasks("grunt-replace");
grunt.loadNpmTasks('grunt-zip');
grunt.loadNpmTasks('grunt-contrib-qunit');
grunt.loadNpmTasks('grunt-contrib-connect');
grunt.loadNpmTasks('grunt-saucelabs');
grunt.loadNpmTasks('grunt-jsfmt');
grunt.loadNpmTasks("grunt-contrib-clean")
grunt.loadNpmTasks("grunt-contrib-concat")
grunt.loadNpmTasks("grunt-contrib-copy")
grunt.loadNpmTasks("grunt-contrib-uglify")
grunt.loadNpmTasks("grunt-execute")
grunt.loadNpmTasks("grunt-md2html")
grunt.loadNpmTasks("grunt-replace")
grunt.loadNpmTasks("grunt-zip")
grunt.loadNpmTasks("grunt-contrib-qunit")
grunt.loadNpmTasks("grunt-contrib-connect")
grunt.loadNpmTasks("grunt-saucelabs")
grunt.loadNpmTasks("grunt-jsfmt")
grunt.loadNpmTasks("grunt-eslint")
grunt.registerTask("build", ["test", "uglify", "zip", "md2html", "replace", "copy", "clean"]);
grunt.registerTask("testall", ["test", "teste2e"]);
grunt.registerTask("test", ["concat", "execute"]);
grunt.registerTask('teste2e', ['connect', 'qunit']);
grunt.registerTask("default", ["build"]);
grunt.registerTask("build", [
"test", "uglify", "zip", "md2html", "replace", "copy", "clean"])
grunt.registerTask("testall", ["test", "teste2e"])
grunt.registerTask("test", ["eslint", "concat", "execute"])
grunt.registerTask("teste2e", ["connect", "qunit"])
grunt.registerTask("default", ["build"])
grunt.registerTask("sauce-qunit", ["connect", "saucelabs-qunit"]);
grunt.registerTask("sauce-custom", ["connect", "saucelabs-custom"]);
grunt.registerTask("sauce-all", ["connect", "saucelabs-qunit", "saucelabs-custom"]);
};
grunt.registerTask("sauce-qunit", ["connect", "saucelabs-qunit"])
grunt.registerTask("sauce-custom", ["connect", "saucelabs-custom"])
grunt.registerTask("sauce-all", [
"connect", "saucelabs-qunit", "saucelabs-custom"])
}

View file

@ -1,3 +1,5 @@
**Note: This is a WIP partial rewrite of Mithril.**
[![JS.ORG](https://img.shields.io/badge/js.org-mithril-ffb400.svg?style=flat-square)](http://js.org)
[![Join the chat at https://gitter.im/lhorie/mithril.js](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/lhorie/mithril.js?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
[![Build Status](https://travis-ci.org/lhorie/mithril.js.svg?branch=master)](https://travis-ci.org/lhorie/mithril.js)

View file

@ -1,90 +1,128 @@
var templateConverter = {};
/* globals m */
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;
"use strict"
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 if (el.nodeType == 1) {
var attrs = {};
for (var j = 0, attr; attr = el.attributes[j]; j++) {
attrs[attr.name] = attr.value;
"use strict"
var virtualFragment = []
for (var i = 0; i < domFragment.length; i++) {
var el = domFragment[i]
if (el.nodeType === 3) {
virtualFragment.push(el.nodeValue)
} else if (el.nodeType === 1) {
var attrs = {}
for (var j = 0; el.attributes.length; j++) {
var attr = el.attributes[j]
attrs[attr.name] = attr.value
}
virtualFragment.push({tag: el.nodeName.toLowerCase(), attrs: attrs, children: recurse(el.childNodes)});
virtualFragment.push({
tag: el.nodeName.toLowerCase(),
attrs: attrs,
children: recurse(el.childNodes)
})
}
}
return virtualFragment;
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])));
"use strict"
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 virtualFragment = arguments[0]
var level = arguments[1]
if (!level) level = 1
var tab = "\n" + new Array(level + 1).join("\t")
var virtuals = []
for (var i = 0; i < virtualFragment.length; i++) {
var el = virtualFragment[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, "\\'") + "']";
for (var j = 0; j < attrNames.length; j++) {
var attrName = attrNames[j]
if (attrName !== "style") {
virtual += "[" + attrName + "='" +
el.attrs[attrName].replace(/'/g, "\\'") + "']"
}
}
if (virtual == "") virtual = "div"
virtual = '"' + virtual + '"';
var style = ""
if (virtual === "") virtual = "div"
virtual = '"' + virtual + '"'
if (el.attrs.style) {
virtual += ", {style: " + ("{\"" + el.attrs.style.replace(/:/g, "\": \"").replace(/;/g, "\", \"") + "}").replace(/, "}|"}/, "}") + "}"
virtual += ", {style: " + ("{\"" + el.attrs.style
.replace(/:/g, "\": \"")
.replace(/;/g, "\", \"") + "}")
.replace(/, "}|"}/, "}") + "}"
}
if (el.children.length > 0) {
virtual += ", " + recurse(el.children, level + 1);
virtual += ", " + recurse(el.children, level + 1)
}
virtual = "m(" + virtual + ")";
virtuals.push(virtual);
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);
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) // eslint-disable-line no-new-wrappers
}
templateConverter.controller = function() {
this.source = m.prop("");
this.output = m.prop("");
"use strict"
this.source = m.prop("")
this.output = m.prop("")
this.convert = function() {
return this.output(new templateConverter.Template(this.source()));
};
};
return this.output(new templateConverter.Template(this.source()))
}
}
templateConverter.view = function(ctrl) {
"use strict"
return m("div", [
m("textarea", {autofocus: true, style: {width:"100%", height: "40%"}, onchange: m.withAttr("value", ctrl.source)}, ctrl.source()),
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())
]);
};
m("textarea", {style: {width: "100%", height: "40%"}}, ctrl.output())
])
}

2626
mithril.js

File diff suppressed because it is too large Load diff

View file

@ -1,46 +1,55 @@
{
"name": "mithril",
"description": "Mithril.js beta build - use this to help us test the releases before they are released",
"version": "0.1.34-beta.0",
"repository": {
"type": "git",
"url": "git@github.com:lhorie/mithril.js.git"
},
"scripts": {
"test": "grunt test"
},
"main": "mithril.js",
"devDependencies": {
"grunt": "*",
"grunt-cli": "*",
"grunt-contrib-copy": "*",
"grunt-contrib-uglify": "*",
"grunt-contrib-clean": "*",
"grunt-contrib-concat": "*",
"grunt-execute": "*",
"grunt-md2html": "*",
"grunt-replace": "*",
"grunt-contrib-qunit": "*",
"grunt-zip": "*",
"grunt-jsfmt": "git://github.com/ysimonson/grunt-jsfmt",
"grunt-contrib-connect": "~0.7.1",
"grunt-contrib-jshint": "~0.10.0",
"grunt-contrib-watch": "~0.6.1",
"grunt-jscs": "^1.1.0",
"grunt-sauce-tunnel": "^0.2.1",
"load-grunt-config": "^0.9.2",
"merge": "^1.1.3",
"publish": "~0.3.2",
"grunt-saucelabs": "*",
"request": "~2.35.0",
"q": "~1.0.0",
"saucelabs": "~0.1.1",
"sauce-tunnel": "~2.0.6",
"colors": "~0.6.2",
"lodash": "~2.4.1"
},
"main": "mithril.js",
"licenses": [{"type": "MIT", "url": "http://opensource.org/licenses/MIT"}],
"files": ["mithril.min.js", "mithril.min.js.map", "mithril.js", "README.*"]
"name": "mithril",
"description": "Mithril.js beta build - use this to help us test the releases before they are released",
"version": "0.1.34-beta.0",
"repository": {
"type": "git",
"url": "git@github.com:lhorie/mithril.js.git"
},
"scripts": {
"test": "grunt test"
},
"main": "mithril.js",
"devDependencies": {
"colors": "~0.6.2",
"grunt": "*",
"grunt-cli": "*",
"grunt-contrib-clean": "*",
"grunt-contrib-concat": "*",
"grunt-contrib-connect": "~0.7.1",
"grunt-contrib-copy": "*",
"grunt-contrib-jshint": "~0.10.0",
"grunt-contrib-qunit": "*",
"grunt-contrib-uglify": "*",
"grunt-contrib-watch": "~0.6.1",
"grunt-eslint": "^16.0.0",
"grunt-execute": "*",
"grunt-jscs": "^1.1.0",
"grunt-jsfmt": "git://github.com/ysimonson/grunt-jsfmt",
"grunt-md2html": "*",
"grunt-replace": "*",
"grunt-sauce-tunnel": "^0.2.1",
"grunt-saucelabs": "*",
"grunt-zip": "*",
"load-grunt-config": "^0.9.2",
"lodash": "~2.4.1",
"merge": "^1.1.3",
"publish": "~0.3.2",
"q": "~1.0.0",
"request": "~2.35.0",
"sauce-tunnel": "~2.0.6",
"saucelabs": "~0.1.1"
},
"licenses": [
{
"type": "MIT",
"url": "http://opensource.org/licenses/MIT"
}
],
"files": [
"mithril.min.js",
"mithril.min.js.map",
"mithril.js",
"README.*"
]
}

23
tests/e2e/.eslintrc Normal file
View file

@ -0,0 +1,23 @@
{
"extend": "../../.eslintrc",
"globals": {
"asyncTest": false,
"deepEqual": false,
"equal": false,
"expect": false,
"module": false,
"notDeepEqual": false,
"notEqual": false,
"notPropEqual": false,
"notStrictEqual": false,
"ok": false,
"propEqual": false,
"QUnit": false,
"raises": false,
"start": false,
"stop": false,
"strictEqual": false,
"test": false,
"throws": false
}
}

View file

@ -1,8 +1,13 @@
//saucelabs reporting; see https://github.com/axemclion/grunt-saucelabs#test-result-details-with-qunit
/* eslint-disable camelcase */
/* global m, Syn */
// saucelabs reporting; see
// https://github.com/axemclion/grunt-saucelabs#test-result-details-with-qunit
var log = []
var testName
QUnit.done(function (test_results) {
"use strict"
var tests = []
for (var i = 0, len = log.length; i < len; i++) {
var details = log[i]
@ -19,6 +24,7 @@ QUnit.done(function (test_results) {
window.global_test_results = test_results
})
QUnit.testStart(function (testDetails) {
"use strict"
QUnit.log(function (details) {
if (!details.result) {
details.name = testDetails.name
@ -27,9 +33,11 @@ QUnit.testStart(function (testDetails) {
})
})
//qunit doesn't support Function.prototype.bind...
// qunit doesn't support Function.prototype.bind...
if (!Function.prototype.bind) {
/* eslint-disable */
Function.prototype.bind = function (oThis) {
"use strict"
if (typeof this !== "function") {
// closest thing possible to the ECMAScript 5
// internal IsCallable function
@ -51,165 +59,181 @@ if (!Function.prototype.bind) {
return fBound
}
/* eslint-enable */
}
//tests
var dummyEl = document.getElementById('dummy')
var dummyEl = document.getElementById("dummy")
test('Mithril accessible as window.m', function() {
test("Mithril accessible as window.m", function() {
"use strict"
expect(1)
ok(window.m)
})
test('m.trust w/ html entities', function() {
test("m.trust w/ html entities", function() {
"use strict"
expect(1)
var view1 = m('div', "a", m.trust("&amp;"), "b")
var view1 = m("div", "a", m.trust("&amp;"), "b")
m.render(dummyEl, view1)
equal(dummyEl.innerHTML, '<div>a&amp;b</div>', 'view1 rendered correctly')
equal(dummyEl.innerHTML, "<div>a&amp;b</div>", "view1 rendered correctly")
})
test('m.trust w/ html entities 2', function() {
test("m.trust w/ html entities 2", function() {
"use strict"
expect(1)
var view1 = m('div', "a", m.trust("&amp;"), "b", m.trust("&amp;"), "c")
var view1 = m("div", "a", m.trust("&amp;"), "b", m.trust("&amp;"), "c")
m.render(dummyEl, view1)
equal(dummyEl.innerHTML, '<div>a&amp;b&amp;c</div>', 'view1 rendered correctly')
equal(dummyEl.innerHTML, "<div>a&amp;b&amp;c</div>",
"view1 rendered correctly")
})
test('array item removal', function() {
test("array item removal", function() {
"use strict"
expect(2)
var view1 = m('div', {}, [
m('div', {}, '0'),
m('div', {}, '1'),
m('div', {}, '2')
var view1 = m("div", {}, [
m("div", {}, "0"),
m("div", {}, "1"),
m("div", {}, "2")
])
var view2= m('div', {}, [
m('div', {}, '0')
var view2 = m("div", {}, [
m("div", {}, "0")
])
m.render(dummyEl, view1)
equal(dummyEl.innerHTML, '<div><div>0</div><div>1</div><div>2</div></div>', 'view1 rendered correctly')
equal(dummyEl.innerHTML, "<div><div>0</div><div>1</div><div>2</div></div>",
"view1 rendered correctly")
m.render(dummyEl, view2)
equal(dummyEl.innerHTML, '<div><div>0</div></div>', 'view2 should be rendered correctly')
equal(dummyEl.innerHTML, "<div><div>0</div></div>",
"view2 should be rendered correctly")
})
test('issue99 regression', function() {
test("issue99 regression", function() {
"use strict"
// see https://github.com/lhorie/mithril.js/issues/99
expect(2)
var view1 = m('div', {}, [
m('div', {}, '0'),
m('div', {}, '1'),
m('div', {}, '2')
var view1 = m("div", {}, [
m("div", {}, "0"),
m("div", {}, "1"),
m("div", {}, "2")
])
var view2= m('div', {}, [
m('span', {}, '0')
var view2 = m("div", {}, [
m("span", {}, "0")
])
m.render(dummyEl, view1)
equal(dummyEl.innerHTML, '<div><div>0</div><div>1</div><div>2</div></div>', 'view1 rendered correctly')
equal(dummyEl.innerHTML, "<div><div>0</div><div>1</div><div>2</div></div>",
"view1 rendered correctly")
m.render(dummyEl, view2)
equal(dummyEl.innerHTML, '<div><span>0</span></div>', 'view2 should be rendered correctly')
equal(dummyEl.innerHTML, "<div><span>0</span></div>",
"view2 should be rendered correctly")
})
test('config handler context', function() {
test("config handler context", function() {
"use strict"
expect(3)
var view = m('div', {config: function(evt, isInitialized, context) {
var view = m("div", {config: function(evt, isInitialized, context) {
equal(context instanceof Object, true)
context.data = 1
}})
m.render(dummyEl, view)
var view = m('div', {config: function(evt, isInitialized, context) {
view = m("div", {config: function(evt, isInitialized, context) {
equal(context instanceof Object, true)
equal(context.data, 1)
}})
m.render(dummyEl, view)
})
test('node identity remove firstChild', function() {
test("node identity remove firstChild", function() {
"use strict"
expect(2)
var view1 = m('div', {}, [
m('div', {key:1}, 'E1'),
m('div', {key:2}, 'E2')
var view1 = m("div", {}, [
m("div", {key: 1}, "E1"),
m("div", {key: 2}, "E2")
])
m.render(dummyEl, view1)
var node2 = dummyEl.firstChild.lastChild
equal(node2.innerHTML, 'E2')
equal(node2.innerHTML, "E2")
var view2 = m('div', {}, [
m('div', {key:2}, 'E2')
var view2 = m("div", {}, [
m("div", {key: 2}, "E2")
])
m.render(dummyEl, view2)
equal(dummyEl.firstChild.firstChild, node2)
})
test('node identity change order', function() {
test("node identity change order", function() {
"use strict"
expect(2)
var view1 = m('div', {}, [
m('div', {key:1}, 'E1'),
m('div', {key:2}, 'E2'),
m('div', {key:3}, 'E3')
var view1 = m("div", {}, [
m("div", {key: 1}, "E1"),
m("div", {key: 2}, "E2"),
m("div", {key: 3}, "E3")
])
m.render(dummyEl, view1)
var e2 = dummyEl.firstChild.firstChild.nextSibling
equal(e2.innerHTML, 'E2')
equal(e2.innerHTML, "E2")
var view2 = m('div', {}, [
m('div', {key:2}, 'E2'),
m('div', {key:1}, 'E1'),
m('div', {key:3}, 'E3')
var view2 = m("div", {}, [
m("div", {key: 2}, "E2"),
m("div", {key: 1}, "E1"),
m("div", {key: 3}, "E3")
])
m.render(dummyEl, view2)
equal(dummyEl.firstChild.firstChild, e2)
})
test('node identity remove in the middle', function() {
test("node identity remove in the middle", function() {
"use strict"
expect(2)
var view1 = m('div', {}, [
m('div', {key:1}, 'E1'),
m('div', {key:2}, 'E2'),
m('div', {key:3}, 'E3')
var view1 = m("div", {}, [
m("div", {key: 1}, "E1"),
m("div", {key: 2}, "E2"),
m("div", {key: 3}, "E3")
])
m.render(dummyEl, view1)
var e3 = dummyEl.firstChild.lastChild
equal(e3.innerHTML, 'E3')
equal(e3.innerHTML, "E3")
var view2 = m('div', {}, [
m('div', {key:1}, 'E1'),
m('div', {key:3}, 'E3')
var view2 = m("div", {}, [
m("div", {key: 1}, "E1"),
m("div", {key: 3}, "E3")
])
m.render(dummyEl, view2)
equal(dummyEl.firstChild.firstChild.nextSibling, e3)
})
test('node identity remove last', function() {
test("node identity remove last", function() {
"use strict"
expect(4)
var view1 = m('div', {}, [
m('div', {key:1}, 'E1'),
m('div', {key:2}, 'E2'),
m('div', {key:3}, 'E3')
var view1 = m("div", {}, [
m("div", {key: 1}, "E1"),
m("div", {key: 2}, "E2"),
m("div", {key: 3}, "E3")
])
m.render(dummyEl, view1)
var e1 = dummyEl.firstChild.firstChild
equal(e1.innerHTML, 'E1')
equal(e1.innerHTML, "E1")
var e2 = dummyEl.firstChild.firstChild.nextSibling
equal(e2.innerHTML, 'E2')
equal(e2.innerHTML, "E2")
var view2 = m('div', {}, [
m('div', {key:1}, 'E1'),
m('div', {key:2}, 'E2')
var view2 = m("div", {}, [
m("div", {key: 1}, "E1"),
m("div", {key: 2}, "E2")
])
m.render(dummyEl, view2)
@ -217,168 +241,176 @@ test('node identity remove last', function() {
equal(dummyEl.firstChild.firstChild.nextSibling, e2)
})
test('node identity shuffle and remove', function() {
test("node identity shuffle and remove", function() {
"use strict"
expect(8)
var view1 = m('div', {}, [
m('div', {key:1}, 'E1'),
m('div', {key:2}, 'E2'),
m('div', {key:3}, 'E3'),
m('div', {key:4}, 'E4'),
m('div', {key:5}, 'E5')
var view1 = m("div", {}, [
m("div", {key: 1}, "E1"),
m("div", {key: 2}, "E2"),
m("div", {key: 3}, "E3"),
m("div", {key: 4}, "E4"),
m("div", {key: 5}, "E5")
])
m.render(dummyEl, view1)
var e1 = dummyEl.firstChild.firstChild
equal(e1.innerHTML, 'E1')
equal(e1.innerHTML, "E1")
var e2 = e1.nextSibling
equal(e2.innerHTML, 'E2')
equal(e2.innerHTML, "E2")
var e3 = e2.nextSibling
equal(e3.innerHTML, 'E3')
equal(e3.innerHTML, "E3")
var e4 = e3.nextSibling
equal(e4.innerHTML, 'E4')
equal(e4.innerHTML, "E4")
var e5 = e4.nextSibling
equal(e5.innerHTML, 'E5')
equal(e5.innerHTML, "E5")
var view2 = m('div', {}, [
m('div', {key:4}, 'E4'),
m('div', {key:10}, 'E10'),
m('div', {key:1}, 'E1'),
m('div', {key:2}, 'E2')
var view2 = m("div", {}, [
m("div", {key: 4}, "E4"),
m("div", {key: 10}, "E10"),
m("div", {key: 1}, "E1"),
m("div", {key: 2}, "E2")
])
m.render(dummyEl, view2)
equal(dummyEl.firstChild.firstChild, e4, 'e4 is first element')
equal(dummyEl.firstChild.firstChild.nextSibling.nextSibling, e1, 'e1 is third element')
equal(dummyEl.firstChild.firstChild.nextSibling.nextSibling.nextSibling, e2, 'e2 is fourth element')
equal(dummyEl.firstChild.firstChild, e4, "e4 is first element")
equal(dummyEl.firstChild.firstChild.nextSibling.nextSibling, e1,
"e1 is third element")
equal(dummyEl.firstChild.firstChild.nextSibling.nextSibling.nextSibling, e2,
"e2 is fourth element")
})
asyncTest('issue214 regression', function() {
asyncTest("issue214 regression", function() {
"use strict"
// see https://github.com/lhorie/mithril.js/issues/214
expect(2)
function controller() {
this.inputValue = m.prop('')
this.inputValue = m.prop("")
}
function view(ctrl) {
return m('input#testinput', {
return m("input#testinput", {
value: ctrl.inputValue(),
onkeyup: m.withAttr('value', ctrl.inputValue)
onkeyup: m.withAttr("value", ctrl.inputValue)
})
}
var ctrl = m.module(dummyEl, { controller: controller, view: view })
Syn.click({}, 'testinput')
.type('0').delay(10)
.type('1').delay(10)
.type('2').delay(10)
.type('3').delay(10)
.type('4').delay(10)
.type('5').delay(10)
.type('6').delay(10)
.type('7').delay(10)
.type('8').delay(10)
.type('9').delay(10)
.type('a').delay(10)
.type('b').delay(10)
.type('c').delay(10)
.type('d').delay(10)
.type('e').delay(10)
.type('f').delay(10)
.type('0').delay(10)
.type('1').delay(10)
.type('2').delay(10)
.type('3').delay(10)
.type('4').delay(10)
.type('5').delay(10)
.type('6').delay(10)
.type('7').delay(10)
.type('8').delay(10)
.type('9').delay(10)
.type('a').delay(10)
.type('b').delay(10)
.type('c').delay(10)
.type('d').delay(10)
.type('e').delay(10)
.type('f').delay(10)
.type('0').delay(10)
.type('1').delay(10)
.type('2').delay(10)
.type('3').delay(10)
.type('4').delay(10)
.type('5').delay(10)
.type('6').delay(10)
.type('7').delay(10)
.type('8').delay(10)
.type('9').delay(10)
.type('a').delay(10)
.type('b').delay(10)
.type('c').delay(10)
.type('d').delay(10)
.type('e').delay(10)
.type('f').delay(10)
.type('0').delay(10)
.type('1').delay(10)
.type('2').delay(10)
.type('3').delay(10)
.type('4').delay(10)
.type('5').delay(10)
.type('6').delay(10)
.type('7').delay(10)
.type('8').delay(10)
.type('9').delay(10)
.type('a').delay(10)
.type('b').delay(10)
.type('c').delay(10)
.type('d').delay(10)
.type('e').delay(10)
.type('f', function() {
equal(ctrl.inputValue(), '0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef')
equal(document.getElementById('testinput').value, '0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef')
Syn.click({}, "testinput")
.type("0").delay(10)
.type("1").delay(10)
.type("2").delay(10)
.type("3").delay(10)
.type("4").delay(10)
.type("5").delay(10)
.type("6").delay(10)
.type("7").delay(10)
.type("8").delay(10)
.type("9").delay(10)
.type("a").delay(10)
.type("b").delay(10)
.type("c").delay(10)
.type("d").delay(10)
.type("e").delay(10)
.type("f").delay(10)
.type("0").delay(10)
.type("1").delay(10)
.type("2").delay(10)
.type("3").delay(10)
.type("4").delay(10)
.type("5").delay(10)
.type("6").delay(10)
.type("7").delay(10)
.type("8").delay(10)
.type("9").delay(10)
.type("a").delay(10)
.type("b").delay(10)
.type("c").delay(10)
.type("d").delay(10)
.type("e").delay(10)
.type("f").delay(10)
.type("0").delay(10)
.type("1").delay(10)
.type("2").delay(10)
.type("3").delay(10)
.type("4").delay(10)
.type("5").delay(10)
.type("6").delay(10)
.type("7").delay(10)
.type("8").delay(10)
.type("9").delay(10)
.type("a").delay(10)
.type("b").delay(10)
.type("c").delay(10)
.type("d").delay(10)
.type("e").delay(10)
.type("f").delay(10)
.type("0").delay(10)
.type("1").delay(10)
.type("2").delay(10)
.type("3").delay(10)
.type("4").delay(10)
.type("5").delay(10)
.type("6").delay(10)
.type("7").delay(10)
.type("8").delay(10)
.type("9").delay(10)
.type("a").delay(10)
.type("b").delay(10)
.type("c").delay(10)
.type("d").delay(10)
.type("e").delay(10)
.type("f", function() {
equal(ctrl.inputValue(),
"0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef")
equal(document.getElementById("testinput").value,
"0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef")
start()
})
})
asyncTest('issue288 regression', function() {
asyncTest("issue288 regression", function() {
"use strict"
// see https://github.com/lhorie/mithril.js/issues/288
expect(2)
function controller() {
this.inputValue = m.prop('')
this.inputValue = m.prop("")
this.submit = function() {
if (this.inputValue()) {
this.inputValue('')
this.inputValue("")
}
}.bind(this);
}.bind(this)
}
function view(ctrl) {
return m('form', { onsubmit: ctrl.submit }, [
m('input#testinput', {
onkeyup: m.withAttr('value', ctrl.inputValue),
return m("form", { onsubmit: ctrl.submit }, [
m("input#testinput", {
onkeyup: m.withAttr("value", ctrl.inputValue),
value: ctrl.inputValue()
}),
m('button[type=submit]')
m("button[type=submit]")
])
}
var ctrl = m.module(dummyEl, { controller: controller, view: view })
Syn.click({}, 'testinput')
.type('a').delay(10)
.type('b').delay(10)
.type('c').delay(10)
.type('d').delay(10)
.type('[enter]', function() {
equal(ctrl.inputValue(), '')
equal(document.getElementById('testinput').value, '')
Syn.click({}, "testinput")
.type("a").delay(10)
.type("b").delay(10)
.type("c").delay(10)
.type("d").delay(10)
.type("[enter]", function() {
equal(ctrl.inputValue(), "")
equal(document.getElementById("testinput").value, "")
start()
})
})
test('issue278 regression', function() {
test("issue278 regression", function() {
"use strict"
// see https://github.com/lhorie/mithril.js/issues/278
expect(1)
@ -389,22 +421,24 @@ test('issue278 regression', function() {
},
view: function(ctrl) {
return m('select#testselect', {
return m("select#testselect", {
size: ctrl.values.length,
multiple: 'multiple'
multiple: "multiple"
}, [
ctrl.values.map(function(v){
var opts = {value: v}
if (ctrl.value().indexOf(v) !== -1) opts.selected = 'selected'
return m('option', opts, v)
if (ctrl.value().indexOf(v) !== -1) {
opts.selected = "selected"
}
return m("option", opts, v)
})
])
}
}
m.render(dummyEl, test.view(new test.controller))
m.render(dummyEl, test.view(new test.controller()))
var select = document.getElementById('testselect')
var select = document.getElementById("testselect")
for (var i = 0, selected = 0; i < select.options.length; i++) {
if (select.options[i].selected) selected++
@ -413,25 +447,30 @@ test('issue278 regression', function() {
equal(selected, 2)
})
test("mixing trusted content", function() {
"use strict"
m.render(dummyEl, [m.trust("<p>1</p><p>2</p>"), m("i", "foo")])
equal(dummyEl.childNodes[2].nodeName, "I")
})
test("mixing trusted content w/ text nodes", function() {
"use strict"
m.render(dummyEl, [m.trust("<p>1</p>123<p>2</p>"), m("i", "foo")])
equal(dummyEl.childNodes[3].nodeName, "I")
})
test("mixing trusted content w/ td", function() {
"use strict"
m.render(dummyEl, [m.trust("<td>1</td><td>2</td>"), m("i", "foo")])
equal(dummyEl.childNodes[1].nodeName, "I")
})
test("0 should not be treated as empty string", function() {
"use strict"
m.render(dummyEl, m("input", {value: ""}))
m.render(dummyEl, m("input", {value: 0}))
equal(dummyEl.childNodes[0].value, "0")
})
test("empty value in <option> should show as attribute", function() {
"use strict"
m.render(dummyEl, m("select", m("option", {value: ""}, "aaa")))
equal(dummyEl.childNodes[0].innerHTML, '<option value="">aaa</option>')
})

File diff suppressed because it is too large Load diff

View file

@ -1,3 +1,4 @@
/* eslint-disable no-extend-native, strict */
if (!Array.prototype.indexOf) {
Array.prototype.indexOf = function(item) {
for (var i = 0; i < this.length; i++) {
@ -31,9 +32,11 @@ if (!Object.keys) {
return keys
}
}
/* eslint-enable no-extend-native, strict */
var mock = {}
mock.window = (function() {
"use strict"
var window = {}
window.document = {}
window.document.childNodes = []
@ -55,11 +58,12 @@ mock.window = (function() {
else this.childNodes.splice(referenceIndex, 0, node)
},
insertAdjacentHTML: function(position, html) {
//todo: accept markup
if (position == "beforebegin") {
this.parentNode.insertBefore(window.document.createTextNode(html), this)
}
else if (position == "beforeend") {
// todo: accept markup
if (position === "beforebegin") {
this.parentNode.insertBefore(
window.document.createTextNode(html),
this)
} else if (position === "beforeend") {
this.appendChild(window.document.createTextNode(html))
}
},
@ -70,7 +74,7 @@ mock.window = (function() {
this.namespaceURI = namespace
this[name] = value.toString()
},
getAttribute: function(name, value) {
getAttribute: function(name) {
return this[name]
},
addEventListener: function () {},
@ -104,23 +108,25 @@ mock.window = (function() {
this.childNodes.splice(index, 1)
child.parentNode = null
}
//getElementsByTagName is only used by JSONP tests, it's not required by Mithril
// getElementsByTagName is only used by JSONP tests, it's not required by
// Mithril
window.document.getElementsByTagName = function(name){
name = name.toLowerCase();
var out = [];
name = name.toLowerCase()
var out = []
var traverse = function(node){
if(node.childNodes && node.childNodes.length > 0){
node.childNodes.map(function(curr){
if(curr.nodeName.toLowerCase() === name)
out.push(curr);
traverse(curr);
});
if (curr.nodeName.toLowerCase() === name) {
out.push(curr)
}
traverse(curr)
})
}
};
}
traverse(window.document);
return out;
traverse(window.document)
return out
}
window.scrollTo = function() {}
window.cancelAnimationFrame = function() {}
@ -156,15 +162,17 @@ mock.window = (function() {
request.$instances = []
return request
}())
window.location = {search: "", pathname: "", hash: ""},
window.location = {search: "", pathname: "", hash: ""}
window.history = {}
window.history.$$length = 0
window.history.pushState = function(data, title, url) {
window.history.$$length++
window.location.pathname = window.location.search = window.location.hash = 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
window.location.pathname = window.location.search =
window.location.hash = url
}
return window
}())
}())

View file

@ -1,15 +1,19 @@
/* eslint-disable no-console */
if (!this.console) {
var log = function(value) {document.write("<pre>" + value + "</pre>")}
var log = function(value) {
"use strict"
document.write("<pre>" + value + "</pre>")
}
this.console = {log: log, error: log}
}
function test(condition) {
"use strict"
test.total++
try {
if (!condition()) throw new Error("failed")
}
catch (e) {
} catch (e) {
console.error(e)
test.failures.push(condition)
}
@ -17,6 +21,7 @@ function test(condition) {
test.total = 0
test.failures = []
test.print = function(print) {
"use strict"
for (var i = 0; i < test.failures.length; i++) {
print(test.failures[i].toString())
}