diff --git a/browser/base/content/aboutSyncTabs-bindings.xml b/browser/base/content/aboutSyncTabs-bindings.xml new file mode 100644 index 000000000000..63e0aed2b312 --- /dev/null +++ b/browser/base/content/aboutSyncTabs-bindings.xml @@ -0,0 +1,80 @@ + + +# ***** 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 Weave. +# +# The Initial Developer of the Original Code is the Mozilla Foundation. +# Portions created by the Initial Developer are Copyright (C) 2009 +# the Initial Developer. All Rights Reserved. +# +# Contributor(s): +# Edward Lee +# Mike Connor +# Paul O’Shannessy +# +# 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 ***** + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/browser/base/content/aboutSyncTabs.css b/browser/base/content/aboutSyncTabs.css new file mode 100644 index 000000000000..055a9a687304 --- /dev/null +++ b/browser/base/content/aboutSyncTabs.css @@ -0,0 +1,7 @@ +richlistitem[type="tab"] { + -moz-binding: url(chrome://browser/content/aboutSyncTabs-bindings.xml#tab-listing); +} + +richlistitem[type="client"] { + -moz-binding: url(chrome://browser/content/aboutSyncTabs-bindings.xml#client-listing); +} diff --git a/browser/base/content/aboutSyncTabs.js b/browser/base/content/aboutSyncTabs.js new file mode 100644 index 000000000000..67e5166b9bb0 --- /dev/null +++ b/browser/base/content/aboutSyncTabs.js @@ -0,0 +1,272 @@ +/* ***** 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 Weave. + * + * The Initial Developer of the Original Code is the Mozilla Foundation. + * Portions created by the Initial Developer are Copyright (C) 2009 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Edward Lee + * Mike Connor + * Paul O’Shannessy + * + * 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 ***** */ + + +const Cu = Components.utils; + +Cu.import("resource://services-sync/service.js"); +Cu.import("resource:///modules/PlacesUIUtils.jsm"); +Cu.import("resource://gre/modules/Services.jsm"); + +let RemoteTabViewer = { + _tabsList: null, + + init: function () { + Services.obs.addObserver(this, "weave:service:login:finish", false); + Services.obs.addObserver(this, "weave:engine:sync:finish", false); + + this._tabsList = document.getElementById("tabsList"); + + this.buildList(true); + }, + + uninit: function () { + Services.obs.removeObserver(this, "weave:service:login:finish"); + Services.obs.removeObserver(this, "weave:engine:sync:finish"); + }, + + buildList: function(force) { + if (!Weave.Service.isLoggedIn || !this._refetchTabs(force)) + return; + //XXXzpao We should say something about not being logged in & not having data + // or tell the appropriate condition. (bug 583344) + + this._generateTabList(); + }, + + createItem: function(attrs) { + let item = document.createElement("richlistitem"); + + // Copy the attributes from the argument into the item + for (let attr in attrs) + item.setAttribute(attr, attrs[attr]); + + if (attrs["type"] == "tab") + item.label = attrs.title != "" ? attrs.title : attrs.url; + + return item; + }, + + filterTabs: function(event) { + let val = event.target.value.toLowerCase(); + let numTabs = this._tabsList.getRowCount(); + let clientTabs = 0; + let currentClient = null; + for (let i = 0;i < numTabs;i++) { + let item = this._tabsList.getItemAtIndex(i); + let hide = false; + if (item.getAttribute("type") == "tab") { + if (item.getAttribute("url").toLowerCase().indexOf(val) == -1 && + item.getAttribute("title").toLowerCase().indexOf(val) == -1) + hide = true; + else + clientTabs++; + } + else if (item.getAttribute("type") == "client") { + if (currentClient) { + if (clientTabs == 0) + currentClient.hidden = true; + } + currentClient = item; + clientTabs = 0; + } + item.hidden = hide; + } + if (clientTabs == 0) + currentClient.hidden = true; + }, + + openSelected: function() { + let items = this._tabsList.selectedItems; + let urls = []; + for (let i = 0;i < items.length;i++) { + if (items[i].getAttribute("type") == "tab") { + urls.push(items[i].getAttribute("url")); + let index = this._tabsList.getIndexOfItem(items[i]); + this._tabsList.removeItemAt(index); + } + } + if (urls.length) { + getTopWin().gBrowser.loadTabs(urls); + this._tabsList.clearSelection(); + } + }, + + bookmarkSingleTab: function() { + let item = this._tabsList.selectedItems[0]; + let uri = Weave.Utils.makeURI(item.getAttribute("url")); + let title = item.getAttribute("title"); + PlacesUIUtils.showMinimalAddBookmarkUI(uri, title); + }, + + bookmarkSelectedTabs: function() { + let items = this._tabsList.selectedItems; + let URIs = []; + for (let i = 0;i < items.length;i++) { + if (items[i].getAttribute("type") == "tab") { + let uri = Weave.Utils.makeURI(items[i].getAttribute("url")); + if (!uri) + continue; + + URIs.push(uri); + } + } + if (URIs.length) + PlacesUIUtils.showMinimalAddMultiBookmarkUI(URIs); + }, + + _generateTabList: function() { + let engine = Weave.Engines.get("tabs"); + let list = this._tabsList; + + // clear out existing richlistitems + let count = list.getRowCount(); + if (count > 0) { + for (let i = count - 1; i >= 0; i--) + list.removeItemAt(i); + } + + for (let [guid, client] in Iterator(engine.getAllClients())) { + // Create the client node, but don't add it in-case we don't show any tabs + let appendClient = true; + let seenURLs = {}; + client.tabs.forEach(function({title, urlHistory, icon}) { + let url = urlHistory[0]; + if (engine.locallyOpenTabMatchesURL(url) || url in seenURLs) + return; + + seenURLs[url] = null; + + if (appendClient) { + let attrs = { + type: "client", + clientName: client.clientName, + class: Weave.Clients.isMobile(client.id) ? "mobile" : "desktop" + }; + let clientEnt = this.createItem(attrs); + list.appendChild(clientEnt); + appendClient = false; + clientEnt.disabled = true; + } + let attrs = { + type: "tab", + title: title || url, + url: url, + icon: Weave.Utils.getIcon(icon) + } + let tab = this.createItem(attrs); + list.appendChild(tab); + }, this); + } + }, + + adjustContextMenu: function(event) { + let mode = "all"; + switch (this._tabsList.selectedItems.length) { + case 0: + break; + case 1: + mode = "single" + break; + default: + mode = "multiple"; + break; + } + let menu = document.getElementById("tabListContext"); + let el = menu.firstChild; + while (el) { + let showFor = el.getAttribute("showFor"); + if (showFor) + el.hidden = showFor != mode && showFor != "all"; + + el = el.nextSibling; + } + }, + + _refetchTabs: function(force) { + if (!force) { + // Don't bother refetching tabs if we already did so recently + let lastFetch = 0; + try { + lastFetch = Services.prefs.getIntPref("services.sync.lastTabFetch"); + } + catch (e) { /* Just use the default value of 0 */ } + let now = Math.floor(Date.now() / 1000); + if (now - lastFetch < 30) + return false; + } + + // if Clients hasn't synced yet this session, need to sync it as well + if (Weave.Clients.lastSync == 0) + Weave.Clients.sync(); + + // Force a sync only for the tabs engine + let engine = Weave.Engines.get("tabs"); + engine.lastModified = null; + engine.sync(); + Services.prefs.setIntPref("services.sync.lastTabFetch", + Math.floor(Date.now() / 1000)); + + return true; + }, + + observe: function(subject, topic, data) { + switch (topic) { + case "weave:service:login:finish": + this.buildList(true); + break; + case "weave:engine:sync:finish": + if (subject == "tabs") + this._generateTabList(); + break; + } + }, + + handleClick: function(event) { + if (event.target.getAttribute("type") != "tab") + return; + + if (event.button == 1) { + let url = event.target.getAttribute("url"); + openUILink(url, event); + let index = this._tabsList.getIndexOfItem(event.target); + this._tabsList.removeItemAt(index); + } + } +} + diff --git a/browser/base/content/aboutSyncTabs.xul b/browser/base/content/aboutSyncTabs.xul new file mode 100644 index 000000000000..f2cf38fb9103 --- /dev/null +++ b/browser/base/content/aboutSyncTabs.xul @@ -0,0 +1,102 @@ + + +# ***** 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 Weave. +# +# The Initial Developer of the Original Code is the Mozilla Foundation. +# Portions created by the Initial Developer are Copyright (C) 2009 +# the Initial Developer. All Rights Reserved. +# +# Contributor(s): +# Edward Lee +# Mike Connor +# Paul O’Shannessy +# +# 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 ***** + + + + + + + %aboutSyncTabsDTD; +]> + + +