diff options
author | Shin'ya Ueoka <ueokande@i-beam.org> | 2020-03-28 21:35:06 +0900 |
---|---|---|
committer | Shin'ya Ueoka <ueokande@i-beam.org> | 2020-03-28 21:43:40 +0900 |
commit | ea63c5f78b4c985e9d6dd106afe4f97bfeedbcd0 (patch) | |
tree | f0accb862f9f3b75c8c86f78361e2acab46f11ef /src/background | |
parent | a8d78f1286fb3fe456a786b2c0e534d212835560 (diff) |
Complete tabs by the completion packages
Diffstat (limited to 'src/background')
21 files changed, 175 insertions, 45 deletions
diff --git a/src/background/completion/CompletionUseCase.ts b/src/background/completion/OpenCompletionUseCase.ts index f7531e7..1b63e7c 100644 --- a/src/background/completion/CompletionUseCase.ts +++ b/src/background/completion/OpenCompletionUseCase.ts @@ -15,7 +15,7 @@ export type HistoryItem = { } @injectable() -export default class CompletionUseCase { +export default class OpenCompletionUseCase { constructor( @inject('BookmarkRepository') private bookmarkRepository: BookmarkRepository, @inject('HistoryRepository') private historyRepository: HistoryRepository, diff --git a/src/background/completion/TabCompletionUseCase.ts b/src/background/completion/TabCompletionUseCase.ts new file mode 100644 index 0000000..7e6dce3 --- /dev/null +++ b/src/background/completion/TabCompletionUseCase.ts @@ -0,0 +1,34 @@ +import { inject, injectable } from "tsyringe"; +import TabItem from "./TabItem"; +import TabRepository from "./TabRepository"; +import TabPresenter from "../presenters/TabPresenter"; +import TabFlag from "../../shared/TabFlag"; + +@injectable() +export default class TabCompletionUseCase { + constructor( + @inject('TabRepository') private tabRepository: TabRepository, + @inject('TabPresenter') private tabPresenter: TabPresenter, + ) { + } + + async queryTabs(query: string, excludePinned: boolean): Promise<TabItem[]> { + const lastTabId = await this.tabPresenter.getLastSelectedId(); + const tabs = await this.tabRepository.queryTabs(query, excludePinned); + return tabs.map(tab => { + let flag = TabFlag.None; + if (tab.active) { + flag = TabFlag.CurrentTab + } else if (tab.id == lastTabId) { + flag = TabFlag.LastTab + } + return { + index: tab.index + 1, + flag: flag, + title: tab.title, + url: tab.url, + faviconUrl : tab.faviconUrl + } + }); + } +} diff --git a/src/background/completion/TabItem.ts b/src/background/completion/TabItem.ts new file mode 100644 index 0000000..630855a --- /dev/null +++ b/src/background/completion/TabItem.ts @@ -0,0 +1,11 @@ +import TabFlag from "../../shared/TabFlag"; + +type TabItem = { + index: number + flag: TabFlag + title: string + url: string + faviconUrl?: string +} + +export default TabItem;
\ No newline at end of file diff --git a/src/background/completion/TabRepository.ts b/src/background/completion/TabRepository.ts new file mode 100644 index 0000000..61fac3b --- /dev/null +++ b/src/background/completion/TabRepository.ts @@ -0,0 +1,12 @@ +export type Tab = { + id: number + index: number + active: boolean + title: string + url: string + faviconUrl?: string +} + +export default interface TabRepository { + queryTabs(query: string, excludePinned: boolean): Promise<Tab[]>; +} diff --git a/src/background/completion/impl/TabRepositoryImpl.ts b/src/background/completion/impl/TabRepositoryImpl.ts new file mode 100644 index 0000000..6692b27 --- /dev/null +++ b/src/background/completion/impl/TabRepositoryImpl.ts @@ -0,0 +1,27 @@ +import TabRepository, { Tab } from "../TabRepository"; + +const COMPLETION_ITEM_LIMIT = 10; + +export default class TabRepositoryImpl implements TabRepository { + async queryTabs(query: string, excludePinned: boolean): Promise<Tab[]> { + const tabs = await browser.tabs.query({ currentWindow: true }); + return tabs + .filter((t) => { + return t.url && t.url.toLowerCase().includes(query.toLowerCase()) || + t.title && t.title.toLowerCase().includes(query.toLowerCase()); + }) + .filter((t) => { + return !(excludePinned && t.pinned); + }) + .filter(item => item.id && item.title && item.url) + .slice(0, COMPLETION_ITEM_LIMIT) + .map(item => ({ + id: item.id!!, + url: item.url!!, + active: item.active, + title: item.title!!, + faviconUrl: item.favIconUrl, + index: item.index, + })) + } +}
\ No newline at end of file diff --git a/src/background/controllers/CompletionController.ts b/src/background/controllers/CompletionController.ts index 313f38b..a268d15 100644 --- a/src/background/controllers/CompletionController.ts +++ b/src/background/controllers/CompletionController.ts @@ -1,14 +1,19 @@ import { ConsoleGetCompletionTypesResponse, - ConsoleRequestBookmarksResponse, ConsoleRequestHistoryResponse, ConsoleRequestSearchEnginesResponse + ConsoleRequestBookmarksResponse, + ConsoleRequestHistoryResponse, + ConsoleRequestSearchEnginesResponse, + ConsoleRequesttabsResponse } from "../../shared/messages"; import { injectable } from "tsyringe"; -import CompletionUseCase from "../completion/CompletionUseCase"; +import OpenCompletionUseCase from "../completion/OpenCompletionUseCase"; +import TabCompletionUseCase from "../completion/TabCompletionUseCase"; @injectable() export default class CompletionController { constructor( - private completionUseCase: CompletionUseCase, + private completionUseCase: OpenCompletionUseCase, + private tabCompletionUseCase: TabCompletionUseCase, ) { } @@ -28,4 +33,8 @@ export default class CompletionController { async requestHistory(query: string): Promise<ConsoleRequestHistoryResponse> { return this.completionUseCase.requestHistory(query); } + + async queryTabs(query: string, excludePinned: boolean): Promise<ConsoleRequesttabsResponse> { + return this.tabCompletionUseCase.queryTabs(query, excludePinned); + } }
\ No newline at end of file diff --git a/src/background/di.ts b/src/background/di.ts index 0b52e0b..c186262 100644 --- a/src/background/di.ts +++ b/src/background/di.ts @@ -6,6 +6,8 @@ import { CachedSettingRepositoryImpl } from "./repositories/CachedSettingReposit import { container } from 'tsyringe'; import HistoryRepositoryImpl from "./completion/impl/HistoryRepositoryImpl"; import BookmarkRepositoryImpl from "./completion/impl/BookmarkRepositoryImpl"; +import TabRepositoryImpl from "./completion/impl/TabRepositoryImpl"; +import {TabPresenterImpl} from "./presenters/TabPresenter"; container.register('LocalSettingRepository', { useValue: LocalSettingRepository }); container.register('SyncSettingRepository', { useClass: SyncSettingRepository }); @@ -13,3 +15,5 @@ container.register('CachedSettingRepository', { useClass: CachedSettingRepositor container.register('Notifier', { useClass: NotifierImpl }); container.register('HistoryRepository', { useClass: HistoryRepositoryImpl }); container.register('BookmarkRepository', { useClass: BookmarkRepositoryImpl }); +container.register('TabRepository', { useClass: TabRepositoryImpl }); +container.register('TabPresenter', { useClass: TabPresenterImpl }); diff --git a/src/background/infrastructures/ContentMessageListener.ts b/src/background/infrastructures/ContentMessageListener.ts index 62cd49f..13aa763 100644 --- a/src/background/infrastructures/ContentMessageListener.ts +++ b/src/background/infrastructures/ContentMessageListener.ts @@ -73,6 +73,8 @@ export default class ContentMessageListener { return this.completionController.requestBookmarks(message.query); case messages.CONSOLE_REQUEST_HISTORY: return this.completionController.requestHistory(message.query); + case messages.CONSOLE_REQUEST_TABS: + return this.completionController.queryTabs(message.query, message.excludePinned); case messages.CONSOLE_ENTER_COMMAND: return this.onConsoleEnterCommand(message.text); case messages.SETTINGS_QUERY: diff --git a/src/background/presenters/TabPresenter.ts b/src/background/presenters/TabPresenter.ts index 33d8bea..bded5a2 100644 --- a/src/background/presenters/TabPresenter.ts +++ b/src/background/presenters/TabPresenter.ts @@ -1,4 +1,3 @@ -import { injectable } from 'tsyringe'; import MemoryStorage from '../infrastructures/MemoryStorage'; const CURRENT_SELECTED_KEY = 'tabs.current.selected'; @@ -6,8 +5,41 @@ const LAST_SELECTED_KEY = 'tabs.last.selected'; type Tab = browser.tabs.Tab; -@injectable() -export default class TabPresenter { +export default interface TabPresenter { + open(url: string, tabId?: number): Promise<Tab>; + + create(url: string, opts?: object): Promise<Tab>; + + getCurrent(): Promise<Tab>; + + getAll(): Promise<Tab[]>; + + getLastSelectedId(): Promise<number | undefined>; + + getByKeyword(keyword: string, excludePinned: boolean): Promise<Tab[]>; + + select(tabId: number): Promise<void>; + + remove(ids: number[]): Promise<void>; + + reopen(): Promise<void>; + + reload(tabId: number, cache: boolean): Promise<void>; + + setPinned(tabId: number, pinned: boolean): Promise<void>; + + duplicate(id: number): Promise<Tab>; + + getZoom(tabId: number): Promise<number>; + + setZoom(tabId: number, factor: number): Promise<void>; + + onSelected( + listener: (arg: { tabId: number, windowId: number}) => void, + ): void; +} + +export class TabPresenterImpl implements TabPresenter { open(url: string, tabId?: number): Promise<Tab> { return browser.tabs.update(tabId, { url }); } @@ -48,15 +80,15 @@ export default class TabPresenter { }); } - select(tabId: number): Promise<Tab> { - return browser.tabs.update(tabId, { active: true }); + async select(tabId: number): Promise<void> { + await browser.tabs.update(tabId, { active: true }); } - remove(ids: number[]): Promise<void> { - return browser.tabs.remove(ids); + async remove(ids: number[]): Promise<void> { + await browser.tabs.remove(ids); } - async reopen(): Promise<any> { + async reopen(): Promise<void> { const window = await browser.windows.getCurrent(); const sessions = await browser.sessions.getRecentlyClosed(); const session = sessions.find((s) => { @@ -66,19 +98,18 @@ export default class TabPresenter { return; } if (session.tab && session.tab.sessionId) { - return browser.sessions.restore(session.tab.sessionId); - } - if (session.window && session.window.sessionId) { - return browser.sessions.restore(session.window.sessionId); + await browser.sessions.restore(session.tab.sessionId); + } else if (session.window && session.window.sessionId) { + await browser.sessions.restore(session.window.sessionId); } } - reload(tabId: number, cache: boolean): Promise<void> { - return browser.tabs.reload(tabId, { bypassCache: cache }); + async reload(tabId: number, cache: boolean): Promise<void> { + await browser.tabs.reload(tabId, { bypassCache: cache }); } - setPinned(tabId: number, pinned: boolean): Promise<Tab> { - return browser.tabs.update(tabId, { pinned }); + async setPinned(tabId: number, pinned: boolean): Promise<void> { + await browser.tabs.update(tabId, { pinned }); } duplicate(id: number): Promise<Tab> { @@ -100,7 +131,7 @@ export default class TabPresenter { } } -const tabPresenter = new TabPresenter(); +const tabPresenter = new TabPresenterImpl(); tabPresenter.onSelected((tab: any) => { const cache = new MemoryStorage(); diff --git a/src/background/usecases/AddonEnabledUseCase.ts b/src/background/usecases/AddonEnabledUseCase.ts index 9abd3dc..51f02e1 100644 --- a/src/background/usecases/AddonEnabledUseCase.ts +++ b/src/background/usecases/AddonEnabledUseCase.ts @@ -1,4 +1,4 @@ -import { injectable } from 'tsyringe'; +import { inject, injectable } from 'tsyringe'; import IndicatorPresenter from '../presenters/IndicatorPresenter'; import TabPresenter from '../presenters/TabPresenter'; import ContentMessageClient from '../infrastructures/ContentMessageClient'; @@ -7,7 +7,7 @@ import ContentMessageClient from '../infrastructures/ContentMessageClient'; export default class AddonEnabledUseCase { constructor( private indicatorPresentor: IndicatorPresenter, - private tabPresenter: TabPresenter, + @inject("TabPresenter") private tabPresenter: TabPresenter, private contentMessageClient: ContentMessageClient, ) { this.indicatorPresentor.onClick((tab) => { diff --git a/src/background/usecases/CommandUseCase.ts b/src/background/usecases/CommandUseCase.ts index 7dba664..d2d707e 100644 --- a/src/background/usecases/CommandUseCase.ts +++ b/src/background/usecases/CommandUseCase.ts @@ -14,7 +14,7 @@ import RepeatUseCase from '../usecases/RepeatUseCase'; @injectable() export default class CommandIndicator { constructor( - private tabPresenter: TabPresenter, + @inject('TabPresenter') private tabPresenter: TabPresenter, private windowPresenter: WindowPresenter, private helpPresenter: HelpPresenter, @inject("CachedSettingRepository") private cachedSettingRepository: CachedSettingRepository, @@ -80,7 +80,7 @@ export default class CommandIndicator { } const current = await this.tabPresenter.getCurrent(); - const tabs = await this.tabPresenter.getByKeyword(keywords); + const tabs = await this.tabPresenter.getByKeyword(keywords, false); if (tabs.length === 0) { throw new RangeError('No matching buffer for ' + keywords); } diff --git a/src/background/usecases/CompletionsUseCase.ts b/src/background/usecases/CompletionsUseCase.ts index b75b635..439c81a 100644 --- a/src/background/usecases/CompletionsUseCase.ts +++ b/src/background/usecases/CompletionsUseCase.ts @@ -5,17 +5,17 @@ import CompletionsRepository from '../repositories/CompletionsRepository'; import CachedSettingRepository from '../repositories/CachedSettingRepository'; import TabPresenter from '../presenters/TabPresenter'; import Properties from '../../shared/settings/Properties'; -import CompletionUseCase from "../completion/CompletionUseCase"; +import OpenCompletionUseCase from "../completion/OpenCompletionUseCase"; type Tab = browser.tabs.Tab; @injectable() export default class CompletionsUseCase { constructor( - private tabPresenter: TabPresenter, + @inject('TabPresenter') private tabPresenter: TabPresenter, private completionsRepository: CompletionsRepository, @inject("CachedSettingRepository") private cachedSettingRepository: CachedSettingRepository, - private completionUseCase: CompletionUseCase + private completionUseCase: OpenCompletionUseCase ) { } diff --git a/src/background/usecases/ConsoleUseCase.ts b/src/background/usecases/ConsoleUseCase.ts index 775a1e0..2de5bc1 100644 --- a/src/background/usecases/ConsoleUseCase.ts +++ b/src/background/usecases/ConsoleUseCase.ts @@ -1,4 +1,4 @@ -import { injectable } from 'tsyringe'; +import { inject, injectable } from 'tsyringe'; import TabPresenter from '../presenters/TabPresenter'; import ConsoleClient from '../infrastructures/ConsoleClient'; @@ -6,7 +6,7 @@ import ConsoleClient from '../infrastructures/ConsoleClient'; export default class ConsoleUseCase { constructor( - private tabPresenter: TabPresenter, + @inject('TabPresenter') private tabPresenter: TabPresenter, private consoleClient: ConsoleClient, ) { } diff --git a/src/background/usecases/FindUseCase.ts b/src/background/usecases/FindUseCase.ts index b8593c6..cb41cd5 100644 --- a/src/background/usecases/FindUseCase.ts +++ b/src/background/usecases/FindUseCase.ts @@ -1,4 +1,4 @@ -import { injectable } from 'tsyringe'; +import { inject, injectable } from 'tsyringe'; import FindRepository from '../repositories/FindRepository'; import TabPresenter from '../presenters/TabPresenter'; import ConsoleClient from '../infrastructures/ConsoleClient'; @@ -6,7 +6,7 @@ import ConsoleClient from '../infrastructures/ConsoleClient'; @injectable() export default class FindUseCase { constructor( - private tabPresenter: TabPresenter, + @inject('TabPresenter') private tabPresenter: TabPresenter, private findRepository: FindRepository, private consoleClient: ConsoleClient, ) { diff --git a/src/background/usecases/LinkUseCase.ts b/src/background/usecases/LinkUseCase.ts index 9c0eab5..be076c7 100644 --- a/src/background/usecases/LinkUseCase.ts +++ b/src/background/usecases/LinkUseCase.ts @@ -1,10 +1,10 @@ -import { injectable } from 'tsyringe'; +import { inject, injectable } from 'tsyringe'; import TabPresenter from '../presenters/TabPresenter'; @injectable() export default class LinkUseCase { constructor( - private tabPresenter: TabPresenter, + @inject('TabPresenter') private tabPresenter: TabPresenter, ) { } diff --git a/src/background/usecases/MarkUseCase.ts b/src/background/usecases/MarkUseCase.ts index eeac40f..2c0bc13 100644 --- a/src/background/usecases/MarkUseCase.ts +++ b/src/background/usecases/MarkUseCase.ts @@ -1,4 +1,4 @@ -import { injectable } from 'tsyringe'; +import { inject, injectable } from 'tsyringe'; import TabPresenter from '../presenters/TabPresenter'; import MarkRepository from '../repositories/MarkRepository'; import ConsoleClient from '../infrastructures/ConsoleClient'; @@ -7,7 +7,7 @@ import ContentMessageClient from '../infrastructures/ContentMessageClient'; @injectable() export default class MarkUseCase { constructor( - private tabPresenter: TabPresenter, + @inject('TabPresenter') private tabPresenter: TabPresenter, private markRepository: MarkRepository, private consoleClient: ConsoleClient, private contentMessageClient: ContentMessageClient, diff --git a/src/background/usecases/NavigateUseCase.ts b/src/background/usecases/NavigateUseCase.ts index 25e7f20..3aa1ed6 100644 --- a/src/background/usecases/NavigateUseCase.ts +++ b/src/background/usecases/NavigateUseCase.ts @@ -1,11 +1,11 @@ -import { injectable } from 'tsyringe'; +import { inject, injectable } from 'tsyringe'; import NavigateClient from '../clients/NavigateClient'; import TabPresenter from '../presenters/TabPresenter'; @injectable() export default class NavigateUseCase { constructor( - private tabPresenter: TabPresenter, + @inject('TabPresenter') private tabPresenter: TabPresenter, private navigateClient: NavigateClient, ) { } diff --git a/src/background/usecases/TabSelectUseCase.ts b/src/background/usecases/TabSelectUseCase.ts index 62098de..271bb6c 100644 --- a/src/background/usecases/TabSelectUseCase.ts +++ b/src/background/usecases/TabSelectUseCase.ts @@ -1,10 +1,10 @@ -import { injectable } from 'tsyringe'; +import { inject, injectable } from 'tsyringe'; import TabPresenter from '../presenters/TabPresenter'; @injectable() export default class TabSelectUseCase { constructor( - private tabPresenter: TabPresenter, + @inject('TabPresenter') private tabPresenter: TabPresenter, ) { } diff --git a/src/background/usecases/TabUseCase.ts b/src/background/usecases/TabUseCase.ts index 66f8573..418dde5 100644 --- a/src/background/usecases/TabUseCase.ts +++ b/src/background/usecases/TabUseCase.ts @@ -1,4 +1,4 @@ -import { injectable } from 'tsyringe'; +import {inject, injectable} from 'tsyringe'; import TabPresenter from '../presenters/TabPresenter'; import WindowPresenter from '../presenters/WindowPresenter'; import BrowserSettingRepository from '../repositories/BrowserSettingRepository'; @@ -6,7 +6,7 @@ import BrowserSettingRepository from '../repositories/BrowserSettingRepository'; @injectable() export default class TabUseCase { constructor( - private tabPresenter: TabPresenter, + @inject('TabPresenter') private tabPresenter: TabPresenter, private windowPresenter: WindowPresenter, private browserSettingRepository: BrowserSettingRepository, ) { diff --git a/src/background/usecases/VersionUseCase.ts b/src/background/usecases/VersionUseCase.ts index 9ea8af9..21a5e2c 100644 --- a/src/background/usecases/VersionUseCase.ts +++ b/src/background/usecases/VersionUseCase.ts @@ -5,7 +5,7 @@ import Notifier from '../presenters/Notifier'; @injectable() export default class VersionUseCase { constructor( - private tabPresenter: TabPresenter, + @inject('TabPresenter') private tabPresenter: TabPresenter, @inject("Notifier") private notifier: Notifier, ) { } diff --git a/src/background/usecases/ZoomUseCase.ts b/src/background/usecases/ZoomUseCase.ts index f598871..ca1368d 100644 --- a/src/background/usecases/ZoomUseCase.ts +++ b/src/background/usecases/ZoomUseCase.ts @@ -1,4 +1,4 @@ -import { injectable } from 'tsyringe'; +import { inject, injectable } from 'tsyringe'; import TabPresenter from '../presenters/TabPresenter'; const ZOOM_SETTINGS: number[] = [ @@ -9,7 +9,7 @@ const ZOOM_SETTINGS: number[] = [ @injectable() export default class ZoomUseCase { constructor( - private tabPresenter: TabPresenter, + @inject('TabPresenter') private tabPresenter: TabPresenter, ) { } |