Skip to content

Commit f96eaa0

Browse files
committed
Refactor api of chrome
1 parent ce501be commit f96eaa0

39 files changed

+374
-274
lines changed

global.d.ts

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -557,3 +557,22 @@ declare namespace timer {
557557
type Callback<T = any> = (result?: Response<T>) => void
558558
}
559559
}
560+
561+
/**
562+
* ABBRs for namespace chrome
563+
*/
564+
// chrome.tabs
565+
declare type ChromeTab = chrome.tabs.Tab
566+
declare type ChromeTabActiveInfo = chrome.tabs.TabActiveInfo
567+
declare type ChromeTabChangeInfo = chrome.tabs.TabChangeInfo
568+
// chrome.windows
569+
declare type ChromeWindow = chrome.windows.Window
570+
// chrome.contextMenus
571+
declare type ChromeContextMenuCreateProps = chrome.contextMenus.CreateProperties
572+
declare type ChromeContextMenuUpdateProps = chrome.contextMenus.UpdateProperties
573+
// chrome.alarms
574+
declare type ChromeAlarm = chrome.alarms.Alarm
575+
// chrome.runtime
576+
declare type ChromeOnInstalledReason = chrome.runtime.OnInstalledReason
577+
declare type ChromeMessageSender = chrome.runtime.MessageSender
578+
declare type ChromeMessageHandler<T = any, R = any> = (req: timer.mq.Request<T>, sender: ChromeMessageSender) => Promise<timer.mq.Response<R>>

src/api/chrome/action.ts

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
import { IS_MV3 } from "@util/constant/environment"
2+
import { handleError } from "./common"
3+
4+
const action = IS_MV3 ? chrome.action : chrome.browserAction
5+
6+
export function setBadgeText(text: string, tabId: number): Promise<void> {
7+
return new Promise(resolve => action?.setBadgeText({ tabId, text }, () => {
8+
handleError('setBadgeText')
9+
resolve()
10+
}))
11+
}

src/api/chrome/alarm.ts

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
import { handleError } from "./common"
2+
3+
type AlarmHandler = (alarm: ChromeAlarm) => PromiseLike<void> | void
4+
5+
export function onAlarm(handler: AlarmHandler) {
6+
chrome.alarms.onAlarm.addListener(handler)
7+
}
8+
9+
export function clearAlarm(name: string): Promise<void> {
10+
return new Promise(resolve => chrome.alarms.clear(name, () => {
11+
handleError('clearAlarm')
12+
resolve()
13+
}))
14+
}
15+
16+
export function createAlarm(name: string, when: number): void {
17+
chrome.alarms.create(name, { when })
18+
}

src/api/chrome/common.ts

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
export function handleError(scene: string) {
2+
try {
3+
const lastError = chrome.runtime.lastError
4+
lastError && console.log(`Errord when ${scene}: ${lastError.message}`)
5+
} catch (e) {
6+
console.info("Can't execute here")
7+
}
8+
}

src/api/chrome/context-menu.ts

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
import { handleError } from "./common"
2+
3+
export function createContextMenu(props: ChromeContextMenuCreateProps): Promise<void> {
4+
return new Promise(resolve => chrome.contextMenus.create(props, () => {
5+
handleError('createContextMenu')
6+
resolve()
7+
}))
8+
}
9+
10+
export function updateContextMenu(menuId: string, props: ChromeContextMenuUpdateProps): Promise<void> {
11+
return new Promise(resolve => chrome.contextMenus.update(menuId, props, () => {
12+
handleError('updateContextMenu')
13+
resolve()
14+
}))
15+
}

src/api/chrome/runtime.ts

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
import { handleError } from "./common"
2+
3+
export function getRuntimeId(): string {
4+
return chrome.runtime.id
5+
}
6+
7+
export function sendMsg2Runtime<T = any, R = any>(code: timer.mq.ReqCode, data?: T): Promise<R> {
8+
const request: timer.mq.Request<T> = { code, data }
9+
return new Promise((resolve, reject) => chrome.runtime.sendMessage(request,
10+
(response: timer.mq.Response<R>) => {
11+
handleError('sendMsg2Runtime')
12+
const resCode = response?.code
13+
resCode === 'success'
14+
? resolve(response.data)
15+
: reject(new Error(response?.msg))
16+
})
17+
)
18+
}
19+
20+
export function onRuntimeMessage<T = any, R = any>(handler: ChromeMessageHandler<T, R>): void {
21+
// Be careful!!!
22+
// Can't use await/async in callback parameter
23+
chrome.runtime.onMessage.addListener((message: timer.mq.Request<T>, sender: chrome.runtime.MessageSender, sendResponse: timer.mq.Callback<R>) => {
24+
handler(message, sender).then((response: timer.mq.Response<R>) => sendResponse(response))
25+
// 'return ture' will force chrome to wait for the response processed in the above promise.
26+
// @see https://github.com/mozilla/webextension-polyfill/issues/130
27+
return true
28+
})
29+
}
30+
31+
export function onInstalled(handler: (reason: ChromeOnInstalledReason) => void): void {
32+
chrome.runtime.onInstalled.addListener(detail => handler(detail.reason))
33+
}
34+
35+
export function getVersion(): string {
36+
return chrome.runtime.getManifest().version
37+
}
38+
39+
export function setUninstallURL(url: string): Promise<void> {
40+
return new Promise(resolve => chrome.runtime.setUninstallURL(url, resolve))
41+
}

src/api/chrome/tab.ts

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
import { handleError } from "./common"
2+
3+
export function getTab(id: number): Promise<ChromeTab> {
4+
return new Promise(resolve => chrome.tabs.get(id, tab => {
5+
handleError("getTab")
6+
resolve(tab)
7+
}))
8+
}
9+
10+
export function createTab(param: chrome.tabs.CreateProperties | string): Promise<ChromeTab> {
11+
const prop: chrome.tabs.CreateProperties = typeof param === 'string' ? { url: param } : param
12+
return new Promise(resolve => chrome.tabs.create(prop, tab => {
13+
handleError("getTab")
14+
resolve(tab)
15+
}))
16+
}
17+
18+
export function listTabs(query?: chrome.tabs.QueryInfo): Promise<ChromeTab[]> {
19+
query = query || {}
20+
return new Promise(resolve => chrome.tabs.query(query, tabs => {
21+
handleError("listTabs")
22+
resolve(tabs || [])
23+
}))
24+
}
25+
26+
export function sendMsg2Tab<T = any, R = any>(tabId: number, code: timer.mq.ReqCode, data: T): Promise<R> {
27+
const request: timer.mq.Request<T> = { code, data }
28+
return new Promise((resolve, reject) => {
29+
chrome.tabs.sendMessage<timer.mq.Request<T>, timer.mq.Response>(tabId, request, response => {
30+
handleError('sendMsgTab')
31+
const resCode = response?.code
32+
resCode === 'success'
33+
? resolve(response.data)
34+
: reject(new Error(response?.msg))
35+
})
36+
})
37+
}
38+
39+
type TabHandler<Event> = (tabId: number, ev: Event, tab?: ChromeTab) => void
40+
41+
export function onTabActivated(handler: TabHandler<ChromeTabActiveInfo>): void {
42+
chrome.tabs.onActivated.addListener((activeInfo: chrome.tabs.TabActiveInfo) => {
43+
handleError("tabActivated")
44+
handler(activeInfo?.tabId, activeInfo)
45+
})
46+
}
47+
48+
export function onTabUpdated(handler: TabHandler<ChromeTabChangeInfo>): void {
49+
chrome.tabs.onUpdated.addListener((tabId: number, changeInfo: ChromeTabChangeInfo, tab: ChromeTab) => {
50+
handleError("tabUpdated")
51+
handler(tabId, changeInfo, tab)
52+
})
53+
}

src/api/chrome/window.ts

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
import { handleError } from "./common"
2+
3+
4+
export function listAllWindows(): Promise<chrome.windows.Window[]> {
5+
return new Promise(resolve => chrome.windows.getAll(windows => {
6+
handleError("listAllWindows")
7+
resolve(windows || [])
8+
}))
9+
}
10+
11+
export function isNoneWindowId(windowId: number) {
12+
return !windowId || windowId === chrome.windows.WINDOW_ID_NONE
13+
}
14+
15+
export function getFocusedNormalWindow(): Promise<chrome.windows.Window> {
16+
return new Promise(resolve => chrome.windows.getLastFocused(
17+
// Only find normal window
18+
{ windowTypes: ['normal'] },
19+
window => {
20+
handleError('getFocusedNormalWindow')
21+
if (!window?.focused || isNoneWindowId(window?.id)) {
22+
resolve(undefined)
23+
} else {
24+
resolve(window)
25+
}
26+
}
27+
))
28+
}
29+
30+
export function getWindow(id: number): Promise<chrome.windows.Window> {
31+
return new Promise(resolve =>
32+
chrome.windows.get(id)
33+
.then(win => resolve(win))
34+
.catch(_ => resolve(undefined))
35+
)
36+
}
37+
38+
type _Handler = (windowId: number) => void
39+
40+
export function onNormalWindowFocusChanged(handler: _Handler) {
41+
chrome.windows.onFocusChanged.addListener(windowId => {
42+
handleError('onWindowFocusChanged')
43+
handler(windowId)
44+
}, { windowTypes: ['normal'] })
45+
}

src/app/components/dashboard/components/calendar-heat-map.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@ import { BASE_TITLE_OPTION } from "../common"
3838
import { getPrimaryTextColor } from "@util/style"
3939
import { getAppPageUrl } from "@util/constant/url"
4040
import { REPORT_ROUTE } from "@app/router/constants"
41+
import { createTab } from "@api/chrome/tab"
4142

4243
const WEEK_NUM = 53
4344

@@ -213,7 +214,7 @@ function handleClick(value: _Value): void {
213214
const query: ReportQueryParam = { ds: currentTs, de: currentTs }
214215

215216
const url = getAppPageUrl(false, REPORT_ROUTE, query)
216-
chrome.tabs.create({ url })
217+
createTab(url)
217218
}
218219

219220
class ChartWrapper {

0 commit comments

Comments
 (0)