Bug 1308061 - Part 2: Implement sessions.onChanged WebExtensions API, r?aswan
MozReview-Commit-ID: 7s6Wen1DcAL
--- a/browser/components/extensions/ext-sessions.js
+++ b/browser/components/extensions/ext-sessions.js
@@ -1,20 +1,32 @@
/* -*- Mode: indent-tabs-mode: nil; js-indent-level: 2 -*- */
/* vim: set sts=2 sw=2 et tw=80: */
"use strict";
Cu.import("resource://gre/modules/ExtensionUtils.jsm");
var {
promiseObserved,
+ SingletonEventManager,
} = ExtensionUtils;
XPCOMUtils.defineLazyModuleGetter(this, "SessionStore",
"resource:///modules/sessionstore/SessionStore.jsm");
+const ssOnChangedTopic = "sessionstore-closed-objects-changed";
+
+let listenerCount = 0;
+
+let observer = {
+ observe: function() {
+ this.emit("changed");
+ },
+};
+EventEmitter.decorate(observer);
+
function getRecentlyClosed(maxResults, extension) {
let recentlyClosed = [];
// Get closed windows
let closedWindowData = SessionStore.getClosedWindowData(false);
for (let window of closedWindowData) {
recentlyClosed.push({
lastModified: window.closedAt,
@@ -82,11 +94,29 @@ extensions.registerSchemaAPI("sessions",
recentlyClosedTabs.sort((a, b) => b.closedAt - a.closedAt);
// Use the closedId of the most recently closed tab to restore it.
closedId = recentlyClosedTabs[0].closedId;
session = SessionStore.undoCloseById(closedId);
}
return createSession(session, extension, closedId);
},
+ onChanged: new SingletonEventManager(context, "sessions.onChanged", fire => {
+ let listener = (event) => {
+ context.runSafe(fire);
+ };
+
+ observer.on("changed", listener);
+ listenerCount++;
+ if (listenerCount == 1) {
+ Services.obs.addObserver(observer, ssOnChangedTopic, false);
+ }
+ return () => {
+ observer.off("changed", listener);
+ listenerCount -= 1;
+ if (!listenerCount) {
+ Services.obs.removeObserver(observer, ssOnChangedTopic);
+ }
+ };
+ }).api(),
},
};
});
--- a/browser/components/extensions/schemas/sessions.json
+++ b/browser/components/extensions/schemas/sessions.json
@@ -126,17 +126,16 @@
]
}
]
}
],
"events": [
{
"name": "onChanged",
- "unsupported": true,
"description": "Fired when recently closed tabs and/or windows are changed. This event does not monitor synced sessions changes.",
"type": "function"
}
],
"properties": {
"MAX_SESSION_RESULTS": {
"value": 25,
"description": "The maximum number of $(ref:sessions.Session) that will be included in a requested list."
--- a/browser/components/extensions/test/browser/browser_ext_sessions_restore.js
+++ b/browser/components/extensions/test/browser/browser_ext_sessions_restore.js
@@ -4,16 +4,24 @@
SimpleTest.requestCompleteLog();
XPCOMUtils.defineLazyModuleGetter(this, "SessionStore",
"resource:///modules/sessionstore/SessionStore.jsm");
add_task(function* test_sessions_restore() {
function background() {
+ let notificationCount = 0;
+ browser.sessions.onChanged.addListener(function listener() {
+ notificationCount++;
+ browser.test.sendMessage("notificationCount", notificationCount);
+ if (notificationCount == 10) {
+ browser.sessions.onChanged.removeListener(listener);
+ }
+ });
browser.test.onMessage.addListener((msg, data) => {
if (msg == "check-sessions") {
browser.sessions.getRecentlyClosed().then(recentlyClosed => {
browser.test.sendMessage("recentlyClosed", recentlyClosed);
});
} else if (msg == "restore") {
browser.sessions.restore(data).then(sessions => {
browser.test.sendMessage("restored", sessions);
@@ -35,16 +43,20 @@ add_task(function* test_sessions_restore
let extension = ExtensionTestUtils.loadExtension({
manifest: {
permissions: ["sessions", "tabs"],
},
background,
});
+ function assertNotificationCount(expected, actual) {
+ is(actual, expected, "the expected number of notifications was fired");
+ }
+
yield extension.startup();
let {Management: {global: {WindowManager, TabManager}}} = Cu.import("resource://gre/modules/Extension.jsm", {});
function checkLocalTab(tab, expectedUrl) {
let realTab = TabManager.getTab(tab.id);
let tabState = JSON.parse(SessionStore.getTabState(realTab));
is(tabState.entries[0].url, expectedUrl, "restored tab has the expected url");
@@ -52,83 +64,103 @@ add_task(function* test_sessions_restore
let win = yield BrowserTestUtils.openNewBrowserWindow();
yield BrowserTestUtils.loadURI(win.gBrowser.selectedBrowser, "about:config");
yield BrowserTestUtils.browserLoaded(win.gBrowser.selectedBrowser);
for (let url of ["about:robots", "about:mozilla"]) {
yield BrowserTestUtils.openNewForegroundTab(win.gBrowser, url);
}
yield BrowserTestUtils.closeWindow(win);
+ let notificationCount = yield extension.awaitMessage("notificationCount");
+ assertNotificationCount(1, notificationCount);
extension.sendMessage("check-sessions");
let recentlyClosed = yield extension.awaitMessage("recentlyClosed");
// Check that our expected window is the most recently closed.
is(recentlyClosed[0].window.tabs.length, 3, "most recently closed window has the expected number of tabs");
// Restore the window.
extension.sendMessage("restore");
+ notificationCount = yield extension.awaitMessage("notificationCount");
+ assertNotificationCount(2, notificationCount);
let restored = yield extension.awaitMessage("restored");
is(restored.length, 1, "restore returned the expected number of sessions");
is(restored[0].window.tabs.length, 3, "restore returned a window with the expected number of tabs");
checkLocalTab(restored[0].window.tabs[0], "about:config");
checkLocalTab(restored[0].window.tabs[1], "about:robots");
checkLocalTab(restored[0].window.tabs[2], "about:mozilla");
// Close the window again.
let window = WindowManager.getWindow(restored[0].window.id);
yield BrowserTestUtils.closeWindow(window);
+ notificationCount = yield extension.awaitMessage("notificationCount");
+ assertNotificationCount(3, notificationCount);
// Restore the window using the sessionId.
extension.sendMessage("check-sessions");
recentlyClosed = yield extension.awaitMessage("recentlyClosed");
extension.sendMessage("restore", recentlyClosed[0].window.sessionId);
+ notificationCount = yield extension.awaitMessage("notificationCount");
+ assertNotificationCount(4, notificationCount);
restored = yield extension.awaitMessage("restored");
is(restored.length, 1, "restore returned the expected number of sessions");
is(restored[0].window.tabs.length, 3, "restore returned a window with the expected number of tabs");
checkLocalTab(restored[0].window.tabs[0], "about:config");
checkLocalTab(restored[0].window.tabs[1], "about:robots");
checkLocalTab(restored[0].window.tabs[2], "about:mozilla");
// Close the window again.
window = WindowManager.getWindow(restored[0].window.id);
yield BrowserTestUtils.closeWindow(window);
+ notificationCount = yield extension.awaitMessage("notificationCount");
+ assertNotificationCount(5, notificationCount);
// Open and close a tab.
let tab = yield BrowserTestUtils.openNewForegroundTab(gBrowser, "about:robots");
yield BrowserTestUtils.removeTab(tab);
+ notificationCount = yield extension.awaitMessage("notificationCount");
+ assertNotificationCount(6, notificationCount);
// Restore the most recently closed item.
extension.sendMessage("restore");
+ notificationCount = yield extension.awaitMessage("notificationCount");
+ assertNotificationCount(7, notificationCount);
restored = yield extension.awaitMessage("restored");
is(restored.length, 1, "restore returned the expected number of sessions");
tab = restored[0].tab;
ok(tab, "restore returned a tab");
checkLocalTab(tab, "about:robots");
// Close the tab again.
let realTab = TabManager.getTab(tab.id);
yield BrowserTestUtils.removeTab(realTab);
+ notificationCount = yield extension.awaitMessage("notificationCount");
+ assertNotificationCount(8, notificationCount);
// Restore the tab using the sessionId.
extension.sendMessage("check-sessions");
recentlyClosed = yield extension.awaitMessage("recentlyClosed");
extension.sendMessage("restore", recentlyClosed[0].tab.sessionId);
+ notificationCount = yield extension.awaitMessage("notificationCount");
+ assertNotificationCount(9, notificationCount);
restored = yield extension.awaitMessage("restored");
is(restored.length, 1, "restore returned the expected number of sessions");
tab = restored[0].tab;
ok(tab, "restore returned a tab");
checkLocalTab(tab, "about:robots");
// Close the tab again.
realTab = TabManager.getTab(tab.id);
yield BrowserTestUtils.removeTab(realTab);
+ notificationCount = yield extension.awaitMessage("notificationCount");
+ assertNotificationCount(10, notificationCount);
// Try to restore something with an invalid sessionId.
extension.sendMessage("restore-reject");
restored = yield extension.awaitMessage("restore-rejected");
yield extension.unload();
});