michael@0: // -*- Mode: js2; tab-width: 2; indent-tabs-mode: nil; js2-basic-offset: 2; js2-skip-preprocessor-directives: t; -*- michael@0: /* This Source Code Form is subject to the terms of the Mozilla Public michael@0: * License, v. 2.0. If a copy of the MPL was not distributed with this michael@0: * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ michael@0: michael@0: "use strict"; michael@0: michael@0: const Cu = Components.utils; michael@0: michael@0: Cu.import("resource://services-sync/main.js"); michael@0: Cu.import("resource://gre/modules/PlacesUtils.jsm", this); michael@0: michael@0: /** michael@0: * Wraps a list/grid control implementing nsIDOMXULSelectControlElement and michael@0: * fills it with the user's synced tabs. michael@0: * michael@0: * Note, the Sync module takes care of initializing the sync service. We should michael@0: * not make calls that start sync or sync tabs since this module loads really michael@0: * early during startup. michael@0: * michael@0: * @param aSet Control implementing nsIDOMXULSelectControlElement. michael@0: * @param aSetUIAccess The UI element that should be hidden when Sync is michael@0: * disabled. Must sanely support 'hidden' attribute. michael@0: * You may only have one UI access point at this time. michael@0: */ michael@0: function RemoteTabsView(aSet, aSetUIAccessList) { michael@0: View.call(this, aSet); michael@0: michael@0: this._uiAccessElements = aSetUIAccessList; michael@0: michael@0: // Sync uses special voodoo observers. michael@0: // If you want to change this code, talk to the fx-si team michael@0: Weave.Svc.Obs.add("weave:service:sync:finish", this); michael@0: Weave.Svc.Obs.add("weave:service:start-over", this); michael@0: michael@0: if (this.isSyncEnabled() ) { michael@0: this.populateGrid(); michael@0: } michael@0: else { michael@0: this.setUIAccessVisible(false); michael@0: } michael@0: } michael@0: michael@0: RemoteTabsView.prototype = Util.extend(Object.create(View.prototype), { michael@0: _set: null, michael@0: _uiAccessElements: [], michael@0: michael@0: handleItemClick: function tabview_handleItemClick(aItem) { michael@0: let url = aItem.getAttribute("value"); michael@0: StartUI.goToURI(url); michael@0: }, michael@0: michael@0: observe: function(subject, topic, data) { michael@0: switch (topic) { michael@0: case "weave:service:sync:finish": michael@0: this.populateGrid(); michael@0: break; michael@0: case "weave:service:start-over": michael@0: this.setUIAccessVisible(false); michael@0: break; michael@0: } michael@0: }, michael@0: michael@0: setUIAccessVisible: function setUIAccessVisible(aVisible) { michael@0: for (let elem of this._uiAccessElements) { michael@0: elem.hidden = !aVisible; michael@0: } michael@0: }, michael@0: michael@0: getIcon: function (iconUri, defaultIcon) { michael@0: try { michael@0: let iconURI = Weave.Utils.makeURI(iconUri); michael@0: return PlacesUtils.favicons.getFaviconLinkForIcon(iconURI).spec; michael@0: } catch(ex) { michael@0: // Do nothing. michael@0: } michael@0: michael@0: // Just give the provided default icon or the system's default. michael@0: return defaultIcon || PlacesUtils.favicons.defaultFavicon.spec; michael@0: }, michael@0: michael@0: populateGrid: function populateGrid() { michael@0: michael@0: let tabsEngine = Weave.Service.engineManager.get("tabs"); michael@0: let list = this._set; michael@0: let seenURLs = new Set(); michael@0: let localURLs = tabsEngine.getOpenURLs(); michael@0: michael@0: // Clear grid, We don't know what has happened to tabs since last sync michael@0: // Also can result in duplicate tabs(bug 864614) michael@0: this._set.clearAll(); michael@0: let show = false; michael@0: for (let [guid, client] in Iterator(tabsEngine.getAllClients())) { michael@0: client.tabs.forEach(function({title, urlHistory, icon}) { michael@0: let url = urlHistory[0]; michael@0: if (!url || getOpenURLs.has(url) || seenURLs.has(url)) { michael@0: return; michael@0: } michael@0: seenURLs.add(url); michael@0: show = true; michael@0: michael@0: // If we wish to group tabs by client, we should be looking for records michael@0: // of {type:client, clientName, class:{mobile, desktop}} and will michael@0: // need to readd logic to reset seenURLs for each client. michael@0: michael@0: let item = this._set.appendItem((title || url), url); michael@0: item.setAttribute("iconURI", this.getIcon(icon)); michael@0: michael@0: }, this); michael@0: } michael@0: this.setUIAccessVisible(show); michael@0: this._set.arrangeItems(); michael@0: }, michael@0: michael@0: destruct: function destruct() { michael@0: Weave.Svc.Obs.remove("weave:engine:sync:finish", this); michael@0: Weave.Svc.Obs.remove("weave:service:logout:start-over", this); michael@0: View.prototype.destruct.call(this); michael@0: }, michael@0: michael@0: isSyncEnabled: function isSyncEnabled() { michael@0: return (Weave.Status.checkSetup() != Weave.CLIENT_NOT_CONFIGURED); michael@0: } michael@0: michael@0: }); michael@0: michael@0: let RemoteTabsStartView = { michael@0: _view: null, michael@0: get _grid() { return document.getElementById("start-remotetabs-grid"); }, michael@0: michael@0: init: function init() { michael@0: let vbox = document.getElementById("start-remotetabs"); michael@0: let uiList = [vbox]; michael@0: this._view = new RemoteTabsView(this._grid, uiList); michael@0: this._grid.removeAttribute("fade"); michael@0: }, michael@0: michael@0: uninit: function uninit() { michael@0: if (this._view) { michael@0: this._view.destruct(); michael@0: } michael@0: }, michael@0: };