1/* 2 This class handles client-side javascript errors in a consistent manner 3 4 All unhandled errors will be caught by this class as it attaches itself to the window.onerror event (IE and Firefox only) 5 6 It is recommended that developers use try/catch in their code and call Aksw.ErrorHandler.handleError passing the error object 7 8 This code was adapted from: 9 Harley Jones, aka <a href="http://extjs.com/forum/member.php?u=118">harley.333</a> 10 11*/ 12 13Aksw.ErrorHandler = function () { 14 15 var internal = { 16 17 getStack: function (a, func) { 18 19 if (func.caller) { 20 internal.getStack(a, func.caller); 21 } 22 var args = []; 23 for (var x = 0; x < func.arguments.length; x++) { 24 args[x] = func.arguments[x]; 25 } 26 a.unshift({ args: args, func: func }); 27 }, 28 29 formatError: function (exObj) { 30 31 var sbDialogMsg = Aksw.StringBuilder(); 32 var sbClipboardMsg = Aksw.StringBuilder(); 33 try { 34 sbDialogMsg.append(internal.createLineItemDialog("Window:", window.location)); 35 sbClipboardMsg.append(internal.createLineItemClipboard("Window:", window.location)); 36 sbDialogMsg.append(internal.createLineItemDialog("Message:", exObj.message)); 37 sbClipboardMsg.append(internal.createLineItemClipboard("Message:", exObj.message)); 38 if (exObj.lineNumber) { 39 sbDialogMsg.append(internal.createLineItemDialog("Line Number:", exObj.lineNumber)); 40 sbClipboardMsg.append(internal.createLineItemClipboard("Line Number:", exObj.lineNumber)); 41 } 42 if (exObj.url) { 43 sbDialogMsg.append(internal.createLineItemDialog("Url:", exObj.url)); 44 sbClipboardMsg.append(internal.createLineItemClipboard("Url:\t", exObj.url)); 45 } 46 if (exObj.description) { 47 sbDialogMsg.append(internal.createLineItemDialog("Description:", exObj.Description)); 48 sbClipboardMsg.append(internal.createLineItemClipboard("Description:", exObj.Description)); 49 } 50 if (exObj.stack) { 51 var stack = exObj.stack; 52 var retObj = internal.writeStackTrace(stack); 53 sbDialogMsg.append(retObj.DialogMsg); 54 sbClipboardMsg.append(retObj.ClipboardMsg); 55 } 56 } 57 catch (e) { } 58 finally { 59 return { DialogMsg: sbDialogMsg.toStringChar(" "), ClipboardMsg: sbClipboardMsg.toStringChar(" ") }; 60 } 61 }, 62 63 createLineItemDialog: function (label, val) { 64 var sHtml = "<div><span><i><b>" + label + "</b></i></span>"; 65 if (typeof (val) != "undefined") { 66 sHtml += "\t<span class='val'>" + val + "</span>"; 67 } 68 sHtml += "</div>"; 69 return sHtml; 70 }, 71 72 createLineItemClipboard: function (label, val) { 73 var sClip = label; 74 if (typeof (val) != "undefined") { 75 sClip += "\t" + val; 76 } 77 sClip += "\n"; 78 return sClip; 79 }, 80 81 writeStackTrace: function (stack) { 82 var sbHtml = Aksw.StringBuilder(); 83 var sbClip = Aksw.StringBuilder(); 84 sbHtml.append("\n<b><h3>Stack</h3></b>\n"); 85 sbClip.append("\n=======================\n Stack\n=======================\n"); 86 87 var i = stack.length; 88 while (stack.length > 0) 89 //for (var i=0; i<stack.length; i++) 90 { 91 var stackObj = stack.shift(); 92 var retObj = internal.internal.writeStackItem("StackItem [" + i + "]", stackObj, i); 93 sbHtml.append(retObj.DialogMsg); 94 sbClip.append(retObj.ClipboardMsg); 95 i--; 96 } 97 return { DialogMsg: sbHtml.toStringChar(" "), ClipboardMsg: sbClip.toStringChar(" ") }; 98 }, 99 100 writeStackItem: function (title, stackObj, stackIdx) { 101 var sbHtml = Aksw.StringBuilder(); 102 var sbClip = Aksw.StringBuilder(); 103 104 // title 105 sbHtml.append("<div style='vertical-align:middle'>"); 106 sbHtml.append("<span style='padding-left:10px'>" + title + "</span>"); 107 sbHtml.append("<div style='background-color:#DD9;border-width:thin;border-color:#000;margin:5px;padding:5px' >"); 108 sbClip.append("\n\n" + title + "\n----------------------------------------\n"); 109 110 // function body 111 sbHtml.append(internal.createLineItemDialog("Function:")); 112 var fBody = stackObj.func.toString(); 113 sbHtml.append(internal.addCodeBlock(fBody)); 114 sbHtml.append("\n"); 115 sbClip.append(internal.createLineItemClipboard("Function:")); 116 sbClip.append(fBody + "\n"); 117 118 // arguments 119 if (stackObj.args && stackObj.args.length > 0) { 120 sbHtml.append(internal.createLineItemDialog("Arguments:")); 121 sbClip.append(internal.createLineItemClipboard("\nArguments:")); 122 var retObj = internal.writeStackItemArguments(stackObj.args); 123 sbHtml.append(retObj.DialogMsg); 124 sbClip.append(retObj.ClipboardMsg); 125 } 126 sbHtml.append("</div></div>\n\n"); 127 sbClip.append("\n"); 128 return { DialogMsg: sbHtml.toStringChar(" "), ClipboardMsg: sbClip.toStringChar(" ") }; 129 }, 130 131 addCodeBlock: function (sCode) { 132 return "<pre>" + sCode + "</pre>"; 133 }, 134 135 writeStackItemArguments: function (argsObj) { 136 try { 137 var sbHtml = Aksw.StringBuilder(); 138 var sbClip = Aksw.StringBuilder(); 139 var argLen = argsObj.length; 140 for (var i = 0; i < argLen; i++) { 141 var argNum = i + 1; 142 var argLine = internal.writeValue(argsObj[i], 1, argNum + ") "); 143 sbHtml.append(argLine); 144 sbClip.append(argLine); 145 } 146 return { DialogMsg: sbHtml.toStringChar(" "), ClipboardMsg: sbClip.toStringChar(" ") }; 147 } 148 catch (ex) { 149 // protect against problematic arguments that otherwise would 150 // cause no stack trace at all to appear. 151 return { DialogMsg: "{Error emitting arguments}", ClipboardMsg: "{Error emitting arguments}" }; 152 } 153 }, 154 155 writeValue: function (x, level, prefix) { 156 try { 157 var s = ""; 158 var argVal; 159 var argType = internal.getType(x); 160 var sArgType = "(" + argType + ")"; 161 162 for (var v = 0; v < level; v++) { 163 s += "\t"; 164 } 165 if (typeof (prefix) != "undefined") { 166 s += prefix; 167 } 168 s += " " + sArgType; 169 170 switch (argType) { 171 case "null": 172 { 173 s += "\n"; 174 break; 175 } 176 case "string": 177 { 178 s += "\t\"" + x + "\"\n"; 179 break; 180 } 181 case "number": 182 case "boolean": 183 { 184 s += "\t" + x.toString() + "\n"; 185 break; 186 } 187 case "Array": 188 { 189 s += "\n"; 190 var aL = x.length; 191 for (var i = 0; i < aL; i++) { 192 s += internal.writeValue(x[i], level
192+ 1, "[" + i + "]:"); 193 } 194 break; 195 } 196 case "Object": 197 { 198 s += "\n"; 199 for (var p in x) { 200 if (typeof x[p] != "function") { 201 s += internal.writeValue(x[p], level + 1, "['" + p + "']:"); 202 } 203 } 204 break; 205 } 206 default: 207 { 208 s += "\t" + x.toString() + "\n"; 209 break; 210 } 211 } // end switch 212 213 return s; 214 } 215 catch (ex) { 216 // protect against problematic arguments that otherwise would 217 // cause no stack trace at all to appear. 218 return "{Error evaluating argument}\n"; 219 } 220 }, 221 222 getType: function (x) { 223 if (x == null) 224 return "null"; 225 226 var t = typeof x; 227 if (t != "object") 228 return t; 229 230 var c = Object.prototype.toString.apply(x); // returns "[object class]" 231 c = c.substring(8, c.length - 1); 232 233 if (c != "Object") 234 return c; 235 236 if (x.constructor == Object) 237 return c; 238 239 if ("classname" in x.constructor.prototype && typeof x.constructor.prototype.classname == "string") 240 return x.constructor.prototype.classname; 241 242 return "<unknown type>"; 243 } 244 }; 245 246 return { 247 248 /** 249 * Sets up a handler for "unhandled" exceptions that bubble up to the browser's window object. 250 * @returns {void} 251 */ 252 init: function () { 253 // window.onerror is the browser's hook for unhandled exceptions (IE and Firefox only) 254 // if another developer is already using window.onerror, let's be respectful 255 256 window.onerror = Aksw.ErrorHandler.handleError; 257 //window.onerror = !window.onerror ? Ext.ux.ErrorHandler.handleError : window.onerror.createSequence(Ext.ux.ErrorHandler.handleError); 258 //window.attachEvent("onerror", Ext.ux.ErrorHandler.handleError); 259 //Ext.EventManager.on(window, 'error', Ext.ux.ErrorHandler.handleError); 260 261 262 // NOTE: the below code was originally included in the forum posting but has been removed for now 263 // as we may or may not want it implemented.. 264 //Ext.select("img").each(function(el, list, index) { 265 // el.on("error", Ext.ux.ErrorHandler.handleError); 266 //}); 267 }, 268 269 /** 270 * This method handles all exception and fires the <b><tt>error</tt></b> event. 271 * @param {Object...} args 272 * @returns {Boolean} Returns <b><tt>true</tt></b>, unless an event handler throws an exception (if this occurs, we allow the browser to handle these exceptions in the default manner). 273 */ 274 handleError: function () { 275 // the arguments collection is not a true Array, so we'll make one 276 //debugger; 277 if (console) { 278 if (console.error) { 279 console.error(arguments); 280 } 281 } 282 283 var args = []; 284 for (var x = 0; x < arguments.length; x++) { 285 args[x] = arguments[x]; 286 } 287 if (args.length > 0) { 288 var ex = { 289 raw: null, 290 isError: false, 291 isUnhandledException: false, 292 isImageLoadingError: false, 293 isScriptLoadingError: false, // Firefox only 294 name: null, 295 message: null, 296 url: null, // Safari and Firefox only 297 lineNumber: null, // Safari and Firefox only 298 stack: null // Firefox and Opera only 299 }; 300 ex.raw = args; 301 ex.isError = args[0] instanceof Error; // Error object thrown in try...catch 302 // Check the signature for a match with an unhandled exception 303 ex.isUnhandledException = (args.length === 3) && (typeof args[2] === "number"); 304 ex.isImageLoadingError = !!args[0].browserEvent && args[1] && args[1].tagName == "IMG"; 305 if (ex.isError) { 306 var err = args[0]; 307 ex.name = err.name || "Error"; // Safari is inconsistent 308 ex.message = err.message || err.type; // Chrome is inconsistent 309 ex.lineNumber = err.line || err.lineNumber; // Safari and Firefox 310 ex.url = err.sourceURL || err.fileName; // Safari and Firefox 311 ex.stack = err.stack || err.stacktrace; // Firefox and Opera 312 } else if (ex.isUnhandledException) { 313 ex.name = "ERR_UNHANDLED"; 314 ex.message = args[0]; 315 ex.url = args[1]; 316 ex.lineNumber = args[2]; 317 if (ex.message == "Error loading script") { 318 ex.isScriptLoadingError = true;
319 ex.name = "ERR_LOAD_SCRIPT"; 320 } 321 } else if (ex.isImageLoadingError) { 322 ex.name = "ERR_LOAD_IMG"; 323 ex.message = "Error loading image"; 324 ex.url = args[1].src; 325 } else { 326 ex.name = "ERR_UNKNOWN"; 327 //console.log(args[0]); 328 ex.message = 'Unknown'; //Ext.encode(args[0]); - there is no equivalent in jQuery 329 } 330 // rebuild the stack (ignore Firefox and Opera) 331 // arguments.callee // the handleError method 332 // arguments.callee.caller // delegate for handleError 333 // arguments.callee.caller.caller // the beginning of the stack 334 //debugger; 335 336 if (arguments.callee && arguments.callee.caller && arguments.callee.caller.caller) { 337 var a = []; 338 internal.getStack(a, arguments.callee.caller.caller); 339 ex.stack = a; 340 } 341 } 342 343 //debugger; 344 var sTitle = ex.isUnhandledException ? "An unhandled exception has occurred" : "An error has occurred"; 345 var retObj = internal.formatError(ex); 346 347 var oWinSize = Aksw.Util.getDocumentSize(); 348 var iEffectiveH = Math.min(200, oWinSize["h"]); 349 var iEffectiveW = Math.min(300, oWinSize["w"]);
350 351 Aksw.Dialog.showError({ 352 title: 'Client-side error', 353 text: retObj.DialogMsg.replace(/\n/g, "<br/>").replace(/\t/g, " "), 354 buttons: ['OK', 'Copy to Clipboard'], 355 callback: function (res) { 356 if (res === 'Copy to Clipboard') { 357 try { 358 Aksw.Util.copyTextToClipboard(retObj.ClipboardMsg); 359 } catch (e) { } 360 } 361 } 362 }); 363 } 364 }; 365 366} (); 367 368// Initialize the Error Handler code 369//Aksw.ErrorHandler.init(); 370
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.