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