Wed, 31 Dec 2014 13:27:57 +0100
Ignore runtime configuration files generated during quality assurance.
1 /* This Source Code Form is subject to the terms of the Mozilla Public
2 * License, v. 2.0. If a copy of the MPL was not distributed with this
3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
5 const Cu = Components.utils;
7 Cu.import("resource://services-sync/main.js");
8 Cu.import("resource:///modules/PlacesUIUtils.jsm");
9 Cu.import("resource://gre/modules/PlacesUtils.jsm", this);
10 Cu.import("resource://gre/modules/Services.jsm");
12 let RemoteTabViewer = {
13 _tabsList: null,
15 init: function () {
16 Services.obs.addObserver(this, "weave:service:login:finish", false);
17 Services.obs.addObserver(this, "weave:engine:sync:finish", false);
19 this._tabsList = document.getElementById("tabsList");
21 this.buildList(true);
22 },
24 uninit: function () {
25 Services.obs.removeObserver(this, "weave:service:login:finish");
26 Services.obs.removeObserver(this, "weave:engine:sync:finish");
27 },
29 buildList: function(force) {
30 if (!Weave.Service.isLoggedIn || !this._refetchTabs(force))
31 return;
32 //XXXzpao We should say something about not being logged in & not having data
33 // or tell the appropriate condition. (bug 583344)
35 this._generateTabList();
36 },
38 createItem: function(attrs) {
39 let item = document.createElement("richlistitem");
41 // Copy the attributes from the argument into the item
42 for (let attr in attrs)
43 item.setAttribute(attr, attrs[attr]);
45 if (attrs["type"] == "tab")
46 item.label = attrs.title != "" ? attrs.title : attrs.url;
48 return item;
49 },
51 filterTabs: function(event) {
52 let val = event.target.value.toLowerCase();
53 let numTabs = this._tabsList.getRowCount();
54 let clientTabs = 0;
55 let currentClient = null;
56 for (let i = 0;i < numTabs;i++) {
57 let item = this._tabsList.getItemAtIndex(i);
58 let hide = false;
59 if (item.getAttribute("type") == "tab") {
60 if (!item.getAttribute("url").toLowerCase().contains(val) &&
61 !item.getAttribute("title").toLowerCase().contains(val))
62 hide = true;
63 else
64 clientTabs++;
65 }
66 else if (item.getAttribute("type") == "client") {
67 if (currentClient) {
68 if (clientTabs == 0)
69 currentClient.hidden = true;
70 }
71 currentClient = item;
72 clientTabs = 0;
73 }
74 item.hidden = hide;
75 }
76 if (clientTabs == 0)
77 currentClient.hidden = true;
78 },
80 openSelected: function() {
81 let items = this._tabsList.selectedItems;
82 let urls = [];
83 for (let i = 0;i < items.length;i++) {
84 if (items[i].getAttribute("type") == "tab") {
85 urls.push(items[i].getAttribute("url"));
86 let index = this._tabsList.getIndexOfItem(items[i]);
87 this._tabsList.removeItemAt(index);
88 }
89 }
90 if (urls.length) {
91 getTopWin().gBrowser.loadTabs(urls);
92 this._tabsList.clearSelection();
93 }
94 },
96 bookmarkSingleTab: function() {
97 let item = this._tabsList.selectedItems[0];
98 let uri = Weave.Utils.makeURI(item.getAttribute("url"));
99 let title = item.getAttribute("title");
100 PlacesUIUtils.showBookmarkDialog({ action: "add"
101 , type: "bookmark"
102 , uri: uri
103 , title: title
104 , hiddenRows: [ "description"
105 , "location"
106 , "loadInSidebar"
107 , "keyword" ]
108 }, window.top);
109 },
111 bookmarkSelectedTabs: function() {
112 let items = this._tabsList.selectedItems;
113 let URIs = [];
114 for (let i = 0;i < items.length;i++) {
115 if (items[i].getAttribute("type") == "tab") {
116 let uri = Weave.Utils.makeURI(items[i].getAttribute("url"));
117 if (!uri)
118 continue;
120 URIs.push(uri);
121 }
122 }
123 if (URIs.length) {
124 PlacesUIUtils.showBookmarkDialog({ action: "add"
125 , type: "folder"
126 , URIList: URIs
127 , hiddenRows: [ "description" ]
128 }, window.top);
129 }
130 },
132 getIcon: function (iconUri, defaultIcon) {
133 try {
134 let iconURI = Weave.Utils.makeURI(iconUri);
135 return PlacesUtils.favicons.getFaviconLinkForIcon(iconURI).spec;
136 } catch(ex) {
137 // Do nothing.
138 }
140 // Just give the provided default icon or the system's default.
141 return defaultIcon || PlacesUtils.favicons.defaultFavicon.spec;
142 },
144 _generateTabList: function() {
145 let engine = Weave.Service.engineManager.get("tabs");
146 let list = this._tabsList;
148 // clear out existing richlistitems
149 let count = list.getRowCount();
150 if (count > 0) {
151 for (let i = count - 1; i >= 0; i--)
152 list.removeItemAt(i);
153 }
155 let seenURLs = new Set();
156 let localURLs = engine.getOpenURLs();
158 for (let [guid, client] in Iterator(engine.getAllClients())) {
159 // Create the client node, but don't add it in-case we don't show any tabs
160 let appendClient = true;
162 client.tabs.forEach(function({title, urlHistory, icon}) {
163 let url = urlHistory[0];
164 if (!url || localURLs.has(url) || seenURLs.has(url)) {
165 return;
166 }
167 seenURLs.add(url);
169 if (appendClient) {
170 let attrs = {
171 type: "client",
172 clientName: client.clientName,
173 class: Weave.Service.clientsEngine.isMobile(client.id) ? "mobile" : "desktop"
174 };
175 let clientEnt = this.createItem(attrs);
176 list.appendChild(clientEnt);
177 appendClient = false;
178 clientEnt.disabled = true;
179 }
180 let attrs = {
181 type: "tab",
182 title: title || url,
183 url: url,
184 icon: this.getIcon(icon),
185 }
186 let tab = this.createItem(attrs);
187 list.appendChild(tab);
188 }, this);
189 }
190 },
192 adjustContextMenu: function(event) {
193 let mode = "all";
194 switch (this._tabsList.selectedItems.length) {
195 case 0:
196 break;
197 case 1:
198 mode = "single"
199 break;
200 default:
201 mode = "multiple";
202 break;
203 }
204 let menu = document.getElementById("tabListContext");
205 let el = menu.firstChild;
206 while (el) {
207 let showFor = el.getAttribute("showFor");
208 if (showFor)
209 el.hidden = showFor != mode && showFor != "all";
211 el = el.nextSibling;
212 }
213 },
215 _refetchTabs: function(force) {
216 if (!force) {
217 // Don't bother refetching tabs if we already did so recently
218 let lastFetch = 0;
219 try {
220 lastFetch = Services.prefs.getIntPref("services.sync.lastTabFetch");
221 }
222 catch (e) { /* Just use the default value of 0 */ }
223 let now = Math.floor(Date.now() / 1000);
224 if (now - lastFetch < 30)
225 return false;
226 }
228 // if Clients hasn't synced yet this session, need to sync it as well
229 if (Weave.Service.clientsEngine.lastSync == 0)
230 Weave.Service.clientsEngine.sync();
232 // Force a sync only for the tabs engine
233 let engine = Weave.Service.engineManager.get("tabs");
234 engine.lastModified = null;
235 engine.sync();
236 Services.prefs.setIntPref("services.sync.lastTabFetch",
237 Math.floor(Date.now() / 1000));
239 return true;
240 },
242 observe: function(subject, topic, data) {
243 switch (topic) {
244 case "weave:service:login:finish":
245 this.buildList(true);
246 break;
247 case "weave:engine:sync:finish":
248 if (subject == "tabs")
249 this._generateTabList();
250 break;
251 }
252 },
254 handleClick: function(event) {
255 if (event.target.getAttribute("type") != "tab")
256 return;
258 if (event.button == 1) {
259 let url = event.target.getAttribute("url");
260 openUILink(url, event);
261 let index = this._tabsList.getIndexOfItem(event.target);
262 this._tabsList.removeItemAt(index);
263 }
264 }
265 }