Upgrade to ExtJS 4.0.0 - Released 04/26/2011
[extjs.git] / src / core / src / lang / Error.js
1 /**
2  * @class Ext.Error
3  * @private
4  * @extends Error
5
6 A wrapper class for the native JavaScript Error object that adds a few useful capabilities for handling
7 errors in an Ext application. When you use Ext.Error to {@link #raise} an error from within any class that
8 uses the Ext 4 class system, the Error class can automatically add the source class and method from which
9 the error was raised. It also includes logic to automatically log the eroor to the console, if available, 
10 with additional metadata about the error. In all cases, the error will always be thrown at the end so that
11 execution will halt.
12
13 Ext.Error also offers a global error {@link #handle handling} method that can be overridden in order to 
14 handle application-wide errors in a single spot. You can optionally {@link #ignore} errors altogether,
15 although in a real application it's usually a better idea to override the handling function and perform
16 logging or some other method of reporting the errors in a way that is meaningful to the application.
17
18 At its simplest you can simply raise an error as a simple string from within any code:
19
20 #Example usage:#
21
22     Ext.Error.raise('Something bad happened!');
23     
24 If raised from plain JavaScript code, the error will be logged to the console (if available) and the message
25 displayed. In most cases however you'll be raising errors from within a class, and it may often be useful to add
26 additional metadata about the error being raised.  The {@link #raise} method can also take a config object.
27 In this form the `msg` attribute becomes the error description, and any other data added to the config gets
28 added to the error object and, if the console is available, logged to the console for inspection.
29
30 #Example usage:#
31  
32     Ext.define('Ext.Foo', {
33         doSomething: function(option){
34             if (someCondition === false) {
35                 Ext.Error.raise({
36                     msg: 'You cannot do that!',
37                     option: option,   // whatever was passed into the method
38                     'error code': 100 // other arbitrary info
39                 });
40             }
41         }
42     });
43
44 If a console is available (that supports the `console.dir` function) you'll see console output like:
45
46     An error was raised with the following data:
47     option:         Object { foo: "bar"}
48         foo:        "bar"
49     error code:     100
50     msg:            "You cannot do that!"
51     sourceClass:   "Ext.Foo"
52     sourceMethod:  "doSomething"
53     
54     uncaught exception: You cannot do that!
55
56 As you can see, the error will report exactly where it was raised and will include as much information as the 
57 raising code can usefully provide.
58
59 If you want to handle all application errors globally you can simply override the static {@link handle} method
60 and provide whatever handling logic you need. If the method returns true then the error is considered handled
61 and will not be thrown to the browser. If anything but true is returned then the error will be thrown normally.
62
63 #Example usage:#
64
65     Ext.Error.handle = function(err) {
66         if (err.someProperty == 'NotReallyAnError') {
67             // maybe log something to the application here if applicable
68             return true;
69         }
70         // any non-true return value (including none) will cause the error to be thrown
71     }
72
73  * Create a new Error object
74  * @param {Object} config The config object
75  * @markdown
76  * @author Brian Moeskau <brian@sencha.com>
77  * @docauthor Brian Moeskau <brian@sencha.com>
78  */
79 Ext.Error = Ext.extend(Error, {
80     statics: {
81         /**
82          * @property ignore
83 Static flag that can be used to globally disable error reporting to the browser if set to true
84 (defaults to false). Note that if you ignore Ext errors it's likely that some other code may fail
85 and throw a native JavaScript error thereafter, so use with caution. In most cases it will probably
86 be preferable to supply a custom error {@link #handle handling} function instead.
87
88 #Example usage:#
89
90     Ext.Error.ignore = true;
91
92          * @markdown
93          * @static
94          */
95         ignore: false,
96
97         /**
98 Raise an error that can include additional data and supports automatic console logging if available. 
99 You can pass a string error message or an object with the `msg` attribute which will be used as the 
100 error message. The object can contain any other name-value attributes (or objects) to be logged 
101 along with the error.
102
103 Note that after displaying the error message a JavaScript error will ultimately be thrown so that 
104 execution will halt.
105
106 #Example usage:#
107
108     Ext.Error.raise('A simple string error message');
109
110     // or...
111
112     Ext.define('Ext.Foo', {
113         doSomething: function(option){
114             if (someCondition === false) {
115                 Ext.Error.raise({
116                     msg: 'You cannot do that!',
117                     option: option,   // whatever was passed into the method
118                     'error code': 100 // other arbitrary info
119                 });
120             }
121         }
122     });
123          * @param {String/Object} err The error message string, or an object containing the 
124          * attribute "msg" that will be used as the error message. Any other data included in
125          * the object will also be logged to the browser console, if available.
126          * @static
127          * @markdown
128          */
129         raise: function(err){
130             err = err || {};
131             if (Ext.isString(err)) {
132                 err = { msg: err };
133             }
134
135             var method = this.raise.caller;
136
137             if (method) {
138                 if (method.$name) {
139                     err.sourceMethod = method.$name;
140                 }
141                 if (method.$owner) {
142                     err.sourceClass = method.$owner.$className;
143                 }
144             }
145
146             if (Ext.Error.handle(err) !== true) {
147                 var global = Ext.global,
148                     con = global.console,
149                     msg = Ext.Error.prototype.toString.call(err),
150                     noConsoleMsg = 'An uncaught error was raised: "' + msg + 
151                         '". Use Firebug or Webkit console for additional details.';
152
153                 if (con) {
154                     if (con.dir) {
155                         con.warn('An uncaught error was raised with the following data:');
156                         con.dir(err);
157                     }
158                     else {
159                         con.warn(noConsoleMsg);
160                     }
161                     if (con.error) {
162                         con.error(msg);
163                     }
164                 }
165                 else if (global.alert){
166                     global.alert(noConsoleMsg);
167                 }
168                 
169                 throw new Ext.Error(err);
170             }
171         },
172
173         /**
174 Globally handle any Ext errors that may be raised, optionally providing custom logic to
175 handle different errors individually. Return true from the function to bypass throwing the
176 error to the browser, otherwise the error will be thrown and execution will halt.
177
178 #Example usage:#
179
180     Ext.Error.handle = function(err) {
181         if (err.someProperty == 'NotReallyAnError') {
182             // maybe log something to the application here if applicable
183             return true;
184         }
185         // any non-true return value (including none) will cause the error to be thrown
186     }
187
188          * @param {Ext.Error} err The Ext.Error object being raised. It will contain any attributes
189          * that were originally raised with it, plus properties about the method and class from which
190          * the error originated (if raised from a class that uses the Ext 4 class system).
191          * @static
192          * @markdown
193          */
194         handle: function(){
195             return Ext.Error.ignore;
196         }
197     },
198
199     /**
200      * @constructor
201      * @param {String/Object} config The error message string, or an object containing the 
202      * attribute "msg" that will be used as the error message. Any other data included in
203      * the object will be applied to the error instance and logged to the browser console, if available.
204      */
205     constructor: function(config){
206         if (Ext.isString(config)) {
207             config = { msg: config };
208         }
209         Ext.apply(this, config);
210     },
211
212     /**
213 Provides a custom string representation of the error object. This is an override of the base JavaScript 
214 `Object.toString` method, which is useful so that when logged to the browser console, an error object will 
215 be displayed with a useful message instead of `[object Object]`, the default `toString` result.
216
217 The default implementation will include the error message along with the raising class and method, if available,
218 but this can be overridden with a custom implementation either at the prototype level (for all errors) or on
219 a particular error instance, if you want to provide a custom description that will show up in the console.
220      * @markdown
221      * @return {String} The error message. If raised from within the Ext 4 class system, the error message
222      * will also include the raising class and method names, if available.
223      */
224     toString: function(){
225         var me = this,
226             className = me.className ? me.className  : '',
227             methodName = me.methodName ? '.' + me.methodName + '(): ' : '',
228             msg = me.msg || '(No description provided)';
229
230         return className + methodName + msg;
231     }
232 });