/** * @author Brian Moeskau <brian@sencha.com> * @docauthor Brian Moeskau <brian@sencha.com> * * A wrapper class for the native JavaScript Error object that adds a few useful capabilities for handling * errors in an Ext application. When you use Ext.Error to {@link #raise} an error from within any class that * uses the Ext 4 class system, the Error class can automatically add the source class and method from which * the error was raised. It also includes logic to automatically log the eroor to the console, if available, * with additional metadata about the error. In all cases, the error will always be thrown at the end so that * execution will halt. * * Ext.Error also offers a global error {@link #handle handling} method that can be overridden in order to * handle application-wide errors in a single spot. You can optionally {@link #ignore} errors altogether, * although in a real application it's usually a better idea to override the handling function and perform * logging or some other method of reporting the errors in a way that is meaningful to the application. * * At its simplest you can simply raise an error as a simple string from within any code: * * Example usage: * * Ext.Error.raise('Something bad happened!'); * * If raised from plain JavaScript code, the error will be logged to the console (if available) and the message * displayed. In most cases however you'll be raising errors from within a class, and it may often be useful to add * additional metadata about the error being raised. The {@link #raise} method can also take a config object. * In this form the `msg` attribute becomes the error description, and any other data added to the config gets * added to the error object and, if the console is available, logged to the console for inspection. * * Example usage: * * Ext.define('Ext.Foo', { * doSomething: function(option){ * if (someCondition === false) { * Ext.Error.raise({ * msg: 'You cannot do that!', * option: option, // whatever was passed into the method * 'error code': 100 // other arbitrary info * }); * } * } * }); * * If a console is available (that supports the `console.dir` function) you'll see console output like: * * An error was raised with the following data: * option: Object { foo: "bar"} * foo: "bar" * error code: 100 * msg: "You cannot do that!" * sourceClass: "Ext.Foo" * sourceMethod: "doSomething" * * uncaught exception: You cannot do that! * * As you can see, the error will report exactly where it was raised and will include as much information as the * raising code can usefully provide. * * If you want to handle all application errors globally you can simply override the static {@link #handle} method * and provide whatever handling logic you need. If the method returns true then the error is considered handled * and will not be thrown to the browser. If anything but true is returned then the error will be thrown normally. * * Example usage: * * Ext.Error.handle = function(err) { * if (err.someProperty == 'NotReallyAnError') { * // maybe log something to the application here if applicable * return true; * } * // any non-true return value (including none) will cause the error to be thrown * } * */ Ext.Error = Ext.extend(Error, { statics: { /** * @property {Boolean} ignore * Static flag that can be used to globally disable error reporting to the browser if set to true * (defaults to false). Note that if you ignore Ext errors it's likely that some other code may fail * and throw a native JavaScript error thereafter, so use with caution. In most cases it will probably * be preferable to supply a custom error {@link #handle handling} function instead. * * Example usage: * * Ext.Error.ignore = true; * * @static */ ignore: false, /** * @property {Boolean} notify * Static flag that can be used to globally control error notification to the user. Unlike * Ex.Error.ignore, this does not effect exceptions. They are still thrown. This value can be * set to false to disable the alert notification (default is true for IE6 and IE7). * * Only the first error will generate an alert. Internally this flag is set to false when the * first error occurs prior to displaying the alert. * * This flag is not used in a release build. * * Example usage: * * Ext.Error.notify = false; * * @static */ //notify: Ext.isIE6 || Ext.isIE7, /** * Raise an error that can include additional data and supports automatic console logging if available. * You can pass a string error message or an object with the `msg` attribute which will be used as the * error message. The object can contain any other name-value attributes (or objects) to be logged * along with the error. * * Note that after displaying the error message a JavaScript error will ultimately be thrown so that * execution will halt. * * Example usage: * * Ext.Error.raise('A simple string error message'); * * // or... * * Ext.define('Ext.Foo', { * doSomething: function(option){ * if (someCondition === false) { * Ext.Error.raise({ * msg: 'You cannot do that!', * option: option, // whatever was passed into the method * 'error code': 100 // other arbitrary info * }); * } * } * }); * * @param {String/Object} err The error message string, or an object containing the attribute "msg" that will be * used as the error message. Any other data included in the object will also be logged to the browser console, * if available. * @static */ raise: function(err){ err = err || {}; if (Ext.isString(err)) { err = { msg: err }; } var method = this.raise.caller; if (method) { if (method.$name) { err.sourceMethod = method.$name; } if (method.$owner) { err.sourceClass = method.$owner.$className; } } if (Ext.Error.handle(err) !== true) { var msg = Ext.Error.prototype.toString.call(err); Ext.log({ msg: msg, level: 'error', dump: err, stack: true }); throw new Ext.Error(err); } }, /** * Globally handle any Ext errors that may be raised, optionally providing custom logic to * handle different errors individually. Return true from the function to bypass throwing the * error to the browser, otherwise the error will be thrown and execution will halt. * * Example usage: * * Ext.Error.handle = function(err) { * if (err.someProperty == 'NotReallyAnError') { * // maybe log something to the application here if applicable * return true; * } * // any non-true return value (including none) will cause the error to be thrown * } * * @param {Ext.Error} err The Ext.Error object being raised. It will contain any attributes that were originally * raised with it, plus properties about the method and class from which the error originated (if raised from a * class that uses the Ext 4 class system). * @static */ handle: function(){ return Ext.Error.ignore; } }, // This is the standard property that is the name of the constructor. name: 'Ext.Error', /** * Creates new Error object. * @param {String/Object} config The error message string, or an object containing the * attribute "msg" that will be used as the error message. Any other data included in * the object will be applied to the error instance and logged to the browser console, if available. */ constructor: function(config){ if (Ext.isString(config)) { config = { msg: config }; } var me = this; Ext.apply(me, config); me.message = me.message || me.msg; // 'message' is standard ('msg' is non-standard) // note: the above does not work in old WebKit (me.message is readonly) (Safari 4) }, /** * Provides a custom string representation of the error object. This is an override of the base JavaScript * `Object.toString` method, which is useful so that when logged to the browser console, an error object will * be displayed with a useful message instead of `[object Object]`, the default `toString` result. * * The default implementation will include the error message along with the raising class and method, if available, * but this can be overridden with a custom implementation either at the prototype level (for all errors) or on * a particular error instance, if you want to provide a custom description that will show up in the console. * @return {String} The error message. If raised from within the Ext 4 class system, the error message will also * include the raising class and method names, if available. */ toString: function(){ var me = this, className = me.className ? me.className : '', methodName = me.methodName ? '.' + me.methodName + '(): ' : '', msg = me.msg || '(No description provided)'; return className + methodName + msg; } }); /* * This mechanism is used to notify the user of the first error encountered on the page. This * was previously internal to Ext.Error.raise and is a desirable feature since errors often * slip silently under the radar. It cannot live in Ext.Error.raise since there are times * where exceptions are handled in a try/catch. */ //<debug> (function () { var prevOnError, timer, errors = 0, extraordinarilyBad = /(out of stack)|(too much recursion)|(stack overflow)|(out of memory)/i, win = Ext.global; if (typeof window === 'undefined') { return; // build system or some such environment... } // This method is called to notify the user of the current error status. function notify () { var counters = Ext.log.counters, supports = Ext.supports, hasOnError = supports && supports.WindowOnError; // TODO - timing // Put log counters to the status bar (for most browsers): if (counters && (counters.error + counters.warn + counters.info + counters.log)) { var msg = [ 'Logged Errors:',counters.error, 'Warnings:',counters.warn, 'Info:',counters.info, 'Log:',counters.log].join(' '); if (errors) { msg = '*** Errors: ' + errors + ' - ' + msg; } else if (counters.error) { msg = '*** ' + msg; } win.status = msg; } // Display an alert on the first error: if (!Ext.isDefined(Ext.Error.notify)) { Ext.Error.notify = Ext.isIE6 || Ext.isIE7; // TODO - timing } if (Ext.Error.notify && (hasOnError ? errors : (counters && counters.error))) { Ext.Error.notify = false; if (timer) { win.clearInterval(timer); // ticks can queue up so stop... timer = null; } alert('Unhandled error on page: See console or log'); poll(); } } // Sets up polling loop. This is the only way to know about errors in some browsers // (Opera/Safari) and is the only way to update the status bar for warnings and other // non-errors. function poll () { timer = win.setInterval(notify, 1000); } // window.onerror sounds ideal but it prevents the built-in error dialog from doing // its (better) thing. poll(); })(); //</debug>