Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions index.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ var hyperscript = require("./hyperscript")
var request = require("./request")
var mountRedraw = require("./mount-redraw")
var domFor = require("./render/domFor")
var errorManager = require("./util/errorManager")

var m = function m() { return hyperscript.apply(this, arguments) }
m.m = hyperscript
Expand All @@ -22,5 +23,6 @@ m.buildPathname = require("./pathname/build")
m.vnode = require("./render/vnode")
m.censor = require("./util/censor")
m.domFor = domFor.domFor
m.errorManager = errorManager.em

module.exports = m
22 changes: 16 additions & 6 deletions render/render.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@

var Vnode = require("../render/vnode")
var df = require("../render/domFor")
var errorManager = require("../util/errorManager").em

var delayedRemoval = df.delayedRemoval
var domFor = df.domFor

Expand Down Expand Up @@ -151,8 +153,12 @@ module.exports = function($window) {
}
initLifecycle(vnode.state, vnode, hooks)
if (vnode.attrs != null) initLifecycle(vnode.attrs, vnode, hooks)
vnode.instance = Vnode.normalize(callHook.call(vnode.state.view, vnode))
if (vnode.instance === vnode) throw Error("A view cannot return the vnode it received as argument")
try {
vnode.instance = Vnode.normalize(callHook.call(vnode.state.view, vnode))
} catch (e) {
vnode.instance = Vnode.normalize(errorManager.fail(e, vnode, true))
}
if (vnode.instance === vnode) errorManager.fail("A view cannot return the vnode it received as argument", vnode, false)
sentinel.$$reentrantLock$$ = null
}
function createComponent(parent, vnode, hooks, ns, nextSibling) {
Expand Down Expand Up @@ -460,8 +466,12 @@ module.exports = function($window) {
}
}
function updateComponent(parent, old, vnode, hooks, nextSibling, ns) {
vnode.instance = Vnode.normalize(callHook.call(vnode.state.view, vnode))
if (vnode.instance === vnode) throw Error("A view cannot return the vnode it received as argument")
try {
vnode.instance = Vnode.normalize(callHook.call(vnode.state.view, vnode))
} catch (e) {
vnode.instance = Vnode.normalize(errorManager.fail(e, vnode, true))
}
if (vnode.instance === vnode) errorManager.fail("A view cannot return the vnode it received as argument", vnode, false)
updateLifecycle(vnode.state, vnode, hooks)
if (vnode.attrs != null) updateLifecycle(vnode.attrs, vnode, hooks)
if (vnode.instance != null) {
Expand Down Expand Up @@ -700,7 +710,7 @@ module.exports = function($window) {
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 }
if (isFileInput && "" + value !== "") { errorManager.log(0, "`value` is read-only on file inputs!"); return }
/* eslint-enable no-implicit-coercion */
}
vnode.dom[key] = value
Expand Down Expand Up @@ -748,7 +758,7 @@ module.exports = function($window) {
}
function updateAttrs(vnode, old, attrs, ns) {
if (old && old === attrs) {
console.warn("Don't reuse attrs object, use new object for every redraw, this will throw in next major")
errorManager.log(1, "Don't reuse attrs object, use new object for every redraw, this will throw in next major")
}
if (attrs != null) {
// If you assign an input type that is not supported by IE 11 with an assignment expression, an error will occur.
Expand Down
83 changes: 83 additions & 0 deletions util/errorManager.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
"use strict"

// Log levels are:
// * 0 error
// * 1 warning
// * 2 info
// * 3 debug

module.exports = {
em: {
logEventListeners:[],
failEventListeners:[],

log(level, message) {
this.executeListeners(
this.logEventListeners,
{level:level,message:message},
() => {
switch (level) {
case 0:
console.error(message)
break;
case 1:
console.warn(message)
break;
case 2:
console.info(message)
break;
case 3:
console.debug(message)
break;
}
})
},

fail(error, vnode, inView) {
return this.executeListeners(
this.failEventListeners,
{error:error, vnode:vnode, inView:inView},
() => {
this.debugVnode(0, vnode)
if (error instanceof Error)
throw error
else
throw new Error(error)
}
)
},

debugVnode(level, vnode) {
if (vnode) {
this.log(level, "Component: " + vnode.tag.name + " with attributes " + JSON.stringify(vnode.attrs))
}
},

addEventListener(name, callback) {
switch (name) {
case "log":
this.addToArray(this.logEventListeners, callback)
break
case "fail":
this.addToArray(this.failEventListeners, callback)
break
}
},

executeListeners(listeners, param, defaultHandler) {
let stopProcessing = false;
for (let i=0 ; i<listeners.length ; i++) {
let returnValue = listeners[i](param, () => {stopProcessing=true})
if (stopProcessing) return returnValue
}
defaultHandler()
},

addToArray(array, object) {
for (let i=0 ; i<array.length ; i++) {
if (array[i] === object) return
}
array.push(object)
}
}
}