mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
791 lines
25 KiB
JavaScript
791 lines
25 KiB
JavaScript
/* -*- Mode: js2; js2-basic-offset: 2; indent-tabs-mode: nil; -*- */
|
|
/* vim: set ft=javascript ts=2 et sw=2 tw=80: */
|
|
/* This Source Code Form is subject to the terms of the Mozilla Public
|
|
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
|
|
* You can obtain one at http://mozilla.org/MPL/2.0/. */
|
|
|
|
"use strict";
|
|
|
|
// This code is appended to the browser content script.
|
|
(function _HUDServiceContent() {
|
|
let Cc = Components.classes;
|
|
let Ci = Components.interfaces;
|
|
let Cu = Components.utils;
|
|
|
|
let tempScope = {};
|
|
Cu.import("resource://gre/modules/XPCOMUtils.jsm", tempScope);
|
|
Cu.import("resource://gre/modules/Services.jsm", tempScope);
|
|
Cu.import("resource://gre/modules/ConsoleAPIStorage.jsm", tempScope);
|
|
Cu.import("resource:///modules/WebConsoleUtils.jsm", tempScope);
|
|
|
|
let XPCOMUtils = tempScope.XPCOMUtils;
|
|
let Services = tempScope.Services;
|
|
let gConsoleStorage = tempScope.ConsoleAPIStorage;
|
|
let WebConsoleUtils = tempScope.WebConsoleUtils;
|
|
let l10n = WebConsoleUtils.l10n;
|
|
tempScope = null;
|
|
|
|
let _alive = true; // Track if this content script should still be alive.
|
|
|
|
/**
|
|
* The Web Console content instance manager.
|
|
*/
|
|
let Manager = {
|
|
get window() content,
|
|
get console() this.window.console,
|
|
sandbox: null,
|
|
hudId: null,
|
|
_sequence: 0,
|
|
_messageListeners: ["WebConsole:Init", "WebConsole:EnableFeature",
|
|
"WebConsole:DisableFeature", "WebConsole:Destroy"],
|
|
_messageHandlers: null,
|
|
_enabledFeatures: null,
|
|
|
|
/**
|
|
* Getter for a unique ID for the current Web Console content instance.
|
|
*/
|
|
get sequenceId() "HUDContent-" + (++this._sequence),
|
|
|
|
/**
|
|
* Initialize the Web Console manager.
|
|
*/
|
|
init: function Manager_init()
|
|
{
|
|
this._enabledFeatures = [];
|
|
this._messageHandlers = {};
|
|
|
|
this._messageListeners.forEach(function(aName) {
|
|
addMessageListener(aName, this);
|
|
}, this);
|
|
|
|
// Need to track the owner XUL window to listen to the unload and TabClose
|
|
// events, to avoid memory leaks.
|
|
let xulWindow = this.window.QueryInterface(Ci.nsIInterfaceRequestor)
|
|
.getInterface(Ci.nsIWebNavigation)
|
|
.QueryInterface(Ci.nsIDocShell)
|
|
.chromeEventHandler.ownerDocument.defaultView;
|
|
|
|
xulWindow.addEventListener("unload", this._onXULWindowClose, false);
|
|
|
|
let tabContainer = xulWindow.gBrowser.tabContainer;
|
|
tabContainer.addEventListener("TabClose", this._onTabClose, false);
|
|
|
|
// Need to track private browsing change and quit application notifications,
|
|
// again to avoid memory leaks. The Web Console main process cannot notify
|
|
// this content script when the XUL window close, tab close, private
|
|
// browsing change and quit application events happen, so we must call
|
|
// Manager.destroy() on our own.
|
|
Services.obs.addObserver(this, "private-browsing-change-granted", false);
|
|
Services.obs.addObserver(this, "quit-application-granted", false);
|
|
},
|
|
|
|
/**
|
|
* The message handler. This method forwards all the remote messages to the
|
|
* appropriate code.
|
|
*/
|
|
receiveMessage: function Manager_receiveMessage(aMessage)
|
|
{
|
|
if (!_alive) {
|
|
return;
|
|
}
|
|
|
|
if (!aMessage.json || (aMessage.name != "WebConsole:Init" &&
|
|
aMessage.json.hudId != this.hudId)) {
|
|
Cu.reportError("Web Console content script: received message " +
|
|
aMessage.name + " from wrong hudId!");
|
|
return;
|
|
}
|
|
|
|
switch (aMessage.name) {
|
|
case "WebConsole:Init":
|
|
this._onInit(aMessage.json);
|
|
break;
|
|
case "WebConsole:EnableFeature":
|
|
this.enableFeature(aMessage.json.feature, aMessage.json);
|
|
break;
|
|
case "WebConsole:DisableFeature":
|
|
this.disableFeature(aMessage.json.feature);
|
|
break;
|
|
case "WebConsole:Destroy":
|
|
this.destroy();
|
|
break;
|
|
default: {
|
|
let handler = this._messageHandlers[aMessage.name];
|
|
handler && handler(aMessage.json);
|
|
break;
|
|
}
|
|
}
|
|
},
|
|
|
|
/**
|
|
* Observe notifications from the nsIObserverService.
|
|
*
|
|
* @param mixed aSubject
|
|
* @param string aTopic
|
|
* @param mixed aData
|
|
*/
|
|
observe: function Manager_observe(aSubject, aTopic, aData)
|
|
{
|
|
if (_alive && (aTopic == "quit-application-granted" ||
|
|
(aTopic == "private-browsing-change-granted" &&
|
|
(aData == "enter" || aData == "exit")))) {
|
|
this.destroy();
|
|
}
|
|
},
|
|
|
|
/**
|
|
* The manager initialization code. This method is called when the Web Console
|
|
* remote process initializes the content process (this code!).
|
|
*
|
|
* @param object aMessage
|
|
* The object received from the remote process. The WebConsole:Init
|
|
* message properties:
|
|
* - hudId - (required) the remote Web Console instance ID.
|
|
* - features - (optional) array of features you want to enable from
|
|
* the start. For each feature you enable you can pass feature-specific
|
|
* options in a property on the JSON object you send with the same name
|
|
* as the feature. See this.enableFeature() for the list of available
|
|
* features.
|
|
* - cachedMessages - (optional) an array of cached messages you want
|
|
* to receive. See this._sendCachedMessages() for the list of available
|
|
* message types.
|
|
*
|
|
* Example message:
|
|
* {
|
|
* hudId: "foo1",
|
|
* features: ["JSTerm", "ConsoleAPI"],
|
|
* ConsoleAPI: { ... }, // ConsoleAPI-specific options
|
|
* cachedMessages: ["ConsoleAPI"],
|
|
* }
|
|
*/
|
|
_onInit: function Manager_onInit(aMessage)
|
|
{
|
|
this.hudId = aMessage.hudId;
|
|
if (aMessage.features) {
|
|
aMessage.features.forEach(function(aFeature) {
|
|
this.enableFeature(aFeature, aMessage[aFeature]);
|
|
}, this);
|
|
}
|
|
|
|
if (aMessage.cachedMessages) {
|
|
this._sendCachedMessages(aMessage.cachedMessages);
|
|
}
|
|
},
|
|
|
|
/**
|
|
* Add a remote message handler. This is used by other components of the Web
|
|
* Console content script.
|
|
*
|
|
* @param string aName
|
|
* Message name to listen for.
|
|
* @param function aCallback
|
|
* Function to execute when the message is received. This function is
|
|
* given the JSON object that came from the remote Web Console
|
|
* instance.
|
|
* Only one callback per message name is allowed!
|
|
*/
|
|
addMessageHandler: function Manager_addMessageHandler(aName, aCallback)
|
|
{
|
|
if (aName in this._messageHandlers) {
|
|
Cu.reportError("Web Console content script: addMessageHandler() called for an existing message handler: " + aName);
|
|
return;
|
|
}
|
|
|
|
this._messageHandlers[aName] = aCallback;
|
|
addMessageListener(aName, this);
|
|
},
|
|
|
|
/**
|
|
* Remove the message handler for the given name.
|
|
*
|
|
* @param string aName
|
|
* Message name for the handler you want removed.
|
|
*/
|
|
removeMessageHandler: function Manager_removeMessageHandler(aName)
|
|
{
|
|
if (!(aName in this._messageHandlers)) {
|
|
return;
|
|
}
|
|
|
|
delete this._messageHandlers[aName];
|
|
removeMessageListener(aName, this);
|
|
},
|
|
|
|
/**
|
|
* Send a message to the remote Web Console instance.
|
|
*
|
|
* @param string aName
|
|
* The name of the message you want to send.
|
|
* @param object aMessage
|
|
* The message object you want to send.
|
|
*/
|
|
sendMessage: function Manager_sendMessage(aName, aMessage)
|
|
{
|
|
aMessage.hudId = this.hudId;
|
|
if (!("id" in aMessage)) {
|
|
aMessage.id = this.sequenceId;
|
|
}
|
|
|
|
sendAsyncMessage(aName, aMessage);
|
|
},
|
|
|
|
/**
|
|
* Enable a feature in the Web Console content script. A feature is generally
|
|
* a set of observers/listeners that are added in the content process. This
|
|
* content script exposes the data via the message manager for the features
|
|
* you enable.
|
|
*
|
|
* Supported features:
|
|
* - JSTerm - a JavaScript "terminal" which allows code execution.
|
|
* - ConsoleAPI - support for routing the window.console API to the remote
|
|
* process.
|
|
* - PageError - route all the nsIScriptErrors from the nsIConsoleService
|
|
* to the remote process.
|
|
*
|
|
* @param string aFeature
|
|
* One of the supported features: JSTerm, ConsoleAPI.
|
|
* @param object [aMessage]
|
|
* Optional JSON message object coming from the remote Web Console
|
|
* instance. This can be used for feature-specific options.
|
|
*/
|
|
enableFeature: function Manager_enableFeature(aFeature, aMessage)
|
|
{
|
|
if (this._enabledFeatures.indexOf(aFeature) != -1) {
|
|
return;
|
|
}
|
|
|
|
switch (aFeature) {
|
|
case "JSTerm":
|
|
JSTerm.init(aMessage);
|
|
break;
|
|
case "ConsoleAPI":
|
|
ConsoleAPIObserver.init(aMessage);
|
|
break;
|
|
case "PageError":
|
|
ConsoleListener.init(aMessage);
|
|
break;
|
|
default:
|
|
Cu.reportError("Web Console content: unknown feature " + aFeature);
|
|
break;
|
|
}
|
|
|
|
this._enabledFeatures.push(aFeature);
|
|
},
|
|
|
|
/**
|
|
* Disable a Web Console content script feature.
|
|
*
|
|
* @see this.enableFeature
|
|
* @param string aFeature
|
|
* One of the supported features - see this.enableFeature() for the
|
|
* list of supported features.
|
|
*/
|
|
disableFeature: function Manager_disableFeature(aFeature)
|
|
{
|
|
let index = this._enabledFeatures.indexOf(aFeature);
|
|
if (index == -1) {
|
|
return;
|
|
}
|
|
this._enabledFeatures.splice(index, 1);
|
|
|
|
switch (aFeature) {
|
|
case "JSTerm":
|
|
JSTerm.destroy();
|
|
break;
|
|
case "ConsoleAPI":
|
|
ConsoleAPIObserver.destroy();
|
|
break;
|
|
case "PageError":
|
|
ConsoleListener.destroy();
|
|
break;
|
|
default:
|
|
Cu.reportError("Web Console content: unknown feature " + aFeature);
|
|
break;
|
|
}
|
|
},
|
|
|
|
/**
|
|
* Send the cached messages to the remote Web Console instance.
|
|
*
|
|
* @private
|
|
* @param array aMessageTypes
|
|
* An array that lists which kinds of messages you want. Supported
|
|
* message types: "ConsoleAPI" and "PageError".
|
|
*/
|
|
_sendCachedMessages: function Manager__sendCachedMessages(aMessageTypes)
|
|
{
|
|
let messages = [];
|
|
|
|
while (aMessageTypes.length > 0) {
|
|
switch (aMessageTypes.shift()) {
|
|
case "ConsoleAPI":
|
|
messages.push.apply(messages, ConsoleAPIObserver.getCachedMessages());
|
|
break;
|
|
case "PageError":
|
|
messages.push.apply(messages, ConsoleListener.getCachedMessages());
|
|
break;
|
|
}
|
|
}
|
|
|
|
messages.sort(function(a, b) { return a.timeStamp - b.timeStamp; });
|
|
|
|
this.sendMessage("WebConsole:CachedMessages", {messages: messages});
|
|
},
|
|
|
|
/**
|
|
* The XUL window "unload" event handler which destroys this content script
|
|
* instance.
|
|
* @private
|
|
*/
|
|
_onXULWindowClose: function Manager__onXULWindowClose()
|
|
{
|
|
if (_alive) {
|
|
Manager.destroy();
|
|
}
|
|
},
|
|
|
|
/**
|
|
* The "TabClose" event handler which destroys this content script
|
|
* instance, if needed.
|
|
* @private
|
|
*/
|
|
_onTabClose: function Manager__onTabClose(aEvent)
|
|
{
|
|
let tab = aEvent.target;
|
|
if (_alive && tab.linkedBrowser.contentWindow === Manager.window) {
|
|
Manager.destroy();
|
|
}
|
|
},
|
|
|
|
/**
|
|
* Destroy the Web Console content script instance.
|
|
*/
|
|
destroy: function Manager_destroy()
|
|
{
|
|
Services.obs.removeObserver(this, "private-browsing-change-granted");
|
|
Services.obs.removeObserver(this, "quit-application-granted");
|
|
|
|
_alive = false;
|
|
let xulWindow = this.window.QueryInterface(Ci.nsIInterfaceRequestor)
|
|
.getInterface(Ci.nsIWebNavigation)
|
|
.QueryInterface(Ci.nsIDocShell)
|
|
.chromeEventHandler.ownerDocument.defaultView;
|
|
|
|
xulWindow.removeEventListener("unload", this._onXULWindowClose, false);
|
|
let tabContainer = xulWindow.gBrowser.tabContainer;
|
|
tabContainer.removeEventListener("TabClose", this._onTabClose, false);
|
|
|
|
this._messageListeners.forEach(function(aName) {
|
|
removeMessageListener(aName, this);
|
|
}, this);
|
|
|
|
this._enabledFeatures.slice().forEach(this.disableFeature, this);
|
|
|
|
this.hudId = null;
|
|
this._messageHandlers = null;
|
|
Manager = ConsoleAPIObserver = JSTerm = ConsoleListener = null;
|
|
Cc = Ci = Cu = XPCOMUtils = Services = gConsoleStorage =
|
|
WebConsoleUtils = l10n = null;
|
|
},
|
|
};
|
|
|
|
/**
|
|
* The JavaScript terminal is meant to allow remote code execution for the Web
|
|
* Console.
|
|
*/
|
|
let JSTerm = {
|
|
/**
|
|
* Evaluation result objects are cached in this object. The chrome process can
|
|
* request any object based on its ID.
|
|
*/
|
|
_objectCache: null,
|
|
|
|
/**
|
|
* Initialize the JavaScript terminal feature.
|
|
*/
|
|
init: function JST_init()
|
|
{
|
|
this._objectCache = {};
|
|
|
|
Manager.addMessageHandler("JSTerm:GetEvalObject",
|
|
this.handleGetEvalObject.bind(this));
|
|
Manager.addMessageHandler("JSTerm:ClearObjectCache",
|
|
this.handleClearObjectCache.bind(this));
|
|
},
|
|
|
|
/**
|
|
* Handler for the remote "JSTerm:GetEvalObject" message. This allows the
|
|
* remote Web Console instance to retrieve an object from the content process.
|
|
*
|
|
* @param object aRequest
|
|
* The message that requests the content object. Properties: cacheId,
|
|
* objectId and resultCacheId.
|
|
*
|
|
* Evaluated objects are stored in "buckets" (cache IDs). Each object
|
|
* is assigned an ID (object ID). You can request a specific object
|
|
* (objectId) from a specific cache (cacheId) and tell where the result
|
|
* should be cached (resultCacheId). The requested object can have
|
|
* further references to other objects - those references will be
|
|
* cached in the "bucket" of your choice (based on resultCacheId). If
|
|
* you do not provide any resultCacheId in the request message, then
|
|
* cacheId will be used.
|
|
*/
|
|
handleGetEvalObject: function JST_handleGetEvalObject(aRequest)
|
|
{
|
|
if (aRequest.cacheId in this._objectCache &&
|
|
aRequest.objectId in this._objectCache[aRequest.cacheId]) {
|
|
let object = this._objectCache[aRequest.cacheId][aRequest.objectId];
|
|
let resultCacheId = aRequest.resultCacheId || aRequest.cacheId;
|
|
let message = {
|
|
id: aRequest.id,
|
|
cacheId: aRequest.cacheId,
|
|
objectId: aRequest.objectId,
|
|
object: this.prepareObjectForRemote(object, resultCacheId),
|
|
childrenCacheId: resultCacheId,
|
|
};
|
|
Manager.sendMessage("JSTerm:EvalObject", message);
|
|
}
|
|
else {
|
|
Cu.reportError("JSTerm:GetEvalObject request " + aRequest.id +
|
|
": stale object.");
|
|
}
|
|
},
|
|
|
|
/**
|
|
* Handler for the remote "JSTerm:ClearObjectCache" message. This allows the
|
|
* remote Web Console instance to clear the cache of objects that it no longer
|
|
* uses.
|
|
*
|
|
* @param object aRequest
|
|
* An object that holds one property: the cacheId you want cleared.
|
|
*/
|
|
handleClearObjectCache: function JST_handleClearObjectCache(aRequest)
|
|
{
|
|
if (aRequest.cacheId in this._objectCache) {
|
|
delete this._objectCache[aRequest.cacheId];
|
|
}
|
|
},
|
|
|
|
/**
|
|
* Prepare an object to be sent to the remote Web Console instance.
|
|
*
|
|
* @param object aObject
|
|
* The object you want to send to the remote Web Console instance.
|
|
* @param number aCacheId
|
|
* Cache ID where you want object references to be stored into. The
|
|
* given object may include references to other objects - those
|
|
* references will be stored in the given cache ID so the remote
|
|
* process can later retrieve them as well.
|
|
* @return array
|
|
* An array that holds one element for each enumerable property and
|
|
* method in aObject. Each element describes the property. For details
|
|
* see WebConsoleUtils.namesAndValuesOf().
|
|
*/
|
|
prepareObjectForRemote:
|
|
function JST_prepareObjectForRemote(aObject, aCacheId)
|
|
{
|
|
// Cache the properties that have inspectable values.
|
|
let propCache = this._objectCache[aCacheId] || {};
|
|
let result = WebConsoleUtils.namesAndValuesOf(aObject, propCache);
|
|
if (!(aCacheId in this._objectCache) && Object.keys(propCache).length > 0) {
|
|
this._objectCache[aCacheId] = propCache;
|
|
}
|
|
|
|
return result;
|
|
},
|
|
|
|
/**
|
|
* Destroy the JSTerm instance.
|
|
*/
|
|
destroy: function JST_destroy()
|
|
{
|
|
Manager.removeMessageHandler("JSTerm:GetEvalObject");
|
|
Manager.removeMessageHandler("JSTerm:ClearObjectCache");
|
|
|
|
delete this._objectCache;
|
|
},
|
|
};
|
|
|
|
/**
|
|
* The window.console API observer. This allows the window.console API messages
|
|
* to be sent to the remote Web Console instance.
|
|
*/
|
|
let ConsoleAPIObserver = {
|
|
QueryInterface: XPCOMUtils.generateQI([Ci.nsIObserver]),
|
|
|
|
/**
|
|
* Initialize the window.console API observer.
|
|
*/
|
|
init: function CAO_init()
|
|
{
|
|
// Note that the observer is process-wide. We will filter the messages as
|
|
// needed, see CAO_observe().
|
|
Services.obs.addObserver(this, "console-api-log-event", false);
|
|
|
|
Manager.addMessageHandler("ConsoleAPI:ClearCache",
|
|
this.handleClearCache.bind(this));
|
|
},
|
|
|
|
/**
|
|
* The console API message observer. When messages are received from the
|
|
* observer service we forward them to the remote Web Console instance.
|
|
*
|
|
* @param object aMessage
|
|
* The message object receives from the observer service.
|
|
* @param string aTopic
|
|
* The message topic received from the observer service.
|
|
*/
|
|
observe: function CAO_observe(aMessage, aTopic)
|
|
{
|
|
if (!_alive || !aMessage || aTopic != "console-api-log-event") {
|
|
return;
|
|
}
|
|
|
|
let apiMessage = aMessage.wrappedJSObject;
|
|
|
|
let msgWindow =
|
|
WebConsoleUtils.getWindowByOuterId(apiMessage.ID, Manager.window);
|
|
if (!msgWindow || msgWindow.top != Manager.window) {
|
|
// Not the same window!
|
|
return;
|
|
}
|
|
|
|
let messageToChrome = {};
|
|
this._prepareApiMessageForRemote(apiMessage, messageToChrome);
|
|
Manager.sendMessage("WebConsole:ConsoleAPI", messageToChrome);
|
|
},
|
|
|
|
/**
|
|
* Prepare a message from the console APi to be sent to the remote Web Console
|
|
* instance.
|
|
*
|
|
* @param object aOriginalMessage
|
|
* The original message received from console-api-log-event.
|
|
* @param object aRemoteMessage
|
|
* The object you want to send to the remote Web Console. This object
|
|
* is updated to hold information from the original message. New
|
|
* properties added:
|
|
* - timeStamp
|
|
* Message timestamp (same as the aOriginalMessage.timeStamp property).
|
|
* - apiMessage
|
|
* An object that copies almost all the properties from
|
|
* aOriginalMessage. Arguments might be skipped if it holds references
|
|
* to objects that cannot be sent as they are to the remote Web Console
|
|
* instance.
|
|
* - argumentsToString
|
|
* Optional: the aOriginalMessage.arguments object stringified.
|
|
*
|
|
* The apiMessage.arguments property is set to hold data appropriate
|
|
* to the message level. A similar approach is used for
|
|
* argumentsToString.
|
|
*/
|
|
_prepareApiMessageForRemote:
|
|
function CAO__prepareApiMessageForRemote(aOriginalMessage, aRemoteMessage)
|
|
{
|
|
aRemoteMessage.apiMessage =
|
|
WebConsoleUtils.cloneObject(aOriginalMessage, true,
|
|
function(aKey, aValue, aObject) {
|
|
// We need to skip the arguments property from the original object.
|
|
if (aKey == "wrappedJSObject" || aObject === aOriginalMessage &&
|
|
aKey == "arguments") {
|
|
return false;
|
|
}
|
|
return true;
|
|
});
|
|
|
|
aRemoteMessage.timeStamp = aOriginalMessage.timeStamp;
|
|
|
|
switch (aOriginalMessage.level) {
|
|
case "trace":
|
|
case "time":
|
|
case "timeEnd":
|
|
case "group":
|
|
case "groupCollapsed":
|
|
aRemoteMessage.apiMessage.arguments =
|
|
WebConsoleUtils.cloneObject(aOriginalMessage.arguments, true);
|
|
break;
|
|
|
|
case "log":
|
|
case "info":
|
|
case "warn":
|
|
case "error":
|
|
case "debug":
|
|
case "groupEnd":
|
|
aRemoteMessage.argumentsToString =
|
|
Array.map(aOriginalMessage.arguments || [],
|
|
this._formatObject.bind(this));
|
|
break;
|
|
|
|
case "dir": {
|
|
aRemoteMessage.objectsCacheId = Manager.sequenceId;
|
|
aRemoteMessage.argumentsToString = [];
|
|
let mapFunction = function(aItem) {
|
|
aRemoteMessage.argumentsToString.push(this._formatObject(aItem));
|
|
if (WebConsoleUtils.isObjectInspectable(aItem)) {
|
|
return JSTerm.prepareObjectForRemote(aItem,
|
|
aRemoteMessage.objectsCacheId);
|
|
}
|
|
return aItem;
|
|
}.bind(this);
|
|
|
|
aRemoteMessage.apiMessage.arguments =
|
|
Array.map(aOriginalMessage.arguments || [], mapFunction);
|
|
break;
|
|
}
|
|
default:
|
|
Cu.reportError("Unknown Console API log level: " +
|
|
aOriginalMessage.level);
|
|
break;
|
|
}
|
|
},
|
|
|
|
/**
|
|
* Format an object's value to be displayed in the Web Console.
|
|
*
|
|
* @private
|
|
* @param object aObject
|
|
* The object you want to display.
|
|
* @return string
|
|
* The string you can display for the given object.
|
|
*/
|
|
_formatObject: function CAO__formatObject(aObject)
|
|
{
|
|
return typeof aObject == "string" ?
|
|
aObject : WebConsoleUtils.formatResult(aObject);
|
|
},
|
|
|
|
/**
|
|
* Get the cached messages for the current inner window.
|
|
*
|
|
* @see this._prepareApiMessageForRemote()
|
|
* @return array
|
|
* The array of cached messages. Each element is a Console API
|
|
* prepared to be sent to the remote Web Console instance.
|
|
*/
|
|
getCachedMessages: function CAO_getCachedMessages()
|
|
{
|
|
let innerWindowId = WebConsoleUtils.getInnerWindowId(Manager.window);
|
|
let messages = gConsoleStorage.getEvents(innerWindowId);
|
|
|
|
let result = messages.map(function(aMessage) {
|
|
let remoteMessage = { _type: "ConsoleAPI" };
|
|
this._prepareApiMessageForRemote(aMessage.wrappedJSObject, remoteMessage);
|
|
return remoteMessage;
|
|
}, this);
|
|
|
|
return result;
|
|
},
|
|
|
|
/**
|
|
* Handler for the "ConsoleAPI:ClearCache" message.
|
|
*/
|
|
handleClearCache: function CAO_handleClearCache()
|
|
{
|
|
let windowId = WebConsoleUtils.getInnerWindowId(Manager.window);
|
|
gConsoleStorage.clearEvents(windowId);
|
|
},
|
|
|
|
/**
|
|
* Destroy the ConsoleAPIObserver listeners.
|
|
*/
|
|
destroy: function CAO_destroy()
|
|
{
|
|
Manager.removeMessageHandler("ConsoleAPI:ClearCache");
|
|
Services.obs.removeObserver(this, "console-api-log-event");
|
|
},
|
|
};
|
|
|
|
/**
|
|
* The nsIConsoleService listener. This is used to send all the page errors
|
|
* (JavaScript, CSS and more) to the remote Web Console instance.
|
|
*/
|
|
let ConsoleListener = {
|
|
QueryInterface: XPCOMUtils.generateQI([Ci.nsIConsoleListener]),
|
|
|
|
/**
|
|
* Initialize the nsIConsoleService listener.
|
|
*/
|
|
init: function CL_init()
|
|
{
|
|
Services.console.registerListener(this);
|
|
},
|
|
|
|
/**
|
|
* The nsIConsoleService observer. This method takes all the script error
|
|
* messages belonging to the current window and sends them to the remote Web
|
|
* Console instance.
|
|
*
|
|
* @param nsIScriptError aScriptError
|
|
* The script error object coming from the nsIConsoleService.
|
|
*/
|
|
observe: function CL_observe(aScriptError)
|
|
{
|
|
if (!_alive || !(aScriptError instanceof Ci.nsIScriptError) ||
|
|
!aScriptError.outerWindowID) {
|
|
return;
|
|
}
|
|
|
|
switch (aScriptError.category) {
|
|
// We ignore chrome-originating errors as we only care about content.
|
|
case "XPConnect JavaScript":
|
|
case "component javascript":
|
|
case "chrome javascript":
|
|
case "chrome registration":
|
|
case "XBL":
|
|
case "XBL Prototype Handler":
|
|
case "XBL Content Sink":
|
|
case "xbl javascript":
|
|
return;
|
|
}
|
|
|
|
let errorWindow =
|
|
WebConsoleUtils.getWindowByOuterId(aScriptError.outerWindowID,
|
|
Manager.window);
|
|
if (!errorWindow || errorWindow.top != Manager.window) {
|
|
return;
|
|
}
|
|
|
|
Manager.sendMessage("WebConsole:PageError", { pageError: aScriptError });
|
|
},
|
|
|
|
/**
|
|
* Get the cached page errors for the current inner window.
|
|
*
|
|
* @return array
|
|
* The array of cached messages. Each element is an nsIScriptError
|
|
* with an added _type property so the remote Web Console instance can
|
|
* tell the difference between various types of cached messages.
|
|
*/
|
|
getCachedMessages: function CL_getCachedMessages()
|
|
{
|
|
let innerWindowId = WebConsoleUtils.getInnerWindowId(Manager.window);
|
|
let result = [];
|
|
let errors = {};
|
|
Services.console.getMessageArray(errors, {});
|
|
|
|
(errors.value || []).forEach(function(aError) {
|
|
if (!(aError instanceof Ci.nsIScriptError) ||
|
|
aError.innerWindowID != innerWindowId) {
|
|
return;
|
|
}
|
|
|
|
let remoteMessage = WebConsoleUtils.cloneObject(aError);
|
|
remoteMessage._type = "PageError";
|
|
result.push(remoteMessage);
|
|
});
|
|
|
|
return result;
|
|
},
|
|
|
|
/**
|
|
* Remove the nsIConsoleService listener.
|
|
*/
|
|
destroy: function CL_destroy()
|
|
{
|
|
Services.console.unregisterListener(this);
|
|
},
|
|
};
|
|
|
|
Manager.init();
|
|
})();
|