-
Notifications
You must be signed in to change notification settings - Fork 0
/
background.js
120 lines (100 loc) · 3.1 KB
/
background.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
/* stick all the options here so we can keep track of them */
let settings = {
'protectDuplicates': true,
'moveOlder': true,
'checkMultiWindow': false
};
/* list of tab IDs that should be protected from removal */
let blessedTabs = new Set();
const TAB_QUERY_OPTIONS = {
windowType: "normal"
};
let replaceTab = (replacedTab, replacementTab, discardedTabs) => {
if (settings.moveOlder) {
browser.tabs.move(replacementTab.id, { index: replacedTab.index, windowId: replacedTab.windowId });
}
/* don't focus backgrounded tabs */
if (replacedTab.active) {
browser.tabs.update(replacementTab.id, { active: replacedTab.active });
}
browser.notifications.create({
"type": "basic",
"title": browser.i18n.getMessage('notificationTitle'),
"message": (replacedTab.url).toString()
}).then(currentNotification => {
setTimeout((notification) => {
browser.notifications.clear(notification);
}, 5000, currentNotification);
});
browser.tabs.remove(discardedTabs.map(tab => tab.id));
};
let getTabQuery = (url) => {
const newURL = new URL(url);
let filter;
switch (newURL.protocol) {
case 'about:':
filter = {
'url': `${newURL.protocol}*`
};
break;
default:
filter = {
'url': `*://${newURL.hostname}/*`
};
break;
}
filter.currentWindow = settings.checkMultiWindow? null : true;
return Object.assign({}, TAB_QUERY_OPTIONS, filter);
}
let checkDuplicateTabs = async (newTab) => {
if (newTab.id === browser.tabs.TAB_ID_NONE || blessedTabs.has(newTab.id)) {
return;
}
/* query to prefilter tabs */
const tabQuery = getTabQuery(newTab.url);
await browser.tabs.query(tabQuery).then(tabs => {
/* return tabs with in the same session and the same URL (including current) */
let copies = tabs.filter(tab => {
return newTab.cookieStoreId === tab.cookieStoreId
&& newTab.url === tab.url && !blessedTabs.has(tab.id);
});
if (copies.length > 1) {
/* TODO handle priorities -- right now it keeps the older tab */
copies.sort((a, b) => a.id - b.id);
/* keep first tab, discard the rest */
[ keptTab, ...discarded ] = copies;
replaceTab(newTab, keptTab, discarded);
}
});
};
/* main routine */
browser.tabs.onUpdated.addListener((id, change, newTab) => {
if (change.url && change.url !== 'about:blank') {
checkDuplicateTabs(newTab);
}
});
/* add protections to newly created tabs */
browser.tabs.onCreated.addListener(tab => {
if ('openerTabId' in tab && tab.status === 'loading' && settings.protectDuplicates) {
blessedTabs.add(tab.id);
}
});
browser.tabs.onRemoved.addListener((id, info) => {
blessedTabs.delete(id);
});
browser.storage.onChanged.addListener((changes, areaName) => {
/* extract just the new values so we can apply them to our options */
let additions = {};
Object.keys(changes).forEach((key) => additions[key] = changes[key].newValue);
Object.assign(settings, additions);
/**
* wipe any 'protected' tabs if the option is disabled so they don't linger if another
* duplicate shows up
*/
if (!settings.protectDuplicates) {
blessedTabs.clear();
}
});
browser.storage.sync.get(null, (data) => {
Object.assign(settings, data);
});