-
-
Save xavierzwirtz/50d83af969380320ff3c to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
.binding-error { | |
border: 4px dashed red !important; | |
background-color: #F88 !important; | |
margin-bottom: 0; | |
} | |
//changed from :after psuedo to handle form elements. | |
.binding-error-message { | |
display: block !important; | |
padding: 0.33333rem 0.5rem 0.5rem !important; | |
margin-top: -1px !important; | |
margin-bottom: 0.88889rem !important; | |
font-size: 0.66667rem !important; | |
font-weight: normal !important; | |
font-style: italic !important; | |
background: #f04124 !important; | |
color: white !important; | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// Ported to JS from Brian Hunts coffee script version. | |
// coffee script version: http://brianmhunt.github.io/articles/knockout-catching-errors/ | |
/* global define */ | |
var __slice = [].slice; | |
var isolate_call = function(binding, fn_name, key) { | |
// binding is the binding object | |
// fn_name is one of `init` or `update` | |
// key is the name of the binding | |
var fn = binding[fn_name]; | |
var wrapped_fn; | |
if (!fn) { | |
return void 0; | |
} | |
if (!_.isFunction(fn)) { | |
console.error("%cERROR%c Binding " + key + "." + fn_name + | |
" is not a function", "color:red", "color:black", | |
binding, fn_name, fn); | |
return void 0; | |
} | |
wrapped_fn = function() { | |
var args, e; | |
args = 1 <= arguments.length ? __slice.call(arguments, 0) : []; | |
try { | |
//Pass-through the call to the original handler. | |
return fn.apply(binding, args); | |
} catch (_error) { | |
e = _error; | |
var node = args[0]; | |
var $node = $(node); | |
console.error("%cERROR%c: Binding " + key + "." + | |
fn_name + " error", "color:red", "color: black", | |
node, e, e.stack); | |
$node.addClass("binding-error"); | |
$node.after( | |
'<div class="binding-error-message">This item may not be working as expected.</div>' | |
); | |
} | |
}; | |
return wrapped_fn; | |
}; | |
var ErrorHandlerBindingProvider = function(ko) { | |
var that = this; | |
var builtInBindingHandlers = _.map(ko.bindingHandlers, function(value, | |
key) { | |
return key; | |
}); | |
that.attach = function() { | |
var isolate_binding_errors = function(binding, key) { | |
var isDefault = _.isUndefined(_.find(builtInBindingHandlers, | |
function( | |
builtInKey) { | |
return builtInKey === key; | |
})) === false; | |
if (!isDefault) { | |
binding.init_fn = binding.init; | |
binding.update_fn = binding.update_fn; | |
binding.init = isolate_call(binding, 'init', key); | |
binding.update = isolate_call(binding, 'update', key); | |
} | |
}; | |
_.each(ko.bindingHandlers, isolate_binding_errors); | |
}; | |
}; | |
var CustomBindingHandlerErrorHandler = function(ko) { | |
// The original binding handler still does the real work; you | |
// can use your own or an alternative such as knockout-secure-binding | |
// here though. | |
var orig; | |
orig = new ko.bindingProvider(); | |
// We also pass through the `nodeHasBindings` call. | |
this.nodeHasBindings = orig.nodeHasBindings; | |
// This returns a map of binding names to respective handlers, given a node | |
// and the bindingContext. | |
this.getBindings = function(node, bindingContext) { | |
var addErrorMessage = function() { | |
var $node = $(node); | |
$node.addClass("binding-error"); | |
$node.after( | |
'<div class="binding-error-message">This item may not be working as expected.</div>' | |
); | |
}; | |
var bindings_map, err; | |
try { | |
// The bindings_map will be `null` if there are no bindings, otherwise | |
// an object mapping { name: binding }. | |
bindings_map = orig.getBindings(node, bindingContext); | |
} catch (_error) { | |
// When there is an error, throw out some useful context. | |
err = _error; | |
console.error("Binding error: ", err.message, "\nNode:", node, | |
"\nContext:", ko.contextFor(node)); | |
addErrorMessage(); | |
return null; | |
} | |
// Pass null straight up. | |
if (bindings_map === null) { | |
return null; | |
} | |
// If there isn't at least one good binding, print some helpful | |
// debugging information. | |
if (!_(bindings_map).keys().any(function(m) { | |
return _.has(ko.bindingHandlers, m); | |
})) { | |
console.error("No bindings found:", bindings_map, "Node:", node); | |
addErrorMessage(); | |
return null; | |
} | |
return bindings_map; | |
}; | |
}; | |
}); | |
ko.bindingProvider.instance = new ErrorHandlerBindingProvider(ko); | |
var customBindingHandlerErrorHandler = new CustomBindingHandlerErrorHandler(ko); //this must be defined before any custom bindings are loaded; | |
customBindingHandlerErrorHandler.attach(ko); //call this before ko.applyBindings is called. | |
ko.applyBindings(viewModel); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment