diff options
Diffstat (limited to 'src/background')
32 files changed, 406 insertions, 368 deletions
diff --git a/src/background/completion/BookmarkRepository.ts b/src/background/completion/BookmarkRepository.ts new file mode 100644 index 0000000..14105c8 --- /dev/null +++ b/src/background/completion/BookmarkRepository.ts @@ -0,0 +1,8 @@ +export type BookmarkItem = { + title: string + url: string +} + +export default interface BookmarkRepository { + queryBookmarks(query: string): Promise<BookmarkItem[]>; +} diff --git a/src/background/completion/HistoryRepository.ts b/src/background/completion/HistoryRepository.ts new file mode 100644 index 0000000..5eb3a2b --- /dev/null +++ b/src/background/completion/HistoryRepository.ts @@ -0,0 +1,8 @@ +export type HistoryItem = { + title: string + url: string +} + +export default interface HistoryRepository { + queryHistories(keywords: string): Promise<HistoryItem[]>; +} diff --git a/src/background/completion/OpenCompletionUseCase.ts b/src/background/completion/OpenCompletionUseCase.ts new file mode 100644 index 0000000..1b63e7c --- /dev/null +++ b/src/background/completion/OpenCompletionUseCase.ts @@ -0,0 +1,59 @@ +import { inject, injectable } from "tsyringe"; +import CachedSettingRepository from "../repositories/CachedSettingRepository"; +import CompletionType from "../../shared/CompletionType"; +import BookmarkRepository from "./BookmarkRepository"; +import HistoryRepository from "./HistoryRepository"; + +export type BookmarkItem = { + title: string + url: string +} + +export type HistoryItem = { + title: string + url: string +} + +@injectable() +export default class OpenCompletionUseCase { + constructor( + @inject('BookmarkRepository') private bookmarkRepository: BookmarkRepository, + @inject('HistoryRepository') private historyRepository: HistoryRepository, + @inject("CachedSettingRepository") private cachedSettingRepository: CachedSettingRepository, + ) { + } + + async getCompletionTypes(): Promise<CompletionType[]> { + const settings = await this.cachedSettingRepository.get(); + const types: CompletionType[] = []; + for (const c of settings.properties.complete) { + switch (c) { + case 's': + types.push(CompletionType.SearchEngines); + break; + case 'h': + types.push(CompletionType.History); + break; + case 'b': + types.push(CompletionType.Bookmarks); + break; + } + // ignore invalid characters in the complete property + } + return types; + } + + async requestSearchEngines(query: string): Promise<string[]> { + const settings = await this.cachedSettingRepository.get(); + return Object.keys(settings.search.engines) + .filter(key => key.startsWith(query)) + } + + requestBookmarks(query: string): Promise<BookmarkItem[]> { + return this.bookmarkRepository.queryBookmarks(query); + } + + requestHistory(query: string): Promise<HistoryItem[]> { + return this.historyRepository.queryHistories(query); + } +}
\ No newline at end of file diff --git a/src/background/completion/PropertyCompletionUseCase.ts b/src/background/completion/PropertyCompletionUseCase.ts new file mode 100644 index 0000000..049cfb8 --- /dev/null +++ b/src/background/completion/PropertyCompletionUseCase.ts @@ -0,0 +1,16 @@ +import { injectable } from "tsyringe"; +import Properties from "../../shared/settings/Properties"; + +type Property = { + name: string; + type: 'string' | 'boolean' | 'number'; +} +@injectable() +export default class PropertyCompletionUseCase { + async getProperties(): Promise<Property[]> { + return Properties.defs().map(def => ({ + name: def.name, + type: def.type, + })); + } +}
\ No newline at end of file diff --git a/src/background/completion/TabCompletionUseCase.ts b/src/background/completion/TabCompletionUseCase.ts new file mode 100644 index 0000000..dec86e9 --- /dev/null +++ b/src/background/completion/TabCompletionUseCase.ts @@ -0,0 +1,55 @@ +import { inject, injectable } from "tsyringe"; +import TabItem from "./TabItem"; +import TabRepository, { Tab } 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 allTabs = await this.tabRepository.getAllTabs(excludePinned); + const num = parseInt(query, 10); + let tabs: Tab[] = []; + if (!isNaN(num)) { + const tab = allTabs.find(t => t.index === num - 1); + if (tab) { + tabs = [tab]; + } + } else if (query == '%') { + const tab = allTabs.find(t => t.active); + if (tab) { + tabs = [tab]; + } + } else if (query == '#') { + const tab = allTabs.find(t => t.id === lastTabId); + if (tab) { + tabs = [tab]; + } + } else { + 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..fe1b601 --- /dev/null +++ b/src/background/completion/TabRepository.ts @@ -0,0 +1,14 @@ +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[]>; + + getAllTabs(excludePinned: boolean): Promise<Tab[]> +} diff --git a/src/background/completion/impl/BookmarkRepositoryImpl.ts b/src/background/completion/impl/BookmarkRepositoryImpl.ts new file mode 100644 index 0000000..58df129 --- /dev/null +++ b/src/background/completion/impl/BookmarkRepositoryImpl.ts @@ -0,0 +1,28 @@ +import { injectable } from "tsyringe"; +import BookmarkRepository, {BookmarkItem} from "../BookmarkRepository"; + +const COMPLETION_ITEM_LIMIT = 10; + +@injectable() +export default class BookmarkRepositoryImpl implements BookmarkRepository { + async queryBookmarks(query: string): Promise<BookmarkItem[]> { + const items = await browser.bookmarks.search({query}); + return items + .filter(item => item.title && item.title.length > 0) + .filter(item => item.type === 'bookmark' && item.url) + .filter((item) => { + let url = undefined; + try { + url = new URL(item.url!!); + } catch (e) { + return false; + } + return url.protocol !== 'place:'; + }) + .slice(0, COMPLETION_ITEM_LIMIT) + .map(item => ({ + title: item.title!!, + url: item.url!!, + })); + } +} diff --git a/src/background/completion/impl/HistoryRepositoryImpl.ts b/src/background/completion/impl/HistoryRepositoryImpl.ts new file mode 100644 index 0000000..42691aa --- /dev/null +++ b/src/background/completion/impl/HistoryRepositoryImpl.ts @@ -0,0 +1,28 @@ +import { injectable } from "tsyringe"; +import * as filters from "./filters"; +import HistoryRepository, {HistoryItem} from "../HistoryRepository"; + +const COMPLETION_ITEM_LIMIT = 10; + +@injectable() +export default class HistoryRepositoryImpl implements HistoryRepository { + async queryHistories(keywords: string): Promise<HistoryItem[]> { + const items = await browser.history.search({ + text: keywords, + startTime: 0, + }); + + return [items] + .map(filters.filterBlankTitle) + .map(filters.filterHttp) + .map(filters.filterByTailingSlash) + .map(pages => filters.filterByPathname(pages, COMPLETION_ITEM_LIMIT)) + .map(pages => filters.filterByOrigin(pages, COMPLETION_ITEM_LIMIT))[0] + .sort((x, y) => Number(y.visitCount) - Number(x.visitCount)) + .slice(0, COMPLETION_ITEM_LIMIT) + .map(item => ({ + title: item.title!!, + url: item.url!!, + })) + } +} diff --git a/src/background/completion/impl/TabRepositoryImpl.ts b/src/background/completion/impl/TabRepositoryImpl.ts new file mode 100644 index 0000000..adcaba7 --- /dev/null +++ b/src/background/completion/impl/TabRepositoryImpl.ts @@ -0,0 +1,41 @@ +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(TabRepositoryImpl.toEntity); + } + + async getAllTabs(excludePinned: boolean): Promise<Tab[]> { + if (excludePinned) { + return (await browser.tabs.query({ currentWindow: true, pinned: true })) + .map(TabRepositoryImpl.toEntity) + + } + return (await browser.tabs.query({ currentWindow: true })) + .map(TabRepositoryImpl.toEntity) + } + + private static toEntity(tab: browser.tabs.Tab,): Tab { + return { + id: tab.id!!, + url: tab.url!!, + active: tab.active, + title: tab.title!!, + faviconUrl: tab.favIconUrl, + index: tab.index, + } + } +} diff --git a/src/background/usecases/filters.ts b/src/background/completion/impl/filters.ts index 98957a7..98957a7 100644 --- a/src/background/usecases/filters.ts +++ b/src/background/completion/impl/filters.ts diff --git a/src/background/controllers/CommandController.ts b/src/background/controllers/CommandController.ts index 7297ef8..16aa6e8 100644 --- a/src/background/controllers/CommandController.ts +++ b/src/background/controllers/CommandController.ts @@ -1,7 +1,5 @@ import { injectable } from 'tsyringe'; -import CompletionsUseCase from '../usecases/CompletionsUseCase'; import CommandUseCase from '../usecases/CommandUseCase'; -import CompletionGroup from '../domains/CompletionGroup'; const trimStart = (str: string): string => { // NOTE String.trimStart is available on Firefox 61 @@ -11,46 +9,10 @@ const trimStart = (str: string): string => { @injectable() export default class CommandController { constructor( - private completionsUseCase: CompletionsUseCase, private commandIndicator: CommandUseCase, ) { } - getCompletions(line: string): Promise<CompletionGroup[]> { - const trimmed = trimStart(line); - const words = trimmed.split(/ +/); - const name = words[0]; - if (words.length === 1) { - return this.completionsUseCase.queryConsoleCommand(name); - } - const keywords = trimStart(trimmed.slice(name.length)); - switch (words[0]) { - case 'o': - case 'open': - case 't': - case 'tabopen': - case 'w': - case 'winopen': - return this.completionsUseCase.queryOpen(name, keywords); - case 'b': - case 'buffer': - return this.completionsUseCase.queryBuffer(name, keywords); - case 'bd': - case 'bdel': - case 'bdelete': - case 'bdeletes': - return this.completionsUseCase.queryBdelete(name, keywords); - case 'bd!': - case 'bdel!': - case 'bdelete!': - case 'bdeletes!': - return this.completionsUseCase.queryBdeleteForce(name, keywords); - case 'set': - return this.completionsUseCase.querySet(name, keywords); - } - return Promise.resolve([]); - } - // eslint-disable-next-line complexity exec(line: string): Promise<any> { const trimmed = trimStart(line); diff --git a/src/background/controllers/CompletionController.ts b/src/background/controllers/CompletionController.ts new file mode 100644 index 0000000..fb6137c --- /dev/null +++ b/src/background/controllers/CompletionController.ts @@ -0,0 +1,47 @@ +import { + ConsoleGetCompletionTypesResponse, + ConsoleGetPropertiesResponse, + ConsoleRequestBookmarksResponse, + ConsoleRequestHistoryResponse, + ConsoleRequestSearchEnginesResponse, + ConsoleRequesttabsResponse +} from "../../shared/messages"; +import { injectable } from "tsyringe"; +import OpenCompletionUseCase from "../completion/OpenCompletionUseCase"; +import TabCompletionUseCase from "../completion/TabCompletionUseCase"; +import PropertyCompletionUseCase from "../completion/PropertyCompletionUseCase"; + +@injectable() +export default class CompletionController { + constructor( + private completionUseCase: OpenCompletionUseCase, + private tabCompletionUseCase: TabCompletionUseCase, + private propertyCompletionUseCase: PropertyCompletionUseCase, + ) { + } + + async getCompletionTypes(): Promise<ConsoleGetCompletionTypesResponse> { + return this.completionUseCase.getCompletionTypes(); + } + + async requestSearchEngines(query: string): Promise<ConsoleRequestSearchEnginesResponse> { + const items = await this.completionUseCase.requestSearchEngines(query); + return items.map(name => ({ title: name })); + } + + async requestBookmarks(query: string): Promise<ConsoleRequestBookmarksResponse> { + return this.completionUseCase.requestBookmarks(query); + } + + 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); + } + + async getProperties(): Promise<ConsoleGetPropertiesResponse> { + return this.propertyCompletionUseCase.getProperties(); + } +}
\ No newline at end of file diff --git a/src/background/di.ts b/src/background/di.ts index 9fc230c..c186262 100644 --- a/src/background/di.ts +++ b/src/background/di.ts @@ -4,8 +4,16 @@ import { LocalSettingRepository, SyncSettingRepository } from "./repositories/Se import { NotifierImpl } from "./presenters/Notifier"; import { CachedSettingRepositoryImpl } from "./repositories/CachedSettingRepository"; 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 }); container.register('CachedSettingRepository', { useClass: CachedSettingRepositoryImpl }); 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/domains/CommandDocs.ts b/src/background/domains/CommandDocs.ts deleted file mode 100644 index e926851..0000000 --- a/src/background/domains/CommandDocs.ts +++ /dev/null @@ -1,12 +0,0 @@ -export default { - set: 'Set a value of the property', - open: 'Open a URL or search by keywords in current tab', - tabopen: 'Open a URL or search by keywords in new tab', - winopen: 'Open a URL or search by keywords in new window', - buffer: 'Select tabs by matched keywords', - bdelete: 'Close a certain tab matched by keywords', - bdeletes: 'Close all tabs matched by keywords', - quit: 'Close the current tab', - quitall: 'Close all tabs', - help: 'Open Vim Vixen help in new tab', -} as {[key: string]: string}; diff --git a/src/background/domains/CompletionGroup.ts b/src/background/domains/CompletionGroup.ts deleted file mode 100644 index 8e89bf0..0000000 --- a/src/background/domains/CompletionGroup.ts +++ /dev/null @@ -1,6 +0,0 @@ -import CompletionItem from './CompletionItem'; - -export default interface CompletionGroup { - name: string; - items: CompletionItem[]; -} diff --git a/src/background/domains/CompletionItem.ts b/src/background/domains/CompletionItem.ts deleted file mode 100644 index 96f6ee6..0000000 --- a/src/background/domains/CompletionItem.ts +++ /dev/null @@ -1,6 +0,0 @@ -export default interface CompletionItem { - readonly caption?: string; - readonly content?: string; - readonly url?: string; - readonly icon?: string; -} diff --git a/src/background/infrastructures/ContentMessageListener.ts b/src/background/infrastructures/ContentMessageListener.ts index d063810..2fbb9cf 100644 --- a/src/background/infrastructures/ContentMessageListener.ts +++ b/src/background/infrastructures/ContentMessageListener.ts @@ -1,7 +1,6 @@ import { injectable } from 'tsyringe'; import * as messages from '../../shared/messages'; import * as operations from '../../shared/operations'; -import CompletionGroup from '../domains/CompletionGroup'; import CommandController from '../controllers/CommandController'; import SettingController from '../controllers/SettingController'; import FindController from '../controllers/FindController'; @@ -9,6 +8,7 @@ import AddonEnabledController from '../controllers/AddonEnabledController'; import LinkController from '../controllers/LinkController'; import OperationController from '../controllers/OperationController'; import MarkController from '../controllers/MarkController'; +import CompletionController from "../controllers/CompletionController"; @injectable() export default class ContentMessageListener { @@ -17,6 +17,7 @@ export default class ContentMessageListener { constructor( private settingController: SettingController, private commandController: CommandController, + private completionController: CompletionController, private findController: FindController, private addonEnabledController: AddonEnabledController, private linkController: LinkController, @@ -61,8 +62,18 @@ export default class ContentMessageListener { message: messages.Message, senderTab: browser.tabs.Tab, ): Promise<any> | any { switch (message.type) { - case messages.CONSOLE_QUERY_COMPLETIONS: - return this.onConsoleQueryCompletions(message.text); + case messages.CONSOLE_GET_COMPLETION_TYPES: + return this.completionController.getCompletionTypes(); + case messages.CONSOLE_REQUEST_SEARCH_ENGINES_MESSAGE: + return this.completionController.requestSearchEngines(message.query); + case messages.CONSOLE_REQUEST_BOOKMARKS: + 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_GET_PROPERTIES: + return this.completionController.getProperties(); case messages.CONSOLE_ENTER_COMMAND: return this.onConsoleEnterCommand(message.text); case messages.SETTINGS_QUERY: @@ -93,11 +104,6 @@ export default class ContentMessageListener { throw new Error('unsupported message: ' + message.type); } - async onConsoleQueryCompletions(line: string): Promise<CompletionGroup[]> { - const completions = await this.commandController.getCompletions(line); - return Promise.resolve(completions); - } - onConsoleEnterCommand(text: string): Promise<any> { return this.commandController.exec(text); } 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/repositories/CompletionsRepository.ts b/src/background/repositories/CompletionsRepository.ts deleted file mode 100644 index dfecff0..0000000 --- a/src/background/repositories/CompletionsRepository.ts +++ /dev/null @@ -1,40 +0,0 @@ -import { injectable } from 'tsyringe'; - -type Tab = browser.tabs.Tab; -type BookmarkTreeNode = browser.bookmarks.BookmarkTreeNode; - -@injectable() -export default class CompletionsRepository { - async queryBookmarks(keywords: string): Promise<BookmarkTreeNode[]> { - const items = await browser.bookmarks.search({ query: keywords }); - return items.filter((item) => { - if (!item.url) { - return false; - } - let url = undefined; - try { - url = new URL(item.url); - } catch (e) { - return false; - } - return item.type === 'bookmark' && url.protocol !== 'place:'; - }); - } - - queryHistories(keywords: string): Promise<browser.history.HistoryItem[]> { - return browser.history.search({ - text: keywords, - startTime: 0, - }); - } - - async queryTabs(keywords: string, excludePinned: boolean): Promise<Tab[]> { - const tabs = await browser.tabs.query({ currentWindow: true }); - return tabs.filter((t) => { - return t.url && t.url.toLowerCase().includes(keywords.toLowerCase()) || - t.title && t.title.toLowerCase().includes(keywords.toLowerCase()); - }).filter((t) => { - return !(excludePinned && t.pinned); - }); - } -} 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 deleted file mode 100644 index 9874644..0000000 --- a/src/background/usecases/CompletionsUseCase.ts +++ /dev/null @@ -1,220 +0,0 @@ -import { injectable, inject } from 'tsyringe'; -import CompletionGroup from '../domains/CompletionGroup'; -import CommandDocs from '../domains/CommandDocs'; -import CompletionsRepository from '../repositories/CompletionsRepository'; -import * as filters from './filters'; -import CachedSettingRepository from '../repositories/CachedSettingRepository'; -import TabPresenter from '../presenters/TabPresenter'; -import Properties from '../../shared/settings/Properties'; - -const COMPLETION_ITEM_LIMIT = 10; - -type Tab = browser.tabs.Tab; -type HistoryItem = browser.history.HistoryItem; - -@injectable() -export default class CompletionsUseCase { - constructor( - private tabPresenter: TabPresenter, - private completionsRepository: CompletionsRepository, - @inject("CachedSettingRepository") private cachedSettingRepository: CachedSettingRepository, - ) { - } - - queryConsoleCommand(prefix: string): Promise<CompletionGroup[]> { - const keys = Object.keys(CommandDocs); - const items = keys - .filter(name => name.startsWith(prefix)) - .map(name => ({ - caption: name, - content: name, - url: CommandDocs[name], - })); - - if (items.length === 0) { - return Promise.resolve([]); - } - return Promise.resolve([{ name: 'Console Command', items }]); - } - - async queryOpen(name: string, keywords: string): Promise<CompletionGroup[]> { - // TODO This logic contains view entities. They should be defined on - // content script - - const settings = await this.cachedSettingRepository.get(); - const groups: CompletionGroup[] = []; - - const complete = settings.properties.complete; - for (const c of complete) { - if (c === 's') { - // eslint-disable-next-line no-await-in-loop - const engines = await this.querySearchEngineItems(name, keywords); - if (engines.length > 0) { - groups.push({ name: 'Search Engines', items: engines }); - } - // browser.history not supported on Android - } else if (c === 'h' && typeof browser.history === 'object') { - // eslint-disable-next-line no-await-in-loop - const histories = await this.queryHistoryItems(name, keywords); - if (histories.length > 0) { - groups.push({ name: 'History', items: histories }); - } - // browser.bookmarks not supported on Android - } else if (c === 'b' && typeof browser.bookmarks === 'object') { - // eslint-disable-next-line no-await-in-loop - const bookmarks = await this.queryBookmarkItems(name, keywords); - if (bookmarks.length > 0) { - groups.push({ name: 'Bookmarks', items: bookmarks }); - } - } - } - return groups; - } - - // eslint-disable-next-line max-statements - async queryBuffer( - name: string, - keywords: string, - ): Promise<CompletionGroup[]> { - const lastId = await this.tabPresenter.getLastSelectedId(); - const trimmed = keywords.trim(); - let tabs: Tab[] = []; - if (trimmed.length > 0 && !isNaN(Number(trimmed))) { - const all = await this.tabPresenter.getAll(); - const index = parseInt(trimmed, 10) - 1; - if (index >= 0 && index < all.length) { - tabs = [all[index]]; - } - } else if (trimmed === '%') { - const all = await this.tabPresenter.getAll(); - const tab = all.find(t => t.active) as Tab; - tabs = [tab]; - } else if (trimmed === '#') { - if (typeof lastId !== 'undefined' && lastId !== null) { - const all = await this.tabPresenter.getAll(); - const tab = all.find(t => t.id === lastId) as Tab; - tabs = [tab]; - } - } else { - tabs = await this.completionsRepository.queryTabs(keywords, false); - } - const flag = (tab: Tab) => { - if (tab.active) { - return '%'; - } else if (tab.id === lastId) { - return '#'; - } - return ' '; - }; - const items = tabs.map(tab => ({ - caption: tab.index + 1 + ': ' + flag(tab) + ' ' + tab.title, - content: name + ' ' + tab.title, - url: tab.url, - icon: tab.favIconUrl, - })); - if (items.length === 0) { - return Promise.resolve([]); - } - return [{ name: 'Buffers', items }]; - } - - queryBdelete(name: string, keywords: string): Promise<CompletionGroup[]> { - return this.queryTabs(name, true, keywords); - } - - queryBdeleteForce( - name: string, keywords: string, - ): Promise<CompletionGroup[]> { - return this.queryTabs(name, false, keywords); - } - - querySet(name: string, keywords: string): Promise<CompletionGroup[]> { - const items = Properties.defs().map((def) => { - if (def.type === 'boolean') { - return [ - { - caption: def.name, - content: name + ' ' + def.name, - url: 'Enable ' + def.description, - }, { - caption: 'no' + def.name, - content: name + ' no' + def.name, - url: 'Disable ' + def.description - } - ]; - } - return [ - { - caption: def.name, - content: name + ' ' + def.name, - url: 'Set ' + def.description, - } - ]; - }); - let flatten = items.reduce((acc, val) => acc.concat(val), []); - flatten = flatten.filter((item) => { - return item.caption.startsWith(keywords); - }); - if (flatten.length === 0) { - return Promise.resolve([]); - } - return Promise.resolve( - [{ name: 'Properties', items: flatten }], - ); - } - - async queryTabs( - name: string, excludePinned: boolean, args: string, - ): Promise<CompletionGroup[]> { - const tabs = await this.completionsRepository.queryTabs(args, excludePinned); - const items = tabs.map(tab => ({ - caption: tab.title, - content: name + ' ' + tab.title, - url: tab.url, - icon: tab.favIconUrl - })); - if (items.length === 0) { - return Promise.resolve([]); - } - return [{ name: 'Buffers', items }]; - } - - async querySearchEngineItems(name: string, keywords: string) { - const settings = await this.cachedSettingRepository.get(); - const engines = Object.keys(settings.search.engines) - .filter(key => key.startsWith(keywords)); - return engines.map(key => ({ - caption: key, - content: name + ' ' + key, - })); - } - - async queryHistoryItems(name: string, keywords: string) { - let histories = await this.completionsRepository.queryHistories(keywords); - histories = [histories] - .map(filters.filterBlankTitle) - .map(filters.filterHttp) - .map(filters.filterByTailingSlash) - .map(pages => filters.filterByPathname(pages, COMPLETION_ITEM_LIMIT)) - .map(pages => filters.filterByOrigin(pages, COMPLETION_ITEM_LIMIT))[0] - .sort((x: HistoryItem, y: HistoryItem): number => { - return Number(y.visitCount) - Number(x.visitCount); - }) - .slice(0, COMPLETION_ITEM_LIMIT); - return histories.map(page => ({ - caption: page.title, - content: name + ' ' + page.url, - url: page.url - })); - } - - async queryBookmarkItems(name: string, keywords: string) { - const bookmarks = await this.completionsRepository.queryBookmarks(keywords); - return bookmarks.slice(0, COMPLETION_ITEM_LIMIT) - .map(page => ({ - caption: page.title, - content: name + ' ' + page.url, - url: page.url - })); - } -} 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, ) { } |