This commit is contained in:
Brian Hackett 2011-08-29 18:41:32 -07:00
Родитель 312278ef46 3e21b474bc
Коммит 2c18d8ec04
51 изменённых файлов: 889 добавлений и 132 удалений

Просмотреть файл

@ -540,6 +540,7 @@ var InspectorUI = {
inspecting: false,
treeLoaded: false,
prefEnabledName: "devtools.inspector.enabled",
isDirty: false,
/**
* Toggle the inspector interface elements on or off.
@ -585,7 +586,7 @@ var InspectorUI = {
get defaultSelection()
{
let doc = this.win.document;
return doc.documentElement.lastElementChild;
return doc.documentElement ? doc.documentElement.lastElementChild : null;
},
initializeTreePanel: function IUI_initializeTreePanel()
@ -779,6 +780,8 @@ var InspectorUI = {
this.toolbar.hidden = false;
this.inspectCmd.setAttribute("checked", true);
gBrowser.addProgressListener(InspectorProgressListener);
},
/**
@ -838,6 +841,8 @@ var InspectorUI = {
this.closing = true;
this.toolbar.hidden = true;
gBrowser.removeProgressListener(InspectorProgressListener);
if (!aKeepStore) {
InspectorStore.deleteStore(this.winID);
this.win.removeEventListener("pagehide", this, true);
@ -1315,6 +1320,8 @@ var InspectorUI = {
// update the HTML tree attribute value
this.editingContext.attrObj.innerHTML = editorInput.value;
this.isDirty = true;
// event notification
Services.obs.notifyObservers(null, INSPECTOR_NOTIFICATIONS.EDITOR_SAVED,
null);
@ -1741,9 +1748,122 @@ var InspectorStore = {
}
};
/**
* The InspectorProgressListener object is an nsIWebProgressListener which
* handles onStateChange events for the inspected browser. If the user makes
* changes to the web page and he tries to navigate away, he is prompted to
* confirm page navigation, such that he's given the chance to prevent the loss
* of edits.
*/
var InspectorProgressListener = {
onStateChange:
function IPL_onStateChange(aProgress, aRequest, aFlag, aStatus)
{
// Remove myself if the Inspector is no longer open.
if (!InspectorUI.isTreePanelOpen) {
gBrowser.removeProgressListener(InspectorProgressListener);
return;
}
// Skip non-start states.
if (!(aFlag & Ci.nsIWebProgressListener.STATE_START)) {
return;
}
// If the request is about to happen in a new window, we are not concerned
// about the request.
if (aProgress.DOMWindow != InspectorUI.win) {
return;
}
if (InspectorUI.isDirty) {
this.showNotification(aRequest);
} else {
InspectorUI.closeInspectorUI();
}
},
/**
* Show an asynchronous notification which asks the user to confirm or cancel
* the page navigation request.
*
* @param nsIRequest aRequest
* The request initiated by the user or by the page itself.
* @returns void
*/
showNotification: function IPL_showNotification(aRequest)
{
aRequest.suspend();
let notificationBox = gBrowser.getNotificationBox(InspectorUI.browser);
let notification = notificationBox.
getNotificationWithValue("inspector-page-navigation");
if (notification) {
notificationBox.removeNotification(notification, true);
}
let cancelRequest = function onCancelRequest() {
if (aRequest) {
aRequest.cancel(Cr.NS_BINDING_ABORTED);
aRequest.resume(); // needed to allow the connection to be cancelled.
aRequest = null;
}
};
let eventCallback = function onNotificationCallback(aEvent) {
if (aEvent == "removed") {
cancelRequest();
}
};
let buttons = [
{
id: "inspector.confirmNavigationAway.buttonLeave",
label: InspectorUI.strings.
GetStringFromName("confirmNavigationAway.buttonLeave"),
accessKey: InspectorUI.strings.
GetStringFromName("confirmNavigationAway.buttonLeaveAccesskey"),
callback: function onButtonLeave() {
if (aRequest) {
aRequest.resume();
aRequest = null;
InspectorUI.closeInspectorUI();
}
},
},
{
id: "inspector.confirmNavigationAway.buttonStay",
label: InspectorUI.strings.
GetStringFromName("confirmNavigationAway.buttonStay"),
accessKey: InspectorUI.strings.
GetStringFromName("confirmNavigationAway.buttonStayAccesskey"),
callback: cancelRequest
},
];
let message = InspectorUI.strings.
GetStringFromName("confirmNavigationAway.message");
notification = notificationBox.appendNotification(message,
"inspector-page-navigation", "chrome://browser/skin/Info.png",
notificationBox.PRIORITY_WARNING_HIGH, buttons, eventCallback);
// Make sure this not a transient notification, to avoid the automatic
// transient notification removal.
notification.persistence = -1;
},
};
/////////////////////////////////////////////////////////////////////////
//// Initializors
//// Initializers
XPCOMUtils.defineLazyGetter(InspectorUI, "inspectCmd", function () {
return document.getElementById("Tools:Inspect");
});
XPCOMUtils.defineLazyGetter(InspectorUI, "strings", function () {
return Services.strings.
createBundle("chrome://browser/locale/inspector.properties");
});

Просмотреть файл

@ -57,6 +57,7 @@ _BROWSER_FILES = \
browser_inspector_registertools.js \
browser_inspector_bug_665880.js \
browser_inspector_editor.js \
browser_inspector_bug_566084_location_changed.js \
$(NULL)
libs:: $(_BROWSER_FILES)

Просмотреть файл

@ -0,0 +1,121 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
let notificationBox = null;
function startLocationTests() {
ok(window.InspectorUI, "InspectorUI variable exists");
Services.obs.addObserver(runInspectorTests, INSPECTOR_NOTIFICATIONS.OPENED, null);
InspectorUI.toggleInspectorUI();
}
function runInspectorTests() {
Services.obs.removeObserver(runInspectorTests, INSPECTOR_NOTIFICATIONS.OPENED, null);
let para = content.document.querySelector("p");
ok(para, "found the paragraph element");
is(para.textContent, "init", "paragraph content is correct");
ok(InspectorUI.inspecting, "Inspector is highlighting");
ok(InspectorUI.isTreePanelOpen, "Inspector Panel is open");
InspectorUI.isDirty = true;
notificationBox = gBrowser.getNotificationBox(gBrowser.selectedBrowser);
notificationBox.addEventListener("AlertActive", alertActive1, false);
gBrowser.selectedBrowser.addEventListener("load", onPageLoad, true);
content.location = "data:text/html,<div>location change test 1 for " +
"inspector</div><p>test1</p>";
}
function alertActive1() {
notificationBox.removeEventListener("AlertActive", alertActive1, false);
let notification = notificationBox.
getNotificationWithValue("inspector-page-navigation");
ok(notification, "found the inspector-page-navigation notification");
// By closing the notification it is expected that page navigation is
// canceled.
executeSoon(function() {
notification.close();
locationTest2();
});
}
function onPageLoad() {
gBrowser.selectedBrowser.removeEventListener("load", onPageLoad, true);
isnot(content.location.href.indexOf("test2"), -1,
"page navigated to the correct location");
let para = content.document.querySelector("p");
ok(para, "found the paragraph element, third time");
is(para.textContent, "test2", "paragraph content is correct");
ok(!InspectorUI.inspecting, "Inspector is not highlighting");
ok(!InspectorUI.isTreePanelOpen, "Inspector Panel is not open");
testEnd();
}
function locationTest2() {
// Location did not change.
let para = content.document.querySelector("p");
ok(para, "found the paragraph element, second time");
is(para.textContent, "init", "paragraph content is correct");
ok(InspectorUI.inspecting, "Inspector is highlighting");
ok(InspectorUI.isTreePanelOpen, "Inspector Panel is open");
notificationBox.addEventListener("AlertActive", alertActive2, false);
content.location = "data:text/html,<div>location change test 2 for " +
"inspector</div><p>test2</p>";
}
function alertActive2() {
notificationBox.removeEventListener("AlertActive", alertActive2, false);
let notification = notificationBox.
getNotificationWithValue("inspector-page-navigation");
ok(notification, "found the inspector-page-navigation notification");
let buttons = notification.querySelectorAll("button");
let buttonLeave = null;
for (let i = 0; i < buttons.length; i++) {
if (buttons[i].buttonInfo.id == "inspector.confirmNavigationAway.buttonLeave") {
buttonLeave = buttons[i];
break;
}
}
ok(buttonLeave, "the Leave page button was found");
// Accept page navigation.
executeSoon(function(){
buttonLeave.doCommand();
});
}
function testEnd() {
notificationBox = null;
InspectorUI.isDirty = false;
gBrowser.removeCurrentTab();
executeSoon(finish);
}
function test() {
waitForExplicitFinish();
gBrowser.selectedTab = gBrowser.addTab();
gBrowser.selectedBrowser.addEventListener("load", function onBrowserLoad() {
gBrowser.selectedBrowser.removeEventListener("load", onBrowserLoad, true);
waitForFocus(startLocationTests, content);
}, true);
content.location = "data:text/html,<div>location change tests for " +
"inspector.</div><p>init</p>";
}

Просмотреть файл

@ -280,7 +280,7 @@ var Scratchpad = {
scriptError.initWithWindowID(ex.message + "\n" + ex.stack, ex.fileName,
"", ex.lineNumber, 0, scriptError.errorFlag,
"content javascript",
this.getWindowId(contentWindow));
this.getInnerWindowId(contentWindow));
Services.console.logMessage(scriptError);
}
@ -633,16 +633,16 @@ var Scratchpad = {
},
/**
* Gets the ID of the outer window of the given DOM window object.
* Gets the ID of the inner window of the given DOM window object.
*
* @param nsIDOMWindow aWindow
* @return integer
* the outer window ID
* the inner window ID
*/
getWindowId: function SP_getWindowId(aWindow)
getInnerWindowId: function SP_getInnerWindowId(aWindow)
{
return aWindow.QueryInterface(Ci.nsIInterfaceRequestor).
getInterface(Ci.nsIDOMWindowUtils).outerWindowID;
getInterface(Ci.nsIDOMWindowUtils).currentInnerWindowID;
},
/**

Просмотреть файл

@ -90,7 +90,7 @@ XPCOMUtils.defineLazyGetter(this, "PropertyPanel", function () {
XPCOMUtils.defineLazyGetter(this, "AutocompletePopup", function () {
var obj = {};
try {
Cu.import("resource://gre/modules/AutocompletePopup.jsm", obj);
Cu.import("resource:///modules/AutocompletePopup.jsm", obj);
}
catch (err) {
Cu.reportError(err);

Просмотреть файл

@ -6,7 +6,7 @@
// Tests that document.body autocompletes in the web console.
Cu.import("resource://gre/modules/PropertyPanel.jsm");
Cu.import("resource:///modules/PropertyPanel.jsm");
function test() {
addTab("data:text/html,Web Console autocompletion bug in document.body");

Просмотреть файл

@ -36,7 +36,7 @@
*
* ***** END LICENSE BLOCK ***** */
Cu.import("resource://gre/modules/HUDService.jsm");
Cu.import("resource:///modules/HUDService.jsm");
function log(aMsg)
{

Просмотреть файл

@ -0,0 +1,9 @@
# LOCALIZATION NOTE (confirmNavigationAway): Used in the Inspector tool, when
# the user tries to navigate away from a web page, to confirm the change of
# page.
confirmNavigationAway.message=Leaving this page will close the Inspector and the changes you have made will be lost.
confirmNavigationAway.buttonLeave=Leave Page
confirmNavigationAway.buttonLeaveAccesskey=L
confirmNavigationAway.buttonStay=Stay on Page
confirmNavigationAway.buttonStayAccesskey=S

Просмотреть файл

@ -16,6 +16,7 @@
locale/browser/browser.properties (%chrome/browser/browser.properties)
locale/browser/scratchpad.properties (%chrome/browser/scratchpad.properties)
locale/browser/scratchpad.dtd (%chrome/browser/scratchpad.dtd)
locale/browser/inspector.properties (%chrome/browser/inspector.properties)
locale/browser/openLocation.dtd (%chrome/browser/openLocation.dtd)
locale/browser/openLocation.properties (%chrome/browser/openLocation.properties)
* locale/browser/pageInfo.dtd (%chrome/browser/pageInfo.dtd)

Просмотреть файл

@ -743,8 +743,8 @@ public:
* @param aColumnNumber Column number within resource containing error.
* @param aErrorFlags See nsIScriptError.
* @param aCategory Name of module reporting error.
* @param [aWindowId=0] (Optional) The window ID of the outer window the
* message originates from.
* @param [aInnerWindowId=0] (Optional) The window ID of the inner window
* the message originates from.
*/
enum PropertiesFile {
eCSS_PROPERTIES,
@ -769,7 +769,7 @@ public:
PRUint32 aColumnNumber,
PRUint32 aErrorFlags,
const char *aCategory,
PRUint64 aWindowId = 0);
PRUint64 aInnerWindowId = 0);
/**
* Report a localized error message to the error console.

Просмотреть файл

@ -720,6 +720,15 @@ public:
return window ? window->WindowID() : 0;
}
/**
* Return the inner window ID.
*/
PRUint64 InnerWindowID()
{
nsPIDOMWindow *window = GetInnerWindow();
return window ? window->WindowID() : 0;
}
/**
* Get the script loader for this document
*/

Просмотреть файл

@ -2733,7 +2733,7 @@ nsContentUtils::ReportToConsole(PropertiesFile aFile,
PRUint32 aColumnNumber,
PRUint32 aErrorFlags,
const char *aCategory,
PRUint64 aWindowId)
PRUint64 aInnerWindowId)
{
NS_ASSERTION((aParams && aParamsLength) || (!aParams && !aParamsLength),
"Supply either both parameters and their number or no"
@ -2767,7 +2767,8 @@ nsContentUtils::ReportToConsole(PropertiesFile aFile,
NS_ConvertUTF8toUTF16(spec).get(), // file name
aSourceLine.get(),
aLineNumber, aColumnNumber,
aErrorFlags, aCategory, aWindowId);
aErrorFlags, aCategory,
aInnerWindowId);
NS_ENSURE_SUCCESS(rv, rv);
nsCOMPtr<nsIScriptError> logError = do_QueryInterface(errorObject);
@ -2788,17 +2789,17 @@ nsContentUtils::ReportToConsole(PropertiesFile aFile,
nsIDocument* aDocument)
{
nsIURI* uri = aURI;
PRUint64 windowID = 0;
PRUint64 innerWindowID = 0;
if (aDocument) {
if (!uri) {
uri = aDocument->GetDocumentURI();
}
windowID = aDocument->OuterWindowID();
innerWindowID = aDocument->InnerWindowID();
}
return ReportToConsole(aFile, aMessageName, aParams, aParamsLength, uri,
aSourceLine, aLineNumber, aColumnNumber, aErrorFlags,
aCategory, windowID);
aCategory, innerWindowID);
}
PRBool

Просмотреть файл

@ -85,7 +85,7 @@ nsEventSource::nsEventSource() :
mLastConvertionResult(NS_OK),
mReadyState(nsIEventSource::CONNECTING),
mScriptLine(0),
mWindowID(0)
mInnerWindowID(0)
{
}
@ -253,7 +253,7 @@ nsEventSource::Init(nsIPrincipal* aPrincipal,
mScriptFile.AssignASCII(filename);
}
mWindowID = nsJSUtils::GetCurrentlyRunningCodeWindowID(cx);
mInnerWindowID = nsJSUtils::GetCurrentlyRunningCodeInnerWindowID(cx);
}
// Get the load group for the page. When requesting we'll add ourselves to it.
@ -1072,7 +1072,7 @@ nsEventSource::PrintErrorOnConsole(const char *aBundleURI,
nsnull,
mScriptLine, 0,
nsIScriptError::errorFlag,
"Event Source", mWindowID);
"Event Source", mInnerWindowID);
// print the error message directly to the JS console
nsCOMPtr<nsIScriptError> logError = do_QueryInterface(errObj);

Просмотреть файл

@ -252,12 +252,12 @@ protected:
// Event Source owner information:
// - the script file name
// - source code line number where the Event Source object was constructed.
// - the window ID of the outer window where the script lives. Note that this
// may not be the same as the Event Source owner window.
// - the ID of the inner window where the script lives. Note that this may not
// be the same as the Event Source owner window.
// These attributes are used for error reporting.
nsString mScriptFile;
PRUint32 mScriptLine;
PRUint64 mWindowID;
PRUint64 mInnerWindowID;
private:
nsEventSource(const nsEventSource& x); // prevent bad usage

Просмотреть файл

@ -357,7 +357,7 @@ nsWebSocketEstablishedConnection::PrintErrorOnConsole(const char *aBundleURI,
NS_ConvertUTF8toUTF16(mOwner->GetScriptFile()).get(),
nsnull,
mOwner->GetScriptLine(), 0, nsIScriptError::errorFlag,
"Web Socket", mOwner->WindowID()
"Web Socket", mOwner->InnerWindowID()
);
// print the error message directly to the JS console
@ -631,7 +631,7 @@ nsWebSocket::nsWebSocket() : mKeepingAlive(PR_FALSE),
mReadyState(nsIMozWebSocket::CONNECTING),
mOutgoingBufferedAmount(0),
mScriptLine(0),
mWindowID(0)
mInnerWindowID(0)
{
NS_ABORT_IF_FALSE(NS_IsMainThread(), "Not running on main thread");
}
@ -1428,7 +1428,7 @@ nsWebSocket::Init(nsIPrincipal* aPrincipal,
}
}
mWindowID = nsJSUtils::GetCurrentlyRunningCodeWindowID(cx);
mInnerWindowID = nsJSUtils::GetCurrentlyRunningCodeInnerWindowID(cx);
}
// parses the url

Просмотреть файл

@ -99,7 +99,7 @@ public:
// Determine if preferences allow WebSocket
static PRBool PrefEnabled();
const PRUint64 WindowID() const { return mWindowID; }
const PRUint64 InnerWindowID() const { return mInnerWindowID; }
const nsCString& GetScriptFile() const { return mScriptFile; }
const PRUint32 GetScriptLine() const { return mScriptLine; }
@ -164,12 +164,12 @@ protected:
// Web Socket owner information:
// - the script file name, UTF8 encoded.
// - source code line number where the Web Socket object was constructed.
// - the window ID of the outer window where the script lives. Note that this
// may not be the same as the Web Socket owner window.
// - the ID of the inner window where the script lives. Note that this may not
// be the same as the Web Socket owner window.
// These attributes are used for error reporting.
nsCString mScriptFile;
PRUint32 mScriptLine;
PRUint64 mWindowID;
PRUint64 mInnerWindowID;
private:
nsWebSocket(const nsWebSocket& x); // prevent bad usage

Просмотреть файл

@ -382,8 +382,8 @@ nsXMLDocument::Load(const nsAString& aUrl, PRBool *aReturn)
nsnull, 0, 0, nsIScriptError::warningFlag,
"DOM",
callingDoc ?
callingDoc->OuterWindowID() :
this->OuterWindowID());
callingDoc->InnerWindowID() :
this->InnerWindowID());
NS_ENSURE_SUCCESS(rv, rv);

Просмотреть файл

@ -43,6 +43,7 @@ let Cc = Components.classes;
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
Cu.import("resource://gre/modules/Services.jsm");
Cu.import("resource://gre/modules/ConsoleAPIStorage.jsm");
function ConsoleAPI() {}
ConsoleAPI.prototype = {
@ -53,12 +54,16 @@ ConsoleAPI.prototype = {
// nsIDOMGlobalPropertyInitializer
init: function CA_init(aWindow) {
let id;
let outerID;
let innerID;
try {
id = aWindow.QueryInterface(Ci.nsIInterfaceRequestor)
.getInterface(Ci.nsIDOMWindowUtils)
.outerWindowID;
} catch (ex) {
let windowUtils = aWindow.QueryInterface(Ci.nsIInterfaceRequestor)
.getInterface(Ci.nsIDOMWindowUtils);
outerID = windowUtils.outerWindowID;
innerID = windowUtils.currentInnerWindowID;
}
catch (ex) {
Cu.reportError(ex);
}
@ -66,26 +71,26 @@ ConsoleAPI.prototype = {
let chromeObject = {
// window.console API
log: function CA_log() {
self.notifyObservers(id, "log", arguments);
self.notifyObservers(outerID, innerID, "log", arguments);
},
info: function CA_info() {
self.notifyObservers(id, "info", arguments);
self.notifyObservers(outerID, innerID, "info", arguments);
},
warn: function CA_warn() {
self.notifyObservers(id, "warn", arguments);
self.notifyObservers(outerID, innerID, "warn", arguments);
},
error: function CA_error() {
self.notifyObservers(id, "error", arguments);
self.notifyObservers(outerID, innerID, "error", arguments);
},
debug: function CA_debug() {
self.notifyObservers(id, "log", arguments);
self.notifyObservers(outerID, innerID, "log", arguments);
},
trace: function CA_trace() {
self.notifyObservers(id, "trace", self.getStackTrace());
self.notifyObservers(outerID, innerID, "trace", self.getStackTrace());
},
// Displays an interactive listing of all the properties of an object.
dir: function CA_dir() {
self.notifyObservers(id, "dir", arguments);
self.notifyObservers(outerID, innerID, "dir", arguments);
},
__exposedProps__: {
log: "r",
@ -125,17 +130,29 @@ ConsoleAPI.prototype = {
},
/**
* Notify all observers of any console API call
* Notify all observers of any console API call.
*
* @param number aOuterWindowID
* The outer window ID from where the message came from.
* @param number aInnerWindowID
* The inner window ID from where the message came from.
* @param string aLevel
* The message level.
* @param mixed aArguments
* The arguments given to the console API call.
**/
notifyObservers: function CA_notifyObservers(aID, aLevel, aArguments) {
if (!aID)
notifyObservers:
function CA_notifyObservers(aOuterWindowID, aInnerWindowID, aLevel, aArguments) {
if (!aOuterWindowID) {
return;
}
let stack = this.getStackTrace();
// Skip the first frame since it contains an internal call.
let frame = stack[1];
let consoleEvent = {
ID: aID,
ID: aOuterWindowID,
innerID: aInnerWindowID,
level: aLevel,
filename: frame.filename,
lineNumber: frame.lineNumber,
@ -145,8 +162,10 @@ ConsoleAPI.prototype = {
consoleEvent.wrappedJSObject = consoleEvent;
ConsoleAPIStorage.recordEvent(aInnerWindowID, consoleEvent);
Services.obs.notifyObservers(consoleEvent,
"console-api-log-event", aID);
"console-api-log-event", aOuterWindowID);
},
/**

Просмотреть файл

@ -0,0 +1,180 @@
/* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is ConsoleStorageService code.
*
* The Initial Developer of the Original Code is Mozilla Foundation
* Portions created by the Initial Developer are Copyright (C) 2010
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* David Dahl <ddahl@mozilla.com> (Original Author)
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
let Cu = Components.utils;
let Ci = Components.interfaces;
let Cc = Components.classes;
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
Cu.import("resource://gre/modules/Services.jsm");
const STORAGE_MAX_EVENTS = 200;
XPCOMUtils.defineLazyGetter(this, "gPrivBrowsing", function () {
// private browsing may not be available in some Gecko Apps
try {
return Cc["@mozilla.org/privatebrowsing;1"].getService(Ci.nsIPrivateBrowsingService);
}
catch (ex) {
return null;
}
});
var EXPORTED_SYMBOLS = ["ConsoleAPIStorage"];
var _consoleStorage = {};
/**
* The ConsoleAPIStorage is meant to cache window.console API calls for later
* reuse by other components when needed. For example, the Web Console code can
* display the cached messages when it opens for the active tab.
*
* ConsoleAPI messages are stored as they come from the ConsoleAPI code, with
* all their properties. They are kept around until the inner window object that
* created the messages is destroyed. Messages are indexed by the inner window
* ID.
*
* Usage:
* Cu.import("resource://gre/modules/ConsoleAPIStorage.jsm");
*
* // Get the cached events array for the window you want (use the inner
* // window ID).
* let events = ConsoleAPIStorage.getEvents(innerWindowID);
* events.forEach(function(event) { ... });
*
* // Clear the events for the given inner window ID.
* ConsoleAPIStorage.clearEvents(innerWindowID);
*/
var ConsoleAPIStorage = {
QueryInterface: XPCOMUtils.generateQI([Ci.nsIObserver]),
/** @private */
observe: function CS_observe(aSubject, aTopic, aData)
{
if (aTopic == "xpcom-shutdown") {
Services.obs.removeObserver(this, "xpcom-shutdown");
Services.obs.removeObserver(this, "inner-window-destroyed");
Services.obs.removeObserver(this, "memory-pressure");
delete _consoleStorage;
}
else if (aTopic == "inner-window-destroyed") {
let innerWindowID = aSubject.QueryInterface(Ci.nsISupportsPRUint64).data;
this.clearEvents(innerWindowID);
}
else if (aTopic == "memory-pressure") {
if (aData == "low-memory") {
this.clearEvents();
}
}
},
/** @private */
init: function CS_init()
{
Services.obs.addObserver(this, "xpcom-shutdown", false);
Services.obs.addObserver(this, "inner-window-destroyed", false);
Services.obs.addObserver(this, "memory-pressure", false);
},
/**
* Get the events array by inner window ID.
*
* @param string aId
* The inner window ID for which you want to get the array of cached
* events.
* @returns array
* The array of cached events for the given window.
*/
getEvents: function CS_getEvents(aId)
{
return _consoleStorage[aId] || [];
},
/**
* Record an event associated with the given window ID.
*
* @param string aWindowID
* The ID of the inner window for which the event occurred.
* @param object aEvent
* A JavaScript object you want to store.
*/
recordEvent: function CS_recordEvent(aWindowID, aEvent)
{
let ID = parseInt(aWindowID);
if (isNaN(ID)) {
throw new Error("Invalid window ID argument");
}
if (gPrivBrowsing && gPrivBrowsing.privateBrowsingEnabled) {
return;
}
if (!_consoleStorage[ID]) {
_consoleStorage[ID] = [];
}
let storage = _consoleStorage[ID];
storage.push(aEvent);
// truncate
if (storage.length > STORAGE_MAX_EVENTS) {
storage.shift();
}
Services.obs.notifyObservers(aEvent, "console-storage-cache-event", ID);
},
/**
* Clear storage data for the given window.
*
* @param string [aId]
* Optional, the inner window ID for which you want to clear the
* messages. If this is not specified all of the cached messages are
* cleared, from all window objects.
*/
clearEvents: function CS_clearEvents(aId)
{
if (aId != null) {
delete _consoleStorage[aId];
}
else {
_consoleStorage = {};
Services.obs.notifyObservers(null, "console-storage-reset", null);
}
},
};
ConsoleAPIStorage.init();

Просмотреть файл

@ -52,6 +52,9 @@ EXTRA_PP_COMPONENTS = \
ConsoleAPI.manifest \
$(NULL)
EXTRA_JS_MODULES = ConsoleAPIStorage.jsm \
$(NULL)
XPIDLSRCS = \
nsIEntropyCollector.idl \
nsIScriptChannel.idl \

Просмотреть файл

@ -1702,7 +1702,7 @@ PrintWarningOnConsole(JSContext *cx, const char *stringBundleProperty)
0, // column for error is not available
nsIScriptError::warningFlag,
"DOM:HTML",
nsJSUtils::GetCurrentlyRunningCodeWindowID(cx));
nsJSUtils::GetCurrentlyRunningCodeInnerWindowID(cx));
if (NS_SUCCEEDED(rv)){
nsCOMPtr<nsIScriptError> logError = do_QueryInterface(scriptError);

Просмотреть файл

@ -540,6 +540,11 @@ public:
return outerWindow && !outerWindow->IsInnerWindow() ? outerWindow : nsnull;
}
static nsGlobalWindow* GetInnerWindowWithId(PRUint64 aInnerWindowID) {
nsGlobalWindow* innerWindow = sWindowsById->Get(aInnerWindowID);
return innerWindow && innerWindow->IsInnerWindow() ? innerWindow : nsnull;
}
static bool HasIndexedDBSupport();
static bool HasPerformanceSupport();

Просмотреть файл

@ -267,11 +267,11 @@ public:
const nsAString& aFileName,
const nsAString& aSourceLine,
PRBool aDispatchEvent,
PRUint64 aWindowID)
PRUint64 aInnerWindowID)
: mScriptGlobal(aScriptGlobal), mLineNr(aLineNr), mColumn(aColumn),
mFlags(aFlags), mErrorMsg(aErrorMsg), mFileName(aFileName),
mSourceLine(aSourceLine), mDispatchEvent(aDispatchEvent),
mWindowID(aWindowID)
mInnerWindowID(aInnerWindowID)
{}
NS_IMETHOD Run()
@ -364,7 +364,7 @@ public:
rv = error2->InitWithWindowID(mErrorMsg.get(), mFileName.get(),
mSourceLine.get(),
mLineNr, mColumn, mFlags,
category, mWindowID);
category, mInnerWindowID);
} else {
rv = errorObject->Init(mErrorMsg.get(), mFileName.get(),
mSourceLine.get(),
@ -393,7 +393,7 @@ public:
nsString mFileName;
nsString mSourceLine;
PRBool mDispatchEvent;
PRUint64 mWindowID;
PRUint64 mInnerWindowID;
static PRBool sHandlingScriptError;
};
@ -474,13 +474,19 @@ NS_ScriptErrorReporter(JSContext *cx,
nsAutoString sourceLine;
sourceLine.Assign(reinterpret_cast<const PRUnichar*>(report->uclinebuf));
nsCOMPtr<nsPIDOMWindow> win = do_QueryInterface(globalObject);
PRUint64 windowID = win ? win->WindowID() : 0;
PRUint64 innerWindowID = 0;
if (win) {
nsCOMPtr<nsPIDOMWindow> innerWin = win->GetCurrentInnerWindow();
if (innerWin) {
innerWindowID = innerWin->WindowID();
}
}
nsContentUtils::AddScriptRunner(
new ScriptErrorEvent(globalObject, report->lineno,
report->uctokenptr - report->uclinebuf,
report->flags, msg, fileName, sourceLine,
report->errorNumber != JSMSG_OUT_OF_MEMORY,
windowID));
innerWindowID));
}
}

Просмотреть файл

@ -163,12 +163,12 @@ nsJSUtils::GetDynamicScriptContext(JSContext *aContext)
}
PRUint64
nsJSUtils::GetCurrentlyRunningCodeWindowID(JSContext *aContext)
nsJSUtils::GetCurrentlyRunningCodeInnerWindowID(JSContext *aContext)
{
if (!aContext)
return 0;
PRUint64 windowID = 0;
PRUint64 innerWindowID = 0;
JSObject *jsGlobal = JS_GetGlobalForScopeChain(aContext);
if (jsGlobal) {
@ -177,10 +177,10 @@ nsJSUtils::GetCurrentlyRunningCodeWindowID(JSContext *aContext)
if (scriptGlobal) {
nsCOMPtr<nsPIDOMWindow> win = do_QueryInterface(scriptGlobal);
if (win)
windowID = win->GetOuterWindow()->WindowID();
innerWindowID = win->WindowID();
}
}
return windowID;
return innerWindowID;
}

Просмотреть файл

@ -71,14 +71,14 @@ public:
static nsIScriptContext *GetDynamicScriptContext(JSContext *aContext);
/**
* Retrieve the outer window ID based on the given JSContext.
* Retrieve the inner window ID based on the given JSContext.
*
* @param JSContext aContext
* The JSContext from which you want to find the outer window ID.
* The JSContext from which you want to find the inner window ID.
*
* @returns PRUint64 the outer window ID.
* @returns PRUint64 the inner window ID.
*/
static PRUint64 GetCurrentlyRunningCodeWindowID(JSContext *aContext);
static PRUint64 GetCurrentlyRunningCodeInnerWindowID(JSContext *aContext);
};

Просмотреть файл

@ -50,6 +50,8 @@ _BROWSER_FILES = \
browser_autofocus_background.js \
browser_ConsoleAPITests.js \
test-console-api.html \
browser_ConsoleStorageAPITests.js \
browser_ConsoleStoragePBTest.js \
browser_autofocus_preference.js \
browser_popup_blocker_save_open_panel.js \
$(NULL)

Просмотреть файл

@ -0,0 +1,104 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
const TEST_URI = "http://example.com/browser/dom/tests/browser/test-console-api.html";
const TEST_URI_NAV = "http://example.com/browser/dom/tests/browser/";
Cu.import("resource://gre/modules/ConsoleAPIStorage.jsm");
var apiCallCount;
var ConsoleObserver = {
QueryInterface: XPCOMUtils.generateQI([Ci.nsIObserver]),
init: function CO_init()
{
Services.obs.addObserver(this, "console-storage-cache-event", false);
apiCallCount = 0;
},
observe: function CO_observe(aSubject, aTopic, aData)
{
if (aTopic == "console-storage-cache-event") {
apiCallCount ++;
if (apiCallCount == 4) {
try {
var tab = gBrowser.selectedTab;
let browser = gBrowser.selectedBrowser;
let win = XPCNativeWrapper.unwrap(browser.contentWindow);
let windowID = getWindowId(win);
let messages = ConsoleAPIStorage.getEvents(windowID);
ok(messages.length >= 4, "Some messages found in the storage service");
ConsoleAPIStorage.clearEvents();
messages = ConsoleAPIStorage.getEvents(windowID);
ok(messages.length == 0, "Cleared Storage, no events found");
// remove the observer so we don't trigger this test again
Services.obs.removeObserver(this, "console-storage-cache-event");
// make sure a closed window's events are in fact removed from the
// storage cache
win.console.log("adding a new event");
// close the window - the storage cache should now be empty
gBrowser.removeTab(tab, {animate: false});
window.QueryInterface(Ci.nsIInterfaceRequestor)
.getInterface(Ci.nsIDOMWindowUtils).garbageCollect();
executeSoon(function (){
// use the old windowID again to see if we have any stray cached messages
messages = ConsoleAPIStorage.getEvents(windowID);
ok(messages.length == 0, "0 events found, tab close is clearing the cache");
finish();
});
} catch (ex) {
dump(ex + "\n\n\n");
dump(ex.stack + "\n\n\n");
}
}
}
}
};
function tearDown()
{
while (gBrowser.tabs.length > 1) {
gBrowser.removeCurrentTab();
}
}
function test()
{
registerCleanupFunction(tearDown);
ConsoleObserver.init();
waitForExplicitFinish();
var tab = gBrowser.addTab(TEST_URI);
gBrowser.selectedTab = tab;
var browser = gBrowser.selectedBrowser;
browser.addEventListener("DOMContentLoaded", function onLoad(event) {
browser.removeEventListener("DOMContentLoaded", onLoad, false);
executeSoon(function test_executeSoon() {
var contentWin = browser.contentWindow;
let win = XPCNativeWrapper.unwrap(contentWin);
win.console.log("this", "is", "a", "log message");
win.console.info("this", "is", "a", "info message");
win.console.warn("this", "is", "a", "warn message");
win.console.error("this", "is", "a", "error message");
});
}, false);
}
function getWindowId(aWindow)
{
return aWindow.QueryInterface(Ci.nsIInterfaceRequestor)
.getInterface(Ci.nsIDOMWindowUtils)
.currentInnerWindowID;
}

Просмотреть файл

@ -0,0 +1,74 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
function test() {
try {
var pb = Cc["@mozilla.org/privatebrowsing;1"].getService(Ci.nsIPrivateBrowsingService);
} catch (ex) {
ok(true, "nothing to do here, PB service doesn't exist");
return;
}
waitForExplicitFinish();
var CSS = {};
Cu.import("resource://gre/modules/ConsoleAPIStorage.jsm", CSS);
function checkStorageOccurs(shouldOccur) {
let win = XPCNativeWrapper.unwrap(browser.contentWindow);
let innerID = getInnerWindowId(win);
let beforeEvents = CSS.ConsoleAPIStorage.getEvents(innerID);
win.console.log("foo bar baz (private: " + !shouldOccur + ")");
let afterEvents = CSS.ConsoleAPIStorage.getEvents(innerID);
is(beforeEvents.length == afterEvents.length - 1,
shouldOccur, "storage should" + (shouldOccur ? "" : "n't") + " occur");
}
function pbObserver(aSubject, aTopic, aData) {
if (aData == "enter") {
checkStorageOccurs(false);
executeSoon(function () { pb.privateBrowsingEnabled = false; });
} else if (aData == "exit") {
executeSoon(finish);
}
}
const TEST_URI = "http://example.com/browser/dom/tests/browser/test-console-api.html";
var tab = gBrowser.selectedTab = gBrowser.addTab(TEST_URI);
var browser = gBrowser.selectedBrowser;
Services.obs.addObserver(pbObserver, "private-browsing", false);
const PB_KEEP_SESSION_PREF = "browser.privatebrowsing.keep_current_session";
Services.prefs.setBoolPref(PB_KEEP_SESSION_PREF, true);
registerCleanupFunction(function () {
gBrowser.removeTab(tab);
Services.obs.removeObserver(pbObserver, "private-browsing");
if (Services.prefs.prefHasUserValue(PB_KEEP_SESSION_PREF))
Services.prefs.clearUserPref(PB_KEEP_SESSION_PREF);
});
browser.addEventListener("DOMContentLoaded", function onLoad(event) {
if (browser.currentURI.spec != TEST_URI)
return;
browser.removeEventListener("DOMContentLoaded", onLoad, false);
checkStorageOccurs(true);
pb.privateBrowsingEnabled = true;
}, false);
}
function getInnerWindowId(aWindow) {
return aWindow.QueryInterface(Ci.nsIInterfaceRequestor)
.getInterface(Ci.nsIDOMWindowUtils)
.currentInnerWindowID;
}

Просмотреть файл

@ -895,11 +895,11 @@ public:
aWorkerPrivate->AssertInnerWindowIsCorrect();
}
PRUint64 windowId;
PRUint64 innerWindowId;
WorkerPrivate* parent = aWorkerPrivate->GetParent();
if (parent) {
windowId = 0;
innerWindowId = 0;
}
else {
AssertIsOnMainThread();
@ -909,13 +909,13 @@ public:
return true;
}
windowId = aWorkerPrivate->GetOuterWindowId();
innerWindowId = aWorkerPrivate->GetInnerWindowId();
}
return ReportErrorRunnable::ReportError(aCx, parent, true, target, mMessage,
mFilename, mLine, mLineNumber,
mColumnNumber, mFlags,
mErrorNumber, windowId);
mErrorNumber, innerWindowId);
}
static bool
@ -923,7 +923,7 @@ public:
bool aFireAtScope, JSObject* aTarget, const nsString& aMessage,
const nsString& aFilename, const nsString& aLine,
PRUint32 aLineNumber, PRUint32 aColumnNumber, PRUint32 aFlags,
PRUint32 aErrorNumber, PRUint64 aWindowId)
PRUint32 aErrorNumber, PRUint64 aInnerWindowId)
{
if (aWorkerPrivate) {
aWorkerPrivate->AssertIsOnWorkerThread();
@ -1030,7 +1030,7 @@ public:
aLine.get(), aLineNumber,
aColumnNumber, aFlags,
"Web Worker",
aWindowId))) {
aInnerWindowId))) {
consoleMessage = do_QueryInterface(scriptError);
NS_ASSERTION(consoleMessage, "This should never fail!");
}
@ -1932,10 +1932,10 @@ WorkerPrivateParent<Derived>::PostMessage(JSContext* aCx, jsval aMessage)
template <class Derived>
PRUint64
WorkerPrivateParent<Derived>::GetOuterWindowId()
WorkerPrivateParent<Derived>::GetInnerWindowId()
{
AssertIsOnMainThread();
return mDocument->OuterWindowID();
return mDocument->InnerWindowID();
}
template <class Derived>

Просмотреть файл

@ -299,7 +299,7 @@ public:
PostMessage(JSContext* aCx, jsval aMessage);
PRUint64
GetOuterWindowId();
GetInnerWindowId();
void
UpdateJSContextOptions(JSContext* aCx, PRUint32 aOptions);

Просмотреть файл

@ -96,15 +96,23 @@ interface nsIScriptError : nsIConsoleMessage
* An interface that nsIScriptError objects can implement to allow
* them to be initialized with a window id.
*/
[scriptable, uuid(35cd0f6a-f5bb-497a-ba83-9c8d089b52cd)]
[scriptable, uuid(4472646b-c928-4d76-9e7c-6b91da7f24cc)]
interface nsIScriptError2 : nsISupports {
/* Get the window id this was initialized with. Zero will be
returned if init() was used instead of initWithWindowId(). */
returned if init() was used instead of initWithWindowID(). */
readonly attribute unsigned long long outerWindowID;
/* Get the inner window id this was initialized with. Zero will be
returned if init() was used instead of initWithWindowID(). */
readonly attribute unsigned long long innerWindowID;
/* Elapsed time, in milliseconds, from a platform-specific zero time to the
time the message was created. */
readonly attribute long long timeStamp;
/* This should be called instead of nsIScriptError.init to
initialize with a window id. The window id should be for the
outer window associated with this error. */
inner window associated with this error. */
void initWithWindowID(in wstring message,
in wstring sourceName,
in wstring sourceLine,
@ -112,7 +120,7 @@ interface nsIScriptError2 : nsISupports {
in PRUint32 columnNumber,
in PRUint32 flags,
in string category,
in unsigned long long windowID);
in unsigned long long innerWindowID);
};
%{ C++

Просмотреть файл

@ -43,6 +43,8 @@
*/
#include "xpcprivate.h"
#include "nsGlobalWindow.h"
#include "nsPIDOMWindow.h"
NS_IMPL_THREADSAFE_ISUPPORTS3(nsScriptError, nsIConsoleMessage, nsIScriptError,
nsIScriptError2)
@ -55,7 +57,9 @@ nsScriptError::nsScriptError()
mColumnNumber(0),
mFlags(0),
mCategory(),
mWindowID(0)
mOuterWindowID(0),
mInnerWindowID(0),
mTimeStamp(0)
{
}
@ -142,7 +146,7 @@ nsScriptError::InitWithWindowID(const PRUnichar *message,
PRUint32 columnNumber,
PRUint32 flags,
const char *category,
PRUint64 aWindowID)
PRUint64 aInnerWindowID)
{
mMessage.Assign(message);
mSourceName.Assign(sourceName);
@ -151,7 +155,18 @@ nsScriptError::InitWithWindowID(const PRUnichar *message,
mColumnNumber = columnNumber;
mFlags = flags;
mCategory.Assign(category);
mWindowID = aWindowID;
mTimeStamp = PR_Now() / 1000;
mInnerWindowID = aInnerWindowID;
if(aInnerWindowID) {
nsGlobalWindow* window =
nsGlobalWindow::GetInnerWindowWithId(aInnerWindowID);
if(window) {
nsPIDOMWindow* outer = window->GetOuterWindow();
if(outer)
mOuterWindowID = outer->WindowID();
}
}
return NS_OK;
}
@ -218,8 +233,22 @@ nsScriptError::ToString(nsACString& /*UTF8*/ aResult)
}
NS_IMETHODIMP
nsScriptError::GetOuterWindowID(PRUint64 *aWindowID)
nsScriptError::GetOuterWindowID(PRUint64 *aOuterWindowID)
{
*aWindowID = mWindowID;
*aOuterWindowID = mOuterWindowID;
return NS_OK;
}
NS_IMETHODIMP
nsScriptError::GetInnerWindowID(PRUint64 *aInnerWindowID)
{
*aInnerWindowID = mInnerWindowID;
return NS_OK;
}
NS_IMETHODIMP
nsScriptError::GetTimeStamp(PRInt64 *aTimeStamp)
{
*aTimeStamp = mTimeStamp;
return NS_OK;
}

Просмотреть файл

@ -2880,7 +2880,7 @@ nsXPCComponents_Utils::ReportError()
if(NS_FAILED(rv) || !argv)
return NS_OK;
const PRUint64 windowID = nsJSUtils::GetCurrentlyRunningCodeWindowID(cx);
const PRUint64 innerWindowID = nsJSUtils::GetCurrentlyRunningCodeInnerWindowID(cx);
JSErrorReport* err = JS_ErrorFromException(cx, argv[0]);
if(err)
@ -2899,7 +2899,7 @@ nsXPCComponents_Utils::ReportError()
err->lineno,
column,
err->flags,
"XPConnect JavaScript", windowID);
"XPConnect JavaScript", innerWindowID);
if(NS_FAILED(rv))
return NS_OK;
@ -2935,8 +2935,8 @@ nsXPCComponents_Utils::ReportError()
rv = scripterr->InitWithWindowID(reinterpret_cast<const PRUnichar *>(msgchars),
NS_ConvertUTF8toUTF16(fileName).get(),
nsnull,
lineNo, 0,
0, "XPConnect JavaScript", windowID);
lineNo, 0, 0,
"XPConnect JavaScript", innerWindowID);
if(NS_SUCCEEDED(rv))
{
nsCOMPtr<nsIScriptError> logError = do_QueryInterface(scripterr);

Просмотреть файл

@ -1827,7 +1827,7 @@ XPCConvert::JSErrorToXPCException(XPCCallContext& ccx,
(const PRUnichar *)report->uclinebuf, report->lineno,
report->uctokenptr - report->uclinebuf, report->flags,
"XPConnect JavaScript",
nsJSUtils::GetCurrentlyRunningCodeWindowID(ccx.GetJSContext()));
nsJSUtils::GetCurrentlyRunningCodeInnerWindowID(ccx.GetJSContext()));
}
if(data)

Просмотреть файл

@ -3885,7 +3885,9 @@ private:
PRUint32 mColumnNumber;
PRUint32 mFlags;
nsCString mCategory;
PRUint64 mWindowID;
PRUint64 mOuterWindowID;
PRUint64 mInnerWindowID;
PRUint64 mTimeStamp;
};
/***************************************************************************/

Просмотреть файл

@ -1218,7 +1218,7 @@ nsXPCWrappedJSClass::CheckForException(XPCCallContext & ccx,
nsnull,
lineNumber, 0, 0,
"XPConnect JavaScript",
nsJSUtils::GetCurrentlyRunningCodeWindowID(cx));
nsJSUtils::GetCurrentlyRunningCodeInnerWindowID(cx));
if(NS_FAILED(rv))
scriptError = nsnull;
}

Просмотреть файл

@ -285,7 +285,7 @@ nsCSSScanner::nsCSSScanner()
, mSVGMode(PR_FALSE)
#ifdef CSS_REPORT_PARSE_ERRORS
, mError(mErrorBuf, NS_ARRAY_LENGTH(mErrorBuf), 0)
, mWindowID(0)
, mInnerWindowID(0)
, mWindowIDCached(PR_FALSE)
, mSheet(nsnull)
, mLoader(nsnull)
@ -449,12 +449,12 @@ nsCSSScanner::OutputError()
if (InitGlobals() && gReportErrors) {
if (!mWindowIDCached) {
if (mSheet) {
mWindowID = mSheet->FindOwningWindowID();
mInnerWindowID = mSheet->FindOwningWindowInnerID();
}
if (mWindowID == 0 && mLoader) {
if (mInnerWindowID == 0 && mLoader) {
nsIDocument* doc = mLoader->GetDocument();
if (doc) {
mWindowID = doc->OuterWindowID();
mInnerWindowID = doc->InnerWindowID();
}
}
mWindowIDCached = PR_TRUE;
@ -471,7 +471,8 @@ nsCSSScanner::OutputError()
mErrorLineNumber,
mErrorColNumber,
nsIScriptError::warningFlag,
"CSS Parser", mWindowID);
"CSS Parser",
mInnerWindowID);
if (NS_SUCCEEDED(rv)) {
nsCOMPtr<nsIScriptError> logError = do_QueryInterface(errorObject);
gConsoleService->LogMessage(logError);
@ -622,7 +623,7 @@ nsCSSScanner::Close()
mFileName.Truncate();
mURI = nsnull;
mError.Truncate();
mWindowID = 0;
mInnerWindowID = 0;
mWindowIDCached = PR_FALSE;
mSheet = nsnull;
mLoader = nsnull;

Просмотреть файл

@ -248,7 +248,7 @@ protected:
PRUint32 mErrorLineNumber, mColNumber, mErrorColNumber;
nsFixedString mError;
PRUnichar mErrorBuf[200];
PRUint64 mWindowID;
PRUint64 mInnerWindowID;
PRBool mWindowIDCached;
nsCSSStyleSheet* mSheet;
mozilla::css::Loader* mLoader;

Просмотреть файл

@ -1252,12 +1252,12 @@ nsCSSStyleSheet::SetOwningDocument(nsIDocument* aDocument)
}
}
/* virtual */ PRUint64
nsCSSStyleSheet::FindOwningWindowID() const
PRUint64
nsCSSStyleSheet::FindOwningWindowInnerID() const
{
PRUint64 windowID = 0;
if (mDocument) {
windowID = mDocument->OuterWindowID();
windowID = mDocument->InnerWindowID();
}
if (windowID == 0 && mOwningNode) {
@ -1265,7 +1265,7 @@ nsCSSStyleSheet::FindOwningWindowID() const
if (node) {
nsIDocument* doc = node->GetOwnerDoc();
if (doc) {
windowID = doc->OuterWindowID();
windowID = doc->InnerWindowID();
}
}
}
@ -1275,13 +1275,13 @@ nsCSSStyleSheet::FindOwningWindowID() const
if (sheet) {
nsRefPtr<nsCSSStyleSheet> cssSheet = do_QueryObject(sheet);
if (cssSheet) {
windowID = cssSheet->FindOwningWindowID();
windowID = cssSheet->FindOwningWindowInnerID();
}
}
}
if (windowID == 0 && mParent) {
windowID = mParent->FindOwningWindowID();
windowID = mParent->FindOwningWindowInnerID();
}
return windowID;

Просмотреть файл

@ -155,8 +155,8 @@ public:
virtual nsIDocument* GetOwningDocument() const; // may be null
virtual void SetOwningDocument(nsIDocument* aDocument);
// Find the ID of the owner outer window.
virtual PRUint64 FindOwningWindowID() const;
// Find the ID of the owner inner window.
PRUint64 FindOwningWindowInnerID() const;
#ifdef DEBUG
virtual void List(FILE* out = stdout, PRInt32 aIndent = 0) const;
#endif

Просмотреть файл

@ -798,14 +798,14 @@ nsUserFontSet::LogMessage(gfxProxyFontEntry *aProxy,
do_CreateInstance(NS_SCRIPTERROR_CONTRACTID, &rv);
NS_ENSURE_SUCCESS(rv, rv);
PRUint64 windowID = GetPresContext()->Document()->OuterWindowID();
PRUint64 innerWindowID = GetPresContext()->Document()->InnerWindowID();
rv = scriptError->InitWithWindowID(NS_ConvertUTF8toUTF16(msg).get(),
href.get(), // file
text.get(), // src line
0, 0, // line & column number
aFlags, // flags
"CSS Loader", // category (make separate?)
windowID);
innerWindowID);
if (NS_SUCCEEDED(rv)){
nsCOMPtr<nsIScriptError> logError = do_QueryInterface(scriptError);
if (logError) {

Просмотреть файл

@ -153,7 +153,7 @@ Decoder::Finish()
NS_ConvertUTF8toUTF16(mImage->GetURIString()).get(),
nsnull,
0, 0, nsIScriptError::errorFlag,
"Image", mImage->WindowID()
"Image", mImage->InnerWindowID()
);
nsCOMPtr<nsIScriptError> error = do_QueryInterface(errorObject);

Просмотреть файл

@ -42,7 +42,7 @@ namespace imagelib {
// Constructor
Image::Image(imgStatusTracker* aStatusTracker) :
mWindowId(0),
mInnerWindowId(0),
mAnimationConsumers(0),
mAnimationMode(kNormalAnimMode),
mInitialized(PR_FALSE),

Просмотреть файл

@ -125,10 +125,10 @@ public:
PRUint32 GetAnimationConsumers() { return mAnimationConsumers; }
#endif
void SetWindowID(PRUint64 aWindowId) {
mWindowId = aWindowId;
void SetInnerWindowID(PRUint64 aInnerWindowId) {
mInnerWindowId = aInnerWindowId;
}
PRUint64 WindowID() const { return mWindowId; }
PRUint64 InnerWindowID() const { return mInnerWindowId; }
PRBool HasError() { return mError; }
@ -144,7 +144,7 @@ protected:
virtual nsresult StartAnimation() = 0;
virtual nsresult StopAnimation() = 0;
PRUint64 mWindowId;
PRUint64 mInnerWindowId;
// Member data shared by all implementations of this abstract class
nsAutoPtr<imgStatusTracker> mStatusTracker;

Просмотреть файл

@ -1709,10 +1709,10 @@ NS_IMETHODIMP imgLoader::LoadImage(nsIURI *aURI,
request->Init(aURI, aURI, loadGroup, newChannel, entry, cacheId, aCX,
aLoadingPrincipal, corsmode);
// Pass the windowID of the loading document, if possible.
// Pass the inner window ID of the loading document, if possible.
nsCOMPtr<nsIDocument> doc = do_QueryInterface(aCX);
if (doc) {
request->SetWindowID(doc->OuterWindowID());
request->SetInnerWindowID(doc->InnerWindowID());
}
// create the proxy listener

Просмотреть файл

@ -184,8 +184,9 @@ NS_IMPL_ISUPPORTS8(imgRequest,
imgRequest::imgRequest() :
mCacheId(0), mValidator(nsnull), mImageSniffers("image-sniffing-services"),
mWindowId(0), mCORSMode(imgIRequest::CORS_NONE), mDecodeRequested(PR_FALSE),
mIsMultiPartChannel(PR_FALSE), mGotData(PR_FALSE), mIsInCache(PR_FALSE)
mInnerWindowId(0), mCORSMode(imgIRequest::CORS_NONE),
mDecodeRequested(PR_FALSE), mIsMultiPartChannel(PR_FALSE), mGotData(PR_FALSE),
mIsInCache(PR_FALSE)
{}
imgRequest::~imgRequest()
@ -1035,7 +1036,7 @@ NS_IMETHODIMP imgRequest::OnDataAvailable(nsIRequest *aRequest, nsISupports *ctx
} else {
mImage = new RasterImage(mStatusTracker.forget());
}
mImage->SetWindowID(mWindowId);
mImage->SetInnerWindowID(mInnerWindowId);
imageType = mImage->GetType();
// Notify any imgRequestProxys that are observing us that we have an Image.

Просмотреть файл

@ -123,12 +123,12 @@ public:
nsresult UnlockImage();
nsresult RequestDecode();
inline void SetWindowID(PRUint64 aWindowId) {
mWindowId = aWindowId;
inline void SetInnerWindowID(PRUint64 aInnerWindowId) {
mInnerWindowId = aInnerWindowId;
}
inline PRUint64 WindowID() const {
return mWindowId;
inline PRUint64 InnerWindowID() const {
return mInnerWindowId;
}
// Set the cache validation information (expiry time, whether we must
@ -257,8 +257,8 @@ private:
nsCOMPtr<nsIAsyncVerifyRedirectCallback> mRedirectCallback;
nsCOMPtr<nsIChannel> mNewRedirectChannel;
// Originating outer window ID. Used for error reporting.
PRUint64 mWindowId;
// The ID of the inner window origin, used for error reporting.
PRUint64 mInnerWindowId;
// The CORS mode (defined in imgIRequest) this image was loaded with. By
// default, imgIRequest::CORS_NONE.

Просмотреть файл

@ -376,7 +376,7 @@ nsExpatDriver::nsExpatDriver()
mInternalState(NS_OK),
mExpatBuffered(0),
mCatalogData(nsnull),
mWindowID(0)
mInnerWindowID(0)
{
}
@ -953,7 +953,7 @@ nsExpatDriver::HandleError()
mLastLine.get(),
lineNumber, colNumber,
nsIScriptError::errorFlag, "malformed-xml",
mWindowID);
mInnerWindowID);
}
// If it didn't initialize, we can't do any logging.
@ -1250,8 +1250,11 @@ nsExpatDriver::WillBuildModel(const CParserContext& aParserContext,
win = do_QueryInterface(global);
}
}
if (win && !win->IsInnerWindow()) {
win = win->GetCurrentInnerWindow();
}
if (win) {
mWindowID = win->GetOuterWindow()->WindowID();
mInnerWindowID = win->WindowID();
}
}

Просмотреть файл

@ -169,7 +169,7 @@ private:
nsString mURISpec;
// Used for error reporting.
PRUint64 mWindowID;
PRUint64 mInnerWindowID;
};
#endif

Просмотреть файл

@ -49,6 +49,24 @@ function testtag_notificationbox(nb)
runTimedTests(tests, -1, nb, null);
}
var notification_last_event, notification_last_event_item;
function notification_eventCallback(event)
{
notification_last_event = event;
notification_last_event_item = this;
}
function testtag_notification_eventCallback(expectedEvent, ntf, testName)
{
SimpleTest.is(notification_last_event, expectedEvent,
testName + ": event name");
SimpleTest.is(notification_last_event_item, ntf,
testName + ": event item");
notification_last_event = null;
notification_last_event_item = null;
}
var tests =
[
{
@ -90,6 +108,33 @@ var tests =
ise(exh, true, "removeNotification again");
testtag_notificationbox_State(nb, "removeNotification again", null, 0);
}
},
{
test: function(nb, ntf) {
// append a new notification, but now with an event callback
var ntf = nb.appendNotification("Notification", "note", "happy.png",
nb.PRIORITY_INFO_LOW,
testtag_notificationbox_buttons,
notification_eventCallback);
ise(ntf && ntf.localName == "notification", true, "append notification with callback");
return ntf;
},
result: function(nb, ntf) {
testtag_notificationbox_State(nb, "append with callback", ntf, 1);
return ntf;
}
},
{
test: function(nb, ntf) {
nb.removeNotification(ntf);
return ntf;
},
result: function(nb, ntf) {
testtag_notificationbox_State(nb, "removeNotification with callback",
null, 0);
testtag_notification_eventCallback("removed", ntf, "removeNotification()");
return [1, null];
}
},

Просмотреть файл

@ -77,6 +77,7 @@
<parameter name="aImage"/>
<parameter name="aPriority"/>
<parameter name="aButtons"/>
<parameter name="aEventCallback"/>
<body>
<![CDATA[
if (aPriority < this.PRIORITY_INFO_LOW ||
@ -99,6 +100,7 @@
newitem.setAttribute("value", aValue);
if (aImage)
newitem.setAttribute("image", aImage);
newitem.eventCallback = aEventCallback;
if (aButtons) {
for (var b = 0; b < aButtons.length; b++) {
@ -148,12 +150,23 @@
if (aItem == this.currentNotification)
this.removeCurrentNotification(aSkipAnimation);
else if (aItem != this._closedNotification)
this.removeChild(aItem);
this._removeNotificationElement(aItem);
return aItem;
]]>
</body>
</method>
<method name="_removeNotificationElement">
<parameter name="aChild"/>
<body>
<![CDATA[
if (aChild.eventCallback)
aChild.eventCallback("removed");
this.removeChild(aChild);
]]>
</body>
</method>
<method name="removeCurrentNotification">
<parameter name="aSkipAnimation"/>
<body>
@ -170,7 +183,7 @@
var notifications = this.allNotifications;
for (var n = notifications.length - 1; n >= 0; n--) {
if (aImmediate)
this.removeChild(notifications[n]);
this._removeNotificationElement(notifications[n]);
else
this.removeNotification(notifications[n]);
}
@ -228,7 +241,7 @@
this.currentNotification = (idx >= 0) ? notifications[idx] : null;
if (skipAnimation) {
this.removeChild(this._closedNotification);
this._removeNotificationElement(this._closedNotification);
this._closedNotification = null;
this._setBlockingState(this.currentNotification);
return;
@ -248,7 +261,7 @@
if (this._animating) {
this._animating = false;
if (this._closedNotification) {
this.removeChild(this._closedNotification);
this._removeNotificationElement(this._closedNotification);
this._closedNotification = null;
}
this._setBlockingState(this.currentNotification);