1 /* See license.txt for terms of usage */ 2 3 // ************************************************************************************************ 4 // Shorcuts and Services 5 6 const Cc = Components.classes; 7 const Ci = Components.interfaces; 8 9 const traceService = Cc["@joehewitt.com/firebug-trace-service;1"].getService(Ci.nsIObserverService); 10 11 const PrefService = Cc["@mozilla.org/preferences-service;1"]; 12 const prefs = PrefService.getService(Ci.nsIPrefBranch2); 13 const prefService = PrefService.getService(Ci.nsIPrefService); 14 15 var gFindBar; 16 17 const reDBG = /extensions\.([^\.]*)\.(DBG_.*)/; 18 const reDBG_FBS = /DBG_FBS_(.*)/; 19 const reEndings = /\r\n|\r|\n/; 20 21 // The lib.js isn't included in this window so, define the global here. 22 // It'll be initialized from window parameters (see initialize method). 23 var FBL; 24 25 // Cache messages that are fired before the content of the window is loaded. 26 var queue = []; 27 28 // ************************************************************************************************ 29 // Trace Window Implementation 30 31 var TraceConsole = 32 { 33 modules: [], 34 35 initialize: function() 36 { 37 var args = window.arguments[0]; 38 FBL = args.FBL; 39 Firebug = args.Firebug; 40 41 // Get pref domain is used for message filtering. Only logs that belong 42 // to this pref-domain will be displayed. 43 this.prefDomain = args.prefDomain; 44 document.title = FBL.$STR("title.Tracing") + ": " + this.prefDomain; 45 46 // Register listeners and observers 47 traceService.addObserver(this, "firebug-trace-on-message", false); 48 prefs.addObserver(this.prefDomain, this, false); 49 50 // Initialize root node of the trace-console window. 51 var consoleFrame = document.getElementById("consoleFrame"); 52 this.consoleNode = consoleFrame.contentDocument.getElementById("panelNode-traceConsole"); 53 Firebug.TraceModule.CommonBaseUI.initializeContent(this.consoleNode, this, this.prefDomain, 54 FBL.bind(this.initializeContent, this)); 55 56 gFindBar = document.getElementById("FindToolbar"); 57 }, 58 59 initializeContent: function(logNode) 60 { 61 this.logs = logNode; 62 63 // Notify listeners 64 Firebug.TraceModule.onLoadConsole(window, logNode); 65 this.registerModule(Firebug.TraceModule); 66 67 // Make sure the UI is localized. 68 this.internationalizeUI(); 69 this.updateTimeInfo(); 70 71 // If the opener is closed the console must be also closed. 72 // (this console uses shared object from the opener (e.g. Firebug) 73 window.opener.addEventListener("close", this.onCloseOpener, true); 74 this.addedOnCloseOpener = true; 75 76 // Fetch all cached messages. 77 for (var i=0; i<queue.length; i++) 78 this.dump(queue[i]); 79 }, 80 81 internationalizeUI: function() 82 { 83 var buttons = ["clearConsole", "findConsole", "separateConsole", 84 "restartFirefox", "closeFirefox", "saveToFile", "loadFromFile"]; 85 86 for (var i=0; i<buttons.length; i++) 87 { 88 var element = document.getElementById(buttons[i]); 89 FBL.internationalize(element, "label"); 90 FBL.internationalize(element, "tooltiptext"); 91 } 92 }, 93 94 updateTimeInfo: function() 95 { 96 var showTime = Firebug.getPref(this.prefDomain, "trace.showTime"); 97 if (showTime) 98 FBL.setClass(this.logs.firstChild, "showTime"); 99 else 100 FBL.removeClass(this.logs.firstChild, "showTime"); 101 }, 102 103 shutdown: function() 104 { 105 traceService.removeObserver(this, "firebug-trace-on-message"); 106 prefs.removeObserver(this.prefDomain, this, false); 107 108 // Notify listeners 109 for (var i=0; i<this.modules.length; ++i) 110 this.modules[i].onUnloadConsole(window); 111 112 // Unregister from the opener 113 if (this.addedOnCloseOpener) 114 { 115 window.opener.removeEventListener("close", this.onCloseOpener, true); 116 delete this.addedOnCloseOpener; 117 } 118 }, 119 120 onCloseOpener: function() 121 { 122 if (FBTrace.DBG_INITIALIZE) 123 FBTrace.sysout("traceConsole.onCloseOpener closing window "+window.location); 124 125 window.close(); 126 }, 127 128 registerModule: function(traceModule) 129 { 130 this.modules.push(traceModule); 131 }, 132 133 unregisterModule: function(module) 134 { 135 for (var i=0; i<this.modules.length; ++i) { 136 if (this.modules[i] == module) { 137 this.modules.splice(i, 1); 138 break; 139 } 140 } 141 }, 142 143 // nsIObserver 144 observe: function(subject, topic, data) 145 { 146 if (topic == "firebug-trace-on-message") 147 { 148 // Display messages only with "firebug.extensions" type. 149 var messageInfo = subject.wrappedJSObject; 150 151 // If the message type isn't specified, use Firebug's pref domain as the default. 152 if (!messageInfo.type) 153 messageInfo.type = "extensions.firebug"; 154 155 if (messageInfo.type != this.prefDomain) 156 return; 157 158 var message = new Firebug.TraceModule.TraceMessage( 159 messageInfo.type, data, messageInfo.obj, messageInfo.scope, 160 messageInfo.time); 161 162 // If the content isn't loaded yet, remember all messages and insert them later. 163 if (this.logs) 164 this.dump(message); 165 else 166 queue.push(message); 167 168 return true; 169 } 170 else if (topic == "nsPref:changed") 171 { 172 if (data == this.prefDomain + ".trace.showTime") 173 this.updateTimeInfo(); 174 } 175 }, 176 177 // ******************************************************************************************** 178 // Interface to the output nodes, going by the name outputNodes 179 180 getScrollingNode: function() 181 { 182 //window.dump(FBL.getStackDump()); 183 //window.dump("traceConsole getScrollingNode this.scrollingNode "+this.scrollingNode+"\n"); 184 185 return this.scrollingNode; 186 }, 187 188 setScrollingNode: function(node) 189 { 190 this.scrollingNode = node; 191 }, 192 193 getTargetNode: function() 194 { 195 //window.dump(FBL.getStackDump()); 196 //window.dump("traceConsole getTargetgNode this.scrollingNode "+this.logs.firstChild+"\n"); 197 198 return this.logs.firstChild; 199 }, 200 201 // ******************************************************************************************** 202 // Message dump 203 204 dump: function(message) 205 { 206 // Notify listeners 207 for (var i=0; i<this.modules.length; ++i) 208 this.modules[i].onDump(message); 209 210 Firebug.TraceModule.dump(message, this); 211 }, 212 213 dumpSeparator: function() 214 { 215 Firebug.TraceModule.MessageTemplate.dumpSeparator(this); 216 }, 217 218 // Trace console toolbar commands 219 onClearConsole: function() 220 { 221 FBL.clearNode(this.logs.firstChild); 222 }, 223 224 onSeparateConsole: function() 225 { 226 Firebug.TraceModule.MessageTemplate.dumpSeparator(this); 227 }, 228 229 onSaveToFile: function() 230 { 231 try 232 { 233 var nsIFilePicker = Ci.nsIFilePicker; 234 var fp = Cc["@mozilla.org/filepicker;1"].getService(nsIFilePicker); 235 fp.init(window, null, nsIFilePicker.modeSave); 236 fp.appendFilter("Firebug Tracing Logs","*.ftl;"); 237 fp.appendFilters(nsIFilePicker.filterAll); 238 fp.filterIndex = 1; 239 fp.defaultString = "firebug-tracing-logs.ftl"; 240 241 var rv = fp.show(); 242 if (rv == nsIFilePicker.returnOK || rv == nsIFilePicker.returnReplace) 243 { 244 var foStream = Cc["@mozilla.org/network/file-output-stream;1"] 245 .createInstance(Ci.nsIFileOutputStream); 246 foStream.init(fp.file, 0x02 | 0x08 | 0x20, 0666, 0); // write, create, truncate 247 248 var appInfo = Cc["@mozilla.org/xre/app-info;1"].getService(Ci.nsIXULAppInfo); 249 var currLocale = Firebug.getPref("general.useragent", "locale"); 250 var systemInfo = Cc["@mozilla.org/system-info;1"].getService(Ci.nsIPropertyBag); 251 252 var log = { version: "1.0" }; 253 254 // Firebug info version 255 log.firebug = Firebug.version; 256 log.app = { 257 name: appInfo.name, 258 version: appInfo.version, 259 platformVersion: appInfo.platformVersion, 260 buildID: appInfo.appBuildID, 261 locale: currLocale 262 }; 263 log.os = { 264 name: systemInfo.getProperty("name"), 265 version: systemInfo.getProperty("version") 266 }; 267 log.date = (new Date()).toGMTString(); 268 log.messages = []; 269 270 // Iterate over all logs and store it into a file. 271 var tbody = this.logs.firstChild; 272 for (var row = tbody.firstChild; row; row = row.nextSibling) 273 this.saveMessage(log, row.repObject); 274 275 var jsonString = JSON.stringify(log, null, " "); 276 foStream.write(jsonString, jsonString.length); 277 foStream.close(); 278 } 279 } 280 catch (err) 281 { 282 alert(err.toString()); 283 } 284 }, 285 286 onLoadFromFile: function() 287 { 288 try 289 { 290 var nsIFilePicker = Ci.nsIFilePicker; 291 var fp = Cc["@mozilla.org/filepicker;1"].getService(nsIFilePicker); 292 fp.init(window, null, nsIFilePicker.modeOpen); 293 fp.appendFilters(nsIFilePicker.filterAll); 294 fp.appendFilter("Firebug Tracing Logs", "*.ftl;"); 295 fp.filterIndex = 1; 296 297 var rv = fp.show(); 298 if (rv != nsIFilePicker.returnOK) 299 return; 300 301 var inputStream = Cc["@mozilla.org/network/file-input-stream;1"] 302 .createInstance(Ci.nsIFileInputStream); 303 inputStream.init(fp.file, -1, -1, 0); // read-only 304 305 // Read and parset the content 306 var jsonString = FBL.readFromStream(inputStream) 307 var log = JSON.parse(jsonString); 308 if (!log) 309 { 310 alert("No log data available."); 311 return; 312 } 313 314 log.filePath = fp.file.path; 315 316 var MessageTemplate = Firebug.TraceModule.MessageTemplate; 317 var TraceModule = Firebug.TraceModule; 318 319 // Create header, dump all logs and create footer. 320 MessageTemplate.dumpSeparator(this, MessageTemplate.importHeaderTag, log); 321 for (var i=0; i<log.messages.length; i++) 322 { 323 var logMsg = log.messages[i]; 324 if (!logMsg.type) 325 continue; 326 else if (logMsg.type == "separator") 327 MessageTemplate.dumpSeparator(this); 328 else 329 MessageTemplate.dump(new TraceModule.ImportedMessage(logMsg), this); 330 } 331 MessageTemplate.dumpSeparator(this, MessageTemplate.importFooterTag); 332 } 333 catch (err) 334 { 335 alert(err.toString()); 336 } 337 }, 338 339 saveMessage: function(log, message) 340 { 341 if (!message) 342 return; 343 344 var text = message.text; 345 text = text ? text.replace(reEndings, "") : "---"; 346 text = text.replace(/"|'/g, ""); 347 348 var msgLog = { 349 index: message.index, 350 text: message.text, 351 type: message.type ? message.type : "", 352 time: message.time, 353 stack: [] 354 }; 355 356 var stack = message.stack; 357 for (var i=0; stack && i<stack.length; i++) 358 { 359 var frame = stack[i]; 360 msgLog.stack.push({ 361 fileName: frame.fileName, 362 lineNumber: frame.lineNumber, 363 funcName: frame.funcName, 364 }); 365 } 366 367 log.messages.push(msgLog); 368 }, 369 370 onRestartFirefox: function() 371 { 372 Cc["@mozilla.org/toolkit/app-startup;1"].getService(Ci.nsIAppStartup). 373 quit(Ci.nsIAppStartup.eRestart | Ci.nsIAppStartup.eAttemptQuit); 374 }, 375 376 onExitFirefox: function() 377 { 378 goQuitApplication(); 379 }, 380 }; 381 382 // ************************************************************************************************ 383