Runtime-deprecate ospec, change change-log to changelog, fix a few assorted bugs (#2578)

This commit is contained in:
Isiah Meadows 2020-09-29 13:27:07 -07:00 committed by GitHub
parent 1630b06106
commit 9f0dc2ab46
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
76 changed files with 484 additions and 410 deletions

View file

@ -1,3 +0,0 @@
# Code of Conduct
Please see https://mithril.js.org/code-of-conduct.html.

1
.github/FUNDING.yml vendored
View file

@ -1 +0,0 @@
open_collective: mithriljs

View file

@ -12,17 +12,18 @@ assignees: isiahmeadows
Optional: Provide the exact version of Mithril you're experiencing issues with. Optional: Provide the exact version of Mithril you're experiencing issues with.
This could matter, even if it's really old like version 0.1.0. Do note that bugs This could matter, even if it's really old like version 0.1.0. Do note that bugs
in older versions are commonly fixed in newer versions and that newer versions in older versions are commonly fixed in newer versions and that newer versions
do end up with a lot more features than older versions, so it's unlikely we'll are much more actively maintained than older versions, so it's unlikely we'll
add new features to older versions like 0.1.x. add new features to older versions like 0.1.x.
--> -->
**Mithril version:** **Mithril version:**
<!-- <!--
Optional: Provide the name and version of both the browser and operating system Optional: Provide the name and version of both the platform (Chrome, Node, etc.)
you're running Mithril on. If it's multiple, feel free to list multiple. This and operating system you're running Mithril on. If it's multiple, feel free to
could matter, even if it's super ancient like IE 6 on Windows XP. list multiple. This could matter, even if it's super ancient like IE 6 on
Windows XP.
--> -->
**Browser and OS:** **Platform and OS:**
<!-- <!--
Optional: Provide a link to your project, if it happens to be open source or if Optional: Provide a link to your project, if it happens to be open source or if

View file

@ -28,4 +28,4 @@
- [ ] I have read the **CONTRIBUTING** document. - [ ] I have read the **CONTRIBUTING** document.
- [ ] I have added tests to cover my changes. - [ ] I have added tests to cover my changes.
- [ ] All new and existing tests passed. - [ ] All new and existing tests passed.
- [ ] I have updated `docs/change-log.md` - [ ] I have updated `docs/changelog.md`

View file

@ -13,11 +13,133 @@ var censor = require("../util/censor")
var sentinel = {} var sentinel = {}
module.exports = function($window, mountRedraw) { module.exports = function($window, mountRedraw) {
var fireAsync var callAsync = $window == null
// In case Mithril's loaded globally without the DOM, let's not break
? null
: typeof $window.setImmediate === "function" ? $window.setImmediate : $window.setTimeout
var p = Promise.resolve()
var scheduled = false
// state === 0: init
// state === 1: scheduled
// state === 2: done
var ready = false
var state = 0
var compiled, fallbackRoute
var currentResolver = sentinel, component, attrs, currentPath, lastUpdate
var RouterRoot = {
onbeforeupdate: function() {
state = state ? 2 : 1
return !(!state || sentinel === currentResolver)
},
onremove: function() {
$window.removeEventListener("popstate", fireAsync, false)
$window.removeEventListener("hashchange", resolveRoute, false)
},
view: function() {
if (!state || sentinel === currentResolver) return
// Wrap in a fragment to preserve existing key semantics
var vnode = [Vnode(component, attrs.key, attrs)]
if (currentResolver) vnode = currentResolver.render(vnode[0])
return vnode
},
}
var SKIP = route.SKIP = {}
function resolveRoute() {
scheduled = false
// Consider the pathname holistically. The prefix might even be invalid,
// but that's not our problem.
var prefix = $window.location.hash
if (route.prefix[0] !== "#") {
prefix = $window.location.search + prefix
if (route.prefix[0] !== "?") {
prefix = $window.location.pathname + prefix
if (prefix[0] !== "/") prefix = "/" + prefix
}
}
// This seemingly useless `.concat()` speeds up the tests quite a bit,
// since the representation is consistently a relatively poorly
// optimized cons string.
var path = prefix.concat()
.replace(/(?:%[a-f89][a-f0-9])+/gim, decodeURIComponent)
.slice(route.prefix.length)
var data = parsePathname(path)
assign(data.params, $window.history.state)
function reject(e) {
console.error(e)
setPath(fallbackRoute, null, {replace: true})
}
loop(0)
function loop(i) {
// state === 0: init
// state === 1: scheduled
// state === 2: done
for (; i < compiled.length; i++) {
if (compiled[i].check(data)) {
var payload = compiled[i].component
var matchedRoute = compiled[i].route
var localComp = payload
var update = lastUpdate = function(comp) {
if (update !== lastUpdate) return
if (comp === SKIP) return loop(i + 1)
component = comp != null && (typeof comp.view === "function" || typeof comp === "function")? comp : "div"
attrs = data.params, currentPath = path, lastUpdate = null
currentResolver = payload.render ? payload : null
if (state === 2) mountRedraw.redraw()
else {
state = 2
mountRedraw.redraw.sync()
}
}
// There's no understating how much I *wish* I could
// use `async`/`await` here...
if (payload.view || typeof payload === "function") {
payload = {}
update(localComp)
}
else if (payload.onmatch) {
p.then(function () {
return payload.onmatch(data.params, path, matchedRoute)
}).then(update, path === fallbackRoute ? null : reject)
}
else update("div")
return
}
}
if (path === fallbackRoute) {
throw new Error("Could not resolve default route " + fallbackRoute + ".")
}
setPath(fallbackRoute, null, {replace: true})
}
}
// Set it unconditionally so `m.route.set` and `m.route.Link` both work,
// even if neither `pushState` nor `hashchange` are supported. It's
// cleared if `hashchange` is used, since that makes it automatically
// async.
function fireAsync() {
if (!scheduled) {
scheduled = true
// TODO: just do `mountRedraw.redraw()` here and elide the timer
// dependency. Note that this will muck with tests a *lot*, so it's
// not as easy of a change as it sounds.
callAsync(resolveRoute)
}
}
function setPath(path, data, options) { function setPath(path, data, options) {
path = buildPathname(path, data) path = buildPathname(path, data)
if (fireAsync != null) { if (ready) {
fireAsync() fireAsync()
var state = options ? options.state : null var state = options ? options.state : null
var title = options ? options.title : null var title = options ? options.title : null
@ -29,18 +151,10 @@ module.exports = function($window, mountRedraw) {
} }
} }
var currentResolver = sentinel, component, attrs, currentPath, lastUpdate
var SKIP = route.SKIP = {}
function route(root, defaultRoute, routes) { function route(root, defaultRoute, routes) {
if (!root) throw new TypeError("DOM element being rendered to does not exist.") if (!root) throw new TypeError("DOM element being rendered to does not exist.")
// 0 = start
// 1 = init
// 2 = ready
var state = 0
var compiled = Object.keys(routes).map(function(route) { compiled = Object.keys(routes).map(function(route) {
if (route[0] !== "/") throw new SyntaxError("Routes must start with a '/'.") if (route[0] !== "/") throw new SyntaxError("Routes must start with a '/'.")
if ((/:([^\/\.-]+)(\.{3})?:/).test(route)) { if ((/:([^\/\.-]+)(\.{3})?:/).test(route)) {
throw new SyntaxError("Route parameter names must be separated with either '/', '.', or '-'.") throw new SyntaxError("Route parameter names must be separated with either '/', '.', or '-'.")
@ -51,13 +165,7 @@ module.exports = function($window, mountRedraw) {
check: compileTemplate(route), check: compileTemplate(route),
} }
}) })
var callAsync = typeof setImmediate === "function" ? setImmediate : setTimeout fallbackRoute = defaultRoute
var p = Promise.resolve()
var scheduled = false
var onremove
fireAsync = null
if (defaultRoute != null) { if (defaultRoute != null) {
var defaultData = parsePathname(defaultRoute) var defaultData = parsePathname(defaultRoute)
@ -66,116 +174,14 @@ module.exports = function($window, mountRedraw) {
} }
} }
function resolveRoute() {
scheduled = false
// Consider the pathname holistically. The prefix might even be invalid,
// but that's not our problem.
var prefix = $window.location.hash
if (route.prefix[0] !== "#") {
prefix = $window.location.search + prefix
if (route.prefix[0] !== "?") {
prefix = $window.location.pathname + prefix
if (prefix[0] !== "/") prefix = "/" + prefix
}
}
// This seemingly useless `.concat()` speeds up the tests quite a bit,
// since the representation is consistently a relatively poorly
// optimized cons string.
var path = prefix.concat()
.replace(/(?:%[a-f89][a-f0-9])+/gim, decodeURIComponent)
.slice(route.prefix.length)
var data = parsePathname(path)
assign(data.params, $window.history.state)
function reject(e) {
console.error(e)
setPath(defaultRoute, null, {replace: true})
}
loop(0)
function loop(i) {
// 0 = init
// 1 = scheduled
// 2 = done
for (; i < compiled.length; i++) {
if (compiled[i].check(data)) {
var payload = compiled[i].component
var matchedRoute = compiled[i].route
var localComp = payload
var update = lastUpdate = function(comp) {
if (update !== lastUpdate) return
if (comp === SKIP) return loop(i + 1)
component = comp != null && (typeof comp.view === "function" || typeof comp === "function")? comp : "div"
attrs = data.params, currentPath = path, lastUpdate = null
currentResolver = payload.render ? payload : null
if (state === 2) mountRedraw.redraw()
else {
state = 2
mountRedraw.redraw.sync()
}
}
// There's no understating how much I *wish* I could
// use `async`/`await` here...
if (payload.view || typeof payload === "function") {
payload = {}
update(localComp)
}
else if (payload.onmatch) {
p.then(function () {
return payload.onmatch(data.params, path, matchedRoute)
}).then(update, path === defaultRoute ? null : reject)
}
else update("div")
return
}
}
if (path === defaultRoute) {
throw new Error("Could not resolve default route " + defaultRoute + ".")
}
setPath(defaultRoute, null, {replace: true})
}
}
// Set it unconditionally so `m.route.set` and `m.route.Link` both work,
// even if neither `pushState` nor `hashchange` are supported. It's
// cleared if `hashchange` is used, since that makes it automatically
// async.
fireAsync = function() {
if (!scheduled) {
scheduled = true
callAsync(resolveRoute)
}
}
if (typeof $window.history.pushState === "function") { if (typeof $window.history.pushState === "function") {
onremove = function() {
$window.removeEventListener("popstate", fireAsync, false)
}
$window.addEventListener("popstate", fireAsync, false) $window.addEventListener("popstate", fireAsync, false)
} else if (route.prefix[0] === "#") { } else if (route.prefix[0] === "#") {
fireAsync = null
onremove = function() {
$window.removeEventListener("hashchange", resolveRoute, false)
}
$window.addEventListener("hashchange", resolveRoute, false) $window.addEventListener("hashchange", resolveRoute, false)
} }
mountRedraw.mount(root, { ready = true
onbeforeupdate: function() { mountRedraw.mount(root, RouterRoot)
state = state ? 2 : 1
return !(!state || sentinel === currentResolver)
},
onremove: onremove,
view: function() {
if (!state || sentinel === currentResolver) return
// Wrap in a fragment to preserve existing key semantics
var vnode = [Vnode(component, attrs.key, attrs)]
if (currentResolver) vnode = currentResolver.render(vnode[0])
return vnode
},
})
resolveRoute() resolveRoute()
} }
route.set = function(path, data, options) { route.set = function(path, data, options) {

View file

@ -1,7 +1,7 @@
"use strict" "use strict"
// Low-priority TODO: remove the dependency on the renderer here. // Low-priority TODO: remove the dependency on the renderer here.
var o = require("../../ospec/ospec") var o = require("ospec")
var components = require("../../test-utils/components") var components = require("../../test-utils/components")
var domMock = require("../../test-utils/domMock") var domMock = require("../../test-utils/domMock")
var throttleMocker = require("../../test-utils/throttleMock") var throttleMocker = require("../../test-utils/throttleMock")

View file

@ -1,7 +1,7 @@
"use strict" "use strict"
// Low-priority TODO: remove the dependency on the renderer here. // Low-priority TODO: remove the dependency on the renderer here.
var o = require("../../ospec/ospec") var o = require("ospec")
var browserMock = require("../../test-utils/browserMock") var browserMock = require("../../test-utils/browserMock")
var throttleMocker = require("../../test-utils/throttleMock") var throttleMocker = require("../../test-utils/throttleMock")
@ -26,14 +26,13 @@ o.spec("route", function() {
// Use precisely what `m.route` uses, for consistency and to ensure timings // Use precisely what `m.route` uses, for consistency and to ensure timings
// are aligned. // are aligned.
var waitFunc = typeof setImmediate === "function" ? setImmediate : setTimeout
function waitCycles(n) { function waitCycles(n) {
n = Math.max(n, 1) n = Math.max(n, 1)
return new Promise(function(resolve) { return new Promise(function(resolve) {
return loop() return loop()
function loop() { function loop() {
if (n === 0) resolve() if (n === 0) resolve()
else { n--; waitFunc(loop) } else { n--; setTimeout(loop, 4) }
} }
}) })
} }
@ -75,6 +74,8 @@ o.spec("route", function() {
o.beforeEach(function() { o.beforeEach(function() {
currentTest = nextID++ currentTest = nextID++
$window = browserMock(env) $window = browserMock(env)
$window.setTimeout = setTimeout
// $window.setImmediate = setImmediate
throttleMock = throttleMocker() throttleMock = throttleMocker()
root = $window.document.body root = $window.document.body

View file

@ -1,12 +1,10 @@
"use strict" "use strict"
// Low-priority TODO: remove the dependency on the renderer here. // Low-priority TODO: remove the dependency on the renderer here.
var o = require("../../ospec/ospec") var o = require("ospec")
var callAsync = require("../../test-utils/callAsync")
var browserMock = require("../../test-utils/browserMock") var browserMock = require("../../test-utils/browserMock")
var throttleMocker = require("../../test-utils/throttleMock") var throttleMocker = require("../../test-utils/throttleMock")
var callAsync = require("../../test-utils/callAsync")
var apiMountRedraw = require("../../api/mount-redraw") var apiMountRedraw = require("../../api/mount-redraw")
var coreRenderer = require("../../render/render") var coreRenderer = require("../../render/render")
var apiRouter = require("../../api/router") var apiRouter = require("../../api/router")
@ -20,6 +18,7 @@ o.spec("route.get/route.set", function() {
o.beforeEach(function() { o.beforeEach(function() {
$window = browserMock(env) $window = browserMock(env)
throttleMock = throttleMocker() throttleMock = throttleMocker()
$window.setTimeout = setTimeout
root = $window.document.body root = $window.document.body
@ -87,7 +86,7 @@ o.spec("route.get/route.set", function() {
route.set("/b") route.set("/b")
o(spy1.callCount).equals(1) o(spy1.callCount).equals(1)
o(spy2.callCount).equals(0) o(spy2.callCount).equals(0)
callAsync(function() { setTimeout(function() {
throttleMock.fire() throttleMock.fire()
o(spy1.callCount).equals(1) o(spy1.callCount).equals(1)
@ -111,10 +110,10 @@ o.spec("route.get/route.set", function() {
route.set("/c") route.set("/c")
o(spy1.callCount).equals(0) o(spy1.callCount).equals(0)
o(spy2.callCount).equals(1) o(spy2.callCount).equals(1)
callAsync(function() { setTimeout(function() {
// Yep, before even the throttle mechanism takes hold. // Yep, before even the throttle mechanism takes hold.
o(route.get()).equals("/b") o(route.get()).equals("/b")
callAsync(function() { setTimeout(function() {
// Yep, before even the throttle mechanism takes hold. // Yep, before even the throttle mechanism takes hold.
o(route.get()).equals("/a") o(route.get()).equals("/a")
throttleMock.fire() throttleMock.fire()
@ -134,7 +133,7 @@ o.spec("route.get/route.set", function() {
}) })
route.set("/other/x/y/z?c=d#e=f") route.set("/other/x/y/z?c=d#e=f")
callAsync(function() { setTimeout(function() {
// Yep, before even the throttle mechanism takes hold. // Yep, before even the throttle mechanism takes hold.
o(route.get()).equals("/other/x/y/z?c=d#e=f") o(route.get()).equals("/other/x/y/z?c=d#e=f")
throttleMock.fire() throttleMock.fire()
@ -150,7 +149,7 @@ o.spec("route.get/route.set", function() {
}) })
route.set(encodeURI("/ö?ö=ö#ö=ö")) route.set(encodeURI("/ö?ö=ö#ö=ö"))
callAsync(function() { setTimeout(function() {
// Yep, before even the throttle mechanism takes hold. // Yep, before even the throttle mechanism takes hold.
o(route.get()).equals("/ö?ö=ö#ö=ö") o(route.get()).equals("/ö?ö=ö#ö=ö")
throttleMock.fire() throttleMock.fire()
@ -166,7 +165,7 @@ o.spec("route.get/route.set", function() {
}) })
route.set("/ö?ö=ö#ö=ö") route.set("/ö?ö=ö#ö=ö")
callAsync(function() { setTimeout(function() {
// Yep, before even the throttle mechanism takes hold. // Yep, before even the throttle mechanism takes hold.
o(route.get()).equals("/ö?ö=ö#ö=ö") o(route.get()).equals("/ö?ö=ö#ö=ö")
throttleMock.fire() throttleMock.fire()
@ -182,7 +181,7 @@ o.spec("route.get/route.set", function() {
}) })
route.set("/other/x/y/z?c=d#e=f") route.set("/other/x/y/z?c=d#e=f")
callAsync(function() { setTimeout(function() {
// Yep, before even the throttle mechanism takes hold. // Yep, before even the throttle mechanism takes hold.
o(route.get()).equals("/other/x/y/z?c=d#e=f") o(route.get()).equals("/other/x/y/z?c=d#e=f")
throttleMock.fire() throttleMock.fire()
@ -197,11 +196,11 @@ o.spec("route.get/route.set", function() {
"/other/:a/:b...": {view: function() {}}, "/other/:a/:b...": {view: function() {}},
}) })
callAsync(function() { setTimeout(function() {
$window.history.pushState(null, null, prefix + "/other/x/y/z?c=d#e=f") $window.history.pushState(null, null, prefix + "/other/x/y/z?c=d#e=f")
$window.onpopstate() $window.onpopstate()
callAsync(function() { setTimeout(function() {
// Yep, before even the throttle mechanism takes hold. // Yep, before even the throttle mechanism takes hold.
o(route.get()).equals("/other/x/y/z?c=d#e=f") o(route.get()).equals("/other/x/y/z?c=d#e=f")
throttleMock.fire() throttleMock.fire()
@ -219,7 +218,7 @@ o.spec("route.get/route.set", function() {
}) })
route.set("/other/:a/:b", {a: "x", b: "y/z", c: "d", e: "f"}) route.set("/other/:a/:b", {a: "x", b: "y/z", c: "d", e: "f"})
callAsync(function() { setTimeout(function() {
// Yep, before even the throttle mechanism takes hold. // Yep, before even the throttle mechanism takes hold.
o(route.get()).equals("/other/x/y%2Fz?c=d&e=f") o(route.get()).equals("/other/x/y%2Fz?c=d&e=f")
throttleMock.fire() throttleMock.fire()
@ -236,7 +235,7 @@ o.spec("route.get/route.set", function() {
route.set("/other", null, {replace: true}) route.set("/other", null, {replace: true})
callAsync(function() { setTimeout(function() {
throttleMock.fire() throttleMock.fire()
$window.history.back() $window.history.back()
o($window.location.href).equals(env.protocol + "//" + (env.hostname === "/" ? "" : env.hostname) + "/") o($window.location.href).equals(env.protocol + "//" + (env.hostname === "/" ? "" : env.hostname) + "/")
@ -253,7 +252,7 @@ o.spec("route.get/route.set", function() {
route.set("/other", null, {replace: false}) route.set("/other", null, {replace: false})
callAsync(function() { setTimeout(function() {
throttleMock.fire() throttleMock.fire()
$window.history.back() $window.history.back()
var slash = prefix[0] === "/" ? "" : "/" var slash = prefix[0] === "/" ? "" : "/"
@ -270,7 +269,7 @@ o.spec("route.get/route.set", function() {
}) })
route.set("/other", null, {state: {a: 1}}) route.set("/other", null, {state: {a: 1}})
callAsync(function() { setTimeout(function() {
throttleMock.fire() throttleMock.fire()
o($window.history.state).deepEquals({a: 1}) o($window.history.state).deepEquals({a: 1})
done() done()

View file

@ -9,8 +9,8 @@
- [v1.x changelog](https://mithril.js.org/archive/v1.1.7/change-log.html) - [v1.x changelog](https://mithril.js.org/archive/v1.1.7/change-log.html)
- [v1.x docs](https://mithril.js.org/archive/v1.1.7/index.html) - [v1.x docs](https://mithril.js.org/archive/v1.1.7/index.html)
- [v0.2 docs](https://mithril.js.org/archive/v0.2.5/index.html) - [v0.2 docs](https://mithril.js.org/archive/v0.2.5/index.html)
- [`ospec` change log](https://github.com/MithrilJS/mithril.js/blob/master/ospec/change-log.md) - [`ospec` change log](https://github.com/MithrilJS/ospec/blob/master/changelog.md)
- [`mithril/stream` change log](https://github.com/MithrilJS/mithril.js/blob/master/stream/change-log.md) - [`mithril-stream` change log](#mithril-stream-change-log)
--- ---
@ -20,6 +20,8 @@
*Note for later: release as semver-minor.* *Note for later: release as semver-minor.*
PSA: changes to [`mithril/stream`](stream.md) are now specified in this changelog. I've also moved the old stream changelog into this file [here](#mithril-stream-change-log).
- Reduced package download size substantially by removing the archive of previous releases' documentation. ([#2561](https://github.com/MithrilJS/mithril.js/pull/2561) [@cztomsik](https://github.com/cztomsik)) - Reduced package download size substantially by removing the archive of previous releases' documentation. ([#2561](https://github.com/MithrilJS/mithril.js/pull/2561) [@cztomsik](https://github.com/cztomsik))
- Improved error messages in multiple places. ([#2536](https://github.com/MithrilJS/mithril.js/pull/2536) [@isiahmeadows](https://github.com/isiahmeadows)) - Improved error messages in multiple places. ([#2536](https://github.com/MithrilJS/mithril.js/pull/2536) [@isiahmeadows](https://github.com/isiahmeadows))
- The redraw reentrancy check was moved from `m.mount` to `m.render` and its error message was updated accordingly. ([#2536](https://github.com/MithrilJS/mithril.js/pull/2536) [@isiahmeadows](https://github.com/isiahmeadows)) - The redraw reentrancy check was moved from `m.mount` to `m.render` and its error message was updated accordingly. ([#2536](https://github.com/MithrilJS/mithril.js/pull/2536) [@isiahmeadows](https://github.com/isiahmeadows))
@ -31,6 +33,9 @@
- Re-add stream bundles. ([#2539](https://github.com/MithrilJS/mithril.js/pull/2539) [@isiahmeadows](https://github.com/isiahmeadows)) - Re-add stream bundles. ([#2539](https://github.com/MithrilJS/mithril.js/pull/2539) [@isiahmeadows](https://github.com/isiahmeadows))
- Remove extra isLifecycleMethod call from removeAttr. ([#2594](https://github.com/MithrilJS/mithril.js/pull/2594) [@ZeikJT](https://github.com/zeikjt)) - Remove extra isLifecycleMethod call from removeAttr. ([#2594](https://github.com/MithrilJS/mithril.js/pull/2594) [@ZeikJT](https://github.com/zeikjt))
- Fix issue where ending a stream in the middle of a stream callback would result in erroneous parent stream state for the rest of that emit. ([#2603](https://github.com/MithrilJS/mithril.js/pull/2603) [@isiahmeadows](https://github.com/isiahmeadows)) - Fix issue where ending a stream in the middle of a stream callback would result in erroneous parent stream state for the rest of that emit. ([#2603](https://github.com/MithrilJS/mithril.js/pull/2603) [@isiahmeadows](https://github.com/isiahmeadows))
- Fix issue where new redraw handlers weren't copied over on update. ([#2578](https://github.com/MithrilJS/mithril.js/pull/2578) [@isiahmeadows](https://github.com/isiahmeadows))
- Make changes to file inputs gracefully handled, and don't break if the current value and old value mismatch (and the new value isn't empty), but instead just log an error. ([#2578](https://github.com/MithrilJS/mithril.js/pull/2578) [@isiahmeadows](https://github.com/isiahmeadows))
- This mainly exists just to kick the can down the road - this is the only case I'm aware of where the DOM itself would be responsible for throwing an error. A proper fix to the greater issue of error handling is much more complex, and I'd rather not block users any longer over this one specific issue.
Important note: if you were using any of these undocumented tools, they are no longer available as of this release. This is not considered a breaking change as they were written for internal usage and as of v2 are all 100% unsupported in userland. Important note: if you were using any of these undocumented tools, they are no longer available as of this release. This is not considered a breaking change as they were written for internal usage and as of v2 are all 100% unsupported in userland.
@ -181,3 +186,22 @@ _2019-07-24_
- docs: clarify valid key usage ([#2452](https://github.com/MithrilJS/mithril.js/pull/2452) [@isiahmeadows](https://github.com/isiahmeadows)) - docs: clarify valid key usage ([#2452](https://github.com/MithrilJS/mithril.js/pull/2452) [@isiahmeadows](https://github.com/isiahmeadows))
- route: don't pollute globals ([#2453](https://github.com/MithrilJS/mithril.js/pull/2453) [@isiahmeadows](https://github.com/isiahmeadows)) - route: don't pollute globals ([#2453](https://github.com/MithrilJS/mithril.js/pull/2453) [@isiahmeadows](https://github.com/isiahmeadows))
- request: track xhr replacements correctly ([#2455](https://github.com/MithrilJS/mithril.js/pull/2455) [@isiahmeadows](https://github.com/isiahmeadows)) - request: track xhr replacements correctly ([#2455](https://github.com/MithrilJS/mithril.js/pull/2455) [@isiahmeadows](https://github.com/isiahmeadows))
## `mithril-stream` change log
Formerly, `mithril/stream` was available standalone as the package `mithril-stream`, but this package has been deprecated and is no longer updated. The changelog for that package prior to being merged back into Mithril proper is below.
### 2.0.0
_2019-02-07_
- when a stream conditionally returns HALT, dependant stream will also end ([#2200](https://github.com/MithrilJS/mithril.js/pull/2200), [#2369](https://github.com/MithrilJS/mithril.js/pull/2369))
- Add `stream.lift` as a user-friendly alternative to `merge -> map` or `combine` ([#1944](https://github.com/MithrilJS/mithril.js/issues/1944))
- renamed HALT to SKIP ([#2207](https://github.com/MithrilJS/mithril.js/pull/2207))
- rewrote implementation ([#2207](https://github.com/MithrilJS/mithril.js/pull/2207))
- Removed `valueOf` & `toString` methods ([#2150](https://github.com/MithrilJS/mithril.js/pull/2150))
- fixed `stream.end` propagation ([#2369](https://github.com/MithrilJS/mithril.js/pull/2369))
### 1.1.0
_2017-07-13_
- Move the "use strict" directive inside the IIFE [#1831](https://github.com/MithrilJS/mithril.js/issues/1831) ([#1893](https://github.com/MithrilJS/mithril.js/pull/1893))

View file

@ -25,6 +25,6 @@
- [Code of Conduct](code-of-conduct.md) - [Code of Conduct](code-of-conduct.md)
- Misc - Misc
- [Framework comparison](framework-comparison.md) - [Framework comparison](framework-comparison.md)
- [Change log/Migration](change-log.md) - [Change log/Migration](changelog.md)
- [v1 Documentation](https://mithril.js.org/archive/v1.1.7/) - [v1 Documentation](https://mithril.js.org/archive/v1.1.7/)
- [v0.2 Documentation](https://mithril.js.org/archive/v0.2.5/) - [v0.2 Documentation](https://mithril.js.org/archive/v0.2.5/)

View file

@ -4,7 +4,6 @@
- [Releasing a new Mithril version](#releasing-a-new-mithril-version) - [Releasing a new Mithril version](#releasing-a-new-mithril-version)
- [Updating mithril.js.org](#updating-mithriljsorg) - [Updating mithril.js.org](#updating-mithriljsorg)
- [Releasing a new ospec version](#releasing-a-new-ospec-version)
## Releasing a new Mithril version ## Releasing a new Mithril version
@ -18,7 +17,7 @@ $ git pull --rebase mithriljs next
``` ```
2. Determine patch level of the change 2. Determine patch level of the change
3. Update information in `docs/change-log.md` to match reality of the new version being prepared for release. 3. Update information in `docs/changelog.md` to match reality of the new version being prepared for release.
- Don't forget to add today's date under the version heading! - Don't forget to add today's date under the version heading!
4. Replace all existing references to `mithril@next` to `mithril` if moving from a release candidate to stable. 4. Replace all existing references to `mithril@next` to `mithril` if moving from a release candidate to stable.
- Note: if making an initial release candidate, don't forget to move all the playground snippets to pull from `mithril@next`! - Note: if making an initial release candidate, don't forget to move all the playground snippets to pull from `mithril@next`!
@ -96,11 +95,11 @@ $ git push mithriljs next
### Update the GitHub release ### Update the GitHub release
16. The GitHub Release will require a manual description & title to be added. I suggest coming up with a fun title & then copying the `docs/change-log.md` entry for the build. 16. The GitHub Release will require a manual description & title to be added. I suggest coming up with a fun title & then copying the `docs/changelog.md` entry for the build.
## Updating mithril.js.org ## Updating mithril.js.org
Fixes to documentation can land whenever, updates to the site are published via Travis. Fixes to documentation can land whenever, updates to the site are built and published via `scripts/update-docs.js`.
```bash ```bash
# These steps assume that MithrilJS/mithril.js is a git remote named "mithriljs" # These steps assume that MithrilJS/mithril.js is a git remote named "mithriljs"
@ -115,69 +114,9 @@ $ git checkout next -- ./docs
# Manually ensure that no new feature docs were added # Manually ensure that no new feature docs were added
$ git push mithriljs $ node scripts/update-docs
``` ```
After the Travis build completes the updated docs should appear on https://mithril.js.org in a few minutes. After the docs build completes, the updated docs should appear on https://mithril.js.org in a few minutes.
**Note:** When updating the stable version with a release candidate out, ***make sure to update the index + navigation to point to the new stable version!!!*** **Note:** When updating the stable version with a release candidate out, ***make sure to update the index + navigation to point to the new stable version!!!***
## Releasing a new ospec version
1. Ensure your local branch is up to date
```bash
$ git checkout next
$ git pull --rebase mithriljs next
```
2. Determine patch level of the change
3. Update `version` field in `ospec/package.json` to match new version being prepared for release.
4. Update `ospec/change-log.md` to match new version being prepared for release.
- Don't forget to add today's date under the version heading!
5. Commit changes to `next`
```
$ git add .
$ git commit -m "chore(ospec): ospec@<version>"
# Push to your branch
$ git push
# Push to MithrilJS/mithril.js
$ git push mithriljs next
```
### Merge from `next` to `master`
5. Switch to `master` and make sure it's up to date
```bash
$ git checkout master
$ git pull --rebase mithriljs master
```
6. merge `next` on top of it
```bash
$ git checkout next -- ./ospec
$ git add .
$ git commit -m "chore(ospec): ospec@<version>"
```
7. Ensure the tests are passing!
### Publish the release
8. Push the changes to `MithrilJS/mithril.js`
```bash
$ git push mithriljs master
```
9. Publish the changes to npm **from the `/ospec` folder**. That bit is important to ensure you don't accidentally ship a new Mithril release!
```bash
$ cd ./ospec
$ npm publish
```

View file

@ -3,6 +3,12 @@
if (typeof module !== "undefined") module["exports"] = m() if (typeof module !== "undefined") module["exports"] = m()
else window.o = m() else window.o = m()
})(function init(name) { })(function init(name) {
console.warn(
"Please switch to the `ospec` package to remove this warning and see " +
"the most recent features. Using the `ospec` bundled within Mithril " +
"is deprecated, and it will be removed in the next major release."
)
var spec = {}, subjects = [], results, only = [], ctx = spec, start, stack = 0, nextTickish, hasProcess = typeof process === "object", hasOwn = ({}).hasOwnProperty var spec = {}, subjects = [], results, only = [], ctx = spec, start, stack = 0, nextTickish, hasProcess = typeof process === "object", hasOwn = ({}).hasOwnProperty
var ospecFileName = getStackName(ensureStackTrace(new Error), /[\/\\](.*?):\d+:\d+/), timeoutStackName var ospecFileName = getStackName(ensureStackTrace(new Error), /[\/\\](.*?):\d+:\d+/), timeoutStackName
var globalTimeout = noTimeoutRightNow var globalTimeout = noTimeoutRightNow

View file

@ -6,7 +6,11 @@ var o, callAsync
if (typeof require !== "undefined") { if (typeof require !== "undefined") {
/* eslint-disable global-require */ /* eslint-disable global-require */
callAsync = require("../../test-utils/callAsync") callAsync = require("../../test-utils/callAsync")
var warn = console.warn
// Let's drop the warning to leave the console a little less noisy.
console.warn = function() {}
o = require("../ospec") o = require("../ospec")
console.warn = warn
/* eslint-enable global-require */ /* eslint-enable global-require */
} else { } else {
callAsync = typeof setImmediate === "function" ? setImmediate : setTimeout callAsync = typeof setImmediate === "function" ? setImmediate : setTimeout

31
package-lock.json generated
View file

@ -259,8 +259,7 @@
"balanced-match": { "balanced-match": {
"version": "1.0.0", "version": "1.0.0",
"resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz", "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz",
"integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=", "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c="
"dev": true
}, },
"bcrypt-pbkdf": { "bcrypt-pbkdf": {
"version": "1.0.2", "version": "1.0.2",
@ -291,7 +290,6 @@
"version": "1.1.11", "version": "1.1.11",
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz",
"integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==",
"dev": true,
"requires": { "requires": {
"balanced-match": "^1.0.0", "balanced-match": "^1.0.0",
"concat-map": "0.0.1" "concat-map": "0.0.1"
@ -523,8 +521,7 @@
"concat-map": { "concat-map": {
"version": "0.0.1", "version": "0.0.1",
"resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz",
"integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=", "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s="
"dev": true
}, },
"core-util-is": { "core-util-is": {
"version": "1.0.2", "version": "1.0.2",
@ -1152,8 +1149,7 @@
"fs.realpath": { "fs.realpath": {
"version": "1.0.0", "version": "1.0.0",
"resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz",
"integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=", "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8="
"dev": true
}, },
"fsevents": { "fsevents": {
"version": "2.1.0", "version": "2.1.0",
@ -1229,7 +1225,6 @@
"version": "7.1.4", "version": "7.1.4",
"resolved": "https://registry.npmjs.org/glob/-/glob-7.1.4.tgz", "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.4.tgz",
"integrity": "sha512-hkLPepehmnKk41pUGm3sYxoFs/umurYfYJCerbXEyFIWcAzvpipAgVkBqqT9RBKMGjnq6kMuyYwha6csxbiM1A==", "integrity": "sha512-hkLPepehmnKk41pUGm3sYxoFs/umurYfYJCerbXEyFIWcAzvpipAgVkBqqT9RBKMGjnq6kMuyYwha6csxbiM1A==",
"dev": true,
"requires": { "requires": {
"fs.realpath": "^1.0.0", "fs.realpath": "^1.0.0",
"inflight": "^1.0.4", "inflight": "^1.0.4",
@ -1437,7 +1432,6 @@
"version": "1.0.6", "version": "1.0.6",
"resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz",
"integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=",
"dev": true,
"requires": { "requires": {
"once": "^1.3.0", "once": "^1.3.0",
"wrappy": "1" "wrappy": "1"
@ -1446,8 +1440,7 @@
"inherits": { "inherits": {
"version": "2.0.4", "version": "2.0.4",
"resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz",
"integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ=="
"dev": true
}, },
"inquirer": { "inquirer": {
"version": "6.5.2", "version": "6.5.2",
@ -2035,7 +2028,6 @@
"version": "3.0.4", "version": "3.0.4",
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz",
"integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==",
"dev": true,
"requires": { "requires": {
"brace-expansion": "^1.1.7" "brace-expansion": "^1.1.7"
} }
@ -2226,7 +2218,6 @@
"version": "1.4.0", "version": "1.4.0",
"resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz",
"integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=",
"dev": true,
"requires": { "requires": {
"wrappy": "1" "wrappy": "1"
} }
@ -2260,6 +2251,14 @@
"integrity": "sha1-u+Z0BseaqFxc/sdm/lc0VV36EnQ=", "integrity": "sha1-u+Z0BseaqFxc/sdm/lc0VV36EnQ=",
"dev": true "dev": true
}, },
"ospec": {
"version": "4.1.1",
"resolved": "https://registry.npmjs.org/ospec/-/ospec-4.1.1.tgz",
"integrity": "sha512-fgWIk1eLDidfB+ixTo3PL3HuuO6iX2LhgWxdnWwqRu2rJdpTowgeAP0RHgt3DSUVyszs964fMuq1tB7Ov2C38A==",
"requires": {
"glob": "^7.1.3"
}
},
"p-finally": { "p-finally": {
"version": "2.0.1", "version": "2.0.1",
"resolved": "https://registry.npmjs.org/p-finally/-/p-finally-2.0.1.tgz", "resolved": "https://registry.npmjs.org/p-finally/-/p-finally-2.0.1.tgz",
@ -2306,8 +2305,7 @@
"path-is-absolute": { "path-is-absolute": {
"version": "1.0.1", "version": "1.0.1",
"resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz",
"integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=", "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18="
"dev": true
}, },
"path-key": { "path-key": {
"version": "2.0.1", "version": "2.0.1",
@ -3137,8 +3135,7 @@
"wrappy": { "wrappy": {
"version": "1.0.2", "version": "1.0.2",
"resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz",
"integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=", "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8="
"dev": true
}, },
"write": { "write": {
"version": "1.0.3", "version": "1.0.3",

View file

@ -5,7 +5,7 @@
"author": "Leo Horie", "author": "Leo Horie",
"license": "MIT", "license": "MIT",
"unpkg": "mithril.min.js", "unpkg": "mithril.min.js",
"repository": "MithrilJS/mithril.js", "repository": "github:MithrilJS/mithril.js",
"scripts": { "scripts": {
"precommit": "lint-staged", "precommit": "lint-staged",
"watch": "run-p watch:**", "watch": "run-p watch:**",
@ -24,7 +24,7 @@
"perf": "node performance/test-perf.js", "perf": "node performance/test-perf.js",
"pretest": "npm run lint", "pretest": "npm run lint",
"test": "run-s test:js", "test": "run-s test:js",
"test:js": "node ospec/bin/ospec", "test:js": "ospec",
"cover": "istanbul cover --print both ospec/bin/ospec", "cover": "istanbul cover --print both ospec/bin/ospec",
"release": "npm version -m 'v%s'", "release": "npm version -m 'v%s'",
"version": "npm run build && git add mithril.js mithril.min.js stream.js stream.min.js README.md" "version": "npm run build && git add mithril.js mithril.min.js stream.js stream.min.js README.md"
@ -45,6 +45,7 @@
"marked": "^0.7.0", "marked": "^0.7.0",
"minimist": "^1.2.0", "minimist": "^1.2.0",
"npm-run-all": "^4.1.5", "npm-run-all": "^4.1.5",
"ospec": "^4.0.1",
"pinpoint": "^1.1.0", "pinpoint": "^1.1.0",
"request": "^2.88.0", "request": "^2.88.0",
"request-promise-native": "^1.0.7", "request-promise-native": "^1.0.7",
@ -61,5 +62,7 @@
"git add" "git add"
] ]
}, },
"dependencies": {} "dependencies": {
"ospec": "*"
}
} }

View file

@ -1,6 +1,6 @@
"use strict" "use strict"
var o = require("../../ospec/ospec") var o = require("ospec")
var buildPathname = require("../../pathname/build") var buildPathname = require("../../pathname/build")
o.spec("buildPathname", function() { o.spec("buildPathname", function() {

View file

@ -1,6 +1,6 @@
"use strict" "use strict"
var o = require("../../ospec/ospec") var o = require("ospec")
var parsePathname = require("../../pathname/parse") var parsePathname = require("../../pathname/parse")
var compileTemplate = require("../../pathname/compileTemplate") var compileTemplate = require("../../pathname/compileTemplate")

View file

@ -1,6 +1,6 @@
"use strict" "use strict"
var o = require("../../ospec/ospec") var o = require("ospec")
var parsePathname = require("../../pathname/parse") var parsePathname = require("../../pathname/parse")
o.spec("parsePathname", function() { o.spec("parsePathname", function() {

View file

@ -6,7 +6,7 @@ var o, callAsync, Promise
if (typeof require !== "undefined") { if (typeof require !== "undefined") {
/* eslint-disable global-require */ /* eslint-disable global-require */
callAsync = require("../../test-utils/callAsync") callAsync = require("../../test-utils/callAsync")
o = require("../../ospec/ospec") o = require("ospec")
Promise = require("../../promise/polyfill") Promise = require("../../promise/polyfill")
/* eslint-enable global-require */ /* eslint-enable global-require */
} else { } else {

View file

@ -1,6 +1,6 @@
"use strict" "use strict"
var o = require("../../ospec/ospec") var o = require("ospec")
var buildQueryString = require("../../querystring/build") var buildQueryString = require("../../querystring/build")
o.spec("buildQueryString", function() { o.spec("buildQueryString", function() {

View file

@ -1,6 +1,6 @@
"use strict" "use strict"
var o = require("../../ospec/ospec") var o = require("ospec")
var parseQueryString = require("../../querystring/parse") var parseQueryString = require("../../querystring/parse")
o.spec("parseQueryString", function() { o.spec("parseQueryString", function() {

View file

@ -726,12 +726,18 @@ module.exports = function($window) {
//attrs //attrs
function setAttrs(vnode, attrs, ns) { function setAttrs(vnode, attrs, ns) {
// If you assign an input type that is not supported by IE 11 with an assignment expression, an error will occur.
//
// Also, the DOM does things to inputs based on the value, so it needs set first.
// See: https://github.com/MithrilJS/mithril.js/issues/2622
if (vnode.tag === "input" && attrs.type != null) vnode.dom.setAttribute("type", attrs.type)
var isFileInput = attrs != null && vnode.tag === "input" && attrs.type === "file"
for (var key in attrs) { for (var key in attrs) {
setAttr(vnode, key, null, attrs[key], ns) setAttr(vnode, key, null, attrs[key], ns, isFileInput)
} }
} }
function setAttr(vnode, key, old, value, ns) { function setAttr(vnode, key, old, value, ns, isFileInput) {
if (key === "key" || key === "is" || value == null || isLifecycleMethod(key) || (old === value && !isFormAttribute(vnode, key)) && typeof value !== "object") return if (key === "key" || key === "is" || value == null || isLifecycleMethod(key) || (old === value && !isFormAttribute(vnode, key)) && typeof value !== "object" || key === "type" && vnode.tag === "input") return
if (key[0] === "o" && key[1] === "n") return updateEvent(vnode, key, value) if (key[0] === "o" && key[1] === "n") return updateEvent(vnode, key, value)
if (key.slice(0, 6) === "xlink:") vnode.dom.setAttributeNS("http://www.w3.org/1999/xlink", key.slice(6), value) if (key.slice(0, 6) === "xlink:") vnode.dom.setAttributeNS("http://www.w3.org/1999/xlink", key.slice(6), value)
else if (key === "style") updateStyle(vnode.dom, old, value) else if (key === "style") updateStyle(vnode.dom, old, value)
@ -740,16 +746,18 @@ module.exports = function($window) {
// Only do the coercion if we're actually going to check the value. // Only do the coercion if we're actually going to check the value.
/* eslint-disable no-implicit-coercion */ /* eslint-disable no-implicit-coercion */
//setting input[value] to same value by typing on focused element moves cursor to end in Chrome //setting input[value] to same value by typing on focused element moves cursor to end in Chrome
if ((vnode.tag === "input" || vnode.tag === "textarea") && vnode.dom.value === "" + value && vnode.dom === activeElement()) return //setting input[type=file][value] to same value causes an error to be generated if it's non-empty
if ((vnode.tag === "input" || vnode.tag === "textarea") && vnode.dom.value === "" + value && (isFileInput || vnode.dom === activeElement())) return
//setting select[value] to same value while having select open blinks select dropdown in Chrome //setting select[value] to same value while having select open blinks select dropdown in Chrome
if (vnode.tag === "select" && old !== null && vnode.dom.value === "" + value) return if (vnode.tag === "select" && old !== null && vnode.dom.value === "" + value) return
//setting option[value] to same value while having select open blinks select dropdown in Chrome //setting option[value] to same value while having select open blinks select dropdown in Chrome
if (vnode.tag === "option" && old !== null && vnode.dom.value === "" + value) return if (vnode.tag === "option" && old !== null && vnode.dom.value === "" + value) return
//setting input[type=file][value] to different value is an error if it's non-empty
// Not ideal, but it at least works around the most common source of uncaught exceptions for now.
if (isFileInput && "" + value !== "") { console.error("`value` is read-only on file inputs!"); return }
/* eslint-enable no-implicit-coercion */ /* eslint-enable no-implicit-coercion */
} }
// If you assign an input type that is not supported by IE 11 with an assignment expression, an error will occur. vnode.dom[key] = value
if (vnode.tag === "input" && key === "type") vnode.dom.setAttribute(key, value)
else vnode.dom[key] = value
} else { } else {
if (typeof value === "boolean") { if (typeof value === "boolean") {
if (value) vnode.dom.setAttribute(key, "") if (value) vnode.dom.setAttribute(key, "")
@ -793,8 +801,14 @@ module.exports = function($window) {
} }
function updateAttrs(vnode, old, attrs, ns) { function updateAttrs(vnode, old, attrs, ns) {
if (attrs != null) { if (attrs != null) {
// If you assign an input type that is not supported by IE 11 with an assignment expression, an error will occur.
//
// Also, the DOM does things to inputs based on the value, so it needs set first.
// See: https://github.com/MithrilJS/mithril.js/issues/2622
if (vnode.tag === "input" && attrs.type != null) vnode.dom.setAttribute("type", attrs.type)
var isFileInput = vnode.tag === "input" && attrs.type === "file"
for (var key in attrs) { for (var key in attrs) {
setAttr(vnode, key, old && old[key], attrs[key], ns) setAttr(vnode, key, old && old[key], attrs[key], ns, isFileInput)
} }
} }
var val var val
@ -897,6 +911,7 @@ module.exports = function($window) {
//event //event
function updateEvent(vnode, key, value) { function updateEvent(vnode, key, value) {
if (vnode.events != null) { if (vnode.events != null) {
vnode.events._ = currentRedraw
if (vnode.events[key] === value) return if (vnode.events[key] === value) return
if (value != null && (typeof value === "function" || typeof value === "object")) { if (value != null && (typeof value === "function" || typeof value === "object")) {
if (vnode.events[key] == null) vnode.dom.addEventListener(key.slice(2), vnode.events, false) if (vnode.events[key] == null) vnode.dom.addEventListener(key.slice(2), vnode.events, false)

View file

@ -1,6 +1,6 @@
"use strict" "use strict"
var o = require("../../ospec/ospec") var o = require("ospec")
var domMock = require("../../test-utils/domMock") var domMock = require("../../test-utils/domMock")
var vdom = require("../../render/render") var vdom = require("../../render/render")

View file

@ -1,6 +1,6 @@
"use strict" "use strict"
var o = require("../../ospec/ospec") var o = require("ospec")
var components = require("../../test-utils/components") var components = require("../../test-utils/components")
var domMock = require("../../test-utils/domMock") var domMock = require("../../test-utils/domMock")
var vdom = require("../../render/render") var vdom = require("../../render/render")

View file

@ -1,6 +1,6 @@
"use strict" "use strict"
var o = require("../../ospec/ospec") var o = require("ospec")
var domMock = require("../../test-utils/domMock") var domMock = require("../../test-utils/domMock")
var vdom = require("../../render/render") var vdom = require("../../render/render")

View file

@ -1,6 +1,6 @@
"use strict" "use strict"
var o = require("../../ospec/ospec") var o = require("ospec")
var domMock = require("../../test-utils/domMock") var domMock = require("../../test-utils/domMock")
var vdom = require("../../render/render") var vdom = require("../../render/render")

View file

@ -1,6 +1,6 @@
"use strict" "use strict"
var o = require("../../ospec/ospec") var o = require("ospec")
var domMock = require("../../test-utils/domMock") var domMock = require("../../test-utils/domMock")
var vdom = require("../../render/render") var vdom = require("../../render/render")

View file

@ -1,6 +1,6 @@
"use strict" "use strict"
var o = require("../../ospec/ospec") var o = require("ospec")
var domMock = require("../../test-utils/domMock") var domMock = require("../../test-utils/domMock")
var vdom = require("../../render/render") var vdom = require("../../render/render")

View file

@ -1,6 +1,6 @@
"use strict" "use strict"
var o = require("../../ospec/ospec") var o = require("ospec")
var domMock = require("../../test-utils/domMock") var domMock = require("../../test-utils/domMock")
var vdom = require("../../render/render") var vdom = require("../../render/render")

View file

@ -1,18 +1,18 @@
"use strict" "use strict"
var o = require("../../ospec/ospec") var o = require("ospec")
var domMock = require("../../test-utils/domMock") var domMock = require("../../test-utils/domMock")
var vdom = require("../../render/render") var vdom = require("../../render/render")
o.spec("event", function() { o.spec("event", function() {
var $window, root, redraw, render var $window, root, redraw, render, reallyRender
o.beforeEach(function() { o.beforeEach(function() {
$window = domMock() $window = domMock()
root = $window.document.body root = $window.document.body
redraw = o.spy() redraw = o.spy()
var renderer = vdom($window) reallyRender = vdom($window)
render = function(dom, vnode) { render = function(dom, vnode) {
return renderer(dom, vnode, redraw) return reallyRender(dom, vnode, redraw)
} }
}) })
@ -355,4 +355,32 @@ o.spec("event", function() {
o(redraw.this).equals(undefined) o(redraw.this).equals(undefined)
o(redraw.args.length).equals(0) o(redraw.args.length).equals(0)
}) })
o("handles changed spy", function() {
var div1 = {tag: "div", attrs: {ontransitionend: function() {}}}
reallyRender(root, [div1], redraw)
var e = $window.document.createEvent("HTMLEvents")
e.initEvent("transitionend", true, true)
div1.dom.dispatchEvent(e)
o(redraw.callCount).equals(1)
o(redraw.this).equals(undefined)
o(redraw.args.length).equals(0)
var replacementRedraw = o.spy()
var div2 = {tag: "div", attrs: {ontransitionend: function() {}}}
reallyRender(root, [div2], replacementRedraw)
var e = $window.document.createEvent("HTMLEvents")
e.initEvent("transitionend", true, true)
div2.dom.dispatchEvent(e)
o(redraw.callCount).equals(1)
o(redraw.this).equals(undefined)
o(redraw.args.length).equals(0)
o(replacementRedraw.callCount).equals(1)
o(replacementRedraw.this).equals(undefined)
o(replacementRedraw.args.length).equals(0)
})
}) })

View file

@ -1,6 +1,6 @@
"use strict" "use strict"
var o = require("../../ospec/ospec") var o = require("ospec")
var fragment = require("../../render/fragment") var fragment = require("../../render/fragment")
var m = require("../../render/hyperscript") var m = require("../../render/hyperscript")

View file

@ -1,6 +1,6 @@
"use strict" "use strict"
var o = require("../../ospec/ospec") var o = require("ospec")
var m = require("../../render/hyperscript") var m = require("../../render/hyperscript")
o.spec("hyperscript", function() { o.spec("hyperscript", function() {

View file

@ -1,6 +1,6 @@
"use strict" "use strict"
var o = require("../../ospec/ospec") var o = require("ospec")
var domMock = require("../../test-utils/domMock") var domMock = require("../../test-utils/domMock")
var vdom = require("../../render/render") var vdom = require("../../render/render")
@ -86,6 +86,89 @@ o.spec("form inputs", function() {
o(updated.dom.checked).equals(true) o(updated.dom.checked).equals(true)
}) })
o("syncs file input value attribute if DOM value differs from vdom value and is empty", function() {
var input = {tag: "input", attrs: {type: "file", value: "", onclick: function() {}}}
var updated = {tag: "input", attrs: {type: "file", value: "", onclick: function() {}}}
var spy = o.spy()
var error = console.error
render(root, [input])
input.dom.value = "test.png"
try {
console.error = spy
render(root, [updated])
} finally {
console.error = error
}
o(updated.dom.value).equals("")
o(spy.callCount).equals(0)
})
o("warns and ignores file input value attribute if DOM value differs from vdom value and is non-empty", function() {
var input = {tag: "input", attrs: {type: "file", value: "", onclick: function() {}}}
var updated = {tag: "input", attrs: {type: "file", value: "other.png", onclick: function() {}}}
var spy = o.spy()
var error = console.error
render(root, [input])
input.dom.value = "test.png"
try {
console.error = spy
render(root, [updated])
} finally {
console.error = error
}
o(updated.dom.value).equals("test.png")
o(spy.callCount).equals(1)
})
o("retains file input value attribute if DOM value is the same as vdom value and is non-empty", function() {
var $window = domMock(o)
var render = vdom($window)
var root = $window.document.createElement("div")
$window.document.body.appendChild(root)
var input = {tag: "input", attrs: {type: "file", value: "", onclick: function() {}}}
var updated1 = {tag: "input", attrs: {type: "file", value: "test.png", onclick: function() {}}}
var updated2 = {tag: "input", attrs: {type: "file", value: "test.png", onclick: function() {}}}
var spy = o.spy()
var error = console.error
render(root, [input])
// Verify our assumptions about the outer element state
o($window.__getSpies(input.dom).valueSetter.callCount).equals(0)
input.dom.value = "test.png"
o($window.__getSpies(input.dom).valueSetter.callCount).equals(1)
try {
console.error = spy
render(root, [updated1])
} finally {
console.error = error
}
o(updated1.dom.value).equals("test.png")
o(spy.callCount).equals(0)
o($window.__getSpies(updated1.dom).valueSetter.callCount).equals(1)
try {
console.error = spy
render(root, [updated2])
} finally {
console.error = error
}
o(updated2.dom.value).equals("test.png")
o(spy.callCount).equals(0)
o($window.__getSpies(updated2.dom).valueSetter.callCount).equals(1)
})
}) })
o.spec("select", function() { o.spec("select", function() {

View file

@ -1,6 +1,6 @@
"use strict" "use strict"
var o = require("../../ospec/ospec") var o = require("ospec")
var Vnode = require("../../render/vnode") var Vnode = require("../../render/vnode")
o.spec("normalize", function() { o.spec("normalize", function() {

View file

@ -1,6 +1,6 @@
"use strict" "use strict"
var o = require("../../ospec/ospec") var o = require("ospec")
var Vnode = require("../../render/vnode") var Vnode = require("../../render/vnode")
o.spec("normalizeChildren", function() { o.spec("normalizeChildren", function() {

View file

@ -1,6 +1,6 @@
"use strict" "use strict"
var o = require("../../ospec/ospec") var o = require("ospec")
var m = require("../../render/hyperscript") var m = require("../../render/hyperscript")
var domMock = require("../../test-utils/domMock") var domMock = require("../../test-utils/domMock")
var vdom = require("../../render/render") var vdom = require("../../render/render")

View file

@ -1,6 +1,6 @@
"use strict" "use strict"
var o = require("../../ospec/ospec") var o = require("ospec")
var callAsync = require("../../test-utils/callAsync") var callAsync = require("../../test-utils/callAsync")
var components = require("../../test-utils/components") var components = require("../../test-utils/components")
var domMock = require("../../test-utils/domMock") var domMock = require("../../test-utils/domMock")

View file

@ -1,6 +1,6 @@
"use strict" "use strict"
var o = require("../../ospec/ospec") var o = require("ospec")
var components = require("../../test-utils/components") var components = require("../../test-utils/components")
var domMock = require("../../test-utils/domMock") var domMock = require("../../test-utils/domMock")
var vdom = require("../../render/render") var vdom = require("../../render/render")

View file

@ -1,6 +1,6 @@
"use strict" "use strict"
var o = require("../../ospec/ospec") var o = require("ospec")
var domMock = require("../../test-utils/domMock") var domMock = require("../../test-utils/domMock")
var vdom = require("../../render/render") var vdom = require("../../render/render")

View file

@ -1,6 +1,6 @@
"use strict" "use strict"
var o = require("../../ospec/ospec") var o = require("ospec")
var domMock = require("../../test-utils/domMock") var domMock = require("../../test-utils/domMock")
var vdom = require("../../render/render") var vdom = require("../../render/render")

View file

@ -1,6 +1,6 @@
"use strict" "use strict"
var o = require("../../ospec/ospec") var o = require("ospec")
var components = require("../../test-utils/components") var components = require("../../test-utils/components")
var domMock = require("../../test-utils/domMock") var domMock = require("../../test-utils/domMock")
var vdom = require("../../render/render") var vdom = require("../../render/render")

View file

@ -1,6 +1,6 @@
"use strict" "use strict"
var o = require("../../ospec/ospec") var o = require("ospec")
var domMock = require("../../test-utils/domMock") var domMock = require("../../test-utils/domMock")
var vdom = require("../../render/render") var vdom = require("../../render/render")

View file

@ -1,6 +1,6 @@
"use strict" "use strict"
var o = require("../../ospec/ospec") var o = require("ospec")
var m = require("../../render/hyperscript") var m = require("../../render/hyperscript")
var domMock = require("../../test-utils/domMock") var domMock = require("../../test-utils/domMock")
var vdom = require("../../render/render") var vdom = require("../../render/render")

View file

@ -1,6 +1,6 @@
"use strict" "use strict"
var o = require("../../ospec/ospec") var o = require("ospec")
var domMock = require("../../test-utils/domMock") var domMock = require("../../test-utils/domMock")
var vdom = require("../../render/render") var vdom = require("../../render/render")

View file

@ -1,6 +1,6 @@
"use strict" "use strict"
var o = require("../../ospec/ospec") var o = require("ospec")
var domMock = require("../../test-utils/domMock") var domMock = require("../../test-utils/domMock")
var vdom = require("../../render/render") var vdom = require("../../render/render")

View file

@ -1,6 +1,6 @@
"use strict" "use strict"
var o = require("../../ospec/ospec") var o = require("ospec")
var trust = require("../../render/trust") var trust = require("../../render/trust")
o.spec("trust", function() { o.spec("trust", function() {

View file

@ -1,6 +1,6 @@
"use strict" "use strict"
var o = require("../../ospec/ospec") var o = require("ospec")
var domMock = require("../../test-utils/domMock") var domMock = require("../../test-utils/domMock")
var vdom = require("../../render/render") var vdom = require("../../render/render")

View file

@ -1,6 +1,6 @@
"use strict" "use strict"
var o = require("../../ospec/ospec") var o = require("ospec")
var domMock = require("../../test-utils/domMock") var domMock = require("../../test-utils/domMock")
var vdom = require("../../render/render") var vdom = require("../../render/render")

View file

@ -1,6 +1,6 @@
"use strict" "use strict"
var o = require("../../ospec/ospec") var o = require("ospec")
var domMock = require("../../test-utils/domMock") var domMock = require("../../test-utils/domMock")
var vdom = require("../../render/render") var vdom = require("../../render/render")

View file

@ -1,6 +1,6 @@
"use strict" "use strict"
var o = require("../../ospec/ospec") var o = require("ospec")
var components = require("../../test-utils/components") var components = require("../../test-utils/components")
var domMock = require("../../test-utils/domMock") var domMock = require("../../test-utils/domMock")
var vdom = require("../../render/render") var vdom = require("../../render/render")

View file

@ -1,6 +1,6 @@
"use strict" "use strict"
var o = require("../../ospec/ospec") var o = require("ospec")
var domMock = require("../../test-utils/domMock") var domMock = require("../../test-utils/domMock")
var vdom = require("../../render/render") var vdom = require("../../render/render")

View file

@ -1,6 +1,6 @@
"use strict" "use strict"
var o = require("../../ospec/ospec") var o = require("ospec")
var domMock = require("../../test-utils/domMock") var domMock = require("../../test-utils/domMock")
var vdom = require("../../render/render") var vdom = require("../../render/render")

View file

@ -1,6 +1,6 @@
"use strict" "use strict"
var o = require("../../ospec/ospec") var o = require("ospec")
var xhrMock = require("../../test-utils/xhrMock") var xhrMock = require("../../test-utils/xhrMock")
var Request = require("../../request/request") var Request = require("../../request/request")
var PromisePolyfill = require("../../promise/promise") var PromisePolyfill = require("../../promise/promise")

View file

@ -1,6 +1,6 @@
"use strict" "use strict"
var o = require("../../ospec/ospec") var o = require("ospec")
var callAsync = require("../../test-utils/callAsync") var callAsync = require("../../test-utils/callAsync")
var xhrMock = require("../../test-utils/xhrMock") var xhrMock = require("../../test-utils/xhrMock")
var Request = require("../../request/request") var Request = require("../../request/request")

View file

@ -143,7 +143,7 @@ class Generator {
let anchor = text.toLowerCase() let anchor = text.toLowerCase()
.replace(/<(\/?)code>/g, "") .replace(/<(\/?)code>/g, "")
.replace(/<a.*?>.+?<\/a>/g, "") .replace(/<a.*?>.+?<\/a>/g, "")
.replace(/\.|\[|\]|&quot;|\/|\(|\)/g, "") .replace(/[.`[\]\/()]|&quot;/g, "")
.replace(/\s/g, "-"); .replace(/\s/g, "-");
const anchorId = anchorIds.get(anchor) const anchorId = anchorIds.get(anchor)

View file

@ -278,8 +278,8 @@ async function lintAll({useCache}) {
await new Promise((resolve, reject) => { await new Promise((resolve, reject) => {
const glob = new Glob(path.resolve(__dirname, "../**/*.md"), { const glob = new Glob(path.resolve(__dirname, "../**/*.md"), {
ignore: [ ignore: [
"**/change-log.md", "**/changelog.md",
"**/migration-v02x.md", "**/migration-*.md",
"**/node_modules/**", "**/node_modules/**",
], ],
nodir: true, nodir: true,
@ -304,10 +304,10 @@ if (require.main === module) {
exec: lintAll, exec: lintAll,
watch() { watch() {
require("chokidar") require("chokidar")
.watch(path.resolve(__dirname, "../**/*.md"), { .watch(path.resolve(__dirname, "../docs/**/*.md"), {
ignored: [ ignore: [
"**/change-log.md", "**/changelog.md",
"**/migration-v02x.md", "**/migration-*.md",
"**/node_modules/**", "**/node_modules/**",
], ],
}) })

View file

@ -123,7 +123,7 @@ async function release({increment, preid, publish}) {
console.error(` console.error(`
Copy the parts listed in "Upcoming" to a new section "### v${version}" in Copy the parts listed in "Upcoming" to a new section "### v${version}" in
docs/change-log.md and clear that section out. Also, add today's date under the docs/changelog.md and clear that section out. Also, add today's date under the
new section's heading to match the others and don't forget to update the table new section's heading to match the others and don't forget to update the table
of contents accordingly. of contents accordingly.
`) `)
@ -138,7 +138,7 @@ of contents accordingly.
// Verify the changelog was updated, and give a chance to retry if it's // Verify the changelog was updated, and give a chance to retry if it's
// prematurely continued. // prematurely continued.
const changes = getChanges() const changes = getChanges()
const isChangelog = /^[ M][ M] docs\/change-log\.md$/ const isChangelog = /^[ M][ M] docs\/changelog\.md$/
const errors = [] const errors = []
console.log("changes", changes) console.log("changes", changes)

View file

@ -2,22 +2,24 @@
const fs = require("fs") const fs = require("fs")
const util = require("util") const util = require("util")
const path = require("path")
const access = util.promisify(fs.access) const access = util.promisify(fs.access)
const writeFile = util.promisify(fs.writeFile) const writeFile = util.promisify(fs.writeFile)
const unlink = util.promisify(fs.unlink) const unlink = util.promisify(fs.unlink)
const o = require("../../ospec/ospec") const o = require("ospec")
const bundle = require("../_bundler-impl") const bundle = require("../_bundler-impl")
o.spec("bundler", async () => { o.spec("bundler", async () => {
let filesCreated let filesCreated
const ns = "./" const root = path.resolve(__dirname, "../..")
const p = (file) => path.join(root, file)
async function write(filepath, data) { async function write(filepath, data) {
try { try {
await access(ns + filepath) await access(p(filepath))
} catch (e) { } catch (e) {
return writeFile(ns + filepath, data, "utf8") return writeFile(p(filepath), data, "utf8")
} }
throw new Error(`Don't call \`write('${filepath}')\`. Cannot overwrite file.`) throw new Error(`Don't call \`write('${filepath}')\`. Cannot overwrite file.`)
} }
@ -28,7 +30,7 @@ o.spec("bundler", async () => {
} }
o.afterEach(() => Promise.all( o.afterEach(() => Promise.all(
filesCreated.map((filepath) => unlink(ns + filepath)) filesCreated.map((filepath) => unlink(p(filepath)))
)) ))
o("relative imports works", async () => { o("relative imports works", async () => {
@ -37,7 +39,7 @@ o.spec("bundler", async () => {
"b.js": "module.exports = 1", "b.js": "module.exports = 1",
}) })
o(await bundle(ns + "a.js")).equals(";(function() {\nvar b = 1\n}());") o(await bundle(p("a.js"))).equals(";(function() {\nvar b = 1\n}());")
}) })
o("relative imports works with semicolons", async () => { o("relative imports works with semicolons", async () => {
await setup({ await setup({
@ -45,7 +47,7 @@ o.spec("bundler", async () => {
"b.js": "module.exports = 1;", "b.js": "module.exports = 1;",
}) })
o(await bundle(ns + "a.js")).equals(";(function() {\nvar b = 1;\n}());") o(await bundle(p("a.js"))).equals(";(function() {\nvar b = 1;\n}());")
}) })
o("relative imports works with let", async () => { o("relative imports works with let", async () => {
await setup({ await setup({
@ -53,7 +55,7 @@ o.spec("bundler", async () => {
"b.js": "module.exports = 1", "b.js": "module.exports = 1",
}) })
o(await bundle(ns + "a.js")).equals(";(function() {\nlet b = 1\n}());") o(await bundle(p("a.js"))).equals(";(function() {\nlet b = 1\n}());")
}) })
o("relative imports works with const", async () => { o("relative imports works with const", async () => {
await setup({ await setup({
@ -61,7 +63,7 @@ o.spec("bundler", async () => {
"b.js": "module.exports = 1", "b.js": "module.exports = 1",
}) })
o(await bundle(ns + "a.js")).equals(";(function() {\nconst b = 1\n}());") o(await bundle(p("a.js"))).equals(";(function() {\nconst b = 1\n}());")
}) })
o("relative imports works with assignment", async () => { o("relative imports works with assignment", async () => {
await setup({ await setup({
@ -69,7 +71,7 @@ o.spec("bundler", async () => {
"b.js": "module.exports = 1", "b.js": "module.exports = 1",
}) })
o(await bundle(ns + "a.js")).equals(";(function() {\nvar a = {}\na.b = 1\n}());") o(await bundle(p("a.js"))).equals(";(function() {\nvar a = {}\na.b = 1\n}());")
}) })
o("relative imports works with reassignment", async () => { o("relative imports works with reassignment", async () => {
await setup({ await setup({
@ -77,7 +79,7 @@ o.spec("bundler", async () => {
"b.js": "module.exports = 1", "b.js": "module.exports = 1",
}) })
o(await bundle(ns + "a.js")).equals(";(function() {\nvar b = {}\nb = 1\n}());") o(await bundle(p("a.js"))).equals(";(function() {\nvar b = {}\nb = 1\n}());")
}) })
o("relative imports removes extra use strict", async () => { o("relative imports removes extra use strict", async () => {
await setup({ await setup({
@ -85,7 +87,7 @@ o.spec("bundler", async () => {
"b.js": '"use strict"\nmodule.exports = 1', "b.js": '"use strict"\nmodule.exports = 1',
}) })
o(await bundle(ns + "a.js")).equals(';(function() {\n"use strict"\nvar b = 1\n}());') o(await bundle(p("a.js"))).equals(';(function() {\n"use strict"\nvar b = 1\n}());')
}) })
o("relative imports removes extra use strict using single quotes", async () => { o("relative imports removes extra use strict using single quotes", async () => {
await setup({ await setup({
@ -93,7 +95,7 @@ o.spec("bundler", async () => {
"b.js": "'use strict'\nmodule.exports = 1", "b.js": "'use strict'\nmodule.exports = 1",
}) })
o(await bundle(ns + "a.js")).equals(";(function() {\n'use strict'\nvar b = 1\n}());") o(await bundle(p("a.js"))).equals(";(function() {\n'use strict'\nvar b = 1\n}());")
}) })
o("relative imports removes extra use strict using mixed quotes", async () => { o("relative imports removes extra use strict using mixed quotes", async () => {
await setup({ await setup({
@ -101,7 +103,7 @@ o.spec("bundler", async () => {
"b.js": "'use strict'\nmodule.exports = 1", "b.js": "'use strict'\nmodule.exports = 1",
}) })
o(await bundle(ns + "a.js")).equals(';(function() {\n"use strict"\nvar b = 1\n}());') o(await bundle(p("a.js"))).equals(';(function() {\n"use strict"\nvar b = 1\n}());')
}) })
o("works w/ window", async () => { o("works w/ window", async () => {
await setup({ await setup({
@ -109,7 +111,7 @@ o.spec("bundler", async () => {
"b.js": "module.exports = function() {return a}", "b.js": "module.exports = function() {return a}",
}) })
o(await bundle(ns + "a.js")).equals(";(function() {\nwindow.a = 1\nvar b = function() {return a}\n}());") o(await bundle(p("a.js"))).equals(";(function() {\nwindow.a = 1\nvar b = function() {return a}\n}());")
}) })
o("works without assignment", async () => { o("works without assignment", async () => {
await setup({ await setup({
@ -117,7 +119,7 @@ o.spec("bundler", async () => {
"b.js": "1 + 1", "b.js": "1 + 1",
}) })
o(await bundle(ns + "a.js")).equals(";(function() {\n1 + 1\n}());") o(await bundle(p("a.js"))).equals(";(function() {\n1 + 1\n}());")
}) })
o("works if used fluently", async () => { o("works if used fluently", async () => {
await setup({ await setup({
@ -125,7 +127,7 @@ o.spec("bundler", async () => {
"b.js": "module.exports = []", "b.js": "module.exports = []",
}) })
o(await bundle(ns + "a.js")).equals(";(function() {\nvar _0 = []\nvar b = _0.toString()\n}());") o(await bundle(p("a.js"))).equals(";(function() {\nvar _0 = []\nvar b = _0.toString()\n}());")
}) })
o("works if used fluently w/ multiline", async () => { o("works if used fluently w/ multiline", async () => {
await setup({ await setup({
@ -133,7 +135,7 @@ o.spec("bundler", async () => {
"b.js": "module.exports = []", "b.js": "module.exports = []",
}) })
o(await bundle(ns + "a.js")).equals(";(function() {\nvar _0 = []\nvar b = _0\n\t.toString()\n}());") o(await bundle(p("a.js"))).equals(";(function() {\nvar _0 = []\nvar b = _0\n\t.toString()\n}());")
}) })
o("works if used w/ curry", async () => { o("works if used w/ curry", async () => {
await setup({ await setup({
@ -141,7 +143,7 @@ o.spec("bundler", async () => {
"b.js": "module.exports = function() {}", "b.js": "module.exports = function() {}",
}) })
o(await bundle(ns + "a.js")).equals(";(function() {\nvar _0 = function() {}\nvar b = _0()\n}());") o(await bundle(p("a.js"))).equals(";(function() {\nvar _0 = function() {}\nvar b = _0()\n}());")
}) })
o("works if used w/ curry w/ multiline", async () => { o("works if used w/ curry w/ multiline", async () => {
await setup({ await setup({
@ -149,7 +151,7 @@ o.spec("bundler", async () => {
"b.js": "module.exports = function() {}", "b.js": "module.exports = function() {}",
}) })
o(await bundle(ns + "a.js")).equals(";(function() {\nvar _0 = function() {}\nvar b = _0\n()\n}());") o(await bundle(p("a.js"))).equals(";(function() {\nvar _0 = function() {}\nvar b = _0\n()\n}());")
}) })
o("works if used fluently in one place and not in another", async () => { o("works if used fluently in one place and not in another", async () => {
await setup({ await setup({
@ -158,7 +160,7 @@ o.spec("bundler", async () => {
"c.js": 'var b = require("./b")\nmodule.exports = function() {return b}', "c.js": 'var b = require("./b")\nmodule.exports = function() {return b}',
}) })
o(await bundle(ns + "a.js")).equals(";(function() {\nvar _0 = []\nvar b = _0.toString()\nvar b0 = _0\nvar c = function() {return b0}\n}());") o(await bundle(p("a.js"))).equals(";(function() {\nvar _0 = []\nvar b = _0.toString()\nvar b0 = _0\nvar c = function() {return b0}\n}());")
}) })
o("works if used in sequence", async () => { o("works if used in sequence", async () => {
await setup({ await setup({
@ -167,7 +169,7 @@ o.spec("bundler", async () => {
"c.js": "var x\nmodule.exports = 2", "c.js": "var x\nmodule.exports = 2",
}) })
o(await bundle(ns + "a.js")).equals(";(function() {\nvar b = 1\nvar x\nvar c = 2\n}());") o(await bundle(p("a.js"))).equals(";(function() {\nvar b = 1\nvar x\nvar c = 2\n}());")
}) })
o("works if assigned to property", async () => { o("works if assigned to property", async () => {
await setup({ await setup({
@ -176,7 +178,7 @@ o.spec("bundler", async () => {
"c.js": "var cc = 2\nmodule.exports = cc", "c.js": "var cc = 2\nmodule.exports = cc",
}) })
o(await bundle(ns + "a.js")).equals(";(function() {\nvar x = {}\nvar bb = 1\nx.b = bb\nvar cc = 2\nx.c = cc\n}());") o(await bundle(p("a.js"))).equals(";(function() {\nvar x = {}\nvar bb = 1\nx.b = bb\nvar cc = 2\nx.c = cc\n}());")
}) })
o("works if assigned to property using bracket notation", async () => { o("works if assigned to property using bracket notation", async () => {
await setup({ await setup({
@ -185,7 +187,7 @@ o.spec("bundler", async () => {
"c.js": "var cc = 2\nmodule.exports = cc", "c.js": "var cc = 2\nmodule.exports = cc",
}) })
o(await bundle(ns + "a.js")).equals(';(function() {\nvar x = {}\nvar bb = 1\nx["b"] = bb\nvar cc = 2\nx["c"] = cc\n}());') o(await bundle(p("a.js"))).equals(';(function() {\nvar x = {}\nvar bb = 1\nx["b"] = bb\nvar cc = 2\nx["c"] = cc\n}());')
}) })
o("works if collision", async () => { o("works if collision", async () => {
await setup({ await setup({
@ -193,7 +195,7 @@ o.spec("bundler", async () => {
"b.js": "var b = 1\nmodule.exports = 2", "b.js": "var b = 1\nmodule.exports = 2",
}) })
o(await bundle(ns + "a.js")).equals(";(function() {\nvar b0 = 1\nvar b = 2\n}());") o(await bundle(p("a.js"))).equals(";(function() {\nvar b0 = 1\nvar b = 2\n}());")
}) })
o("works if multiple aliases", async () => { o("works if multiple aliases", async () => {
await setup({ await setup({
@ -202,7 +204,7 @@ o.spec("bundler", async () => {
"c.js": "var b = {}\nmodule.exports = b", "c.js": "var b = {}\nmodule.exports = b",
}) })
o(await bundle(ns + "a.js")).equals(";(function() {\nvar b = {}\nb.x = 1\n}());") o(await bundle(p("a.js"))).equals(";(function() {\nvar b = {}\nb.x = 1\n}());")
}) })
o("works if multiple collision", async () => { o("works if multiple collision", async () => {
await setup({ await setup({
@ -212,7 +214,7 @@ o.spec("bundler", async () => {
"d.js": "var a = 3\nmodule.exports = a", "d.js": "var a = 3\nmodule.exports = a",
}) })
o(await bundle(ns + "a.js")).equals(";(function() {\nvar a = 1\nvar b = a\nvar a0 = 2\nvar c = a0\nvar a1 = 3\nvar d = a1\n}());") o(await bundle(p("a.js"))).equals(";(function() {\nvar a = 1\nvar b = a\nvar a0 = 2\nvar c = a0\nvar a1 = 3\nvar d = a1\n}());")
}) })
o("works if included multiple times", async () => { o("works if included multiple times", async () => {
await setup({ await setup({
@ -221,7 +223,7 @@ o.spec("bundler", async () => {
"c.js": 'var a = require("./a").toString()\nvar b = require("./b")', "c.js": 'var a = require("./a").toString()\nvar b = require("./b")',
}) })
o(await bundle(ns + "c.js")).equals(";(function() {\nvar _0 = 123\nvar a = _0.toString()\nvar a0 = _0.toString()\nvar b = a0\n}());") o(await bundle(p("c.js"))).equals(";(function() {\nvar _0 = 123\nvar a = _0.toString()\nvar a0 = _0.toString()\nvar b = a0\n}());")
}) })
o("works if included multiple times reverse", async () => { o("works if included multiple times reverse", async () => {
await setup({ await setup({
@ -230,7 +232,7 @@ o.spec("bundler", async () => {
"c.js": 'var b = require("./b")\nvar a = require("./a").toString()', "c.js": 'var b = require("./b")\nvar a = require("./a").toString()',
}) })
o(await bundle(ns + "c.js")).equals(";(function() {\nvar _0 = 123\nvar a0 = _0.toString()\nvar b = a0\nvar a = _0.toString()\n}());") o(await bundle(p("c.js"))).equals(";(function() {\nvar _0 = 123\nvar a0 = _0.toString()\nvar b = a0\nvar a = _0.toString()\n}());")
}) })
o("reuses binding if possible", async () => { o("reuses binding if possible", async () => {
await setup({ await setup({
@ -240,7 +242,7 @@ o.spec("bundler", async () => {
"d.js": "module.exports = 1", "d.js": "module.exports = 1",
}) })
o(await bundle(ns + "a.js")).equals(";(function() {\nvar d = 1\nvar b = function() {return d + 1}\nvar c = function() {return d + 2}\n}());") o(await bundle(p("a.js"))).equals(";(function() {\nvar d = 1\nvar b = function() {return d + 1}\nvar c = function() {return d + 2}\n}());")
}) })
o("disambiguates conflicts if imported collides with itself", async () => { o("disambiguates conflicts if imported collides with itself", async () => {
await setup({ await setup({
@ -248,7 +250,7 @@ o.spec("bundler", async () => {
"b.js": "var b = 1\nmodule.exports = function() {return b}", "b.js": "var b = 1\nmodule.exports = function() {return b}",
}) })
o(await bundle(ns + "a.js")).equals(";(function() {\nvar b0 = 1\nvar b = function() {return b0}\n}());") o(await bundle(p("a.js"))).equals(";(function() {\nvar b0 = 1\nvar b = function() {return b0}\n}());")
}) })
o("disambiguates conflicts if imported collides with something else", async () => { o("disambiguates conflicts if imported collides with something else", async () => {
await setup({ await setup({
@ -256,7 +258,7 @@ o.spec("bundler", async () => {
"b.js": "var a = 2\nmodule.exports = function() {return a}", "b.js": "var a = 2\nmodule.exports = function() {return a}",
}) })
o(await bundle(ns + "a.js")).equals(";(function() {\nvar a = 1\nvar a0 = 2\nvar b = function() {return a0}\n}());") o(await bundle(p("a.js"))).equals(";(function() {\nvar a = 1\nvar a0 = 2\nvar b = function() {return a0}\n}());")
}) })
o("disambiguates conflicts if imported collides with function declaration", async () => { o("disambiguates conflicts if imported collides with function declaration", async () => {
await setup({ await setup({
@ -264,7 +266,7 @@ o.spec("bundler", async () => {
"b.js": "var a = 2\nmodule.exports = function() {return a}", "b.js": "var a = 2\nmodule.exports = function() {return a}",
}) })
o(await bundle(ns + "a.js")).equals(";(function() {\nfunction a() {}\nvar a0 = 2\nvar b = function() {return a0}\n}());") o(await bundle(p("a.js"))).equals(";(function() {\nfunction a() {}\nvar a0 = 2\nvar b = function() {return a0}\n}());")
}) })
o("disambiguates conflicts if imported collides with another module's private", async () => { o("disambiguates conflicts if imported collides with another module's private", async () => {
await setup({ await setup({
@ -273,7 +275,7 @@ o.spec("bundler", async () => {
"c.js": "var a = 2\nmodule.exports = function() {return a}", "c.js": "var a = 2\nmodule.exports = function() {return a}",
}) })
o(await bundle(ns + "a.js")).equals(";(function() {\nvar a = 1\nvar b = function() {return a}\nvar a0 = 2\nvar c = function() {return a0}\n}());") o(await bundle(p("a.js"))).equals(";(function() {\nvar a = 1\nvar b = function() {return a}\nvar a0 = 2\nvar c = function() {return a0}\n}());")
}) })
o("does not mess up strings", async () => { o("does not mess up strings", async () => {
await setup({ await setup({
@ -281,7 +283,7 @@ o.spec("bundler", async () => {
"b.js": 'var b = "b b b \\" b"\nmodule.exports = function() {return b}', "b.js": 'var b = "b b b \\" b"\nmodule.exports = function() {return b}',
}) })
o(await bundle(ns + "a.js")).equals(';(function() {\nvar b0 = "b b b \\\" b"\nvar b = function() {return b0}\n}());') o(await bundle(p("a.js"))).equals(';(function() {\nvar b0 = "b b b \\\" b"\nvar b = function() {return b0}\n}());')
}) })
o("does not mess up properties", async () => { o("does not mess up properties", async () => {
await setup({ await setup({
@ -289,6 +291,6 @@ o.spec("bundler", async () => {
"b.js": "var b = {b: 1}\nmodule.exports = function() {return b.b}", "b.js": "var b = {b: 1}\nmodule.exports = function() {return b.b}",
}) })
o(await bundle(ns + "a.js")).equals(";(function() {\nvar b0 = {b: 1}\nvar b = function() {return b0.b}\n}());") o(await bundle(p("a.js"))).equals(";(function() {\nvar b0 = {b: 1}\nvar b = function() {return b0.b}\n}());")
}) })
}) })

View file

@ -1,21 +0,0 @@
The MIT License (MIT)
Copyright (c) 2017 Leo Horie
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

View file

@ -1,6 +0,0 @@
mithril-stream [![npm Version](https://img.shields.io/npm/v/mithril-stream.svg)](https://www.npmjs.com/package/mithril-stream) [![npm License](https://img.shields.io/npm/l/mithril-stream.svg)](https://www.npmjs.com/package/mithril-stream)
==============
Mithril's `m.stream` as a standalone module.
See [mithril.js.org/stream.html](https://mithril.js.org/stream.html) for docs/usage.

View file

@ -1,22 +0,0 @@
# Change log for stream
- [Upcoming](#upcoming)
- [v2.0.0](#v200)
- [v1.1.0](#v110)
### Upcoming...
### 2.0.0
_2019-02-07_
- when a stream conditionally returns HALT, dependant stream will also end ([#2200](https://github.com/MithrilJS/mithril.js/pull/2200), [#2369](https://github.com/MithrilJS/mithril.js/pull/2369))
- Add `stream.lift` as a user-friendly alternative to `merge -> map` or `combine` ([#1944](https://github.com/MithrilJS/mithril.js/issues/1944))
- renamed HALT to SKIP ([#2207](https://github.com/MithrilJS/mithril.js/pull/2207))
- rewrote implementation ([#2207](https://github.com/MithrilJS/mithril.js/pull/2207))
- Removed `valueOf` & `toString` methods ([#2150](https://github.com/MithrilJS/mithril.js/pull/2150))
- fixed `stream.end` propagation ([#2369](https://github.com/MithrilJS/mithril.js/pull/2369))
### 1.1.0
_2017-07-13_
- Move the "use strict" directive inside the IIFE [#1831](https://github.com/MithrilJS/mithril.js/issues/1831) ([#1893](https://github.com/MithrilJS/mithril.js/pull/1893))

View file

@ -1,13 +0,0 @@
{
"name": "mithril-stream",
"version": "2.0.0",
"description": "Streaming data, mithril-style",
"main": "stream.js",
"directories": {
"test": "tests"
},
"keywords": [ "stream", "reactive", "data" ],
"author": "Leo Horie <lhorie@hotmail.com>",
"license": "MIT",
"repository": "MithrilJS/mithril.js"
}

View file

@ -1,6 +1,6 @@
"use strict" "use strict"
var o = require("../../ospec/ospec") var o = require("ospec")
var stream = require("../stream") var stream = require("../stream")
o.spec("scan", function() { o.spec("scan", function() {

View file

@ -1,6 +1,6 @@
"use strict" "use strict"
var o = require("../../ospec/ospec") var o = require("ospec")
var stream = require("../stream") var stream = require("../stream")
o.spec("scanMerge", function() { o.spec("scanMerge", function() {

View file

@ -1,6 +1,6 @@
"use strict" "use strict"
var o = require("../../ospec/ospec") var o = require("ospec")
var Stream = require("../stream") var Stream = require("../stream")
o.spec("stream", function() { o.spec("stream", function() {

View file

@ -495,6 +495,37 @@ module.exports = function(options) {
set: valueSetter, set: valueSetter,
enumerable: true, enumerable: true,
}) })
Object.defineProperty(element, "valueAsDate", {
get: function() {
if (this.getAttribute("type") !== "date") return null
return new Date(value).getTime()
},
set: function(v) {
if (this.getAttribute("type") !== "date") throw new Error("invalid state")
var time = new Date(v).getTime()
return valueSetter(isNaN(time) ? "" : new Date(time).toUTCString())
},
enumerable: true,
})
Object.defineProperty(element, "valueAsNumber", {
get: function() {
switch (this.getAttribute("type")) {
case "date": return new Date(value).getTime()
case "number": return new Date(value).getTime()
default: return NaN
}
},
set: function(v) {
v = Number(v)
if (!isNaN(v) && !isFinite(v)) throw new TypeError("infinite value")
switch (this.getAttribute("type")) {
case "date": return valueSetter(isNaN(v) ? "" : new Date(v).toUTCString())
case "number": return valueSetter(String(value))
default: throw new Error("invalid state")
}
},
enumerable: true,
})
// we currently emulate the non-ie behavior, but emulating ie may be more useful (throw when an invalid type is set) // we currently emulate the non-ie behavior, but emulating ie may be more useful (throw when an invalid type is set)
var typeSetter = spy(function(v) { var typeSetter = spy(function(v) {

View file

@ -1,6 +1,6 @@
"use strict" "use strict"
var o = require("../../ospec/ospec") var o = require("ospec")
var browserMock = require("../../test-utils/browserMock") var browserMock = require("../../test-utils/browserMock")
var callAsync = require("../../test-utils/callAsync") var callAsync = require("../../test-utils/callAsync")
o.spec("browserMock", function() { o.spec("browserMock", function() {

View file

@ -1,6 +1,6 @@
"use strict" "use strict"
var o = require("../../ospec/ospec") var o = require("ospec")
var callAsync = require("../../test-utils/callAsync") var callAsync = require("../../test-utils/callAsync")
o.spec("callAsync", function() { o.spec("callAsync", function() {

View file

@ -1,6 +1,6 @@
"use strict" "use strict"
var o = require("../../ospec/ospec") var o = require("ospec")
var components = require("../../test-utils/components") var components = require("../../test-utils/components")
o.spec("test-utils/components", function() { o.spec("test-utils/components", function() {

View file

@ -1,6 +1,6 @@
"use strict" "use strict"
var o = require("../../ospec/ospec") var o = require("ospec")
var domMock = require("../../test-utils/domMock") var domMock = require("../../test-utils/domMock")
o.spec("domMock", function() { o.spec("domMock", function() {

View file

@ -1,6 +1,6 @@
"use strict" "use strict"
var o = require("../../ospec/ospec") var o = require("ospec")
var parseURL = require("../../test-utils/parseURL") var parseURL = require("../../test-utils/parseURL")
o.spec("parseURL", function() { o.spec("parseURL", function() {

View file

@ -1,6 +1,6 @@
"use strict" "use strict"
var o = require("../../ospec/ospec") var o = require("ospec")
var pushStateMock = require("../../test-utils/pushStateMock") var pushStateMock = require("../../test-utils/pushStateMock")
var callAsync = require("../../test-utils/callAsync") var callAsync = require("../../test-utils/callAsync")
o.spec("pushStateMock", function() { o.spec("pushStateMock", function() {

View file

@ -1,6 +1,6 @@
"use strict" "use strict"
var o = require("../../ospec/ospec") var o = require("ospec")
var throttleMocker = require("../../test-utils/throttleMock") var throttleMocker = require("../../test-utils/throttleMock")
o.spec("throttleMock", function() { o.spec("throttleMock", function() {

View file

@ -1,6 +1,6 @@
"use strict" "use strict"
var o = require("../../ospec/ospec") var o = require("ospec")
var xhrMock = require("../../test-utils/xhrMock") var xhrMock = require("../../test-utils/xhrMock")
var parseQueryString = require("../../querystring/parse") var parseQueryString = require("../../querystring/parse")

View file

@ -1,12 +1,13 @@
"use strict" "use strict"
var o = require("../ospec/ospec") var o = require("ospec")
var browserMock = require("../test-utils/browserMock") var browserMock = require("../test-utils/browserMock")
var components = require("../test-utils/components") var components = require("../test-utils/components")
o.spec("api", function() { o.spec("api", function() {
var FRAME_BUDGET = Math.floor(1000 / 60) var FRAME_BUDGET = Math.floor(1000 / 60)
var mock = browserMock(), root var mock = browserMock(), root
mock.setTimeout = setTimeout
if (typeof global !== "undefined") { if (typeof global !== "undefined") {
global.window = mock global.window = mock
global.requestAnimationFrame = mock.requestAnimationFrame global.requestAnimationFrame = mock.requestAnimationFrame

View file

@ -1,6 +1,6 @@
"use strict" "use strict"
var o = require("../../ospec/ospec") var o = require("ospec")
var censor = require("../../util/censor") var censor = require("../../util/censor")
o.spec("censor", function() { o.spec("censor", function() {