Add a WrappedError class

This commit is contained in:
Jonathan Frederic 2014-11-03 13:35:19 -08:00 committed by Jonathan Frederic
parent b16b2e8749
commit 1d1572421f
5 changed files with 96 additions and 42 deletions

View File

@ -606,7 +606,7 @@ define([
});
};
var load = function(class_name, module_name, registry) {
var load_class = function(class_name, module_name, registry) {
// Tries to load a class
//
// Tries to load a class from a module using require.js, if a module
@ -618,8 +618,7 @@ define([
if (module_name) {
require([module_name], function(module) {
if (module[class_name] === undefined) {
console.error('Class '+class_name+' not found in module '+module_name)
reject();
reject(new Error('Class '+class_name+' not found in module '+module_name));
} else {
resolve(module[class_name]);
}
@ -628,14 +627,18 @@ define([
if (registry && registry[class_name]) {
resolve(registry[class_name]);
} else {
console.error('Class '+class_name+' not found in registry ', registry);
reject();
reject(new Error({
message: 'Class '+class_name+' not found in registry ',
registry: registry
}));
}
}
});
};
var resolve_dict = function(d) {
// Resolve a promiseful dictionary.
// Returns a single Promise.
var keys = Object.keys(d);
var values = [];
keys.forEach(function(key) {
@ -650,6 +653,46 @@ define([
});
};
var WrappedError = function(message, error){
// Wrappable Error class
// The Error class doesn't actually act on `this`. Instead it always
// returns a new instance of Error. Here we capture that instance so we
// can apply it's properties to `this`.
var tmp = Error.apply(this, [message]);
// Copy the properties of the error over to this.
var properties = Object.getOwnPropertyNames(tmp);
for (var i = 0; i < properties.length; i++) {
this[properties[i]] = tmp[properties[i]];
}
// Keep a stack of the original error messages.
if (error instanceof WrappedError) {
this.error_stack = error.error_stack;
} else {
this.error_stack = [error];
}
this.error_stack.push(tmp);
return this;
};
WrappedError.prototype = Object.create(Error.prototype, {});
var reject = function(message, log) {
// Creates a wrappable Promise rejection function.
//
// Creates a function that returns a Promise.reject with a new WrappedError
// that has the provided message and wraps the original error that
// caused the promise to reject.
return function(error) {
var wrapped_error = new WrappedError(message, error);
if (log) console.error(wrapped_error);
return Promise.reject(wrapped_error);
};
};
var utils = {
regex_split : regex_split,
uuid : uuid,
@ -679,8 +722,10 @@ define([
XHR_ERROR : XHR_ERROR,
wrap_ajax_error : wrap_ajax_error,
promising_ajax : promising_ajax,
load: load,
load_class: load_class,
resolve_dict: resolve_dict,
WrappedError: WrappedError,
reject: reject,
};
// Backwards compatability.

View File

@ -67,18 +67,21 @@ define([
var content = msg.content;
var that = this;
utils.load_class(content.target_name, content.target_module, this.targets)
.then(function(target) {
return utils.load_class(content.target_name, content.target_module,
this.targets).then(function(target) {
var comm = new Comm(content.target_name, content.comm_id);
that.register_comm(comm);
try {
target(comm, msg);
} catch (e) {
console.log("Exception opening new comm:", e, e.stack, msg);
comm.close();
that.unregister_comm(comm);
var error = new utils.WrappedError("Exception opening new comm", e);
return Promise.reject(error);
}
}, $.proxy(console.error, console));
return comm;
}, utils.reject('Could not open comm', true));
};
CommManager.prototype.comm_close = function (msg) {

View File

@ -48,26 +48,33 @@ define([
//--------------------------------------------------------------------
WidgetManager.prototype.display_view = function(msg, model) {
// Displays a view for a particular model.
var cell = this.get_msg_cell(msg.parent_header.msg_id);
if (cell === null) {
console.log("Could not determine where the display" +
" message was from. Widget will not be displayed");
} else {
var dummy = null;
if (cell.widget_subarea) {
dummy = $('<div />');
cell.widget_subarea.append(dummy);
}
var that = this;
this.create_view(model, {cell: cell}).then(function(view) {
that._handle_display_view(view);
if (dummy) {
dummy.replaceWith(view.$el);
return new Promise(function(resolve, reject) {
var cell = this.get_msg_cell(msg.parent_header.msg_id);
if (cell === null) {
reject(new Error("Could not determine where the display" +
" message was from. Widget will not be displayed"));
} else {
var dummy = null;
if (cell.widget_subarea) {
dummy = $('<div />');
cell.widget_subarea.append(dummy);
}
view.trigger('displayed');
});
}
var that = this;
this.create_view(model, {cell: cell}).then(function(view) {
that._handle_display_view(view);
if (dummy) {
dummy.replaceWith(view.$el);
}
view.trigger('displayed');
resolve(view);
}, function(error) {
reject(new utils.WrappedError('Could not display view', error));
});
}
});
};
WidgetManager.prototype._handle_display_view = function (view) {
@ -79,7 +86,7 @@ define([
if (view.additional_elements) {
for (var i = 0; i < view.additional_elements.length; i++) {
this.keyboard_manager.register_events(view.additional_elements[i]);
this.keyboard_manager.register_events(view.additional_elements[i]);
}
}
}
@ -87,7 +94,7 @@ define([
WidgetManager.prototype.create_view = function(model, options) {
// Creates a promise for a view of a given model
return utils.load(model.get('_view_name'), model.get('_view_module'),
return utils.load_class(model.get('_view_name'), model.get('_view_module'),
WidgetManager._view_types).then(function(ViewType) {
// If a view is passed into the method, use that view's cell as
@ -102,10 +109,7 @@ define([
view.listenTo(model, 'destroy', view.remove);
view.render();
return view;
}, function(error) {
console.error(error);
return Promise.reject(error);
});
}, utils.reject("Couldn't create a view for model id '" + String(model.id) + "'"));
};
WidgetManager.prototype.get_msg_cell = function (msg_id) {
@ -177,7 +181,7 @@ define([
this.create_model({
model_name: msg.content.data.model_name,
model_module: msg.content.data.model_module,
comm: comm});
comm: comm}).handle($.proxy(console.error, error));
};
WidgetManager.prototype.create_model = function (options) {
@ -215,17 +219,18 @@ define([
var that = this;
var model_id = comm.comm_id;
var model_promise = utils.load(options.model_name, options.model_module, WidgetManager._model_types)
var model_promise = utils.load_class(options.model_name, options.model_module, WidgetManager._model_types)
.then(function(ModelType) {
var widget_model = new ModelType(that, model_id, comm);
widget_model.once('comm:close', function () {
delete that._models[model_id];
});
return widget_model;
}, function(error) {
delete that._models[model_id];
console.error(error);
return Promise.reject(error);
var wrapped_error = new utils.WrappedError("Couldn't create model", error);
return Promise.reject(wrapped_error);
});
this._models[model_id] = model_promise;
return model_promise;

View File

@ -322,7 +322,7 @@ define(["widgets/js/manager",
// Remember the view by id.
that.child_views[child_view.id] = child_view;
return child_view;
});
}, utils.reject("Couldn't create child view"));
},
pop_child_view: function(child_model) {

View File

@ -4,8 +4,9 @@
define([
"widgets/js/widget",
"jqueryui",
"base/js/utils",
"bootstrap",
], function(widget, $){
], function(widget, $, utils){
var BoxView = widget.DOMWidgetView.extend({
initialize: function(){
@ -84,7 +85,7 @@ define([
that.after_displayed(function() {
view.trigger('displayed');
});
});
}, utils.reject("Couldn't add child view to box", true));
},
});