michael@0: /* This Source Code Form is subject to the terms of the Mozilla Public michael@0: * License, v. 2.0. If a copy of the MPL was not distributed with this michael@0: * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ michael@0: michael@0: let Ci = Components.interfaces; michael@0: let Cc = Components.classes; michael@0: michael@0: dump("### ConsoleAPIObserver.js loaded\n"); michael@0: michael@0: /* michael@0: * ConsoleAPIObserver michael@0: * michael@0: */ michael@0: michael@0: var ConsoleAPIObserver = { michael@0: init: function init() { michael@0: addMessageListener("Browser:TabOpen", this); michael@0: addMessageListener("Browser:TabClose", this); michael@0: }, michael@0: michael@0: receiveMessage: function receiveMessage(aMessage) { michael@0: let json = aMessage.json; michael@0: switch (aMessage.name) { michael@0: case "Browser:TabOpen": michael@0: Services.obs.addObserver(this, "console-api-log-event", false); michael@0: break; michael@0: case "Browser:TabClose": michael@0: Services.obs.removeObserver(this, "console-api-log-event"); michael@0: break; michael@0: } michael@0: }, michael@0: michael@0: observe: function observe(aMessage, aTopic, aData) { michael@0: let contentWindowId = content.QueryInterface(Ci.nsIInterfaceRequestor).getInterface(Ci.nsIDOMWindowUtils).outerWindowID; michael@0: aMessage = aMessage.wrappedJSObject; michael@0: if (aMessage.ID != contentWindowId) michael@0: return; michael@0: michael@0: let mappedArguments = Array.map(aMessage.arguments, this.formatResult, this); michael@0: let joinedArguments = Array.join(mappedArguments, " "); michael@0: michael@0: if (aMessage.level == "error" || aMessage.level == "warn") { michael@0: let flag = (aMessage.level == "error" ? Ci.nsIScriptError.errorFlag : Ci.nsIScriptError.warningFlag); michael@0: let consoleMsg = Cc["@mozilla.org/scripterror;1"].createInstance(Ci.nsIScriptError); michael@0: consoleMsg.init(joinedArguments, null, null, 0, 0, flag, "content javascript"); michael@0: Services.console.logMessage(consoleMsg); michael@0: } else if (aMessage.level == "trace") { michael@0: let bundle = Services.strings.createBundle("chrome://global/locale/headsUpDisplay.properties"); michael@0: let args = aMessage.arguments; michael@0: let filename = this.abbreviateSourceURL(args[0].filename); michael@0: let functionName = args[0].functionName || bundle.GetStringFromName("stacktrace.anonymousFunction"); michael@0: let lineNumber = args[0].lineNumber; michael@0: michael@0: let body = bundle.formatStringFromName("stacktrace.outputMessage", [filename, functionName, lineNumber], 3); michael@0: body += "\n"; michael@0: args.forEach(function(aFrame) { michael@0: body += aFrame.filename + " :: " + aFrame.functionName + " :: " + aFrame.lineNumber + "\n"; michael@0: }); michael@0: michael@0: Services.console.logStringMessage(body); michael@0: } else { michael@0: Services.console.logStringMessage(joinedArguments); michael@0: } michael@0: }, michael@0: michael@0: getResultType: function getResultType(aResult) { michael@0: let type = aResult === null ? "null" : typeof aResult; michael@0: if (type == "object" && aResult.constructor && aResult.constructor.name) michael@0: type = aResult.constructor.name; michael@0: return type.toLowerCase(); michael@0: }, michael@0: michael@0: formatResult: function formatResult(aResult) { michael@0: let output = ""; michael@0: let type = this.getResultType(aResult); michael@0: switch (type) { michael@0: case "string": michael@0: case "boolean": michael@0: case "date": michael@0: case "error": michael@0: case "number": michael@0: case "regexp": michael@0: output = aResult.toString(); michael@0: break; michael@0: case "null": michael@0: case "undefined": michael@0: output = type; michael@0: break; michael@0: default: michael@0: output = aResult.toString(); michael@0: break; michael@0: } michael@0: michael@0: return output; michael@0: }, michael@0: michael@0: abbreviateSourceURL: function abbreviateSourceURL(aSourceURL) { michael@0: // Remove any query parameters. michael@0: let hookIndex = aSourceURL.indexOf("?"); michael@0: if (hookIndex > -1) michael@0: aSourceURL = aSourceURL.substring(0, hookIndex); michael@0: michael@0: // Remove a trailing "/". michael@0: if (aSourceURL[aSourceURL.length - 1] == "/") michael@0: aSourceURL = aSourceURL.substring(0, aSourceURL.length - 1); michael@0: michael@0: // Remove all but the last path component. michael@0: let slashIndex = aSourceURL.lastIndexOf("/"); michael@0: if (slashIndex > -1) michael@0: aSourceURL = aSourceURL.substring(slashIndex + 1); michael@0: michael@0: return aSourceURL; michael@0: } michael@0: }; michael@0: this.ConsoleAPIObserver = ConsoleAPIObserver; michael@0: michael@0: ConsoleAPIObserver.init(); michael@0: