/
tabs.ts
123 lines (118 loc) · 3.35 KB
/
tabs.ts
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
121
122
123
import EventSource from '../event-source';
export type Tab = {
active: boolean
attention?: boolean
audible?: boolean
autoDiscardable?: boolean
cookieStoreId?: string
discarded?: boolean
favIconUrl?: string
height?: number
hidden: boolean
highlighted: boolean
id?: number
incognito: boolean
index: number
isArticle: boolean
isInReaderMode: boolean
lastAccessed: number
mutedInfo?: any
openerTabId?: number
pinned: boolean
selected: boolean
sessionId?: string
status?: string
title?: string
url?: string
width?: number
windowId: number
}
type TabQuery = {
active?: boolean
pinned?: boolean
audible?: boolean
muted?: boolean
highlighted?: boolean
discarded?: boolean
autoDiscardable?: boolean
currentWindow?: boolean
lastFocusedWindow?: boolean
status?: string
title?: string
url?: string | string[]
windowId?: number
windowType?: string
index?: number
}
export default (probe?: (key: string, value: any) => void) => {
const tabStore = new Map<number, Tab>()
const tabs = {
create(properties, cb) {
cb && cb({
active: true,
id: 1,
})
},
query(q: TabQuery, cb) {
const matches = []
const searchKeys = new Set(Object.keys(q));
// ignore these keys
['currentWindow', 'lastFocusedWindow', 'title', 'url'].forEach((k) => searchKeys.delete(k));
[...tabStore.values()].filter((tab) => {
if (searchKeys.size !== 0 && ![...searchKeys].every((k) => tab[k] === q[k])) {
return;
}
if (Array.isArray(q.url)) {
if (q.url.every((url) => tab.url.match(new RegExp(url)) === null)) {
return;
}
} else {
if (tab.url.match(new RegExp(q.url)) === null) {
return;
}
}
matches.push(tab);
});
// console.log('xxx tab q', q, matches);
cb(matches);
},
get(tabId: number, cb: (tab: Tab) => void) {
cb(tabStore.get(tabId));
},
getCurrent(cb: (tab: Tab) => void) {
const current = [...tabStore.values()].find((tab) => tab.active);
cb(current);
},
sendMessage(tabId, message) {
probe && probe('chrome.tabs.message', message.action);
},
connect() {
return {
postMessage(message) {
probe && probe('chrome.tabs.postMessage', message.action);
},
onMessage: new EventSource('runtime.connect().onMessage'),
}
},
onActivated: new EventSource('tabs.onActivated'),
onRemoved: new EventSource('tabs.onRemoved'),
onCreated: new EventSource('tabs.onCreated'),
onUpdated: new EventSource('tabs.onUpdated'),
onReplaced: new EventSource('tabs.onReplaced'),
onHighlighted: new EventSource('tabs.onHighlighted'),
};
tabs.onCreated.addListener((tab: Tab) => tabStore.set(tab.id, tab));
tabs.onRemoved.addListener((tabId: number) => tabStore.delete(tabId));
tabs.onUpdated.addListener((tabId: number, changeInfo, tab: Tab) => tabStore.set(tabId, tab));
tabs.onActivated.addListener((activeInfo: { tabId: number }) => {
tabs.getCurrent((tab) => {
if (tab) tab.active = false
});
tabStore.get(activeInfo.tabId).active = true;
});;
tabs.onReplaced.addListener((addedTabId: number, removedTabId: number) => {
tabStore.set(addedTabId, tabStore.get(removedTabId));
tabStore.delete(removedTabId);
});
return tabs;
}