diff options
Diffstat (limited to 'services/cloudsync/CloudSyncTabs.jsm')
-rw-r--r-- | services/cloudsync/CloudSyncTabs.jsm | 318 |
1 files changed, 0 insertions, 318 deletions
diff --git a/services/cloudsync/CloudSyncTabs.jsm b/services/cloudsync/CloudSyncTabs.jsm deleted file mode 100644 index 7debc26782..0000000000 --- a/services/cloudsync/CloudSyncTabs.jsm +++ /dev/null @@ -1,318 +0,0 @@ -/* 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.EXPORTED_SYMBOLS = ["Tabs"]; - -const Cu = Components.utils; - -Cu.import("resource://gre/modules/XPCOMUtils.jsm"); -Cu.import("resource://gre/modules/Services.jsm"); -Cu.import("resource://gre/modules/CloudSyncEventSource.jsm"); -Cu.import("resource://gre/modules/Promise.jsm"); -Cu.import("resource://services-common/observers.js"); - -XPCOMUtils.defineLazyModuleGetter(this, "PrivateBrowsingUtils", "resource://gre/modules/PrivateBrowsingUtils.jsm"); -XPCOMUtils.defineLazyServiceGetter(this, "Session", "@mozilla.org/browser/sessionstore;1", "nsISessionStore"); - -const DATA_VERSION = 1; - -var ClientRecord = function (params) { - this.id = params.id; - this.name = params.name || "?"; - this.tabs = new Set(); -} - -ClientRecord.prototype = { - version: DATA_VERSION, - - update: function (params) { - if (this.id !== params.id) { - throw new Error("expected " + this.id + " to equal " + params.id); - } - - this.name = params.name; - } -}; - -var TabRecord = function (params) { - this.url = params.url || ""; - this.update(params); -}; - -TabRecord.prototype = { - version: DATA_VERSION, - - update: function (params) { - if (this.url && this.url !== params.url) { - throw new Error("expected " + this.url + " to equal " + params.url); - } - - if (params.lastUsed && params.lastUsed < this.lastUsed) { - return; - } - - this.title = params.title || ""; - this.icon = params.icon || ""; - this.lastUsed = params.lastUsed || 0; - }, -}; - -var TabCache = function () { - this.tabs = new Map(); - this.clients = new Map(); -}; - -TabCache.prototype = { - merge: function (client, tabs) { - if (!client || !client.id) { - return; - } - - if (!tabs) { - return; - } - - let cRecord; - if (this.clients.has(client.id)) { - try { - cRecord = this.clients.get(client.id); - } catch (e) { - throw new Error("unable to update client: " + e); - } - } else { - cRecord = new ClientRecord(client); - this.clients.set(cRecord.id, cRecord); - } - - for (let tab of tabs) { - if (!tab || 'object' !== typeof(tab)) { - continue; - } - - let tRecord; - if (this.tabs.has(tab.url)) { - tRecord = this.tabs.get(tab.url); - try { - tRecord.update(tab); - } catch (e) { - throw new Error("unable to update tab: " + e); - } - } else { - tRecord = new TabRecord(tab); - this.tabs.set(tRecord.url, tRecord); - } - - if (tab.deleted) { - cRecord.tabs.delete(tRecord); - } else { - cRecord.tabs.add(tRecord); - } - } - }, - - clear: function (client) { - if (client) { - this.clients.delete(client.id); - } else { - this.clients = new Map(); - this.tabs = new Map(); - } - }, - - get: function () { - let results = []; - for (let client of this.clients.values()) { - results.push(client); - } - return results; - }, - - isEmpty: function () { - return 0 == this.clients.size; - }, - -}; - -this.Tabs = function () { - let suspended = true; - - let topics = [ - "pageshow", - "TabOpen", - "TabClose", - "TabSelect", - ]; - - let update = function (event) { - if (event.originalTarget.linkedBrowser) { - if (PrivateBrowsingUtils.isBrowserPrivate(event.originalTarget.linkedBrowser) && - !PrivateBrowsingUtils.permanentPrivateBrowsing) { - return; - } - } - - eventSource.emit("change"); - }; - - let registerListenersForWindow = function (window) { - for (let topic of topics) { - window.addEventListener(topic, update, false); - } - window.addEventListener("unload", unregisterListeners, false); - }; - - let unregisterListenersForWindow = function (window) { - window.removeEventListener("unload", unregisterListeners, false); - for (let topic of topics) { - window.removeEventListener(topic, update, false); - } - }; - - let unregisterListeners = function (event) { - unregisterListenersForWindow(event.target); - }; - - let observer = { - observe: function (subject, topic, data) { - switch (topic) { - case "domwindowopened": - let onLoad = () => { - subject.removeEventListener("load", onLoad, false); - // Only register after the window is done loading to avoid unloads. - registerListenersForWindow(subject); - }; - - // Add tab listeners now that a window has opened. - subject.addEventListener("load", onLoad, false); - break; - } - } - }; - - let resume = function () { - if (suspended) { - Observers.add("domwindowopened", observer); - let wins = Services.wm.getEnumerator("navigator:browser"); - while (wins.hasMoreElements()) { - registerListenersForWindow(wins.getNext()); - } - } - }.bind(this); - - let suspend = function () { - if (!suspended) { - Observers.remove("domwindowopened", observer); - let wins = Services.wm.getEnumerator("navigator:browser"); - while (wins.hasMoreElements()) { - unregisterListenersForWindow(wins.getNext()); - } - } - }.bind(this); - - let eventTypes = [ - "change", - ]; - - let eventSource = new EventSource(eventTypes, suspend, resume); - - let tabCache = new TabCache(); - - let getWindowEnumerator = function () { - return Services.wm.getEnumerator("navigator:browser"); - }; - - let shouldSkipWindow = function (win) { - return win.closed || - PrivateBrowsingUtils.isWindowPrivate(win); - }; - - let getTabState = function (tab) { - return JSON.parse(Session.getTabState(tab)); - }; - - let getLocalTabs = function (filter) { - let deferred = Promise.defer(); - - filter = (undefined === filter) ? true : filter; - let filteredUrls = new RegExp("^(about:.*|chrome://weave/.*|wyciwyg:.*|file:.*)$"); // FIXME: should be a pref (B#1044304) - - let allTabs = []; - - let currentState = JSON.parse(Session.getBrowserState()); - currentState.windows.forEach(function (window) { - if (window.isPrivate) { - return; - } - window.tabs.forEach(function (tab) { - if (!tab.entries.length) { - return; - } - - // Get only the latest entry - // FIXME: support full history (B#1044306) - let entry = tab.entries[tab.index - 1]; - - if (!entry.url || filter && filteredUrls.test(entry.url)) { - return; - } - - allTabs.push(new TabRecord({ - title: entry.title, - url: entry.url, - icon: tab.attributes && tab.attributes.image || "", - lastUsed: tab.lastAccessed, - })); - }); - }); - - deferred.resolve(allTabs); - - return deferred.promise; - }; - - let mergeRemoteTabs = function (client, tabs) { - let deferred = Promise.defer(); - - deferred.resolve(tabCache.merge(client, tabs)); - Observers.notify("cloudsync:tabs:update"); - - return deferred.promise; - }; - - let clearRemoteTabs = function (client) { - let deferred = Promise.defer(); - - deferred.resolve(tabCache.clear(client)); - Observers.notify("cloudsync:tabs:update"); - - return deferred.promise; - }; - - let getRemoteTabs = function () { - let deferred = Promise.defer(); - - deferred.resolve(tabCache.get()); - - return deferred.promise; - }; - - let hasRemoteTabs = function () { - return !tabCache.isEmpty(); - }; - - /* PUBLIC API */ - this.addEventListener = eventSource.addEventListener; - this.removeEventListener = eventSource.removeEventListener; - this.getLocalTabs = getLocalTabs.bind(this); - this.mergeRemoteTabs = mergeRemoteTabs.bind(this); - this.clearRemoteTabs = clearRemoteTabs.bind(this); - this.getRemoteTabs = getRemoteTabs.bind(this); - this.hasRemoteTabs = hasRemoteTabs.bind(this); -}; - -Tabs.prototype = { -}; -this.Tabs = Tabs; |