Source code

Revision control

Other Tools

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/. */
4
5
/*
6
* Provides functions to handle remote tabs (ie, tabs known by Sync) in
7
* the awesomebar.
8
*/
9
10
"use strict";
11
12
var EXPORTED_SYMBOLS = ["PlacesRemoteTabsAutocompleteProvider"];
13
14
const { XPCOMUtils } = ChromeUtils.import(
16
);
17
const { Services } = ChromeUtils.import("resource://gre/modules/Services.jsm");
18
ChromeUtils.defineModuleGetter(
19
this,
20
"SyncedTabs",
22
);
23
24
XPCOMUtils.defineLazyGetter(this, "weaveXPCService", function() {
25
try {
26
return Cc["@mozilla.org/weave/service;1"].getService(
27
Ci.nsISupports
28
).wrappedJSObject;
29
} catch (ex) {
30
// The app didn't build Sync.
31
}
32
return null;
33
});
34
35
// from MDN...
36
function escapeRegExp(string) {
37
return string.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
38
}
39
40
// Build the in-memory structure we use.
41
async function buildItems() {
42
// This is sorted by most recent client, most recent tab.
43
let tabsData = [];
44
// If Sync isn't initialized (either due to lag at startup or due to no user
45
// being signed in), don't reach in to Weave.Service as that may initialize
46
// Sync unnecessarily - we'll get an observer notification later when it
47
// becomes ready and has synced a list of tabs.
48
if (weaveXPCService.ready) {
49
let clients = await SyncedTabs.getTabClients();
50
SyncedTabs.sortTabClientsByLastUsed(clients);
51
for (let client of clients) {
52
for (let tab of client.tabs) {
53
tabsData.push({ tab, client });
54
}
55
}
56
}
57
return tabsData;
58
}
59
60
// Manage the cache of the items we use.
61
// The cache itself.
62
let _items = null;
63
64
// Ensure the cache is good.
65
async function ensureItems() {
66
if (!_items) {
67
_items = await buildItems();
68
}
69
return _items;
70
}
71
72
// A preference used to disable the showing of icons in remote tab records.
73
const PREF_SHOW_REMOTE_ICONS = "services.sync.syncedTabs.showRemoteIcons";
74
let showRemoteIcons;
75
76
// A preference used to disable the synced tabs from showing in awesomebar
77
// matches.
78
const PREF_SHOW_REMOTE_TABS = "services.sync.syncedTabs.showRemoteTabs";
79
let showRemoteTabs;
80
81
// An observer to invalidate _items and watch for changed prefs.
82
function observe(subject, topic, data) {
83
switch (topic) {
84
case "weave:engine:sync:finish":
85
if (data == "tabs") {
86
// The tabs engine just finished syncing, so may have a different list
87
// of tabs then we previously cached.
88
_items = null;
89
}
90
break;
91
92
case "weave:service:start-over":
93
// Sync is being reset due to the user disconnecting - we must invalidate
94
// the cache so we don't supply tabs from a different user.
95
_items = null;
96
break;
97
98
case "nsPref:changed":
99
if (data == PREF_SHOW_REMOTE_ICONS) {
100
showRemoteIcons = Services.prefs.getBoolPref(
101
PREF_SHOW_REMOTE_ICONS,
102
true
103
);
104
} else if (data == PREF_SHOW_REMOTE_TABS) {
105
showRemoteTabs = Services.prefs.getBoolPref(
106
PREF_SHOW_REMOTE_TABS,
107
true
108
);
109
}
110
break;
111
112
default:
113
break;
114
}
115
}
116
117
Services.obs.addObserver(observe, "weave:engine:sync:finish");
118
Services.obs.addObserver(observe, "weave:service:start-over");
119
120
// Observe the prefs for showing remote icons and tabs and prime
121
// our bools that reflect their values.
122
Services.prefs.addObserver(PREF_SHOW_REMOTE_ICONS, observe);
123
Services.prefs.addObserver(PREF_SHOW_REMOTE_TABS, observe);
124
observe(null, "nsPref:changed", PREF_SHOW_REMOTE_ICONS);
125
observe(null, "nsPref:changed", PREF_SHOW_REMOTE_TABS);
126
127
// This public object is a static singleton.
128
var PlacesRemoteTabsAutocompleteProvider = {
129
// a promise that resolves with an array of matching remote tabs.
130
async getMatches(searchString, maxMatches) {
131
// If Sync isn't configured we bail early.
132
if (
133
!weaveXPCService ||
134
!weaveXPCService.ready ||
135
!weaveXPCService.enabled
136
) {
137
return [];
138
}
139
140
if (!showRemoteTabs || !maxMatches) {
141
return [];
142
}
143
144
let re = new RegExp(escapeRegExp(searchString), "i");
145
let matches = [];
146
let tabsData = await ensureItems();
147
for (let { tab, client } of tabsData) {
148
if (re.test(tab.url) || (tab.title && re.test(tab.title))) {
149
matches.push({
150
url: tab.url,
151
title: tab.title,
152
icon: showRemoteIcons ? tab.icon : null,
153
deviceName: client.name,
154
lastUsed: tab.lastUsed * 1000,
155
});
156
if (matches.length == maxMatches) {
157
break;
158
}
159
}
160
}
161
162
return matches;
163
},
164
};