diff options
author | Shin'ya Ueoka <ueokande@i-beam.org> | 2020-05-02 17:25:56 +0900 |
---|---|---|
committer | GitHub <noreply@github.com> | 2020-05-02 17:25:56 +0900 |
commit | 5df0537bcf65a341e79852b1b30379c73318529c (patch) | |
tree | aee5efe52412855f620cb514a13a2c14373f27b7 /src | |
parent | 685f2b7b69218b06b5bb676069e35f79c5048c9b (diff) | |
parent | 75abd90ecb8201ad845b266f96220d8adfe19b2d (diff) |
Merge pull request #749 from ueokande/qa-0.28
QA 0.28
Diffstat (limited to 'src')
158 files changed, 3117 insertions, 2884 deletions
diff --git a/src/background/Application.ts b/src/background/Application.ts index c2c48b5..69fe4a4 100644 --- a/src/background/Application.ts +++ b/src/background/Application.ts @@ -1,7 +1,7 @@ -import { injectable, inject } from 'tsyringe'; -import ContentMessageListener from './infrastructures/ContentMessageListener'; -import SettingController from './controllers/SettingController'; -import VersionController from './controllers/VersionController'; +import { injectable, inject } from "tsyringe"; +import ContentMessageListener from "./infrastructures/ContentMessageListener"; +import SettingController from "./controllers/SettingController"; +import VersionController from "./controllers/VersionController"; import SettingRepository from "./repositories/SettingRepository"; @injectable() @@ -10,15 +10,15 @@ export default class Application { private contentMessageListener: ContentMessageListener, private settingController: SettingController, private versionController: VersionController, - @inject("SyncSettingRepository") private syncSettingRepository: SettingRepository, - ) { - } + @inject("SyncSettingRepository") + private syncSettingRepository: SettingRepository + ) {} run() { this.settingController.reload(); browser.runtime.onInstalled.addListener((details) => { - if (details.reason !== 'install' && details.reason !== 'update') { + if (details.reason !== "install" && details.reason !== "update") { return; } this.versionController.notify(); diff --git a/src/background/clients/NavigateClient.ts b/src/background/clients/NavigateClient.ts index bdd94ec..40ceb45 100644 --- a/src/background/clients/NavigateClient.ts +++ b/src/background/clients/NavigateClient.ts @@ -1,5 +1,5 @@ -import { injectable } from 'tsyringe'; -import * as messages from '../../shared/messages'; +import { injectable } from "tsyringe"; +import * as messages from "../../shared/messages"; @injectable() export default class NavigateClient { diff --git a/src/background/completion/BookmarkRepository.ts b/src/background/completion/BookmarkRepository.ts index 14105c8..4dec12e 100644 --- a/src/background/completion/BookmarkRepository.ts +++ b/src/background/completion/BookmarkRepository.ts @@ -1,7 +1,7 @@ export type BookmarkItem = { - title: string - url: string -} + 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 index 5eb3a2b..446d110 100644 --- a/src/background/completion/HistoryRepository.ts +++ b/src/background/completion/HistoryRepository.ts @@ -1,7 +1,7 @@ export type HistoryItem = { - title: string - url: string -} + 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 index 1b63e7c..e678c2f 100644 --- a/src/background/completion/OpenCompletionUseCase.ts +++ b/src/background/completion/OpenCompletionUseCase.ts @@ -5,38 +5,39 @@ import BookmarkRepository from "./BookmarkRepository"; import HistoryRepository from "./HistoryRepository"; export type BookmarkItem = { - title: string - url: string -} + title: string; + url: string; +}; export type HistoryItem = { - title: string - url: string -} + 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, - ) { - } + @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; + 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 } @@ -45,8 +46,9 @@ export default class OpenCompletionUseCase { async requestSearchEngines(query: string): Promise<string[]> { const settings = await this.cachedSettingRepository.get(); - return Object.keys(settings.search.engines) - .filter(key => key.startsWith(query)) + return Object.keys(settings.search.engines).filter((key) => + key.startsWith(query) + ); } requestBookmarks(query: string): Promise<BookmarkItem[]> { @@ -56,4 +58,4 @@ export default class OpenCompletionUseCase { 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 index 049cfb8..7b72259 100644 --- a/src/background/completion/PropertyCompletionUseCase.ts +++ b/src/background/completion/PropertyCompletionUseCase.ts @@ -3,14 +3,14 @@ import Properties from "../../shared/settings/Properties"; type Property = { name: string; - type: 'string' | 'boolean' | 'number'; -} + type: "string" | "boolean" | "number"; +}; @injectable() export default class PropertyCompletionUseCase { async getProperties(): Promise<Property[]> { - return Properties.defs().map(def => ({ + 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 index dec86e9..d0d3bb7 100644 --- a/src/background/completion/TabCompletionUseCase.ts +++ b/src/background/completion/TabCompletionUseCase.ts @@ -7,10 +7,9 @@ import TabFlag from "../../shared/TabFlag"; @injectable() export default class TabCompletionUseCase { constructor( - @inject('TabRepository') private tabRepository: TabRepository, - @inject('TabPresenter') private tabPresenter: TabPresenter, - ) { - } + @inject("TabRepository") private tabRepository: TabRepository, + @inject("TabPresenter") private tabPresenter: TabPresenter + ) {} async queryTabs(query: string, excludePinned: boolean): Promise<TabItem[]> { const lastTabId = await this.tabPresenter.getLastSelectedId(); @@ -18,17 +17,17 @@ export default class TabCompletionUseCase { const num = parseInt(query, 10); let tabs: Tab[] = []; if (!isNaN(num)) { - const tab = allTabs.find(t => t.index === num - 1); + const tab = allTabs.find((t) => t.index === num - 1); if (tab) { tabs = [tab]; } - } else if (query == '%') { - const tab = allTabs.find(t => t.active); + } 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); + } else if (query == "#") { + const tab = allTabs.find((t) => t.id === lastTabId); if (tab) { tabs = [tab]; } @@ -36,20 +35,20 @@ export default class TabCompletionUseCase { tabs = await this.tabRepository.queryTabs(query, excludePinned); } - return tabs.map(tab => { + return tabs.map((tab) => { let flag = TabFlag.None; if (tab.active) { - flag = TabFlag.CurrentTab + flag = TabFlag.CurrentTab; } else if (tab.id == lastTabId) { - flag = TabFlag.LastTab + flag = TabFlag.LastTab; } return { index: tab.index + 1, flag: flag, title: tab.title, url: tab.url, - faviconUrl : tab.faviconUrl - } + faviconUrl: tab.faviconUrl, + }; }); } } diff --git a/src/background/completion/TabItem.ts b/src/background/completion/TabItem.ts index 630855a..eb7b657 100644 --- a/src/background/completion/TabItem.ts +++ b/src/background/completion/TabItem.ts @@ -1,11 +1,11 @@ import TabFlag from "../../shared/TabFlag"; type TabItem = { - index: number - flag: TabFlag - title: string - url: string - faviconUrl?: string -} + index: number; + flag: TabFlag; + title: string; + url: string; + faviconUrl?: string; +}; -export default TabItem;
\ No newline at end of file +export default TabItem; diff --git a/src/background/completion/TabRepository.ts b/src/background/completion/TabRepository.ts index fe1b601..57dbf21 100644 --- a/src/background/completion/TabRepository.ts +++ b/src/background/completion/TabRepository.ts @@ -1,14 +1,14 @@ export type Tab = { - id: number - index: number - active: boolean - title: string - url: string - faviconUrl?: string -} + 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[]> + getAllTabs(excludePinned: boolean): Promise<Tab[]>; } diff --git a/src/background/completion/impl/BookmarkRepositoryImpl.ts b/src/background/completion/impl/BookmarkRepositoryImpl.ts index 3b80b93..2bc779d 100644 --- a/src/background/completion/impl/BookmarkRepositoryImpl.ts +++ b/src/background/completion/impl/BookmarkRepositoryImpl.ts @@ -1,5 +1,5 @@ -import BookmarkRepository, {BookmarkItem} from "../BookmarkRepository"; -import {HistoryItem} from "../HistoryRepository"; +import BookmarkRepository, { BookmarkItem } from "../BookmarkRepository"; +import { HistoryItem } from "../HistoryRepository"; import PrefetchAndCache from "./PrefetchAndCache"; const COMPLETION_ITEM_LIMIT = 10; @@ -8,7 +8,7 @@ export default class CachedBookmarkRepository implements BookmarkRepository { private bookmarkCache: PrefetchAndCache<BookmarkItem>; constructor() { - this.bookmarkCache = new PrefetchAndCache(this.getter, this.filter, 10,); + this.bookmarkCache = new PrefetchAndCache(this.getter, this.filter, 10); } queryBookmarks(query: string): Promise<BookmarkItem[]> { @@ -16,10 +16,10 @@ export default class CachedBookmarkRepository implements BookmarkRepository { } private async getter(query: string): Promise<BookmarkItem[]> { - const items = await browser.bookmarks.search({query}); + 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) => item.title && item.title.length > 0) + .filter((item) => item.type === "bookmark" && item.url) .filter((item) => { let url = undefined; try { @@ -27,20 +27,23 @@ export default class CachedBookmarkRepository implements BookmarkRepository { } catch (e) { return false; } - return url.protocol !== 'place:'; + return url.protocol !== "place:"; }) .slice(0, COMPLETION_ITEM_LIMIT) - .map(item => ({ + .map((item) => ({ title: item.title!!, url: item.url!!, })); } private filter(items: HistoryItem[], query: string) { - return items.filter(item => { - return query.split(' ').every(keyword => { - return item.title.toLowerCase().includes(keyword.toLowerCase()) || item.url!!.includes(keyword) + return items.filter((item) => { + return query.split(" ").every((keyword) => { + return ( + item.title.toLowerCase().includes(keyword.toLowerCase()) || + item.url!!.includes(keyword) + ); }); - }) - }; + }); + } } diff --git a/src/background/completion/impl/HistoryRepositoryImpl.ts b/src/background/completion/impl/HistoryRepositoryImpl.ts index cd55cd0..b1992a4 100644 --- a/src/background/completion/impl/HistoryRepositoryImpl.ts +++ b/src/background/completion/impl/HistoryRepositoryImpl.ts @@ -1,5 +1,5 @@ import * as filters from "./filters"; -import HistoryRepository, {HistoryItem} from "../HistoryRepository"; +import HistoryRepository, { HistoryItem } from "../HistoryRepository"; import PrefetchAndCache from "./PrefetchAndCache"; const COMPLETION_ITEM_LIMIT = 10; @@ -8,13 +8,17 @@ export default class CachedHistoryRepository implements HistoryRepository { private historyCache: PrefetchAndCache<browser.history.HistoryItem>; constructor() { - this.historyCache = new PrefetchAndCache(this.getter, this.filter, 10) + this.historyCache = new PrefetchAndCache(this.getter, this.filter, 10); } async queryHistories(keywords: string): Promise<HistoryItem[]> { const items = await this.historyCache.get(keywords); - const filterOrKeep = <T>(source: T[], filter: (items: T[]) => T[], min: number): T[] => { + const filterOrKeep = <T>( + source: T[], + filter: (items: T[]) => T[], + min: number + ): T[] => { const filtered = filter(source); if (filtered.length < min) { return source; @@ -23,17 +27,23 @@ export default class CachedHistoryRepository implements HistoryRepository { }; return [items] - .map(items => filterOrKeep(items, filters.filterByPathname, COMPLETION_ITEM_LIMIT)) - .map(items => filterOrKeep(items, filters.filterByOrigin, 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!!, - })); + .map((items) => + filterOrKeep(items, filters.filterByPathname, COMPLETION_ITEM_LIMIT) + ) + .map((items) => + filterOrKeep(items, filters.filterByOrigin, 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!!, + })); } - private async getter (keywords: string): Promise<browser.history.HistoryItem[]> { + private async getter( + keywords: string + ): Promise<browser.history.HistoryItem[]> { const items = await browser.history.search({ text: keywords, startTime: 0, @@ -42,14 +52,17 @@ export default class CachedHistoryRepository implements HistoryRepository { return [items] .map(filters.filterBlankTitle) .map(filters.filterHttp) - .map(filters.filterByTailingSlash)[0] + .map(filters.filterByTailingSlash)[0]; } private filter(items: browser.history.HistoryItem[], query: string) { - return items.filter(item => { - return query.split(' ').every(keyword => { - return item.title!!.toLowerCase().includes(keyword.toLowerCase()) || item.url!!.includes(keyword) + return items.filter((item) => { + return query.split(" ").every((keyword) => { + return ( + item.title!!.toLowerCase().includes(keyword.toLowerCase()) || + item.url!!.includes(keyword) + ); }); - }) - }; + }); + } } diff --git a/src/background/completion/impl/PrefetchAndCache.ts b/src/background/completion/impl/PrefetchAndCache.ts index 3c074c2..d2889b0 100644 --- a/src/background/completion/impl/PrefetchAndCache.ts +++ b/src/background/completion/impl/PrefetchAndCache.ts @@ -5,14 +5,14 @@ const WHITESPACE = /\s/; // `shortKey` returns a shorten key to pre-fetch completions and store in the // cache. The shorten key is generated by the following rules: -// +// // 1. If the query contains a space in the middle: i.e. the query consists of // multiple words, the method removes the last word from the query, and // returns joined remaining words with space. -// +// // 2. If the query is a single word and it's an URL, the method returns a new // URL excluding search query with the upper path of the original URL. -// +// // 3. If the query is a single word and it's not an URL, the method returns a // word with the half-length of the original query. // @@ -29,11 +29,15 @@ const WHITESPACE = /\s/; // export const shortKey = (query: string): string => { if (WHITESPACE.test(query)) { - return query.split(WHITESPACE).filter(word => word.length > 0).slice(0, -1).join(' '); + return query + .split(WHITESPACE) + .filter((word) => word.length > 0) + .slice(0, -1) + .join(" "); } let url; try { - url = new URL(query) + url = new URL(query); } catch (e) { return query.slice(0, query.length / 2); } @@ -42,12 +46,12 @@ export const shortKey = (query: string): string => { // may be on typing or removing URLs such as "such as https://goog" return query.slice(0, query.length / 2); } - if (url.pathname.endsWith('/')) { + if (url.pathname.endsWith("/")) { // remove parameters and move to upper path - return new URL('..', url).href; + return new URL("..", url).href; } // remove parameters - return new URL('.', url).href; + return new URL(".", url).href; }; export default class PrefetchAndCache<T> { @@ -58,9 +62,8 @@ export default class PrefetchAndCache<T> { constructor( private getter: Getter<T>, private filter: Filter<T>, - private prefetchThrethold: number = 1, - ) { - } + private prefetchThrethold: number = 1 + ) {} async get(query: string): Promise<T[]> { query = query.trim(); @@ -79,7 +82,7 @@ export default class PrefetchAndCache<T> { private needToRefresh(query: string): boolean { if (!this.shortKey) { // no cache - return true + return true; } if (query.length < this.shortKey.length) { @@ -89,17 +92,17 @@ export default class PrefetchAndCache<T> { } if (!query.startsWith(this.shortKey)) { - // queyr: "hello_w" - // shorten: "hello_morning" - return true + // queyr: "hello_w" + // shorten: "hello_morning" + return true; } - if (query.slice(this.shortKey.length).includes(' ')) { + if (query.slice(this.shortKey.length).includes(" ")) { // queyr: "hello x" // shorten: "hello" return true; } - return false + return false; } } diff --git a/src/background/completion/impl/TabRepositoryImpl.ts b/src/background/completion/impl/TabRepositoryImpl.ts index adcaba7..5e33e5a 100644 --- a/src/background/completion/impl/TabRepositoryImpl.ts +++ b/src/background/completion/impl/TabRepositoryImpl.ts @@ -1,34 +1,34 @@ 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()); + 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) + .filter((item) => item.id && item.title && item.url) .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) + 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 { + private static toEntity(tab: browser.tabs.Tab): Tab { return { id: tab.id!!, url: tab.url!!, @@ -36,6 +36,6 @@ export default class TabRepositoryImpl implements TabRepository { title: tab.title!!, faviconUrl: tab.favIconUrl, index: tab.index, - } + }; } } diff --git a/src/background/completion/impl/filters.ts b/src/background/completion/impl/filters.ts index 3aa56e4..523491d 100644 --- a/src/background/completion/impl/filters.ts +++ b/src/background/completion/impl/filters.ts @@ -1,32 +1,36 @@ type Item = browser.history.HistoryItem; const filterHttp = (items: Item[]): Item[] => { - const httpsHosts = items.map(x => new URL(x.url as string)) - .filter(x => x.protocol === 'https:') - .map(x => x.host); + const httpsHosts = items + .map((x) => new URL(x.url as string)) + .filter((x) => x.protocol === "https:") + .map((x) => x.host); const hostsSet = new Set(httpsHosts); return items.filter((item: Item) => { const url = new URL(item.url as string); - return url.protocol === 'https:' || !hostsSet.has(url.host); + return url.protocol === "https:" || !hostsSet.has(url.host); }); }; const filterBlankTitle = (items: Item[]): Item[] => { - return items.filter(item => item.title && item.title !== ''); + return items.filter((item) => item.title && item.title !== ""); }; const filterByTailingSlash = (items: Item[]): Item[] => { - const urls = items.map(item => new URL(item.url as string)); + const urls = items.map((item) => new URL(item.url as string)); const simplePaths = urls - .filter(url => url.hash === '' && url.search === '') - .map(url => url.origin + url.pathname); + .filter((url) => url.hash === "" && url.search === "") + .map((url) => url.origin + url.pathname); const pathsSet = new Set(simplePaths); return items.filter((item) => { const url = new URL(item.url as string); - if (url.hash !== '' || url.search !== '' || - url.pathname.slice(-1) !== '/') { + if ( + url.hash !== "" || + url.search !== "" || + url.pathname.slice(-1) !== "/" + ) { return true; } return !pathsSet.has(url.origin + url.pathname.slice(0, -1)); @@ -34,14 +38,15 @@ const filterByTailingSlash = (items: Item[]): Item[] => { }; const filterByPathname = (items: Item[]): Item[] => { - const hash: {[key: string]: Item} = {}; + const hash: { [key: string]: Item } = {}; for (const item of items) { const url = new URL(item.url as string); const pathname = url.origin + url.pathname; if (!hash[pathname]) { hash[pathname] = item; - } else if ((hash[pathname].url as string).length > - (item.url as string).length) { + } else if ( + (hash[pathname].url as string).length > (item.url as string).length + ) { hash[pathname] = item; } } @@ -49,13 +54,14 @@ const filterByPathname = (items: Item[]): Item[] => { }; const filterByOrigin = (items: Item[]): Item[] => { - const hash: {[key: string]: Item} = {}; + const hash: { [key: string]: Item } = {}; for (const item of items) { const origin = new URL(item.url as string).origin; if (!hash[origin]) { hash[origin] = item; - } else if ((hash[origin].url as string).length > - (item.url as string).length) { + } else if ( + (hash[origin].url as string).length > (item.url as string).length + ) { hash[origin] = item; } } @@ -63,6 +69,9 @@ const filterByOrigin = (items: Item[]): Item[] => { }; export { - filterHttp, filterBlankTitle, filterByTailingSlash, - filterByPathname, filterByOrigin + filterHttp, + filterBlankTitle, + filterByTailingSlash, + filterByPathname, + filterByOrigin, }; diff --git a/src/background/controllers/AddonEnabledController.ts b/src/background/controllers/AddonEnabledController.ts index 903df40..170abdf 100644 --- a/src/background/controllers/AddonEnabledController.ts +++ b/src/background/controllers/AddonEnabledController.ts @@ -1,13 +1,9 @@ -import { injectable } from 'tsyringe'; -import AddonEnabledUseCase from '../usecases/AddonEnabledUseCase'; +import { injectable } from "tsyringe"; +import AddonEnabledUseCase from "../usecases/AddonEnabledUseCase"; @injectable() export default class AddonEnabledController { - - constructor( - private addonEnabledUseCase: AddonEnabledUseCase, - ) { - } + constructor(private addonEnabledUseCase: AddonEnabledUseCase) {} indicate(enabled: boolean): Promise<any> { return this.addonEnabledUseCase.indicate(enabled); diff --git a/src/background/controllers/CommandController.ts b/src/background/controllers/CommandController.ts index 16aa6e8..f19303f 100644 --- a/src/background/controllers/CommandController.ts +++ b/src/background/controllers/CommandController.ts @@ -1,17 +1,14 @@ -import { injectable } from 'tsyringe'; -import CommandUseCase from '../usecases/CommandUseCase'; +import { injectable } from "tsyringe"; +import CommandUseCase from "../usecases/CommandUseCase"; const trimStart = (str: string): string => { // NOTE String.trimStart is available on Firefox 61 - return str.replace(/^\s+/, ''); + return str.replace(/^\s+/, ""); }; @injectable() export default class CommandController { - constructor( - private commandIndicator: CommandUseCase, - ) { - } + constructor(private commandIndicator: CommandUseCase) {} // eslint-disable-next-line complexity exec(line: string): Promise<any> { @@ -24,44 +21,44 @@ export default class CommandController { const keywords = trimStart(trimmed.slice(name.length)); switch (words[0]) { - case 'o': - case 'open': - return this.commandIndicator.open(keywords); - case 't': - case 'tabopen': - return this.commandIndicator.tabopen(keywords); - case 'w': - case 'winopen': - return this.commandIndicator.winopen(keywords); - case 'b': - case 'buffer': - return this.commandIndicator.buffer(keywords); - case 'bd': - case 'bdel': - case 'bdelete': - return this.commandIndicator.bdelete(false, keywords); - case 'bd!': - case 'bdel!': - case 'bdelete!': - return this.commandIndicator.bdelete(true, keywords); - case 'bdeletes': - return this.commandIndicator.bdeletes(false, keywords); - case 'bdeletes!': - return this.commandIndicator.bdeletes(true, keywords); - case 'addbookmark': - return this.commandIndicator.addbookmark(keywords); - case 'q': - case 'quit': - return this.commandIndicator.quit(); - case 'qa': - case 'quitall': - return this.commandIndicator.quitAll(); - case 'set': - return this.commandIndicator.set(keywords); - case 'h': - case 'help': - return this.commandIndicator.help(); + case "o": + case "open": + return this.commandIndicator.open(keywords); + case "t": + case "tabopen": + return this.commandIndicator.tabopen(keywords); + case "w": + case "winopen": + return this.commandIndicator.winopen(keywords); + case "b": + case "buffer": + return this.commandIndicator.buffer(keywords); + case "bd": + case "bdel": + case "bdelete": + return this.commandIndicator.bdelete(false, keywords); + case "bd!": + case "bdel!": + case "bdelete!": + return this.commandIndicator.bdelete(true, keywords); + case "bdeletes": + return this.commandIndicator.bdeletes(false, keywords); + case "bdeletes!": + return this.commandIndicator.bdeletes(true, keywords); + case "addbookmark": + return this.commandIndicator.addbookmark(keywords); + case "q": + case "quit": + return this.commandIndicator.quit(); + case "qa": + case "quitall": + return this.commandIndicator.quitAll(); + case "set": + return this.commandIndicator.set(keywords); + case "h": + case "help": + return this.commandIndicator.help(); } - throw new Error(words[0] + ' command is not defined'); + throw new Error(words[0] + " command is not defined"); } } diff --git a/src/background/controllers/CompletionController.ts b/src/background/controllers/CompletionController.ts index fb6137c..35538be 100644 --- a/src/background/controllers/CompletionController.ts +++ b/src/background/controllers/CompletionController.ts @@ -4,7 +4,7 @@ import { ConsoleRequestBookmarksResponse, ConsoleRequestHistoryResponse, ConsoleRequestSearchEnginesResponse, - ConsoleRequesttabsResponse + ConsoleRequesttabsResponse, } from "../../shared/messages"; import { injectable } from "tsyringe"; import OpenCompletionUseCase from "../completion/OpenCompletionUseCase"; @@ -16,20 +16,23 @@ export default class CompletionController { constructor( private completionUseCase: OpenCompletionUseCase, private tabCompletionUseCase: TabCompletionUseCase, - private propertyCompletionUseCase: PropertyCompletionUseCase, - ) { - } + private propertyCompletionUseCase: PropertyCompletionUseCase + ) {} async getCompletionTypes(): Promise<ConsoleGetCompletionTypesResponse> { return this.completionUseCase.getCompletionTypes(); } - async requestSearchEngines(query: string): Promise<ConsoleRequestSearchEnginesResponse> { + async requestSearchEngines( + query: string + ): Promise<ConsoleRequestSearchEnginesResponse> { const items = await this.completionUseCase.requestSearchEngines(query); - return items.map(name => ({ title: name })); + return items.map((name) => ({ title: name })); } - async requestBookmarks(query: string): Promise<ConsoleRequestBookmarksResponse> { + async requestBookmarks( + query: string + ): Promise<ConsoleRequestBookmarksResponse> { return this.completionUseCase.requestBookmarks(query); } @@ -37,11 +40,14 @@ export default class CompletionController { return this.completionUseCase.requestHistory(query); } - async queryTabs(query: string, excludePinned: boolean): Promise<ConsoleRequesttabsResponse> { + async queryTabs( + query: string, + excludePinned: boolean + ): Promise<ConsoleRequesttabsResponse> { return this.tabCompletionUseCase.queryTabs(query, excludePinned); } async getProperties(): Promise<ConsoleGetPropertiesResponse> { - return this.propertyCompletionUseCase.getProperties(); + return this.propertyCompletionUseCase.getProperties(); } -}
\ No newline at end of file +} diff --git a/src/background/controllers/FindController.ts b/src/background/controllers/FindController.ts index 1cec962..92dfeb0 100644 --- a/src/background/controllers/FindController.ts +++ b/src/background/controllers/FindController.ts @@ -1,12 +1,9 @@ -import { injectable } from 'tsyringe'; -import FindUseCase from '../usecases/FindUseCase'; +import { injectable } from "tsyringe"; +import FindUseCase from "../usecases/FindUseCase"; @injectable() export default class FindController { - constructor( - private findUseCase: FindUseCase, - ) { - } + constructor(private findUseCase: FindUseCase) {} getKeyword(): Promise<string> { return this.findUseCase.getKeyword(); diff --git a/src/background/controllers/LinkController.ts b/src/background/controllers/LinkController.ts index af6148e..a410bc7 100644 --- a/src/background/controllers/LinkController.ts +++ b/src/background/controllers/LinkController.ts @@ -1,19 +1,18 @@ -import { injectable } from 'tsyringe'; -import LinkUseCase from '../usecases/LinkUseCase'; +import { injectable } from "tsyringe"; +import LinkUseCase from "../usecases/LinkUseCase"; @injectable() export default class LinkController { - constructor( - private linkUseCase: LinkUseCase, - ) { - } + constructor(private linkUseCase: LinkUseCase) {} openToTab(url: string, tabId: number): Promise<void> { return this.linkUseCase.openToTab(url, tabId); } openNewTab( - url: string, openerId: number, background: boolean, + url: string, + openerId: number, + background: boolean ): Promise<void> { return this.linkUseCase.openNewTab(url, openerId, background); } diff --git a/src/background/controllers/MarkController.ts b/src/background/controllers/MarkController.ts index 4726fbc..0d468f2 100644 --- a/src/background/controllers/MarkController.ts +++ b/src/background/controllers/MarkController.ts @@ -1,12 +1,9 @@ -import { injectable } from 'tsyringe'; -import MarkUseCase from '../usecases/MarkUseCase'; +import { injectable } from "tsyringe"; +import MarkUseCase from "../usecases/MarkUseCase"; @injectable() export default class MarkController { - constructor( - private markUseCase: MarkUseCase, - ) { - } + constructor(private markUseCase: MarkUseCase) {} setGlobal(key: string, x: number, y: number): Promise<any> { return this.markUseCase.setGlobal(key, x, y); diff --git a/src/background/controllers/OperationController.ts b/src/background/controllers/OperationController.ts index 181dd19..5a7047d 100644 --- a/src/background/controllers/OperationController.ts +++ b/src/background/controllers/OperationController.ts @@ -1,12 +1,12 @@ -import { injectable } from 'tsyringe'; -import * as operations from '../../shared/operations'; -import FindUseCase from '../usecases/FindUseCase'; -import ConsoleUseCase from '../usecases/ConsoleUseCase'; -import TabUseCase from '../usecases/TabUseCase'; -import TabSelectUseCase from '../usecases/TabSelectUseCase'; -import ZoomUseCase from '../usecases/ZoomUseCase'; -import NavigateUseCase from '../usecases/NavigateUseCase'; -import RepeatUseCase from '../usecases/RepeatUseCase'; +import { injectable } from "tsyringe"; +import * as operations from "../../shared/operations"; +import FindUseCase from "../usecases/FindUseCase"; +import ConsoleUseCase from "../usecases/ConsoleUseCase"; +import TabUseCase from "../usecases/TabUseCase"; +import TabSelectUseCase from "../usecases/TabSelectUseCase"; +import ZoomUseCase from "../usecases/ZoomUseCase"; +import NavigateUseCase from "../usecases/NavigateUseCase"; +import RepeatUseCase from "../usecases/RepeatUseCase"; @injectable() export default class OperationController { @@ -17,9 +17,8 @@ export default class OperationController { private tabSelectUseCase: TabSelectUseCase, private zoomUseCase: ZoomUseCase, private navigateUseCase: NavigateUseCase, - private repeatUseCase: RepeatUseCase, - ) { - } + private repeatUseCase: RepeatUseCase + ) {} async exec(repeat: number, op: operations.Operation): Promise<any> { await this.doOperation(repeat, op); @@ -31,91 +30,96 @@ export default class OperationController { // eslint-disable-next-line complexity, max-lines-per-function async doOperation( repeat: number, - operation: operations.Operation, + operation: operations.Operation ): Promise<any> { // eslint-disable-next-line complexity, max-lines-per-function const opFunc = (() => { switch (operation.type) { - case operations.TAB_CLOSE: - return () => this.tabUseCase.close(false, operation.select === 'left'); - case operations.TAB_CLOSE_RIGHT: - return () => this.tabUseCase.closeRight(); - case operations.TAB_CLOSE_FORCE: - return () => this.tabUseCase.close(true); - case operations.TAB_REOPEN: - return () => this.tabUseCase.reopen(); - case operations.TAB_PREV: - return () => this.tabSelectUseCase.selectPrev(1); - case operations.TAB_NEXT: - return () => this.tabSelectUseCase.selectNext(1); - case operations.TAB_FIRST: - return () => this.tabSelectUseCase.selectFirst(); - case operations.TAB_LAST: - return () => this.tabSelectUseCase.selectLast(); - case operations.TAB_PREV_SEL: - return () => this.tabSelectUseCase.selectPrevSelected(); - case operations.TAB_RELOAD: - return () => this.tabUseCase.reload(operation.cache); - case operations.TAB_PIN: - return () => this.tabUseCase.setPinned(true); - case operations.TAB_UNPIN: - return () => this.tabUseCase.setPinned(false); - case operations.TAB_TOGGLE_PINNED: - return () => this.tabUseCase.togglePinned(); - case operations.TAB_DUPLICATE: - return () => this.tabUseCase.duplicate(); - case operations.PAGE_SOURCE: - return () => this.tabUseCase.openPageSource(); - case operations.PAGE_HOME: - return () => this.tabUseCase.openHome(operation.newTab); - case operations.ZOOM_IN: - return () => this.zoomUseCase.zoomIn(); - case operations.ZOOM_OUT: - return () => this.zoomUseCase.zoomOut(); - case operations.ZOOM_NEUTRAL: - return () => this.zoomUseCase.zoomNutoral(); - case operations.COMMAND_SHOW: - return () => this.consoleUseCase.showCommand(); - case operations.COMMAND_SHOW_OPEN: - return () => this.consoleUseCase.showOpenCommand(operation.alter); - case operations.COMMAND_SHOW_TABOPEN: - return () => this.consoleUseCase.showTabopenCommand(operation.alter); - case operations.COMMAND_SHOW_WINOPEN: - return () => this.consoleUseCase.showWinopenCommand(operation.alter); - case operations.COMMAND_SHOW_BUFFER: - return () => this.consoleUseCase.showBufferCommand(); - case operations.COMMAND_SHOW_ADDBOOKMARK: - return () => this.consoleUseCase.showAddbookmarkCommand( - operation.alter); - case operations.FIND_START: - return () => this.findUseCase.findStart(); - case operations.CANCEL: - return () => this.consoleUseCase.hideConsole(); - case operations.NAVIGATE_HISTORY_PREV: - return () => this.navigateUseCase.openHistoryPrev(); - case operations.NAVIGATE_HISTORY_NEXT: - return () => this.navigateUseCase.openHistoryNext(); - case operations.NAVIGATE_LINK_PREV: - return () => this.navigateUseCase.openLinkPrev(); - case operations.NAVIGATE_LINK_NEXT: - return () => this.navigateUseCase.openLinkNext(); - case operations.NAVIGATE_PARENT: - return () => this.navigateUseCase.openParent(); - case operations.NAVIGATE_ROOT: - return () => this.navigateUseCase.openRoot(); - case operations.REPEAT_LAST: - return () => { - const last = this.repeatUseCase.getLastOperation(); - if (typeof last !== 'undefined') { - return this.doOperation(1, last); - } - return Promise.resolve(); - }; - case operations.INTERNAL_OPEN_URL: - return () => this.tabUseCase.openURL( - operation.url, operation.newTab, operation.newWindow); - default: - throw new Error('unknown operation: ' + operation.type); + case operations.TAB_CLOSE: + return () => + this.tabUseCase.close(false, operation.select === "left"); + case operations.TAB_CLOSE_RIGHT: + return () => this.tabUseCase.closeRight(); + case operations.TAB_CLOSE_FORCE: + return () => this.tabUseCase.close(true); + case operations.TAB_REOPEN: + return () => this.tabUseCase.reopen(); + case operations.TAB_PREV: + return () => this.tabSelectUseCase.selectPrev(1); + case operations.TAB_NEXT: + return () => this.tabSelectUseCase.selectNext(1); + case operations.TAB_FIRST: + return () => this.tabSelectUseCase.selectFirst(); + case operations.TAB_LAST: + return () => this.tabSelectUseCase.selectLast(); + case operations.TAB_PREV_SEL: + return () => this.tabSelectUseCase.selectPrevSelected(); + case operations.TAB_RELOAD: + return () => this.tabUseCase.reload(operation.cache); + case operations.TAB_PIN: + return () => this.tabUseCase.setPinned(true); + case operations.TAB_UNPIN: + return () => this.tabUseCase.setPinned(false); + case operations.TAB_TOGGLE_PINNED: + return () => this.tabUseCase.togglePinned(); + case operations.TAB_DUPLICATE: + return () => this.tabUseCase.duplicate(); + case operations.PAGE_SOURCE: + return () => this.tabUseCase.openPageSource(); + case operations.PAGE_HOME: + return () => this.tabUseCase.openHome(operation.newTab); + case operations.ZOOM_IN: + return () => this.zoomUseCase.zoomIn(); + case operations.ZOOM_OUT: + return () => this.zoomUseCase.zoomOut(); + case operations.ZOOM_NEUTRAL: + return () => this.zoomUseCase.zoomNutoral(); + case operations.COMMAND_SHOW: + return () => this.consoleUseCase.showCommand(); + case operations.COMMAND_SHOW_OPEN: + return () => this.consoleUseCase.showOpenCommand(operation.alter); + case operations.COMMAND_SHOW_TABOPEN: + return () => this.consoleUseCase.showTabopenCommand(operation.alter); + case operations.COMMAND_SHOW_WINOPEN: + return () => this.consoleUseCase.showWinopenCommand(operation.alter); + case operations.COMMAND_SHOW_BUFFER: + return () => this.consoleUseCase.showBufferCommand(); + case operations.COMMAND_SHOW_ADDBOOKMARK: + return () => + this.consoleUseCase.showAddbookmarkCommand(operation.alter); + case operations.FIND_START: + return () => this.findUseCase.findStart(); + case operations.CANCEL: + return () => this.consoleUseCase.hideConsole(); + case operations.NAVIGATE_HISTORY_PREV: + return () => this.navigateUseCase.openHistoryPrev(); + case operations.NAVIGATE_HISTORY_NEXT: + return () => this.navigateUseCase.openHistoryNext(); + case operations.NAVIGATE_LINK_PREV: + return () => this.navigateUseCase.openLinkPrev(); + case operations.NAVIGATE_LINK_NEXT: + return () => this.navigateUseCase.openLinkNext(); + case operations.NAVIGATE_PARENT: + return () => this.navigateUseCase.openParent(); + case operations.NAVIGATE_ROOT: + return () => this.navigateUseCase.openRoot(); + case operations.REPEAT_LAST: + return () => { + const last = this.repeatUseCase.getLastOperation(); + if (typeof last !== "undefined") { + return this.doOperation(1, last); + } + return Promise.resolve(); + }; + case operations.INTERNAL_OPEN_URL: + return () => + this.tabUseCase.openURL( + operation.url, + operation.newTab, + operation.newWindow + ); + default: + throw new Error("unknown operation: " + operation.type); } })(); @@ -125,4 +129,3 @@ export default class OperationController { } } } - diff --git a/src/background/controllers/SettingController.ts b/src/background/controllers/SettingController.ts index 26edc07..4248746 100644 --- a/src/background/controllers/SettingController.ts +++ b/src/background/controllers/SettingController.ts @@ -1,15 +1,14 @@ -import { injectable } from 'tsyringe'; -import SettingUseCase from '../usecases/SettingUseCase'; -import ContentMessageClient from '../infrastructures/ContentMessageClient'; -import Settings from '../../shared/settings/Settings'; +import { injectable } from "tsyringe"; +import SettingUseCase from "../usecases/SettingUseCase"; +import ContentMessageClient from "../infrastructures/ContentMessageClient"; +import Settings from "../../shared/settings/Settings"; @injectable() export default class SettingController { constructor( private settingUseCase: SettingUseCase, - private contentMessageClient: ContentMessageClient, - ) { - } + private contentMessageClient: ContentMessageClient + ) {} getSetting(): Promise<Settings> { return this.settingUseCase.getCached(); diff --git a/src/background/controllers/VersionController.ts b/src/background/controllers/VersionController.ts index b00185a..92fca9e 100644 --- a/src/background/controllers/VersionController.ts +++ b/src/background/controllers/VersionController.ts @@ -1,12 +1,9 @@ -import { injectable } from 'tsyringe'; -import VersionUseCase from '../usecases/VersionUseCase'; +import { injectable } from "tsyringe"; +import VersionUseCase from "../usecases/VersionUseCase"; @injectable() export default class VersionController { - constructor( - private versionUseCase: VersionUseCase, - ) { - } + constructor(private versionUseCase: VersionUseCase) {} notify(): Promise<void> { return this.versionUseCase.notify(); diff --git a/src/background/di.ts b/src/background/di.ts index c186262..5e6ad03 100644 --- a/src/background/di.ts +++ b/src/background/di.ts @@ -1,19 +1,28 @@ /* eslint-disable max-len */ -import { LocalSettingRepository, SyncSettingRepository } from "./repositories/SettingRepository"; +import { + LocalSettingRepository, + SyncSettingRepository, +} from "./repositories/SettingRepository"; import { NotifierImpl } from "./presenters/Notifier"; import { CachedSettingRepositoryImpl } from "./repositories/CachedSettingRepository"; -import { container } from 'tsyringe'; +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"; +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 }); +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/index.ts b/src/background/index.ts index f75c53b..6fe68af 100644 --- a/src/background/index.ts +++ b/src/background/index.ts @@ -1,7 +1,7 @@ -import 'reflect-metadata'; -import { container } from 'tsyringe'; -import Application from './Application'; -import './di'; +import "reflect-metadata"; +import { container } from "tsyringe"; +import Application from "./Application"; +import "./di"; const app = container.resolve(Application); app.run(); diff --git a/src/background/infrastructures/ConsoleClient.ts b/src/background/infrastructures/ConsoleClient.ts index 1385fe7..8d0af89 100644 --- a/src/background/infrastructures/ConsoleClient.ts +++ b/src/background/infrastructures/ConsoleClient.ts @@ -1,5 +1,5 @@ -import { injectable } from 'tsyringe'; -import * as messages from '../../shared/messages'; +import { injectable } from "tsyringe"; +import * as messages from "../../shared/messages"; @injectable() export default class ConsoleClient { @@ -12,7 +12,7 @@ export default class ConsoleClient { showFind(tabId: number): Promise<any> { return browser.tabs.sendMessage(tabId, { - type: messages.CONSOLE_SHOW_FIND + type: messages.CONSOLE_SHOW_FIND, }); } @@ -36,4 +36,3 @@ export default class ConsoleClient { }); } } - diff --git a/src/background/infrastructures/ContentMessageClient.ts b/src/background/infrastructures/ContentMessageClient.ts index b6c0c23..e889392 100644 --- a/src/background/infrastructures/ContentMessageClient.ts +++ b/src/background/infrastructures/ContentMessageClient.ts @@ -1,12 +1,12 @@ -import { injectable } from 'tsyringe'; -import * as messages from '../../shared/messages'; +import { injectable } from "tsyringe"; +import * as messages from "../../shared/messages"; @injectable() export default class ContentMessageClient { async broadcastSettingsChanged(): Promise<void> { const tabs = await browser.tabs.query({}); for (const tab of tabs) { - if (!tab.id || tab.url && tab.url.startsWith('about:')) { + if (!tab.id || (tab.url && tab.url.startsWith("about:"))) { continue; } browser.tabs.sendMessage(tab.id, { @@ -19,7 +19,7 @@ export default class ContentMessageClient { const enabled = await browser.tabs.sendMessage(tabId, { type: messages.ADDON_ENABLED_QUERY, }); - return enabled as any as boolean; + return (enabled as any) as boolean; } async toggleAddonEnabled(tabId: number): Promise<void> { diff --git a/src/background/infrastructures/ContentMessageListener.ts b/src/background/infrastructures/ContentMessageListener.ts index 2fbb9cf..6978d35 100644 --- a/src/background/infrastructures/ContentMessageListener.ts +++ b/src/background/infrastructures/ContentMessageListener.ts @@ -1,18 +1,18 @@ -import { injectable } from 'tsyringe'; -import * as messages from '../../shared/messages'; -import * as operations from '../../shared/operations'; -import CommandController from '../controllers/CommandController'; -import SettingController from '../controllers/SettingController'; -import FindController from '../controllers/FindController'; -import AddonEnabledController from '../controllers/AddonEnabledController'; -import LinkController from '../controllers/LinkController'; -import OperationController from '../controllers/OperationController'; -import MarkController from '../controllers/MarkController'; +import { injectable } from "tsyringe"; +import * as messages from "../../shared/messages"; +import * as operations from "../../shared/operations"; +import CommandController from "../controllers/CommandController"; +import SettingController from "../controllers/SettingController"; +import FindController from "../controllers/FindController"; +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 { - private consolePorts: {[tabId: number]: browser.runtime.Port}; + private consolePorts: { [tabId: number]: browser.runtime.Port }; constructor( private settingController: SettingController, @@ -22,21 +22,29 @@ export default class ContentMessageListener { private addonEnabledController: AddonEnabledController, private linkController: LinkController, private operationController: OperationController, - private markController: MarkController, + private markController: MarkController ) { this.consolePorts = {}; } run(): void { - browser.runtime.onMessage.addListener(( - message: any, sender: browser.runtime.MessageSender, - ) => { - try { - const ret = this.onMessage(message, sender.tab as browser.tabs.Tab); - if (!(ret instanceof Promise)) { - return {}; - } - return ret.catch((e) => { + browser.runtime.onMessage.addListener( + (message: any, sender: browser.runtime.MessageSender) => { + try { + const ret = this.onMessage(message, sender.tab as browser.tabs.Tab); + if (!(ret instanceof Promise)) { + return {}; + } + return ret.catch((e) => { + if (!sender.tab || !sender.tab.id) { + return; + } + return browser.tabs.sendMessage(sender.tab.id, { + type: messages.CONSOLE_SHOW_ERROR, + text: e.message, + }); + }); + } catch (e) { if (!sender.tab || !sender.tab.id) { return; } @@ -44,64 +52,62 @@ export default class ContentMessageListener { type: messages.CONSOLE_SHOW_ERROR, text: e.message, }); - }); - } catch (e) { - if (!sender.tab || !sender.tab.id) { - return; } - return browser.tabs.sendMessage(sender.tab.id, { - type: messages.CONSOLE_SHOW_ERROR, - text: e.message, - }); } - }); + ); browser.runtime.onConnect.addListener(this.onConnected.bind(this)); } onMessage( - message: messages.Message, senderTab: browser.tabs.Tab, + message: messages.Message, + senderTab: browser.tabs.Tab ): Promise<any> | any { switch (message.type) { - 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: - return this.onSettingsQuery(); - case messages.FIND_GET_KEYWORD: - return this.onFindGetKeyword(); - case messages.FIND_SET_KEYWORD: - return this.onFindSetKeyword(message.keyword); - case messages.ADDON_ENABLED_RESPONSE: - return this.onAddonEnabledResponse(message.enabled); - case messages.OPEN_URL: - return this.onOpenUrl( - message.newTab, - message.url, - senderTab.id as number, - message.background); - case messages.BACKGROUND_OPERATION: - return this.onBackgroundOperation(message.repeat, message.operation); - case messages.MARK_SET_GLOBAL: - return this.onMarkSetGlobal(message.key, message.x, message.y); - case messages.MARK_JUMP_GLOBAL: - return this.onMarkJumpGlobal(message.key); - case messages.CONSOLE_FRAME_MESSAGE: - return this.onConsoleFrameMessage( - senderTab.id as number, message.message, - ); + 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: + return this.onSettingsQuery(); + case messages.FIND_GET_KEYWORD: + return this.onFindGetKeyword(); + case messages.FIND_SET_KEYWORD: + return this.onFindSetKeyword(message.keyword); + case messages.ADDON_ENABLED_RESPONSE: + return this.onAddonEnabledResponse(message.enabled); + case messages.OPEN_URL: + return this.onOpenUrl( + message.newTab, + message.url, + senderTab.id as number, + message.background + ); + case messages.BACKGROUND_OPERATION: + return this.onBackgroundOperation(message.repeat, message.operation); + case messages.MARK_SET_GLOBAL: + return this.onMarkSetGlobal(message.key, message.x, message.y); + case messages.MARK_JUMP_GLOBAL: + return this.onMarkJumpGlobal(message.key); + case messages.CONSOLE_FRAME_MESSAGE: + return this.onConsoleFrameMessage( + senderTab.id as number, + message.message + ); } - throw new Error('unsupported message: ' + message.type); + throw new Error("unsupported message: " + message.type); } onConsoleEnterCommand(text: string): Promise<any> { @@ -125,7 +131,10 @@ export default class ContentMessageListener { } onOpenUrl( - newTab: boolean, url: string, openerId: number, background: boolean, + newTab: boolean, + url: string, + openerId: number, + background: boolean ): Promise<any> { if (newTab) { return this.linkController.openNewTab(url, openerId, background); @@ -154,7 +163,7 @@ export default class ContentMessageListener { } onConnected(port: browser.runtime.Port): void { - if (port.name !== 'vimvixen-console') { + if (port.name !== "vimvixen-console") { return; } diff --git a/src/background/infrastructures/MemoryStorage.ts b/src/background/infrastructures/MemoryStorage.ts index af445a6..ad7bcd7 100644 --- a/src/background/infrastructures/MemoryStorage.ts +++ b/src/background/infrastructures/MemoryStorage.ts @@ -1,10 +1,10 @@ -const db: {[key: string]: any} = {}; +const db: { [key: string]: any } = {}; export default class MemoryStorage { set(name: string, value: any): void { const data = JSON.stringify(value); - if (typeof data === 'undefined') { - throw new Error('value is not serializable'); + if (typeof data === "undefined") { + throw new Error("value is not serializable"); } db[name] = data; } diff --git a/src/background/presenters/HelpPresenter.ts b/src/background/presenters/HelpPresenter.ts index f5c3a6b..7fa0597 100644 --- a/src/background/presenters/HelpPresenter.ts +++ b/src/background/presenters/HelpPresenter.ts @@ -1,6 +1,6 @@ -import { injectable } from 'tsyringe'; +import { injectable } from "tsyringe"; -const url = 'https://ueokande.github.io/vim-vixen/'; +const url = "https://ueokande.github.io/vim-vixen/"; @injectable() export default class HelpPresenter { diff --git a/src/background/presenters/IndicatorPresenter.ts b/src/background/presenters/IndicatorPresenter.ts index 6a33e62..5b4b673 100644 --- a/src/background/presenters/IndicatorPresenter.ts +++ b/src/background/presenters/IndicatorPresenter.ts @@ -1,18 +1,17 @@ -import { injectable } from 'tsyringe'; +import { injectable } from "tsyringe"; @injectable() export default class IndicatorPresenter { indicate(enabled: boolean): Promise<void> { const path = enabled - ? 'resources/enabled_32x32.png' - : 'resources/disabled_32x32.png'; - if (typeof browser.browserAction.setIcon === 'function') { + ? "resources/enabled_32x32.png" + : "resources/disabled_32x32.png"; + if (typeof browser.browserAction.setIcon === "function") { return browser.browserAction.setIcon({ path }); } // setIcon not supported on Android return Promise.resolve(); - } onClick(listener: (arg: browser.tabs.Tab) => void): void { diff --git a/src/background/presenters/Notifier.ts b/src/background/presenters/Notifier.ts index 57d58cb..2cd3225 100644 --- a/src/background/presenters/Notifier.ts +++ b/src/background/presenters/Notifier.ts @@ -1,5 +1,5 @@ -const NOTIFICATION_ID_UPDATE = 'vimvixen-update'; -const NOTIFICATION_ID_INVALID_SETTINGS = 'vimvixen-update-invalid-settings'; +const NOTIFICATION_ID_UPDATE = "vimvixen-update"; +const NOTIFICATION_ID_INVALID_SETTINGS = "vimvixen-update-invalid-settings"; export default interface Notifier { notifyUpdated(version: string, onclick: () => void): Promise<void>; @@ -10,7 +10,7 @@ export default interface Notifier { export class NotifierImpl implements NotifierImpl { async notifyUpdated(version: string, onclick: () => void): Promise<void> { const title = `Vim Vixen ${version} has been installed`; - const message = 'Click here to see release notes'; + const message = "Click here to see release notes"; const listener = (id: string) => { if (id !== NOTIFICATION_ID_UPDATE) { @@ -22,8 +22,8 @@ export class NotifierImpl implements NotifierImpl { browser.notifications.onClicked.addListener(listener); await browser.notifications.create(NOTIFICATION_ID_UPDATE, { - 'type': 'basic', - 'iconUrl': browser.extension.getURL('resources/icon_48x48.png'), + type: "basic", + iconUrl: browser.extension.getURL("resources/icon_48x48.png"), title, message, }); @@ -32,7 +32,8 @@ export class NotifierImpl implements NotifierImpl { async notifyInvalidSettings(onclick: () => void): Promise<void> { const title = `Loaded settings is invalid`; // eslint-disable-next-line max-len - const message = 'The default settings is used due to the last saved settings is invalid. Check your current settings from the add-on preference'; + const message = + "The default settings is used due to the last saved settings is invalid. Check your current settings from the add-on preference"; const listener = (id: string) => { if (id !== NOTIFICATION_ID_INVALID_SETTINGS) { @@ -44,8 +45,8 @@ export class NotifierImpl implements NotifierImpl { browser.notifications.onClicked.addListener(listener); await browser.notifications.create(NOTIFICATION_ID_INVALID_SETTINGS, { - 'type': 'basic', - 'iconUrl': browser.extension.getURL('resources/icon_48x48.png'), + type: "basic", + iconUrl: browser.extension.getURL("resources/icon_48x48.png"), title, message, }); diff --git a/src/background/presenters/TabPresenter.ts b/src/background/presenters/TabPresenter.ts index bded5a2..09cfa23 100644 --- a/src/background/presenters/TabPresenter.ts +++ b/src/background/presenters/TabPresenter.ts @@ -1,7 +1,7 @@ -import MemoryStorage from '../infrastructures/MemoryStorage'; +import MemoryStorage from "../infrastructures/MemoryStorage"; -const CURRENT_SELECTED_KEY = 'tabs.current.selected'; -const LAST_SELECTED_KEY = 'tabs.last.selected'; +const CURRENT_SELECTED_KEY = "tabs.current.selected"; +const LAST_SELECTED_KEY = "tabs.last.selected"; type Tab = browser.tabs.Tab; @@ -35,7 +35,7 @@ export default interface TabPresenter { setZoom(tabId: number, factor: number): Promise<void>; onSelected( - listener: (arg: { tabId: number, windowId: number}) => void, + listener: (arg: { tabId: number; windowId: number }) => void ): void; } @@ -50,7 +50,8 @@ export class TabPresenterImpl implements TabPresenter { async getCurrent(): Promise<Tab> { const tabs = await browser.tabs.query({ - active: true, currentWindow: true + active: true, + currentWindow: true, }); return tabs[0]; } @@ -62,22 +63,24 @@ export class TabPresenterImpl implements TabPresenter { async getLastSelectedId(): Promise<number | undefined> { const cache = new MemoryStorage(); const tabId = await cache.get(LAST_SELECTED_KEY); - if (tabId === null || typeof tabId === 'undefined') { + if (tabId === null || typeof tabId === "undefined") { return; } return tabId; } - async getByKeyword( - keyword: string, excludePinned = false, - ): Promise<Tab[]> { + async getByKeyword(keyword: string, excludePinned = false): Promise<Tab[]> { const tabs = await browser.tabs.query({ currentWindow: true }); - return tabs.filter((t) => { - return t.url && t.url.toLowerCase().includes(keyword.toLowerCase()) || - t.title && t.title.toLowerCase().includes(keyword.toLowerCase()); - }).filter((t) => { - return !(excludePinned && t.pinned); - }); + return tabs + .filter((t) => { + return ( + (t.url && t.url.toLowerCase().includes(keyword.toLowerCase())) || + (t.title && t.title.toLowerCase().includes(keyword.toLowerCase())) + ); + }) + .filter((t) => { + return !(excludePinned && t.pinned); + }); } async select(tabId: number): Promise<void> { @@ -125,7 +128,7 @@ export class TabPresenterImpl implements TabPresenter { } onSelected( - listener: (arg: { tabId: number, windowId: number}) => void, + listener: (arg: { tabId: number; windowId: number }) => void ): void { browser.tabs.onActivated.addListener(listener); } diff --git a/src/background/presenters/WindowPresenter.ts b/src/background/presenters/WindowPresenter.ts index 150a48b..4f37f5d 100644 --- a/src/background/presenters/WindowPresenter.ts +++ b/src/background/presenters/WindowPresenter.ts @@ -1,4 +1,4 @@ -import { injectable } from 'tsyringe'; +import { injectable } from "tsyringe"; @injectable() export default class WindowPresenter { diff --git a/src/background/repositories/BookmarkRepository.ts b/src/background/repositories/BookmarkRepository.ts index 0d2a1fc..e6e55c9 100644 --- a/src/background/repositories/BookmarkRepository.ts +++ b/src/background/repositories/BookmarkRepository.ts @@ -1,17 +1,18 @@ -import { injectable } from 'tsyringe'; +import { injectable } from "tsyringe"; @injectable() export default class BookmarkRepository { async create( - title: string, url: string + title: string, + url: string ): Promise<browser.bookmarks.BookmarkTreeNode> { const item = await browser.bookmarks.create({ - type: 'bookmark', + type: "bookmark", title, url, }); if (!item) { - throw new Error('Could not create a bookmark'); + throw new Error("Could not create a bookmark"); } return item; } diff --git a/src/background/repositories/BrowserSettingRepository.ts b/src/background/repositories/BrowserSettingRepository.ts index a47b64d..20013f4 100644 --- a/src/background/repositories/BrowserSettingRepository.ts +++ b/src/background/repositories/BrowserSettingRepository.ts @@ -1,18 +1,17 @@ -import { injectable } from 'tsyringe'; -import * as urls from '../../shared/urls'; +import { injectable } from "tsyringe"; +import * as urls from "../../shared/urls"; declare namespace browser.browserSettings.homepageOverride { - type BrowserSettings = { value: string; levelOfControl: LevelOfControlType; }; type LevelOfControlType = - 'not_controllable' | - 'controlled_by_other_extensions' | - 'controllable_by_this_extension' | - 'controlled_by_this_extension'; + | "not_controllable" + | "controlled_by_other_extensions" + | "controllable_by_this_extension" + | "controlled_by_this_extension"; function get(param: object): Promise<BrowserSettings>; } @@ -21,6 +20,6 @@ declare namespace browser.browserSettings.homepageOverride { export default class BrowserSettingRepository { async getHomepageUrls(): Promise<string[]> { const { value } = await browser.browserSettings.homepageOverride.get({}); - return value.split('|').map(urls.normalizeUrl); + return value.split("|").map(urls.normalizeUrl); } } diff --git a/src/background/repositories/CachedSettingRepository.ts b/src/background/repositories/CachedSettingRepository.ts index 1af15d4..e3d3950 100644 --- a/src/background/repositories/CachedSettingRepository.ts +++ b/src/background/repositories/CachedSettingRepository.ts @@ -1,17 +1,15 @@ -import MemoryStorage from '../infrastructures/MemoryStorage'; -import Settings from '../../shared/settings/Settings'; -import Properties from '../../shared/settings/Properties'; +import MemoryStorage from "../infrastructures/MemoryStorage"; +import Settings from "../../shared/settings/Settings"; +import Properties from "../../shared/settings/Properties"; -const CACHED_SETTING_KEY = 'setting'; +const CACHED_SETTING_KEY = "setting"; export default interface CachedSettingRepository { get(): Promise<Settings>; update(value: Settings): Promise<void>; - setProperty( - name: string, value: string | number | boolean, - ): Promise<void>; + setProperty(name: string, value: string | number | boolean): Promise<void>; } export class CachedSettingRepositoryImpl implements CachedSettingRepository { @@ -28,35 +26,36 @@ export class CachedSettingRepositoryImpl implements CachedSettingRepository { update(value: Settings): Promise<void> { this.cache.set(CACHED_SETTING_KEY, value.toJSON()); - return Promise.resolve() + return Promise.resolve(); } async setProperty( - name: string, value: string | number | boolean, + name: string, + value: string | number | boolean ): Promise<void> { const def = Properties.def(name); if (!def) { - throw new Error('unknown property: ' + name); + throw new Error("unknown property: " + name); } if (typeof value !== def.type) { throw new TypeError(`property type of ${name} mismatch: ${typeof value}`); } let newValue = value; - if (typeof value === 'string' && value === '') { + if (typeof value === "string" && value === "") { newValue = def.defaultValue; } const current = await this.get(); switch (name) { - case 'hintchars': - current.properties.hintchars = newValue as string; - break; - case 'smoothscroll': - current.properties.smoothscroll = newValue as boolean; - break; - case 'complete': - current.properties.complete = newValue as string; - break; + case "hintchars": + current.properties.hintchars = newValue as string; + break; + case "smoothscroll": + current.properties.smoothscroll = newValue as boolean; + break; + case "complete": + current.properties.complete = newValue as string; + break; } await this.update(current); } diff --git a/src/background/repositories/FindRepository.ts b/src/background/repositories/FindRepository.ts index 6a087f5..be56284 100644 --- a/src/background/repositories/FindRepository.ts +++ b/src/background/repositories/FindRepository.ts @@ -1,7 +1,7 @@ -import { injectable } from 'tsyringe'; -import MemoryStorage from '../infrastructures/MemoryStorage'; +import { injectable } from "tsyringe"; +import MemoryStorage from "../infrastructures/MemoryStorage"; -const FIND_KEYWORD_KEY = 'find-keyword'; +const FIND_KEYWORD_KEY = "find-keyword"; @injectable() export default class FindRepository { @@ -20,4 +20,3 @@ export default class FindRepository { return Promise.resolve(); } } - diff --git a/src/background/repositories/MarkRepository.ts b/src/background/repositories/MarkRepository.ts index 1f4ab0c..e2c1e94 100644 --- a/src/background/repositories/MarkRepository.ts +++ b/src/background/repositories/MarkRepository.ts @@ -1,8 +1,8 @@ -import { injectable } from 'tsyringe'; -import MemoryStorage from '../infrastructures/MemoryStorage'; -import GlobalMark from '../domains/GlobalMark'; +import { injectable } from "tsyringe"; +import MemoryStorage from "../infrastructures/MemoryStorage"; +import GlobalMark from "../domains/GlobalMark"; -const MARK_KEY = 'mark'; +const MARK_KEY = "mark"; @injectable() export default class MarkRepository { @@ -34,4 +34,3 @@ export default class MarkRepository { return this.cache.get(MARK_KEY) || {}; } } - diff --git a/src/background/repositories/RepeatRepository.ts b/src/background/repositories/RepeatRepository.ts index c7f7a71..e3ab43d 100644 --- a/src/background/repositories/RepeatRepository.ts +++ b/src/background/repositories/RepeatRepository.ts @@ -1,8 +1,8 @@ -import { injectable } from 'tsyringe'; -import { Operation } from '../../shared/operations'; -import MemoryStorage from '../infrastructures/MemoryStorage'; +import { injectable } from "tsyringe"; +import { Operation } from "../../shared/operations"; +import MemoryStorage from "../infrastructures/MemoryStorage"; -const REPEAT_KEY = 'repeat'; +const REPEAT_KEY = "repeat"; @injectable() export default class RepeatRepository { diff --git a/src/background/repositories/SettingRepository.ts b/src/background/repositories/SettingRepository.ts index b522045..d726cfb 100644 --- a/src/background/repositories/SettingRepository.ts +++ b/src/background/repositories/SettingRepository.ts @@ -1,4 +1,4 @@ -import SettingData from '../../shared/SettingData'; +import SettingData from "../../shared/SettingData"; export default interface SettingRepository { load(): Promise<SettingData | null>; @@ -8,7 +8,7 @@ export default interface SettingRepository { export class LocalSettingRepository implements SettingRepository { async load(): Promise<SettingData | null> { - const {settings} = await browser.storage.local.get('settings'); + const { settings } = await browser.storage.local.get("settings"); if (!settings) { return null; } @@ -17,7 +17,7 @@ export class LocalSettingRepository implements SettingRepository { onChange(callback: () => void) { browser.storage.onChanged.addListener((changes, area) => { - if (area !== 'local') { + if (area !== "local") { return; } if (changes.settings) { @@ -29,7 +29,7 @@ export class LocalSettingRepository implements SettingRepository { export class SyncSettingRepository implements SettingRepository { async load(): Promise<SettingData | null> { - const {settings} = await browser.storage.sync.get('settings'); + const { settings } = await browser.storage.sync.get("settings"); if (!settings) { return null; } @@ -38,7 +38,7 @@ export class SyncSettingRepository implements SettingRepository { onChange(callback: () => void) { browser.storage.onChanged.addListener((changes, area) => { - if (area !== 'sync') { + if (area !== "sync") { return; } if (changes.settings) { @@ -46,4 +46,4 @@ export class SyncSettingRepository implements SettingRepository { } }); } -}
\ No newline at end of file +} diff --git a/src/background/usecases/AddonEnabledUseCase.ts b/src/background/usecases/AddonEnabledUseCase.ts index 51f02e1..f563ab0 100644 --- a/src/background/usecases/AddonEnabledUseCase.ts +++ b/src/background/usecases/AddonEnabledUseCase.ts @@ -1,21 +1,21 @@ -import { inject, injectable } from 'tsyringe'; -import IndicatorPresenter from '../presenters/IndicatorPresenter'; -import TabPresenter from '../presenters/TabPresenter'; -import ContentMessageClient from '../infrastructures/ContentMessageClient'; +import { inject, injectable } from "tsyringe"; +import IndicatorPresenter from "../presenters/IndicatorPresenter"; +import TabPresenter from "../presenters/TabPresenter"; +import ContentMessageClient from "../infrastructures/ContentMessageClient"; @injectable() export default class AddonEnabledUseCase { constructor( private indicatorPresentor: IndicatorPresenter, @inject("TabPresenter") private tabPresenter: TabPresenter, - private contentMessageClient: ContentMessageClient, + private contentMessageClient: ContentMessageClient ) { this.indicatorPresentor.onClick((tab) => { if (tab.id) { this.onIndicatorClick(tab.id); } }); - this.tabPresenter.onSelected(info => this.onTabSelected(info.tabId)); + this.tabPresenter.onSelected((info) => this.onTabSelected(info.tabId)); } indicate(enabled: boolean): Promise<void> { diff --git a/src/background/usecases/CommandUseCase.ts b/src/background/usecases/CommandUseCase.ts index d2d707e..811ec77 100644 --- a/src/background/usecases/CommandUseCase.ts +++ b/src/background/usecases/CommandUseCase.ts @@ -1,29 +1,29 @@ -import { injectable, inject } from 'tsyringe'; -import * as operations from '../../shared/operations'; -import * as parsers from './parsers'; -import * as urls from '../../shared/urls'; -import TabPresenter from '../presenters/TabPresenter'; -import WindowPresenter from '../presenters/WindowPresenter'; -import HelpPresenter from '../presenters/HelpPresenter'; -import CachedSettingRepository from '../repositories/CachedSettingRepository'; -import BookmarkRepository from '../repositories/BookmarkRepository'; -import ConsoleClient from '../infrastructures/ConsoleClient'; -import ContentMessageClient from '../infrastructures/ContentMessageClient'; -import RepeatUseCase from '../usecases/RepeatUseCase'; +import { injectable, inject } from "tsyringe"; +import * as operations from "../../shared/operations"; +import * as parsers from "./parsers"; +import * as urls from "../../shared/urls"; +import TabPresenter from "../presenters/TabPresenter"; +import WindowPresenter from "../presenters/WindowPresenter"; +import HelpPresenter from "../presenters/HelpPresenter"; +import CachedSettingRepository from "../repositories/CachedSettingRepository"; +import BookmarkRepository from "../repositories/BookmarkRepository"; +import ConsoleClient from "../infrastructures/ConsoleClient"; +import ContentMessageClient from "../infrastructures/ContentMessageClient"; +import RepeatUseCase from "../usecases/RepeatUseCase"; @injectable() export default class CommandIndicator { constructor( - @inject('TabPresenter') private tabPresenter: TabPresenter, + @inject("TabPresenter") private tabPresenter: TabPresenter, private windowPresenter: WindowPresenter, private helpPresenter: HelpPresenter, - @inject("CachedSettingRepository") private cachedSettingRepository: CachedSettingRepository, + @inject("CachedSettingRepository") + private cachedSettingRepository: CachedSettingRepository, private bookmarkRepository: BookmarkRepository, private consoleClient: ConsoleClient, private contentMessageClient: ContentMessageClient, - private repeatUseCase: RepeatUseCase, - ) { - } + private repeatUseCase: RepeatUseCase + ) {} async open(keywords: string): Promise<browser.tabs.Tab> { const url = await this.urlOrSearch(keywords); @@ -67,14 +67,14 @@ export default class CommandIndicator { throw new RangeError(`tab ${index + 1} does not exist`); } return this.tabPresenter.select(tabs[index].id as number); - } else if (keywords.trim() === '%') { + } else if (keywords.trim() === "%") { // Select current window return; - } else if (keywords.trim() === '#') { + } else if (keywords.trim() === "#") { // Select last selected window const lastId = await this.tabPresenter.getLastSelectedId(); - if (typeof lastId === 'undefined' || lastId === null) { - throw new Error('No last selected tab'); + if (typeof lastId === "undefined" || lastId === null) { + throw new Error("No last selected tab"); } return this.tabPresenter.select(lastId); } @@ -82,7 +82,7 @@ export default class CommandIndicator { const current = await this.tabPresenter.getCurrent(); const tabs = await this.tabPresenter.getByKeyword(keywords, false); if (tabs.length === 0) { - throw new RangeError('No matching buffer for ' + keywords); + throw new RangeError("No matching buffer for " + keywords); } for (const tab of tabs) { if (tab.index > current.index) { @@ -96,9 +96,9 @@ export default class CommandIndicator { const excludePinned = !force; const tabs = await this.tabPresenter.getByKeyword(keywords, excludePinned); if (tabs.length === 0) { - throw new Error('No matching buffer for ' + keywords); + throw new Error("No matching buffer for " + keywords); } else if (tabs.length > 1) { - throw new Error('More than one match for ' + keywords); + throw new Error("More than one match for " + keywords); } return this.tabPresenter.remove([tabs[0].id as number]); } @@ -106,7 +106,7 @@ export default class CommandIndicator { async bdeletes(force: boolean, keywords: string): Promise<any> { const excludePinned = !force; const tabs = await this.tabPresenter.getByKeyword(keywords, excludePinned); - const ids = tabs.map(tab => tab.id as number); + const ids = tabs.map((tab) => tab.id as number); return this.tabPresenter.remove(ids); } @@ -117,14 +117,14 @@ export default class CommandIndicator { async quitAll(): Promise<any> { const tabs = await this.tabPresenter.getAll(); - const ids = tabs.map(tab => tab.id as number); + const ids = tabs.map((tab) => tab.id as number); this.tabPresenter.remove(ids); } async addbookmark(title: string): Promise<any> { const tab = await this.tabPresenter.getCurrent(); const item = await this.bookmarkRepository.create(title, tab.url as string); - const message = 'Saved current page: ' + item.url; + const message = "Saved current page: " + item.url; return this.consoleClient.showInfo(tab.id as number, message); } diff --git a/src/background/usecases/ConsoleUseCase.ts b/src/background/usecases/ConsoleUseCase.ts index 2de5bc1..195c70f 100644 --- a/src/background/usecases/ConsoleUseCase.ts +++ b/src/background/usecases/ConsoleUseCase.ts @@ -1,59 +1,57 @@ -import { inject, injectable } from 'tsyringe'; -import TabPresenter from '../presenters/TabPresenter'; -import ConsoleClient from '../infrastructures/ConsoleClient'; +import { inject, injectable } from "tsyringe"; +import TabPresenter from "../presenters/TabPresenter"; +import ConsoleClient from "../infrastructures/ConsoleClient"; @injectable() export default class ConsoleUseCase { - constructor( - @inject('TabPresenter') private tabPresenter: TabPresenter, - private consoleClient: ConsoleClient, - ) { - } + @inject("TabPresenter") private tabPresenter: TabPresenter, + private consoleClient: ConsoleClient + ) {} async showCommand(): Promise<any> { const tab = await this.tabPresenter.getCurrent(); - return this.consoleClient.showCommand(tab.id as number, ''); + return this.consoleClient.showCommand(tab.id as number, ""); } async showOpenCommand(alter: boolean): Promise<any> { const tab = await this.tabPresenter.getCurrent(); - let command = 'open '; + let command = "open "; if (alter) { - command += tab.url || ''; + command += tab.url || ""; } return this.consoleClient.showCommand(tab.id as number, command); } async showTabopenCommand(alter: boolean): Promise<any> { const tab = await this.tabPresenter.getCurrent(); - let command = 'tabopen '; + let command = "tabopen "; if (alter) { - command += tab.url || ''; + command += tab.url || ""; } return this.consoleClient.showCommand(tab.id as number, command); } async showWinopenCommand(alter: boolean): Promise<any> { const tab = await this.tabPresenter.getCurrent(); - let command = 'winopen '; + let command = "winopen "; if (alter) { - command += tab.url || ''; + command += tab.url || ""; } return this.consoleClient.showCommand(tab.id as number, command); } async showBufferCommand(): Promise<any> { const tab = await this.tabPresenter.getCurrent(); - const command = 'buffer '; + const command = "buffer "; return this.consoleClient.showCommand(tab.id as number, command); } async showAddbookmarkCommand(alter: boolean): Promise<any> { const tab = await this.tabPresenter.getCurrent(); - let command = 'addbookmark '; + let command = "addbookmark "; if (alter) { - command += tab.title || ''; + command += tab.title || ""; } return this.consoleClient.showCommand(tab.id as number, command); } diff --git a/src/background/usecases/FindUseCase.ts b/src/background/usecases/FindUseCase.ts index cb41cd5..facc461 100644 --- a/src/background/usecases/FindUseCase.ts +++ b/src/background/usecases/FindUseCase.ts @@ -1,16 +1,15 @@ -import { inject, injectable } from 'tsyringe'; -import FindRepository from '../repositories/FindRepository'; -import TabPresenter from '../presenters/TabPresenter'; -import ConsoleClient from '../infrastructures/ConsoleClient'; +import { inject, injectable } from "tsyringe"; +import FindRepository from "../repositories/FindRepository"; +import TabPresenter from "../presenters/TabPresenter"; +import ConsoleClient from "../infrastructures/ConsoleClient"; @injectable() export default class FindUseCase { constructor( - @inject('TabPresenter') private tabPresenter: TabPresenter, + @inject("TabPresenter") private tabPresenter: TabPresenter, private findRepository: FindRepository, - private consoleClient: ConsoleClient, - ) { - } + private consoleClient: ConsoleClient + ) {} getKeyword(): Promise<string> { return this.findRepository.getKeyword(); diff --git a/src/background/usecases/LinkUseCase.ts b/src/background/usecases/LinkUseCase.ts index be076c7..d2cd464 100644 --- a/src/background/usecases/LinkUseCase.ts +++ b/src/background/usecases/LinkUseCase.ts @@ -1,24 +1,23 @@ -import { inject, injectable } from 'tsyringe'; -import TabPresenter from '../presenters/TabPresenter'; +import { inject, injectable } from "tsyringe"; +import TabPresenter from "../presenters/TabPresenter"; @injectable() export default class LinkUseCase { - constructor( - @inject('TabPresenter') private tabPresenter: TabPresenter, - ) { - } + constructor(@inject("TabPresenter") private tabPresenter: TabPresenter) {} openToTab(url: string, tabId: number): Promise<any> { return this.tabPresenter.open(url, tabId); } async openNewTab( - url: string, openerId: number, background: boolean, + url: string, + openerId: number, + background: boolean ): Promise<any> { const properties: any = { active: !background }; const platform = await browser.runtime.getPlatformInfo(); - if (platform.os !== 'android') { + if (platform.os !== "android") { // openerTabId not supported on Android properties.openerTabId = openerId; } diff --git a/src/background/usecases/MarkUseCase.ts b/src/background/usecases/MarkUseCase.ts index 2c0bc13..9da9a21 100644 --- a/src/background/usecases/MarkUseCase.ts +++ b/src/background/usecases/MarkUseCase.ts @@ -1,18 +1,17 @@ -import { inject, injectable } from 'tsyringe'; -import TabPresenter from '../presenters/TabPresenter'; -import MarkRepository from '../repositories/MarkRepository'; -import ConsoleClient from '../infrastructures/ConsoleClient'; -import ContentMessageClient from '../infrastructures/ContentMessageClient'; +import { inject, injectable } from "tsyringe"; +import TabPresenter from "../presenters/TabPresenter"; +import MarkRepository from "../repositories/MarkRepository"; +import ConsoleClient from "../infrastructures/ConsoleClient"; +import ContentMessageClient from "../infrastructures/ContentMessageClient"; @injectable() export default class MarkUseCase { constructor( - @inject('TabPresenter') private tabPresenter: TabPresenter, + @inject("TabPresenter") private tabPresenter: TabPresenter, private markRepository: MarkRepository, private consoleClient: ConsoleClient, - private contentMessageClient: ContentMessageClient, - ) { - } + private contentMessageClient: ContentMessageClient + ) {} async setGlobal(key: string, x: number, y: number): Promise<any> { const tab = await this.tabPresenter.getCurrent(); @@ -26,7 +25,9 @@ export default class MarkUseCase { const mark = await this.markRepository.getMark(key); if (!mark) { return this.consoleClient.showError( - current.id as number, 'Mark is not set'); + current.id as number, + "Mark is not set" + ); } try { await this.contentMessageClient.scrollTo(mark.tabId, mark.x, mark.y); @@ -34,7 +35,10 @@ export default class MarkUseCase { } catch (e) { const tab = await this.tabPresenter.create(mark.url); return this.markRepository.setMark(key, { - tabId: tab.id as number, url: mark.url, x: mark.x, y: mark.y, + tabId: tab.id as number, + url: mark.url, + x: mark.x, + y: mark.y, }); } } diff --git a/src/background/usecases/NavigateUseCase.ts b/src/background/usecases/NavigateUseCase.ts index 3aa1ed6..2e887e7 100644 --- a/src/background/usecases/NavigateUseCase.ts +++ b/src/background/usecases/NavigateUseCase.ts @@ -1,14 +1,13 @@ -import { inject, injectable } from 'tsyringe'; -import NavigateClient from '../clients/NavigateClient'; -import TabPresenter from '../presenters/TabPresenter'; +import { inject, injectable } from "tsyringe"; +import NavigateClient from "../clients/NavigateClient"; +import TabPresenter from "../presenters/TabPresenter"; @injectable() export default class NavigateUseCase { constructor( - @inject('TabPresenter') private tabPresenter: TabPresenter, - private navigateClient: NavigateClient, - ) { - } + @inject("TabPresenter") private tabPresenter: TabPresenter, + private navigateClient: NavigateClient + ) {} async openHistoryNext(): Promise<void> { const tab = await this.tabPresenter.getCurrent(); @@ -34,16 +33,16 @@ export default class NavigateUseCase { const tab = await this.tabPresenter.getCurrent(); const url = new URL(tab.url!!); if (url.hash.length > 0) { - url.hash = ''; + url.hash = ""; } else if (url.search.length > 0) { - url.search = ''; + url.search = ""; } else { const basenamePattern = /\/[^/]+$/; const lastDirPattern = /\/[^/]+\/$/; if (basenamePattern.test(url.pathname)) { - url.pathname = url.pathname.replace(basenamePattern, '/'); + url.pathname = url.pathname.replace(basenamePattern, "/"); } else if (lastDirPattern.test(url.pathname)) { - url.pathname = url.pathname.replace(lastDirPattern, '/'); + url.pathname = url.pathname.replace(lastDirPattern, "/"); } } await this.tabPresenter.open(url.href); diff --git a/src/background/usecases/RepeatUseCase.ts b/src/background/usecases/RepeatUseCase.ts index d78de34..d7235ee 100644 --- a/src/background/usecases/RepeatUseCase.ts +++ b/src/background/usecases/RepeatUseCase.ts @@ -1,15 +1,12 @@ -import { injectable } from 'tsyringe'; -import * as operations from '../../shared/operations'; -import RepeatRepository from '../repositories/RepeatRepository'; +import { injectable } from "tsyringe"; +import * as operations from "../../shared/operations"; +import RepeatRepository from "../repositories/RepeatRepository"; type Operation = operations.Operation; @injectable() export default class RepeatUseCase { - constructor( - private repeatRepository: RepeatRepository, - ) { - } + constructor(private repeatRepository: RepeatRepository) {} storeLastOperation(op: Operation): void { this.repeatRepository.setLastOperation(op); @@ -22,28 +19,28 @@ export default class RepeatUseCase { // eslint-disable-next-line complexity isRepeatable(op: Operation): boolean { switch (op.type) { - case operations.NAVIGATE_HISTORY_PREV: - case operations.NAVIGATE_HISTORY_NEXT: - case operations.NAVIGATE_LINK_PREV: - case operations.NAVIGATE_LINK_NEXT: - case operations.NAVIGATE_PARENT: - case operations.NAVIGATE_ROOT: - case operations.PAGE_SOURCE: - case operations.PAGE_HOME: - case operations.TAB_CLOSE: - case operations.TAB_CLOSE_FORCE: - case operations.TAB_CLOSE_RIGHT: - case operations.TAB_REOPEN: - case operations.TAB_RELOAD: - case operations.TAB_PIN: - case operations.TAB_UNPIN: - case operations.TAB_TOGGLE_PINNED: - case operations.TAB_DUPLICATE: - case operations.ZOOM_IN: - case operations.ZOOM_OUT: - case operations.ZOOM_NEUTRAL: - case operations.INTERNAL_OPEN_URL: - return true; + case operations.NAVIGATE_HISTORY_PREV: + case operations.NAVIGATE_HISTORY_NEXT: + case operations.NAVIGATE_LINK_PREV: + case operations.NAVIGATE_LINK_NEXT: + case operations.NAVIGATE_PARENT: + case operations.NAVIGATE_ROOT: + case operations.PAGE_SOURCE: + case operations.PAGE_HOME: + case operations.TAB_CLOSE: + case operations.TAB_CLOSE_FORCE: + case operations.TAB_CLOSE_RIGHT: + case operations.TAB_REOPEN: + case operations.TAB_RELOAD: + case operations.TAB_PIN: + case operations.TAB_UNPIN: + case operations.TAB_TOGGLE_PINNED: + case operations.TAB_DUPLICATE: + case operations.ZOOM_IN: + case operations.ZOOM_OUT: + case operations.ZOOM_NEUTRAL: + case operations.INTERNAL_OPEN_URL: + return true; } return false; } diff --git a/src/background/usecases/SettingUseCase.ts b/src/background/usecases/SettingUseCase.ts index 69b4572..ccee227 100644 --- a/src/background/usecases/SettingUseCase.ts +++ b/src/background/usecases/SettingUseCase.ts @@ -1,20 +1,21 @@ -import {inject, injectable} from 'tsyringe'; -import CachedSettingRepository from '../repositories/CachedSettingRepository'; -import SettingData, {DefaultSettingData} from '../../shared/SettingData'; -import Settings from '../../shared/settings/Settings'; -import Notifier from '../presenters/Notifier'; +import { inject, injectable } from "tsyringe"; +import CachedSettingRepository from "../repositories/CachedSettingRepository"; +import SettingData, { DefaultSettingData } from "../../shared/SettingData"; +import Settings from "../../shared/settings/Settings"; +import Notifier from "../presenters/Notifier"; import SettingRepository from "../repositories/SettingRepository"; @injectable() export default class SettingUseCase { - constructor( - @inject("LocalSettingRepository") private localSettingRepository: SettingRepository, - @inject("SyncSettingRepository") private syncSettingRepository: SettingRepository, - @inject("CachedSettingRepository") private cachedSettingRepository: CachedSettingRepository, - @inject("Notifier") private notifier: Notifier, - ) { - } + @inject("LocalSettingRepository") + private localSettingRepository: SettingRepository, + @inject("SyncSettingRepository") + private syncSettingRepository: SettingRepository, + @inject("CachedSettingRepository") + private cachedSettingRepository: CachedSettingRepository, + @inject("Notifier") private notifier: Notifier + ) {} getCached(): Promise<Settings> { return this.cachedSettingRepository.get(); @@ -42,7 +43,7 @@ export default class SettingUseCase { private async loadSettings(): Promise<SettingData> { const sync = await this.syncSettingRepository.load(); if (sync) { - return sync; + return sync; } const local = await this.localSettingRepository.load(); if (local) { @@ -52,7 +53,7 @@ export default class SettingUseCase { } private showUnableToLoad(e: Error) { - console.error('unable to load settings', e); + console.error("unable to load settings", e); this.notifier.notifyInvalidSettings(() => { browser.runtime.openOptionsPage(); }); diff --git a/src/background/usecases/TabSelectUseCase.ts b/src/background/usecases/TabSelectUseCase.ts index 271bb6c..663ceb8 100644 --- a/src/background/usecases/TabSelectUseCase.ts +++ b/src/background/usecases/TabSelectUseCase.ts @@ -1,19 +1,16 @@ -import { inject, injectable } from 'tsyringe'; -import TabPresenter from '../presenters/TabPresenter'; +import { inject, injectable } from "tsyringe"; +import TabPresenter from "../presenters/TabPresenter"; @injectable() export default class TabSelectUseCase { - constructor( - @inject('TabPresenter') private tabPresenter: TabPresenter, - ) { - } + constructor(@inject("TabPresenter") private tabPresenter: TabPresenter) {} async selectPrev(count: number): Promise<any> { const tabs = await this.tabPresenter.getAll(); if (tabs.length < 2) { return; } - const tab = tabs.find(t => t.active); + const tab = tabs.find((t) => t.active); if (!tab) { return; } @@ -26,7 +23,7 @@ export default class TabSelectUseCase { if (tabs.length < 2) { return; } - const tab = tabs.find(t => t.active); + const tab = tabs.find((t) => t.active); if (!tab) { return; } @@ -46,7 +43,7 @@ export default class TabSelectUseCase { async selectPrevSelected(): Promise<any> { const tabId = await this.tabPresenter.getLastSelectedId(); - if (tabId === null || typeof tabId === 'undefined') { + if (tabId === null || typeof tabId === "undefined") { return Promise.resolve(); } return this.tabPresenter.select(tabId); diff --git a/src/background/usecases/TabUseCase.ts b/src/background/usecases/TabUseCase.ts index 418dde5..1439107 100644 --- a/src/background/usecases/TabUseCase.ts +++ b/src/background/usecases/TabUseCase.ts @@ -1,16 +1,15 @@ -import {inject, injectable} from 'tsyringe'; -import TabPresenter from '../presenters/TabPresenter'; -import WindowPresenter from '../presenters/WindowPresenter'; -import BrowserSettingRepository from '../repositories/BrowserSettingRepository'; +import { inject, injectable } from "tsyringe"; +import TabPresenter from "../presenters/TabPresenter"; +import WindowPresenter from "../presenters/WindowPresenter"; +import BrowserSettingRepository from "../repositories/BrowserSettingRepository"; @injectable() export default class TabUseCase { constructor( - @inject('TabPresenter') private tabPresenter: TabPresenter, + @inject("TabPresenter") private tabPresenter: TabPresenter, private windowPresenter: WindowPresenter, - private browserSettingRepository: BrowserSettingRepository, - ) { - } + private browserSettingRepository: BrowserSettingRepository + ) {} async close(force: boolean, selectLeft = false): Promise<any> { const tab = await this.tabPresenter.getCurrent(); @@ -27,7 +26,7 @@ export default class TabUseCase { async closeRight(): Promise<any> { const tabs = await this.tabPresenter.getAll(); tabs.sort((t1, t2) => t1.index - t2.index); - const index = tabs.findIndex(t => t.active); + const index = tabs.findIndex((t) => t.active); if (index < 0) { return; } @@ -65,16 +64,18 @@ export default class TabUseCase { async openPageSource(): Promise<any> { const tab = await this.tabPresenter.getCurrent(); - const url = 'view-source:' + tab.url; + const url = "view-source:" + tab.url; return this.tabPresenter.create(url); } async openHome(newTab: boolean): Promise<any> { const tab = await this.tabPresenter.getCurrent(); const urls = await this.browserSettingRepository.getHomepageUrls(); - if (urls.length === 1 && urls[0] === 'about:home') { + if (urls.length === 1 && urls[0] === "about:home") { // eslint-disable-next-line max-len - throw new Error('Cannot open Firefox Home (about:home) by WebExtensions, set your custom URLs'); + throw new Error( + "Cannot open Firefox Home (about:home) by WebExtensions, set your custom URLs" + ); } if (urls.length === 1 && !newTab) { return this.tabPresenter.open(urls[0], tab.id); @@ -85,7 +86,9 @@ export default class TabUseCase { } async openURL( - url: string, newTab?: boolean, newWindow?: boolean, + url: string, + newTab?: boolean, + newWindow?: boolean ): Promise<void> { if (newWindow) { await this.windowPresenter.create(url); diff --git a/src/background/usecases/VersionUseCase.ts b/src/background/usecases/VersionUseCase.ts index 21a5e2c..74df8a8 100644 --- a/src/background/usecases/VersionUseCase.ts +++ b/src/background/usecases/VersionUseCase.ts @@ -1,14 +1,13 @@ -import { injectable, inject } from 'tsyringe'; -import TabPresenter from '../presenters/TabPresenter'; -import Notifier from '../presenters/Notifier'; +import { injectable, inject } from "tsyringe"; +import TabPresenter from "../presenters/TabPresenter"; +import Notifier from "../presenters/Notifier"; @injectable() export default class VersionUseCase { constructor( - @inject('TabPresenter') private tabPresenter: TabPresenter, - @inject("Notifier") private notifier: Notifier, - ) { - } + @inject("TabPresenter") private tabPresenter: TabPresenter, + @inject("Notifier") private notifier: Notifier + ) {} notify(): Promise<void> { const manifest = browser.runtime.getManifest(); @@ -22,6 +21,6 @@ export default class VersionUseCase { if (version) { return `https://github.com/ueokande/vim-vixen/releases/tag/${version}`; } - return 'https://github.com/ueokande/vim-vixen/releases/'; + return "https://github.com/ueokande/vim-vixen/releases/"; } } diff --git a/src/background/usecases/ZoomUseCase.ts b/src/background/usecases/ZoomUseCase.ts index ca1368d..173e4d7 100644 --- a/src/background/usecases/ZoomUseCase.ts +++ b/src/background/usecases/ZoomUseCase.ts @@ -1,23 +1,32 @@ -import { inject, injectable } from 'tsyringe'; -import TabPresenter from '../presenters/TabPresenter'; +import { inject, injectable } from "tsyringe"; +import TabPresenter from "../presenters/TabPresenter"; const ZOOM_SETTINGS: number[] = [ - 0.33, 0.50, 0.66, 0.75, 0.80, 0.90, 1.00, - 1.10, 1.25, 1.50, 1.75, 2.00, 2.50, 3.00 + 0.33, + 0.5, + 0.66, + 0.75, + 0.8, + 0.9, + 1.0, + 1.1, + 1.25, + 1.5, + 1.75, + 2.0, + 2.5, + 3.0, ]; @injectable() export default class ZoomUseCase { - constructor( - @inject('TabPresenter') private tabPresenter: TabPresenter, - ) { - } + constructor(@inject("TabPresenter") private tabPresenter: TabPresenter) {} async zoomIn(): Promise<any> { const tab = await this.tabPresenter.getCurrent(); const tabId = tab.id as number; const current = await this.tabPresenter.getZoom(tabId); - const factor = ZOOM_SETTINGS.find(f => f > current); + const factor = ZOOM_SETTINGS.find((f) => f > current); if (factor) { return this.tabPresenter.setZoom(tabId as number, factor); } @@ -27,7 +36,9 @@ export default class ZoomUseCase { const tab = await this.tabPresenter.getCurrent(); const tabId = tab.id as number; const current = await this.tabPresenter.getZoom(tabId); - const factor = ZOOM_SETTINGS.slice(0).reverse().find(f => f < current); + const factor = ZOOM_SETTINGS.slice(0) + .reverse() + .find((f) => f < current); if (factor) { return this.tabPresenter.setZoom(tabId as number, factor); } diff --git a/src/background/usecases/parsers.ts b/src/background/usecases/parsers.ts index 99ff2eb..23a6193 100644 --- a/src/background/usecases/parsers.ts +++ b/src/background/usecases/parsers.ts @@ -1,36 +1,39 @@ -import Properties from '../../shared/settings/Properties'; +import Properties from "../../shared/settings/Properties"; const mustNumber = (v: any): number => { const num = Number(v); if (isNaN(num)) { - throw new Error('Not number: ' + v); + throw new Error("Not number: " + v); } return num; }; -const parseSetOption = ( - args: string, -): any[] => { - let [key, value]: any[] = args.split('='); +const parseSetOption = (args: string): any[] => { + let [key, value]: any[] = args.split("="); if (value === undefined) { - value = !key.startsWith('no'); + value = !key.startsWith("no"); key = value ? key : key.slice(2); } const def = Properties.def(key); if (!def) { - throw new Error('Unknown property: ' + key); + throw new Error("Unknown property: " + key); } - if (def.type === 'boolean' && typeof value !== 'boolean' || - def.type !== 'boolean' && typeof value === 'boolean') { - throw new Error('Invalid argument: ' + args); + if ( + (def.type === "boolean" && typeof value !== "boolean") || + (def.type !== "boolean" && typeof value === "boolean") + ) { + throw new Error("Invalid argument: " + args); } switch (def.type) { - case 'string': return [key, value]; - case 'number': return [key, mustNumber(value)]; - case 'boolean': return [key, value]; - default: - throw new Error('Unknown property type: ' + def.type); + case "string": + return [key, value]; + case "number": + return [key, mustNumber(value)]; + case "boolean": + return [key, value]; + default: + throw new Error("Unknown property type: " + def.type); } }; diff --git a/src/console/Completions.ts b/src/console/Completions.ts index ec9135f..a18f160 100644 --- a/src/console/Completions.ts +++ b/src/console/Completions.ts @@ -1,11 +1,11 @@ type Completions = { - readonly name: string; - readonly items: { - readonly caption?: string; - readonly content?: string; - readonly url?: string; - readonly icon?: string; - }[]; -}[] + readonly name: string; + readonly items: { + readonly caption?: string; + readonly content?: string; + readonly url?: string; + readonly icon?: string; + }[]; +}[]; -export default Completions;
\ No newline at end of file +export default Completions; diff --git a/src/console/actions/console.ts b/src/console/actions/console.ts index e44c974..205676b 100644 --- a/src/console/actions/console.ts +++ b/src/console/actions/console.ts @@ -1,6 +1,6 @@ -import * as messages from '../../shared/messages'; -import * as actions from './index'; -import {Command} from "../../shared/Command"; +import * as messages from "../../shared/messages"; +import * as actions from "./index"; +import { Command } from "../../shared/Command"; import CompletionClient from "../clients/CompletionClient"; import CompletionType from "../../shared/CompletionType"; import Completions from "../Completions"; @@ -9,23 +9,23 @@ import TabFlag from "../../shared/TabFlag"; const completionClient = new CompletionClient(); const commandDocs = { - [Command.Set]: 'Set a value of the property', - [Command.Open]: 'Open a URL or search by keywords in current tab', - [Command.TabOpen]: 'Open a URL or search by keywords in new tab', - [Command.WindowOpen]: 'Open a URL or search by keywords in new window', - [Command.Buffer]: 'Select tabs by matched keywords', - [Command.BufferDelete]: 'Close a certain tab matched by keywords', - [Command.BuffersDelete]: 'Close all tabs matched by keywords', - [Command.Quit]: 'Close the current tab', - [Command.QuitAll]: 'Close all tabs', - [Command.AddBookmark]: 'Add current page to bookmarks', - [Command.Help]: 'Open Vim Vixen help in new tab', + [Command.Set]: "Set a value of the property", + [Command.Open]: "Open a URL or search by keywords in current tab", + [Command.TabOpen]: "Open a URL or search by keywords in new tab", + [Command.WindowOpen]: "Open a URL or search by keywords in new window", + [Command.Buffer]: "Select tabs by matched keywords", + [Command.BufferDelete]: "Close a certain tab matched by keywords", + [Command.BuffersDelete]: "Close all tabs matched by keywords", + [Command.Quit]: "Close the current tab", + [Command.QuitAll]: "Close all tabs", + [Command.AddBookmark]: "Add current page to bookmarks", + [Command.Help]: "Open Vim Vixen help in new tab", }; -const propertyDocs: {[key: string]: string} = { - 'hintchars': 'hint characters on follow mode', - 'smoothscroll': 'smooth scroll', - 'complete': 'which are completed at the open page', +const propertyDocs: { [key: string]: string } = { + hintchars: "hint characters on follow mode", + smoothscroll: "smooth scroll", + complete: "which are completed at the open page", }; const hide = (): actions.ConsoleAction => { @@ -52,27 +52,32 @@ const showFind = (): actions.ShowFindAction => { const showError = (text: string): actions.ShowErrorAction => { return { type: actions.CONSOLE_SHOW_ERROR, - text: text + text: text, }; }; const showInfo = (text: string): actions.ShowInfoAction => { return { type: actions.CONSOLE_SHOW_INFO, - text: text + text: text, }; }; const hideCommand = (): actions.HideCommandAction => { - window.top.postMessage(JSON.stringify({ - type: messages.CONSOLE_UNFOCUS, - }), '*'); + window.top.postMessage( + JSON.stringify({ + type: messages.CONSOLE_UNFOCUS, + }), + "*" + ); return { type: actions.CONSOLE_HIDE_COMMAND, }; }; -const enterCommand = async(text: string): Promise<actions.HideCommandAction> => { +const enterCommand = async ( + text: string +): Promise<actions.HideCommandAction> => { await browser.runtime.sendMessage({ type: messages.CONSOLE_ENTER_COMMAND, text, @@ -81,10 +86,13 @@ const enterCommand = async(text: string): Promise<actions.HideCommandAction> => }; const enterFind = (text?: string): actions.HideCommandAction => { - window.top.postMessage(JSON.stringify({ - type: messages.CONSOLE_ENTER_FIND, - text, - }), '*'); + window.top.postMessage( + JSON.stringify({ + type: messages.CONSOLE_ENTER_FIND, + text, + }), + "*" + ); return hideCommand(); }; @@ -97,25 +105,30 @@ const setConsoleText = (consoleText: string): actions.SetConsoleTextAction => { const getCommandCompletions = (text: string): actions.SetCompletionsAction => { const items = Object.entries(commandDocs) - .filter(([name]) => name.startsWith(text.trimLeft())) - .map(([name, doc]) => ({ - caption: name, - content: name, - url: doc, - })); - const completions = [{ - name: "Console Command", - items, - }]; + .filter(([name]) => name.startsWith(text.trimLeft())) + .map(([name, doc]) => ({ + caption: name, + content: name, + url: doc, + })); + const completions = [ + { + name: "Console Command", + items, + }, + ]; return { type: actions.CONSOLE_SET_COMPLETIONS, completions, completionSource: text, - } + }; }; -const getOpenCompletions = async( - types: CompletionType[], original: string, command: Command, query: string, +const getOpenCompletions = async ( + types: CompletionType[], + original: string, + command: Command, + query: string ): Promise<actions.SetCompletionsAction> => { const completions: Completions = []; for (const type of types) { @@ -126,11 +139,11 @@ const getOpenCompletions = async( break; } completions.push({ - name: 'Search Engines', - items: items.map(key => ({ + name: "Search Engines", + items: items.map((key) => ({ caption: key.title, - content: command + ' ' + key.title, - })) + content: command + " " + key.title, + })), }); break; } @@ -140,11 +153,11 @@ const getOpenCompletions = async( break; } completions.push({ - name: 'History', - items: items.map(item => ({ + name: "History", + items: items.map((item) => ({ caption: item.title, - content: command + ' ' + item.url, - url: item.url + content: command + " " + item.url, + url: item.url, })), }); break; @@ -155,12 +168,12 @@ const getOpenCompletions = async( break; } completions.push({ - name: 'Bookmarks', - items: items.map(item => ({ + name: "Bookmarks", + items: items.map((item) => ({ caption: item.title, - content: command + ' ' + item.url, - url: item.url - })) + content: command + " " + item.url, + url: item.url, + })), }); break; } @@ -175,61 +188,75 @@ const getOpenCompletions = async( }; const getTabCompletions = async ( - original: string, command: Command, query: string, excludePinned: boolean, + original: string, + command: Command, + query: string, + excludePinned: boolean ): Promise<actions.SetCompletionsAction> => { - const items = await completionClient.requestTabs(query, excludePinned); - let completions: Completions = []; - if (items.length > 0) { - completions = [{ - name: 'Buffers', - items: items.map(item => ({ - content: command + ' ' + item.url, - caption: `${item.index}: ${item.flag != TabFlag.None ? item.flag : ' ' } ${item.title}`, + const items = await completionClient.requestTabs(query, excludePinned); + let completions: Completions = []; + if (items.length > 0) { + completions = [ + { + name: "Buffers", + items: items.map((item) => ({ + content: command + " " + item.url, + caption: `${item.index}: ${ + item.flag != TabFlag.None ? item.flag : " " + } ${item.title}`, url: item.url, icon: item.faviconUrl, })), - }]; - } - return { - type: actions.CONSOLE_SET_COMPLETIONS, - completions, - completionSource: original, - } + }, + ]; + } + return { + type: actions.CONSOLE_SET_COMPLETIONS, + completions, + completionSource: original, + }; }; -const getPropertyCompletions = async( - original: string, command: Command, query: string, +const getPropertyCompletions = async ( + original: string, + command: Command, + query: string ): Promise<actions.SetCompletionsAction> => { const properties = await completionClient.getProperties(); const items = properties - .map(item => { - const desc = propertyDocs[item.name] || ''; - if (item.type === 'boolean') { - return [{ + .map((item) => { + const desc = propertyDocs[item.name] || ""; + if (item.type === "boolean") { + return [ + { caption: item.name, - content: command + ' ' + item.name, - url: 'Enable ' + desc, - }, { - caption: 'no' + item.name, - content: command + ' no' + item.name, - url: 'Disable ' + desc, - }]; - } else { - return [{ + content: command + " " + item.name, + url: "Enable " + desc, + }, + { + caption: "no" + item.name, + content: command + " no" + item.name, + url: "Disable " + desc, + }, + ]; + } else { + return [ + { caption: item.name, - content: name + ' ' + item.name, - url: 'Set ' + desc, - }]; - } - }) - .reduce((acc, val) => acc.concat(val), []) - .filter(item => item.caption.startsWith(query)); - const completions: Completions = [{ name: 'Properties', items }]; + content: name + " " + item.name, + url: "Set " + desc, + }, + ]; + } + }) + .reduce((acc, val) => acc.concat(val), []) + .filter((item) => item.caption.startsWith(query)); + const completions: Completions = [{ name: "Properties", items }]; return { type: actions.CONSOLE_SET_COMPLETIONS, completions, completionSource: original, - } + }; }; const completionNext = (): actions.CompletionNextAction => { @@ -245,7 +272,19 @@ const completionPrev = (): actions.CompletionPrevAction => { }; export { - hide, showCommand, showFind, showError, showInfo, hideCommand, setConsoleText, enterCommand, enterFind, - getCommandCompletions, getOpenCompletions, getTabCompletions, getPropertyCompletions, - completionNext, completionPrev, + hide, + showCommand, + showFind, + showError, + showInfo, + hideCommand, + setConsoleText, + enterCommand, + enterFind, + getCommandCompletions, + getOpenCompletions, + getTabCompletions, + getPropertyCompletions, + completionNext, + completionPrev, }; diff --git a/src/console/actions/index.ts b/src/console/actions/index.ts index e292608..308a093 100644 --- a/src/console/actions/index.ts +++ b/src/console/actions/index.ts @@ -1,16 +1,16 @@ import Completions from "../Completions"; import CompletionType from "../../shared/CompletionType"; -export const CONSOLE_HIDE = 'console.hide'; -export const CONSOLE_SHOW_COMMAND = 'console.show.command'; -export const CONSOLE_SHOW_ERROR = 'console.show.error'; -export const CONSOLE_SHOW_INFO = 'console.show.info'; -export const CONSOLE_HIDE_COMMAND = 'console.hide.command'; -export const CONSOLE_SET_CONSOLE_TEXT = 'console.set.command'; -export const CONSOLE_SET_COMPLETIONS = 'console.set.completions'; -export const CONSOLE_COMPLETION_NEXT = 'console.completion.next'; -export const CONSOLE_COMPLETION_PREV = 'console.completion.prev'; -export const CONSOLE_SHOW_FIND = 'console.show.find'; +export const CONSOLE_HIDE = "console.hide"; +export const CONSOLE_SHOW_COMMAND = "console.show.command"; +export const CONSOLE_SHOW_ERROR = "console.show.error"; +export const CONSOLE_SHOW_INFO = "console.show.info"; +export const CONSOLE_HIDE_COMMAND = "console.hide.command"; +export const CONSOLE_SET_CONSOLE_TEXT = "console.set.command"; +export const CONSOLE_SET_COMPLETIONS = "console.set.completions"; +export const CONSOLE_COMPLETION_NEXT = "console.completion.next"; +export const CONSOLE_COMPLETION_PREV = "console.completion.prev"; +export const CONSOLE_SHOW_FIND = "console.show.find"; export interface HideAction { type: typeof CONSOLE_HIDE; @@ -60,7 +60,13 @@ export interface CompletionPrevAction { } export type ConsoleAction = - HideAction | ShowCommand | ShowFindAction | ShowErrorAction | - ShowInfoAction | HideCommandAction | SetConsoleTextAction | - SetCompletionsAction | CompletionNextAction | CompletionPrevAction; - + | HideAction + | ShowCommand + | ShowFindAction + | ShowErrorAction + | ShowInfoAction + | HideCommandAction + | SetConsoleTextAction + | SetCompletionsAction + | CompletionNextAction + | CompletionPrevAction; diff --git a/src/console/clients/CompletionClient.ts b/src/console/clients/CompletionClient.ts index 56dc665..64119e8 100644 --- a/src/console/clients/CompletionClient.ts +++ b/src/console/clients/CompletionClient.ts @@ -1,84 +1,87 @@ import * as messages from "../../shared/messages"; import { - ConsoleGetCompletionTypesResponse, ConsoleGetPropertiesResponse, + ConsoleGetCompletionTypesResponse, + ConsoleGetPropertiesResponse, ConsoleRequestBookmarksResponse, - ConsoleRequestHistoryResponse, ConsoleRequestSearchEnginesResponse, ConsoleRequesttabsResponse + ConsoleRequestHistoryResponse, + ConsoleRequestSearchEnginesResponse, + ConsoleRequesttabsResponse, } from "../../shared/messages"; import CompletionType from "../../shared/CompletionType"; import TabFlag from "../../shared/TabFlag"; export type SearchEngines = { - title: string -} + title: string; +}; export type BookmarkItem = { - title: string - url: string -} + title: string; + url: string; +}; export type HistoryItem = { - title: string - url: string -} + title: string; + url: string; +}; export type TabItem = { - index: number - flag: TabFlag - title: string - url: string - faviconUrl?: string -} + index: number; + flag: TabFlag; + title: string; + url: string; + faviconUrl?: string; +}; export type Property = { - name: string - type: 'string' | 'boolean' | 'number'; -} + name: string; + type: "string" | "boolean" | "number"; +}; export default class CompletionClient { async getCompletionTypes(): Promise<CompletionType[]> { - const resp = await browser.runtime.sendMessage({ + const resp = (await browser.runtime.sendMessage({ type: messages.CONSOLE_GET_COMPLETION_TYPES, - }) as ConsoleGetCompletionTypesResponse; + })) as ConsoleGetCompletionTypesResponse; return resp; } async requestSearchEngines(query: string): Promise<SearchEngines[]> { - const resp = await browser.runtime.sendMessage({ + const resp = (await browser.runtime.sendMessage({ type: messages.CONSOLE_REQUEST_SEARCH_ENGINES_MESSAGE, query, - }) as ConsoleRequestSearchEnginesResponse; + })) as ConsoleRequestSearchEnginesResponse; return resp; } async requestBookmarks(query: string): Promise<BookmarkItem[]> { - const resp = await browser.runtime.sendMessage({ + const resp = (await browser.runtime.sendMessage({ type: messages.CONSOLE_REQUEST_BOOKMARKS, query, - }) as ConsoleRequestBookmarksResponse; + })) as ConsoleRequestBookmarksResponse; return resp; } async requestHistory(query: string): Promise<HistoryItem[]> { - const resp = await browser.runtime.sendMessage({ + const resp = (await browser.runtime.sendMessage({ type: messages.CONSOLE_REQUEST_HISTORY, query, - }) as ConsoleRequestHistoryResponse; + })) as ConsoleRequestHistoryResponse; return resp; } async requestTabs(query: string, excludePinned: boolean): Promise<TabItem[]> { - const resp = await browser.runtime.sendMessage({ + const resp = (await browser.runtime.sendMessage({ type: messages.CONSOLE_REQUEST_TABS, query, excludePinned, - }) as ConsoleRequesttabsResponse; + })) as ConsoleRequesttabsResponse; return resp; } async getProperties(): Promise<Property[]> { - const resp = await browser.runtime.sendMessage({ + const resp = (await browser.runtime.sendMessage({ type: messages.CONSOLE_GET_PROPERTIES, - }) as ConsoleGetPropertiesResponse; + })) as ConsoleGetPropertiesResponse; return resp; } } diff --git a/src/console/commandline/CommandLineParser.ts b/src/console/commandline/CommandLineParser.ts index a166f49..ffff375 100644 --- a/src/console/commandline/CommandLineParser.ts +++ b/src/console/commandline/CommandLineParser.ts @@ -2,9 +2,9 @@ import CommandParser from "./CommandParser"; import { Command } from "../../shared/Command"; export type CommandLine = { - readonly command: Command, - readonly args: string -} + readonly command: Command; + readonly args: string; +}; export enum InputPhase { OnCommand, @@ -17,11 +17,11 @@ export default class CommandLineParser { inputPhase(line: string): InputPhase { line = line.trimLeft(); if (line.length == 0) { - return InputPhase.OnCommand + return InputPhase.OnCommand; } const command = line.split(/\s+/, 1)[0]; if (line.length == command.length) { - return InputPhase.OnCommand + return InputPhase.OnCommand; } return InputPhase.OnArgs; } @@ -33,6 +33,6 @@ export default class CommandLineParser { return { command: this.commandParser.parse(command), args: args, - } + }; } } diff --git a/src/console/commandline/CommandParser.ts b/src/console/commandline/CommandParser.ts index 5228c77..7488cbc 100644 --- a/src/console/commandline/CommandParser.ts +++ b/src/console/commandline/CommandParser.ts @@ -9,43 +9,43 @@ export class UnknownCommandError extends Error { export default class CommandParser { parse(value: string): Command { switch (value) { - case 'o': - case 'open': - return Command.Open; - case 't': - case 'tabopen': - return Command.TabOpen; - case 'w': - case 'winopen': - return Command.WindowOpen; - case 'b': - case 'buffer': - return Command.Buffer; - case 'bd': - case 'bdel': - case 'bdelete': - return Command.BufferDelete; - case 'bd!': - case 'bdel!': - case 'bdelete!': - return Command.BufferDeleteForce; - case 'bdeletes': - return Command.BuffersDelete; - case 'bdeletes!': - return Command.BuffersDeleteForce; - case 'addbookmark': - return Command.AddBookmark; - case 'q': - case 'quit': - return Command.Quit; - case 'qa': - case 'quitall': - return Command.QuitAll; - case 'set': - return Command.Set; - case 'h': - case 'help': - return Command.Help; + case "o": + case "open": + return Command.Open; + case "t": + case "tabopen": + return Command.TabOpen; + case "w": + case "winopen": + return Command.WindowOpen; + case "b": + case "buffer": + return Command.Buffer; + case "bd": + case "bdel": + case "bdelete": + return Command.BufferDelete; + case "bd!": + case "bdel!": + case "bdelete!": + return Command.BufferDeleteForce; + case "bdeletes": + return Command.BuffersDelete; + case "bdeletes!": + return Command.BuffersDeleteForce; + case "addbookmark": + return Command.AddBookmark; + case "q": + case "quit": + return Command.Quit; + case "qa": + case "quitall": + return Command.QuitAll; + case "set": + return Command.Set; + case "h": + case "help": + return Command.Help; } throw new UnknownCommandError(value); } diff --git a/src/console/components/Console.tsx b/src/console/components/Console.tsx index 3fe5cee..d74040d 100644 --- a/src/console/components/Console.tsx +++ b/src/console/components/Console.tsx @@ -1,19 +1,21 @@ -import './console.scss'; -import { connect } from 'react-redux'; -import React from 'react'; -import Input from './console/Input'; -import Completion from './console/Completion'; -import Message from './console/Message'; -import * as consoleActions from '../../console/actions/console'; -import { State as AppState } from '../reducers'; -import CommandLineParser, { InputPhase } from "../commandline/CommandLineParser"; +import "./console.scss"; +import { connect } from "react-redux"; +import React from "react"; +import Input from "./console/Input"; +import Completion from "./console/Completion"; +import Message from "./console/Message"; +import * as consoleActions from "../../console/actions/console"; +import { State as AppState } from "../reducers"; +import CommandLineParser, { + InputPhase, +} from "../commandline/CommandLineParser"; import { Command } from "../../shared/Command"; const COMPLETION_MAX_ITEMS = 33; type StateProps = ReturnType<typeof mapStateToProps>; interface DispatchProps { - dispatch: (action: any) => void, + dispatch: (action: any) => void; } type Props = StateProps & DispatchProps; @@ -29,7 +31,7 @@ class Console extends React.Component<Props> { } onBlur() { - if (this.props.mode === 'command' || this.props.mode === 'find') { + if (this.props.mode === "command" || this.props.mode === "find") { return this.props.dispatch(consoleActions.hideCommand()); } } @@ -39,11 +41,12 @@ class Console extends React.Component<Props> { e.preventDefault(); const value = (e.target as HTMLInputElement).value; - if (this.props.mode === 'command') { + if (this.props.mode === "command") { return this.props.dispatch(consoleActions.enterCommand(value)); - } else if (this.props.mode === 'find') { - return this.props.dispatch(consoleActions.enterFind( - value === '' ? undefined : value)); + } else if (this.props.mode === "find") { + return this.props.dispatch( + consoleActions.enterFind(value === "" ? undefined : value) + ); } } @@ -61,94 +64,95 @@ class Console extends React.Component<Props> { onKeyDown(e: React.KeyboardEvent<HTMLInputElement>) { switch (e.key) { - case 'Escape': - return this.props.dispatch(consoleActions.hideCommand()); - case 'Enter': - return this.doEnter(e); - case 'Tab': - if (e.shiftKey) { - this.props.dispatch(consoleActions.completionPrev()); - } else { - this.props.dispatch(consoleActions.completionNext()); - } - e.stopPropagation(); - e.preventDefault(); - break; - case '[': - if (e.ctrlKey) { - e.preventDefault(); - return this.props.dispatch(consoleActions.hideCommand()); - } - break; - case 'c': - if (e.ctrlKey) { - e.preventDefault(); + case "Escape": return this.props.dispatch(consoleActions.hideCommand()); - } - break; - case 'm': - if (e.ctrlKey) { + case "Enter": return this.doEnter(e); - } - break; - case 'n': - if (e.ctrlKey) { - this.selectNext(e); - } - break; - case 'p': - if (e.ctrlKey) { - this.selectPrev(e); - } - break; + case "Tab": + if (e.shiftKey) { + this.props.dispatch(consoleActions.completionPrev()); + } else { + this.props.dispatch(consoleActions.completionNext()); + } + e.stopPropagation(); + e.preventDefault(); + break; + case "[": + if (e.ctrlKey) { + e.preventDefault(); + return this.props.dispatch(consoleActions.hideCommand()); + } + break; + case "c": + if (e.ctrlKey) { + e.preventDefault(); + return this.props.dispatch(consoleActions.hideCommand()); + } + break; + case "m": + if (e.ctrlKey) { + return this.doEnter(e); + } + break; + case "n": + if (e.ctrlKey) { + this.selectNext(e); + } + break; + case "p": + if (e.ctrlKey) { + this.selectPrev(e); + } + break; } } onChange(e: React.ChangeEvent<HTMLInputElement>) { const text = e.target.value; this.props.dispatch(consoleActions.setConsoleText(text)); - if (this.props.mode !== 'command') { - return + if (this.props.mode !== "command") { + return; } - this.updateCompletions(text) + this.updateCompletions(text); } - componentDidUpdate(prevProps: Props) { - if (prevProps.mode !== 'command' && this.props.mode === 'command') { + if (prevProps.mode !== "command" && this.props.mode === "command") { this.updateCompletions(this.props.consoleText); this.focus(); - } else if (prevProps.mode !== 'find' && this.props.mode === 'find') { + } else if (prevProps.mode !== "find" && this.props.mode === "find") { this.focus(); } } render() { switch (this.props.mode) { - case 'command': - case 'find': - return <div className='vimvixen-console-command-wrapper'> - <Completion - size={COMPLETION_MAX_ITEMS} - completions={this.props.completions} - select={this.props.select} - /> - <Input - ref={this.input} - mode={this.props.mode} - onBlur={this.onBlur.bind(this)} - onKeyDown={this.onKeyDown.bind(this)} - onChange={this.onChange.bind(this)} - value={this.props.consoleText} - /> - </div>; - case 'info': - case 'error': - return <Message mode={ this.props.mode } > - { this.props.messageText } - </Message>; - default: - return null; + case "command": + case "find": + return ( + <div className="vimvixen-console-command-wrapper"> + <Completion + size={COMPLETION_MAX_ITEMS} + completions={this.props.completions} + select={this.props.select} + /> + <Input + ref={this.input} + mode={this.props.mode} + onBlur={this.onBlur.bind(this)} + onKeyDown={this.onKeyDown.bind(this)} + onChange={this.onChange.bind(this)} + value={this.props.consoleText} + /> + </div> + ); + case "info": + case "error": + return ( + <Message mode={this.props.mode}>{this.props.messageText}</Message> + ); + default: + return null; } } @@ -166,25 +170,40 @@ class Console extends React.Component<Props> { } else { const cmd = this.commandLineParser.parse(text); switch (cmd.command) { - case Command.Open: - case Command.TabOpen: - case Command.WindowOpen: - this.props.dispatch(consoleActions.getOpenCompletions(this.props.completionTypes, text, cmd.command, cmd.args)); - break; - case Command.Buffer: - this.props.dispatch(consoleActions.getTabCompletions(text, cmd.command, cmd.args, false)); - break; - case Command.BufferDelete: - case Command.BuffersDelete: - this.props.dispatch(consoleActions.getTabCompletions(text, cmd.command, cmd.args, true)); - break; - case Command.BufferDeleteForce: - case Command.BuffersDeleteForce: - this.props.dispatch(consoleActions.getTabCompletions(text, cmd.command, cmd.args, false)); - break; - case Command.Set: - this.props.dispatch(consoleActions.getPropertyCompletions(text, cmd.command, cmd.args)); - break; + case Command.Open: + case Command.TabOpen: + case Command.WindowOpen: + this.props.dispatch( + consoleActions.getOpenCompletions( + this.props.completionTypes, + text, + cmd.command, + cmd.args + ) + ); + break; + case Command.Buffer: + this.props.dispatch( + consoleActions.getTabCompletions(text, cmd.command, cmd.args, false) + ); + break; + case Command.BufferDelete: + case Command.BuffersDelete: + this.props.dispatch( + consoleActions.getTabCompletions(text, cmd.command, cmd.args, true) + ); + break; + case Command.BufferDeleteForce: + case Command.BuffersDeleteForce: + this.props.dispatch( + consoleActions.getTabCompletions(text, cmd.command, cmd.args, false) + ); + break; + case Command.Set: + this.props.dispatch( + consoleActions.getPropertyCompletions(text, cmd.command, cmd.args) + ); + break; } } } @@ -192,6 +211,4 @@ class Console extends React.Component<Props> { const mapStateToProps = (state: AppState) => ({ ...state }); -export default connect( - mapStateToProps, -)(Console); +export default connect(mapStateToProps)(Console); diff --git a/src/console/components/console/Completion.tsx b/src/console/components/console/Completion.tsx index e2fa1de..9b4cf15 100644 --- a/src/console/components/console/Completion.tsx +++ b/src/console/components/console/Completion.tsx @@ -1,6 +1,6 @@ -import React from 'react'; -import CompletionItem from './CompletionItem'; -import CompletionTitle from './CompletionTitle'; +import React from "react"; +import CompletionItem from "./CompletionItem"; +import CompletionTitle from "./CompletionTitle"; interface Item { icon?: string; @@ -52,8 +52,10 @@ class Completion extends React.Component<Props, State> { if (nextProps.select < 0) { viewOffset = 0; } else if (prevState.select < nextProps.select) { - viewOffset = Math.max(prevState.viewOffset, - viewSelect - nextProps.size + 1); + viewOffset = Math.max( + prevState.viewOffset, + viewSelect - nextProps.size + 1 + ); } else if (prevState.select > nextProps.select) { viewOffset = Math.min(prevState.viewOffset, viewSelect); } @@ -65,18 +67,17 @@ class Completion extends React.Component<Props, State> { let index = 0; for (const group of this.props.completions) { - eles.push(<CompletionTitle - key={`group-${index}`} - title={ group.name } - />); + eles.push(<CompletionTitle key={`group-${index}`} title={group.name} />); for (const item of group.items) { - eles.push(<CompletionItem - key={`item-${index}`} - icon={item.icon} - caption={item.caption} - url={item.url} - highlight={index === this.props.select} - / >); + eles.push( + <CompletionItem + key={`item-${index}`} + icon={item.icon} + caption={item.caption} + url={item.url} + highlight={index === this.props.select} + /> + ); ++index; } } @@ -84,11 +85,7 @@ class Completion extends React.Component<Props, State> { const viewOffset = this.state.viewOffset; eles = eles.slice(viewOffset, viewOffset + this.props.size); - return ( - <ul className='vimvixen-console-completion'> - { eles } - </ul> - ); + return <ul className="vimvixen-console-completion">{eles}</ul>; } } diff --git a/src/console/components/console/CompletionItem.tsx b/src/console/components/console/CompletionItem.tsx index 1cbf3de..657f360 100644 --- a/src/console/components/console/CompletionItem.tsx +++ b/src/console/components/console/CompletionItem.tsx @@ -1,5 +1,5 @@ -import React from 'react'; -import PropTypes from 'prop-types'; +import React from "react"; +import PropTypes from "prop-types"; interface Props { highlight: boolean; @@ -9,21 +9,21 @@ interface Props { } const CompletionItem = (props: Props) => { - let className = 'vimvixen-console-completion-item'; + let className = "vimvixen-console-completion-item"; if (props.highlight) { - className += ' vimvixen-completion-selected'; + className += " vimvixen-completion-selected"; } - return <li - className={className} - style={{ backgroundImage: 'url(' + props.icon + ')' }} - > - <span - className='vimvixen-console-completion-item-caption' - >{props.caption}</span> - <span - className='vimvixen-console-completion-item-url' - >{props.url}</span> - </li>; + return ( + <li + className={className} + style={{ backgroundImage: "url(" + props.icon + ")" }} + > + <span className="vimvixen-console-completion-item-caption"> + {props.caption} + </span> + <span className="vimvixen-console-completion-item-url">{props.url}</span> + </li> + ); }; CompletionItem.propTypes = { diff --git a/src/console/components/console/CompletionTitle.tsx b/src/console/components/console/CompletionTitle.tsx index 2543619..7257006 100644 --- a/src/console/components/console/CompletionTitle.tsx +++ b/src/console/components/console/CompletionTitle.tsx @@ -1,13 +1,11 @@ -import React from 'react'; +import React from "react"; interface Props { title: string; } const CompletionTitle = (props: Props) => { - return <li className='vimvixen-console-completion-title'> - {props.title} - </li>; + return <li className="vimvixen-console-completion-title">{props.title}</li>; }; export default CompletionTitle; diff --git a/src/console/components/console/Input.tsx b/src/console/components/console/Input.tsx index 54ea251..e412a0c 100644 --- a/src/console/components/console/Input.tsx +++ b/src/console/components/console/Input.tsx @@ -1,4 +1,4 @@ -import React from 'react'; +import React from "react"; interface Props { mode: string; @@ -24,20 +24,18 @@ class Input extends React.Component<Props> { } render() { - let prompt = ''; - if (this.props.mode === 'command') { - prompt = ':'; - } else if (this.props.mode === 'find') { - prompt = '/'; + let prompt = ""; + if (this.props.mode === "command") { + prompt = ":"; + } else if (this.props.mode === "find") { + prompt = "/"; } return ( - <div className='vimvixen-console-command'> - <i className='vimvixen-console-command-prompt'> - { prompt } - </i> + <div className="vimvixen-console-command"> + <i className="vimvixen-console-command-prompt">{prompt}</i> <input - className='vimvixen-console-command-input' + className="vimvixen-console-command-input" ref={this.input} onBlur={this.props.onBlur} onKeyDown={this.props.onKeyDown} diff --git a/src/console/components/console/Message.tsx b/src/console/components/console/Message.tsx index 9fa2788..fd1c9d7 100644 --- a/src/console/components/console/Message.tsx +++ b/src/console/components/console/Message.tsx @@ -1,4 +1,4 @@ -import React from 'react'; +import React from "react"; interface Props { mode: string; @@ -7,18 +7,18 @@ interface Props { const Message = (props: Props) => { switch (props.mode) { - case 'error': - return ( - <p className='vimvixen-console-message vimvixen-console-error'> - { props.children } - </p> - ); - case 'info': - return ( - <p className='vimvixen-console-message vimvixen-console-info'> - { props.children } - </p> - ); + case "error": + return ( + <p className="vimvixen-console-message vimvixen-console-error"> + {props.children} + </p> + ); + case "info": + return ( + <p className="vimvixen-console-message vimvixen-console-info"> + {props.children} + </p> + ); } return null; }; diff --git a/src/console/index.tsx b/src/console/index.tsx index 7bee746..e1a9dd3 100644 --- a/src/console/index.tsx +++ b/src/console/index.tsx @@ -1,43 +1,41 @@ -import * as messages from '../shared/messages'; -import reducers from './reducers'; -import { createStore, applyMiddleware } from 'redux'; -import promise from 'redux-promise'; -import * as consoleActions from './actions/console'; -import { Provider } from 'react-redux'; -import Console from './components/Console'; -import React from 'react'; -import ReactDOM from 'react-dom'; +import * as messages from "../shared/messages"; +import reducers from "./reducers"; +import { createStore, applyMiddleware } from "redux"; +import promise from "redux-promise"; +import * as consoleActions from "./actions/console"; +import { Provider } from "react-redux"; +import Console from "./components/Console"; +import React from "react"; +import ReactDOM from "react-dom"; -const store = createStore( - reducers, - applyMiddleware(promise), -); +const store = createStore(reducers, applyMiddleware(promise)); -window.addEventListener('load', () => { - const wrapper = document.getElementById('vimvixen-console'); +window.addEventListener("load", () => { + const wrapper = document.getElementById("vimvixen-console"); ReactDOM.render( - <Provider store={store} > + <Provider store={store}> <Console></Console> </Provider>, - wrapper); + wrapper + ); }); const onMessage = async (message: any): Promise<any> => { const msg = messages.valueOf(message); switch (msg.type) { - case messages.CONSOLE_SHOW_COMMAND: - return store.dispatch(await consoleActions.showCommand(msg.command)); - case messages.CONSOLE_SHOW_FIND: - return store.dispatch(consoleActions.showFind()); - case messages.CONSOLE_SHOW_ERROR: - return store.dispatch(consoleActions.showError(msg.text)); - case messages.CONSOLE_SHOW_INFO: - return store.dispatch(consoleActions.showInfo(msg.text)); - case messages.CONSOLE_HIDE: - return store.dispatch(consoleActions.hide()); + case messages.CONSOLE_SHOW_COMMAND: + return store.dispatch(await consoleActions.showCommand(msg.command)); + case messages.CONSOLE_SHOW_FIND: + return store.dispatch(consoleActions.showFind()); + case messages.CONSOLE_SHOW_ERROR: + return store.dispatch(consoleActions.showError(msg.text)); + case messages.CONSOLE_SHOW_INFO: + return store.dispatch(consoleActions.showInfo(msg.text)); + case messages.CONSOLE_HIDE: + return store.dispatch(consoleActions.hide()); } }; browser.runtime.onMessage.addListener(onMessage); -const port = browser.runtime.connect(undefined, { name: 'vimvixen-console' }); +const port = browser.runtime.connect(undefined, { name: "vimvixen-console" }); port.onMessage.addListener(onMessage); diff --git a/src/console/reducers/index.ts b/src/console/reducers/index.ts index f1508bb..f2ffed7 100644 --- a/src/console/reducers/index.ts +++ b/src/console/reducers/index.ts @@ -1,4 +1,4 @@ -import * as actions from '../actions'; +import * as actions from "../actions"; import Completions from "../Completions"; import CompletionType from "../../shared/CompletionType"; @@ -14,11 +14,11 @@ export interface State { } const defaultState = { - mode: '', - messageText: '', - consoleText: '', + mode: "", + messageText: "", + consoleText: "", completionTypes: [], - completionSource: '', + completionSource: "", completions: [], select: -1, viewIndex: 0, @@ -33,7 +33,7 @@ const nextSelection = (state: State): number => { } const length = state.completions - .map(g => g.items.length) + .map((g) => g.items.length) .reduce((x, y) => x + y); if (state.select + 1 < length) { return state.select + 1; @@ -43,7 +43,7 @@ const nextSelection = (state: State): number => { const prevSelection = (state: State): number => { const length = state.completions - .map(g => g.items.length) + .map((g) => g.items.length) .reduce((x, y) => x + y); if (state.select < 0) { return length - 1; @@ -55,66 +55,74 @@ const nextConsoleText = (completions: any[], select: number, defaults: any) => { if (select < 0) { return defaults; } - const items = completions.map(g => g.items).reduce((g1, g2) => g1.concat(g2)); + const items = completions + .map((g) => g.items) + .reduce((g1, g2) => g1.concat(g2)); return items[select].content; }; // eslint-disable-next-line max-lines-per-function export default function reducer( state: State = defaultState, - action: actions.ConsoleAction, + action: actions.ConsoleAction ): State { switch (action.type) { - case actions.CONSOLE_HIDE: - return { ...state, - mode: '', }; - case actions.CONSOLE_SHOW_COMMAND: - return { ...state, - mode: 'command', - consoleText: action.text, - completionTypes: action.completionTypes, - completions: []}; - case actions.CONSOLE_SHOW_FIND: - return { ...state, - mode: 'find', - consoleText: '', - completions: []}; - case actions.CONSOLE_SHOW_ERROR: - return { ...state, - mode: 'error', - messageText: action.text, }; - case actions.CONSOLE_SHOW_INFO: - return { ...state, - mode: 'info', - messageText: action.text, }; - case actions.CONSOLE_HIDE_COMMAND: - return { - ...state, - mode: state.mode === 'command' || state.mode === 'find' ? '' : state.mode, - }; - case actions.CONSOLE_SET_CONSOLE_TEXT: - return { ...state, - consoleText: action.consoleText, }; - case actions.CONSOLE_SET_COMPLETIONS: - return { ...state, - completions: action.completions, - completionSource: action.completionSource, - select: -1 }; - case actions.CONSOLE_COMPLETION_NEXT: { - const select = nextSelection(state); - return { ...state, - select: select, - consoleText: nextConsoleText( - state.completions, select, state.completionSource) }; - } - case actions.CONSOLE_COMPLETION_PREV: { - const select = prevSelection(state); - return { ...state, - select: select, - consoleText: nextConsoleText( - state.completions, select, state.completionSource) }; - } - default: - return state; + case actions.CONSOLE_HIDE: + return { ...state, mode: "" }; + case actions.CONSOLE_SHOW_COMMAND: + return { + ...state, + mode: "command", + consoleText: action.text, + completionTypes: action.completionTypes, + completions: [], + }; + case actions.CONSOLE_SHOW_FIND: + return { ...state, mode: "find", consoleText: "", completions: [] }; + case actions.CONSOLE_SHOW_ERROR: + return { ...state, mode: "error", messageText: action.text }; + case actions.CONSOLE_SHOW_INFO: + return { ...state, mode: "info", messageText: action.text }; + case actions.CONSOLE_HIDE_COMMAND: + return { + ...state, + mode: + state.mode === "command" || state.mode === "find" ? "" : state.mode, + }; + case actions.CONSOLE_SET_CONSOLE_TEXT: + return { ...state, consoleText: action.consoleText }; + case actions.CONSOLE_SET_COMPLETIONS: + return { + ...state, + completions: action.completions, + completionSource: action.completionSource, + select: -1, + }; + case actions.CONSOLE_COMPLETION_NEXT: { + const select = nextSelection(state); + return { + ...state, + select: select, + consoleText: nextConsoleText( + state.completions, + select, + state.completionSource + ), + }; + } + case actions.CONSOLE_COMPLETION_PREV: { + const select = prevSelection(state); + return { + ...state, + select: select, + consoleText: nextConsoleText( + state.completions, + select, + state.completionSource + ), + }; + } + default: + return state; } } diff --git a/src/content/Application.ts b/src/content/Application.ts index fbfeb6d..996bbbc 100644 --- a/src/content/Application.ts +++ b/src/content/Application.ts @@ -1,25 +1,24 @@ -import { injectable } from 'tsyringe'; -import MessageListener from './MessageListener'; -import FindController from './controllers/FindController'; -import MarkController from './controllers/MarkController'; -import FollowMasterController from './controllers/FollowMasterController'; -import FollowSlaveController from './controllers/FollowSlaveController'; -import FollowKeyController from './controllers/FollowKeyController'; -import InputDriver from './InputDriver'; -import KeymapController from './controllers/KeymapController'; -import AddonEnabledUseCase from './usecases/AddonEnabledUseCase'; -import MarkKeyController from './controllers/MarkKeyController'; -import AddonEnabledController from './controllers/AddonEnabledController'; -import SettingController from './controllers/SettingController'; -import ConsoleFrameController from './controllers/ConsoleFrameController'; -import NavigateController from './controllers/NavigateController'; -import * as messages from '../shared/messages'; +import { injectable } from "tsyringe"; +import MessageListener from "./MessageListener"; +import FindController from "./controllers/FindController"; +import MarkController from "./controllers/MarkController"; +import FollowMasterController from "./controllers/FollowMasterController"; +import FollowSlaveController from "./controllers/FollowSlaveController"; +import FollowKeyController from "./controllers/FollowKeyController"; +import InputDriver from "./InputDriver"; +import KeymapController from "./controllers/KeymapController"; +import AddonEnabledUseCase from "./usecases/AddonEnabledUseCase"; +import MarkKeyController from "./controllers/MarkKeyController"; +import AddonEnabledController from "./controllers/AddonEnabledController"; +import SettingController from "./controllers/SettingController"; +import ConsoleFrameController from "./controllers/ConsoleFrameController"; +import NavigateController from "./controllers/NavigateController"; +import * as messages from "../shared/messages"; type Message = messages.Message; @injectable() export default class Application { - // eslint-disable-next-line max-params constructor( private messageListener: MessageListener, @@ -34,9 +33,8 @@ export default class Application { private addonEnabledController: AddonEnabledController, private settingController: SettingController, private consoleFrameController: ConsoleFrameController, - private navigateController: NavigateController, - ) { - } + private navigateController: NavigateController + ) {} run() { this.routeCommonComponents(); @@ -49,30 +47,30 @@ export default class Application { private routeMasterComponents() { this.messageListener.onWebMessage((msg: Message, sender: Window) => { switch (msg.type) { - case messages.CONSOLE_ENTER_FIND: - return this.findController.start(msg); - case messages.FIND_NEXT: - return this.findController.next(msg); - case messages.FIND_PREV: - return this.findController.prev(msg); - case messages.CONSOLE_UNFOCUS: - return this.consoleFrameController.unfocus(msg); - case messages.FOLLOW_START: - return this.followMasterController.followStart(msg); - case messages.FOLLOW_RESPONSE_COUNT_TARGETS: - return this.followMasterController.responseCountTargets(msg, sender); - case messages.FOLLOW_KEY_PRESS: - return this.followMasterController.keyPress(msg); + case messages.CONSOLE_ENTER_FIND: + return this.findController.start(msg); + case messages.FIND_NEXT: + return this.findController.next(msg); + case messages.FIND_PREV: + return this.findController.prev(msg); + case messages.CONSOLE_UNFOCUS: + return this.consoleFrameController.unfocus(msg); + case messages.FOLLOW_START: + return this.followMasterController.followStart(msg); + case messages.FOLLOW_RESPONSE_COUNT_TARGETS: + return this.followMasterController.responseCountTargets(msg, sender); + case messages.FOLLOW_KEY_PRESS: + return this.followMasterController.keyPress(msg); } return undefined; }); this.messageListener.onBackgroundMessage((msg: Message) => { switch (msg.type) { - case messages.ADDON_ENABLED_QUERY: - return this.addonEnabledController.getAddonEnabled(msg); - case messages.TAB_SCROLL_TO: - return this.markController.scrollTo(msg); + case messages.ADDON_ENABLED_QUERY: + return this.addonEnabledController.getAddonEnabled(msg); + case messages.TAB_SCROLL_TO: + return this.markController.scrollTo(msg); } return undefined; }); @@ -81,47 +79,47 @@ export default class Application { private routeCommonComponents() { this.messageListener.onWebMessage((msg: Message) => { switch (msg.type) { - case messages.FOLLOW_REQUEST_COUNT_TARGETS: - return this.followSlaveController.countTargets(msg); - case messages.FOLLOW_CREATE_HINTS: - return this.followSlaveController.createHints(msg); - case messages.FOLLOW_SHOW_HINTS: - return this.followSlaveController.showHints(msg); - case messages.FOLLOW_ACTIVATE: - return this.followSlaveController.activate(msg); - case messages.FOLLOW_REMOVE_HINTS: - return this.followSlaveController.clear(msg); + case messages.FOLLOW_REQUEST_COUNT_TARGETS: + return this.followSlaveController.countTargets(msg); + case messages.FOLLOW_CREATE_HINTS: + return this.followSlaveController.createHints(msg); + case messages.FOLLOW_SHOW_HINTS: + return this.followSlaveController.showHints(msg); + case messages.FOLLOW_ACTIVATE: + return this.followSlaveController.activate(msg); + case messages.FOLLOW_REMOVE_HINTS: + return this.followSlaveController.clear(msg); } return undefined; }); this.messageListener.onBackgroundMessage((msg: Message): any => { switch (msg.type) { - case messages.SETTINGS_CHANGED: - return this.settingController.reloadSettings(msg); - case messages.ADDON_TOGGLE_ENABLED: - return this.addonEnabledUseCase.toggle(); - case messages.NAVIGATE_HISTORY_NEXT: - return this.navigateController.openHistoryNext(msg); - case messages.NAVIGATE_HISTORY_PREV: - return this.navigateController.openHistoryPrev(msg); - case messages.NAVIGATE_LINK_NEXT: - return this.navigateController.openLinkNext(msg); - case messages.NAVIGATE_LINK_PREV: - return this.navigateController.openLinkPrev(msg); + case messages.SETTINGS_CHANGED: + return this.settingController.reloadSettings(msg); + case messages.ADDON_TOGGLE_ENABLED: + return this.addonEnabledUseCase.toggle(); + case messages.NAVIGATE_HISTORY_NEXT: + return this.navigateController.openHistoryNext(msg); + case messages.NAVIGATE_HISTORY_PREV: + return this.navigateController.openHistoryPrev(msg); + case messages.NAVIGATE_LINK_NEXT: + return this.navigateController.openLinkNext(msg); + case messages.NAVIGATE_LINK_PREV: + return this.navigateController.openLinkPrev(msg); } }); const inputDriver = new InputDriver(window.document.body); - inputDriver.onKey(key => this.followKeyController.press(key)); - inputDriver.onKey(key => this.markKeyController.press(key)); - inputDriver.onKey(key => this.keymapController.press(key)); + inputDriver.onKey((key) => this.followKeyController.press(key)); + inputDriver.onKey((key) => this.markKeyController.press(key)); + inputDriver.onKey((key) => this.keymapController.press(key)); this.settingController.initSettings(); } private routeFocusEvents() { - window.addEventListener('blur', () => { + window.addEventListener("blur", () => { this.keymapController.onBlurWindow(); }); } diff --git a/src/content/InputDriver.ts b/src/content/InputDriver.ts index cf28205..76c1fc9 100644 --- a/src/content/InputDriver.ts +++ b/src/content/InputDriver.ts @@ -1,24 +1,24 @@ -import * as dom from '../shared/utils/dom'; -import Key from '../shared/settings/Key'; +import * as dom from "../shared/utils/dom"; +import Key from "../shared/settings/Key"; const cancelKey = (e: KeyboardEvent): boolean => { - if (e.key === 'Escape') { + if (e.key === "Escape") { return true; } - if (e.key === '[' && e.ctrlKey) { + if (e.key === "[" && e.ctrlKey) { return true; } return false; }; const modifiedKeyName = (name: string): string => { - if (name === ' ') { - return 'Space'; + if (name === " ") { + return "Space"; } if (name.length === 1) { return name; - } else if (name === 'Escape') { - return 'Esc'; + } else if (name === "Escape") { + return "Esc"; } return name; }; @@ -44,7 +44,7 @@ export const keyFromKeyboardEvent = (e: KeyboardEvent): Key => { }; export default class InputDriver { - private pressed: {[key: string]: string} = {}; + private pressed: { [key: string]: string } = {}; private onKeyListeners: ((key: Key) => boolean)[] = []; @@ -52,9 +52,9 @@ export default class InputDriver { this.pressed = {}; this.onKeyListeners = []; - target.addEventListener('keypress', this.onKeyPress.bind(this)); - target.addEventListener('keydown', this.onKeyDown.bind(this)); - target.addEventListener('keyup', this.onKeyUp.bind(this)); + target.addEventListener("keypress", this.onKeyPress.bind(this)); + target.addEventListener("keydown", this.onKeyDown.bind(this)); + target.addEventListener("keyup", this.onKeyUp.bind(this)); } onKey(cb: (key: Key) => boolean) { @@ -62,18 +62,18 @@ export default class InputDriver { } private onKeyPress(e: KeyboardEvent) { - if (this.pressed[e.key] && this.pressed[e.key] !== 'keypress') { + if (this.pressed[e.key] && this.pressed[e.key] !== "keypress") { return; } - this.pressed[e.key] = 'keypress'; + this.pressed[e.key] = "keypress"; this.capture(e); } private onKeyDown(e: KeyboardEvent) { - if (this.pressed[e.key] && this.pressed[e.key] !== 'keydown') { + if (this.pressed[e.key] && this.pressed[e.key] !== "keydown") { return; } - this.pressed[e.key] = 'keydown'; + this.pressed[e.key] = "keydown"; this.capture(e); } @@ -93,7 +93,7 @@ export default class InputDriver { } return; } - if (['Shift', 'Control', 'Alt', 'OS'].includes(e.key)) { + if (["Shift", "Control", "Alt", "OS"].includes(e.key)) { // pressing only meta key is ignored return; } @@ -110,9 +110,11 @@ export default class InputDriver { } private fromInput(e: Element) { - return e instanceof HTMLInputElement || + return ( + e instanceof HTMLInputElement || e instanceof HTMLTextAreaElement || e instanceof HTMLSelectElement || - dom.isContentEditable(e); + dom.isContentEditable(e) + ); } } diff --git a/src/content/MessageListener.ts b/src/content/MessageListener.ts index e1f7c75..3fe1dcd 100644 --- a/src/content/MessageListener.ts +++ b/src/content/MessageListener.ts @@ -1,14 +1,12 @@ -import { injectable } from 'tsyringe'; -import { Message, valueOf } from '../shared/messages'; +import { injectable } from "tsyringe"; +import { Message, valueOf } from "../shared/messages"; export type WebExtMessageSender = browser.runtime.MessageSender; @injectable() export default class MessageListener { - onWebMessage( - listener: (msg: Message, sender: Window) => void, - ) { - window.addEventListener('message', (event: MessageEvent) => { + onWebMessage(listener: (msg: Message, sender: Window) => void) { + window.addEventListener("message", (event: MessageEvent) => { const sender = event.source; if (!(sender instanceof Window)) { return; @@ -25,12 +23,12 @@ export default class MessageListener { } onBackgroundMessage( - listener: (msg: Message, sender: WebExtMessageSender) => any, + listener: (msg: Message, sender: WebExtMessageSender) => any ) { browser.runtime.onMessage.addListener( (msg: any, sender: WebExtMessageSender) => { return listener(valueOf(msg), sender); - }, + } ); } } diff --git a/src/content/client/AddonIndicatorClient.ts b/src/content/client/AddonIndicatorClient.ts index b5f7e6a..861ef40 100644 --- a/src/content/client/AddonIndicatorClient.ts +++ b/src/content/client/AddonIndicatorClient.ts @@ -1,4 +1,4 @@ -import * as messages from '../../shared/messages'; +import * as messages from "../../shared/messages"; export default interface AddonIndicatorClient { setEnabled(enabled: boolean): Promise<void>; diff --git a/src/content/client/ConsoleClient.ts b/src/content/client/ConsoleClient.ts index b4fbb04..0aac8d0 100644 --- a/src/content/client/ConsoleClient.ts +++ b/src/content/client/ConsoleClient.ts @@ -1,4 +1,4 @@ -import * as messages from '../../shared/messages'; +import * as messages from "../../shared/messages"; export default interface ConsoleClient { info(text: string): Promise<void>; diff --git a/src/content/client/FindClient.ts b/src/content/client/FindClient.ts index 8b2aca4..7da5069 100644 --- a/src/content/client/FindClient.ts +++ b/src/content/client/FindClient.ts @@ -1,4 +1,4 @@ -import * as messages from '../../shared/messages'; +import * as messages from "../../shared/messages"; export default interface FindClient { getGlobalLastKeyword(): Promise<string | null>; diff --git a/src/content/client/FindMasterClient.ts b/src/content/client/FindMasterClient.ts index 9ed38dd..9c3f812 100644 --- a/src/content/client/FindMasterClient.ts +++ b/src/content/client/FindMasterClient.ts @@ -1,4 +1,4 @@ -import * as messages from '../../shared/messages'; +import * as messages from "../../shared/messages"; export default interface FindMasterClient { findNext(): void; @@ -8,14 +8,20 @@ export default interface FindMasterClient { export class FindMasterClientImpl implements FindMasterClient { findNext(): void { - window.top.postMessage(JSON.stringify({ - type: messages.FIND_NEXT, - }), '*'); + window.top.postMessage( + JSON.stringify({ + type: messages.FIND_NEXT, + }), + "*" + ); } findPrev(): void { - window.top.postMessage(JSON.stringify({ - type: messages.FIND_PREV, - }), '*'); + window.top.postMessage( + JSON.stringify({ + type: messages.FIND_PREV, + }), + "*" + ); } } diff --git a/src/content/client/FollowMasterClient.ts b/src/content/client/FollowMasterClient.ts index 6681e8a..f068683 100644 --- a/src/content/client/FollowMasterClient.ts +++ b/src/content/client/FollowMasterClient.ts @@ -1,5 +1,5 @@ -import * as messages from '../../shared/messages'; -import Key from '../../shared/settings/Key'; +import * as messages from "../../shared/messages"; +import Key from "../../shared/settings/Key"; export default interface FollowMasterClient { startFollow(newTab: boolean, background: boolean): void; @@ -40,6 +40,6 @@ export class FollowMasterClientImpl implements FollowMasterClient { } private postMessage(msg: messages.Message): void { - this.window.postMessage(JSON.stringify(msg), '*'); + this.window.postMessage(JSON.stringify(msg), "*"); } } diff --git a/src/content/client/FollowSlaveClient.ts b/src/content/client/FollowSlaveClient.ts index 4360200..eb9651a 100644 --- a/src/content/client/FollowSlaveClient.ts +++ b/src/content/client/FollowSlaveClient.ts @@ -1,4 +1,4 @@ -import * as messages from '../../shared/messages'; +import * as messages from "../../shared/messages"; interface Size { width: number; @@ -69,6 +69,6 @@ export class FollowSlaveClientImpl implements FollowSlaveClient { } private postMessage(msg: messages.Message): void { - this.target.postMessage(JSON.stringify(msg), '*'); + this.target.postMessage(JSON.stringify(msg), "*"); } } diff --git a/src/content/client/FollowSlaveClientFactory.ts b/src/content/client/FollowSlaveClientFactory.ts index 166dfca..beaa77a 100644 --- a/src/content/client/FollowSlaveClientFactory.ts +++ b/src/content/client/FollowSlaveClientFactory.ts @@ -1,4 +1,4 @@ -import FollowSlaveClient, { FollowSlaveClientImpl } from './FollowSlaveClient'; +import FollowSlaveClient, { FollowSlaveClientImpl } from "./FollowSlaveClient"; export default interface FollowSlaveClientFactory { create(window: Window): FollowSlaveClient; diff --git a/src/content/client/MarkClient.ts b/src/content/client/MarkClient.ts index c6295c0..d1f00ae 100644 --- a/src/content/client/MarkClient.ts +++ b/src/content/client/MarkClient.ts @@ -1,5 +1,5 @@ -import Mark from '../domains/Mark'; -import * as messages from '../../shared/messages'; +import Mark from "../domains/Mark"; +import * as messages from "../../shared/messages"; export default interface MarkClient { setGloablMark(key: string, mark: Mark): Promise<void>; diff --git a/src/content/client/OperationClient.ts b/src/content/client/OperationClient.ts index 9c72c75..2bc7aee 100644 --- a/src/content/client/OperationClient.ts +++ b/src/content/client/OperationClient.ts @@ -1,11 +1,13 @@ -import * as operations from '../../shared/operations'; -import * as messages from '../../shared/messages'; +import * as operations from "../../shared/operations"; +import * as messages from "../../shared/messages"; export default interface OperationClient { execBackgroundOp(repeat: number, op: operations.Operation): Promise<void>; internalOpenUrl( - url: string, newTab?: boolean, background?: boolean, + url: string, + newTab?: boolean, + background?: boolean ): Promise<void>; } @@ -19,7 +21,9 @@ export class OperationClientImpl implements OperationClient { } internalOpenUrl( - url: string, newTab?: boolean, background?: boolean, + url: string, + newTab?: boolean, + background?: boolean ): Promise<void> { return browser.runtime.sendMessage({ type: messages.BACKGROUND_OPERATION, diff --git a/src/content/client/SettingClient.ts b/src/content/client/SettingClient.ts index f89f3cd..11d7075 100644 --- a/src/content/client/SettingClient.ts +++ b/src/content/client/SettingClient.ts @@ -1,5 +1,5 @@ -import Settings from '../../shared/settings/Settings'; -import * as messages from '../../shared/messages'; +import Settings from "../../shared/settings/Settings"; +import * as messages from "../../shared/messages"; export default interface SettingClient { load(): Promise<Settings>; diff --git a/src/content/client/TabsClient.ts b/src/content/client/TabsClient.ts index 39348df..9169a3d 100644 --- a/src/content/client/TabsClient.ts +++ b/src/content/client/TabsClient.ts @@ -1,4 +1,4 @@ -import * as messages from '../../shared/messages'; +import * as messages from "../../shared/messages"; export default interface TabsClient { openUrl(url: string, newTab: boolean, background?: boolean): Promise<void>; @@ -8,7 +8,7 @@ export class TabsClientImpl implements TabsClient { async openUrl( url: string, newTab: boolean, - background?: boolean, + background?: boolean ): Promise<void> { await browser.runtime.sendMessage({ type: messages.OPEN_URL, diff --git a/src/content/controllers/AddonEnabledController.ts b/src/content/controllers/AddonEnabledController.ts index 59b45fa..9ef56a9 100644 --- a/src/content/controllers/AddonEnabledController.ts +++ b/src/content/controllers/AddonEnabledController.ts @@ -1,16 +1,13 @@ -import { injectable } from 'tsyringe'; -import * as messages from '../../shared/messages'; -import AddonEnabledUseCase from '../usecases/AddonEnabledUseCase'; +import { injectable } from "tsyringe"; +import * as messages from "../../shared/messages"; +import AddonEnabledUseCase from "../usecases/AddonEnabledUseCase"; @injectable() export default class AddonEnabledController { - constructor( - private addonEnabledUseCase: AddonEnabledUseCase, - ) { - } + constructor(private addonEnabledUseCase: AddonEnabledUseCase) {} getAddonEnabled( - _message: messages.AddonEnabledQueryMessage, + _message: messages.AddonEnabledQueryMessage ): Promise<boolean> { const enabled = this.addonEnabledUseCase.getEnabled(); return Promise.resolve(enabled); diff --git a/src/content/controllers/ConsoleFrameController.ts b/src/content/controllers/ConsoleFrameController.ts index ae26b7c..84e0ce6 100644 --- a/src/content/controllers/ConsoleFrameController.ts +++ b/src/content/controllers/ConsoleFrameController.ts @@ -1,13 +1,10 @@ -import { injectable } from 'tsyringe'; -import ConsoleFrameUseCase from '../usecases/ConsoleFrameUseCase'; -import * as messages from '../../shared/messages'; +import { injectable } from "tsyringe"; +import ConsoleFrameUseCase from "../usecases/ConsoleFrameUseCase"; +import * as messages from "../../shared/messages"; @injectable() export default class ConsoleFrameController { - constructor( - private consoleFrameUseCase: ConsoleFrameUseCase, - ) { - } + constructor(private consoleFrameUseCase: ConsoleFrameUseCase) {} unfocus(_message: messages.Message) { this.consoleFrameUseCase.unfocus(); diff --git a/src/content/controllers/FindController.ts b/src/content/controllers/FindController.ts index 7735176..3087d5d 100644 --- a/src/content/controllers/FindController.ts +++ b/src/content/controllers/FindController.ts @@ -1,13 +1,10 @@ -import { injectable } from 'tsyringe'; -import * as messages from '../../shared/messages'; -import FindUseCase from '../usecases/FindUseCase'; +import { injectable } from "tsyringe"; +import * as messages from "../../shared/messages"; +import FindUseCase from "../usecases/FindUseCase"; @injectable() export default class FindController { - constructor( - private findUseCase: FindUseCase, - ) { - } + constructor(private findUseCase: FindUseCase) {} async start(m: messages.ConsoleEnterFindMessage): Promise<void> { await this.findUseCase.startFind(m.text); diff --git a/src/content/controllers/FollowKeyController.ts b/src/content/controllers/FollowKeyController.ts index 0fd94ff..45d202a 100644 --- a/src/content/controllers/FollowKeyController.ts +++ b/src/content/controllers/FollowKeyController.ts @@ -1,13 +1,10 @@ -import { injectable } from 'tsyringe'; -import FollowSlaveUseCase from '../usecases/FollowSlaveUseCase'; -import Key from '../../shared/settings/Key'; +import { injectable } from "tsyringe"; +import FollowSlaveUseCase from "../usecases/FollowSlaveUseCase"; +import Key from "../../shared/settings/Key"; @injectable() export default class FollowKeyController { - constructor( - private followSlaveUseCase: FollowSlaveUseCase, - ) { - } + constructor(private followSlaveUseCase: FollowSlaveUseCase) {} press(key: Key): boolean { if (!this.followSlaveUseCase.isFollowMode()) { diff --git a/src/content/controllers/FollowMasterController.ts b/src/content/controllers/FollowMasterController.ts index fa99820..e7895fa 100644 --- a/src/content/controllers/FollowMasterController.ts +++ b/src/content/controllers/FollowMasterController.ts @@ -1,30 +1,27 @@ -import { injectable } from 'tsyringe'; -import FollowMasterUseCase from '../usecases/FollowMasterUseCase'; -import * as messages from '../../shared/messages'; +import { injectable } from "tsyringe"; +import FollowMasterUseCase from "../usecases/FollowMasterUseCase"; +import * as messages from "../../shared/messages"; @injectable() export default class FollowMasterController { - constructor( - private followMasterUseCase: FollowMasterUseCase, - ) { - } + constructor(private followMasterUseCase: FollowMasterUseCase) {} followStart(m: messages.FollowStartMessage): void { this.followMasterUseCase.startFollow(m.newTab, m.background); } responseCountTargets( - m: messages.FollowResponseCountTargetsMessage, sender: Window, + m: messages.FollowResponseCountTargetsMessage, + sender: Window ): void { this.followMasterUseCase.createSlaveHints(m.count, sender); } keyPress(message: messages.FollowKeyPressMessage): void { - if (message.key === '[' && message.ctrlKey) { + if (message.key === "[" && message.ctrlKey) { this.followMasterUseCase.cancelFollow(); } else { this.followMasterUseCase.enqueue(message.key); } } } - diff --git a/src/content/controllers/FollowSlaveController.ts b/src/content/controllers/FollowSlaveController.ts index 65ce477..25f0505 100644 --- a/src/content/controllers/FollowSlaveController.ts +++ b/src/content/controllers/FollowSlaveController.ts @@ -1,13 +1,10 @@ -import { injectable } from 'tsyringe'; -import * as messages from '../../shared/messages'; -import FollowSlaveUseCase from '../usecases/FollowSlaveUseCase'; +import { injectable } from "tsyringe"; +import * as messages from "../../shared/messages"; +import FollowSlaveUseCase from "../usecases/FollowSlaveUseCase"; @injectable() export default class FollowSlaveController { - constructor( - private usecase: FollowSlaveUseCase, - ) { - } + constructor(private usecase: FollowSlaveUseCase) {} countTargets(m: messages.FollowRequestCountTargetsMessage): void { this.usecase.countTargets(m.viewSize, m.framePosition); diff --git a/src/content/controllers/KeymapController.ts b/src/content/controllers/KeymapController.ts index 639b4a1..092e55c 100644 --- a/src/content/controllers/KeymapController.ts +++ b/src/content/controllers/KeymapController.ts @@ -1,15 +1,15 @@ -import { injectable, inject } from 'tsyringe'; -import * as operations from '../../shared/operations'; -import KeymapUseCase from '../usecases/KeymapUseCase'; -import AddonEnabledUseCase from '../usecases/AddonEnabledUseCase'; -import FindSlaveUseCase from '../usecases/FindSlaveUseCase'; -import ScrollUseCase from '../usecases/ScrollUseCase'; -import FocusUseCase from '../usecases/FocusUseCase'; -import ClipboardUseCase from '../usecases/ClipboardUseCase'; -import OperationClient from '../client/OperationClient'; -import MarkKeyyUseCase from '../usecases/MarkKeyUseCase'; -import FollowMasterClient from '../client/FollowMasterClient'; -import Key from '../../shared/settings/Key'; +import { injectable, inject } from "tsyringe"; +import * as operations from "../../shared/operations"; +import KeymapUseCase from "../usecases/KeymapUseCase"; +import AddonEnabledUseCase from "../usecases/AddonEnabledUseCase"; +import FindSlaveUseCase from "../usecases/FindSlaveUseCase"; +import ScrollUseCase from "../usecases/ScrollUseCase"; +import FocusUseCase from "../usecases/FocusUseCase"; +import ClipboardUseCase from "../usecases/ClipboardUseCase"; +import OperationClient from "../client/OperationClient"; +import MarkKeyyUseCase from "../usecases/MarkKeyUseCase"; +import FollowMasterClient from "../client/FollowMasterClient"; +import Key from "../../shared/settings/Key"; @injectable() export default class KeymapController { @@ -22,13 +22,12 @@ export default class KeymapController { private clipbaordUseCase: ClipboardUseCase, private markKeyUseCase: MarkKeyyUseCase, - @inject('OperationClient') + @inject("OperationClient") private operationClient: OperationClient, - @inject('FollowMasterClient') - private followMasterClient: FollowMasterClient, - ) { - } + @inject("FollowMasterClient") + private followMasterClient: FollowMasterClient + ) {} // eslint-disable-next-line complexity, max-lines-per-function press(key: Key): boolean { @@ -43,47 +42,46 @@ export default class KeymapController { const doFunc = ((op: operations.Operation) => { switch (op.type) { - case operations.ADDON_ENABLE: - return () => this.addonEnabledUseCase.enable(); - case operations.ADDON_DISABLE: - return () => this.addonEnabledUseCase.disable(); - case operations.ADDON_TOGGLE_ENABLED: - return () => this.addonEnabledUseCase.toggle(); - case operations.FIND_NEXT: - return () => this.findSlaveUseCase.findNext(); - case operations.FIND_PREV: - return () => this.findSlaveUseCase.findPrev(); - case operations.SCROLL_VERTICALLY: - return () => this.scrollUseCase.scrollVertically(op.count); - case operations.SCROLL_HORIZONALLY: - return () => this.scrollUseCase.scrollHorizonally(op.count); - case operations.SCROLL_PAGES: - return () => this.scrollUseCase.scrollPages(op.count); - case operations.SCROLL_TOP: - return () => this.scrollUseCase.scrollToTop(); - case operations.SCROLL_BOTTOM: - return () => this.scrollUseCase.scrollToBottom(); - case operations.SCROLL_HOME: - return () => this.scrollUseCase.scrollToHome(); - case operations.SCROLL_END: - return () => this.scrollUseCase.scrollToEnd(); - case operations.FOLLOW_START: - return () => this.followMasterClient.startFollow( - op.newTab, op.background); - case operations.MARK_SET_PREFIX: - return () => this.markKeyUseCase.enableSetMode(); - case operations.MARK_JUMP_PREFIX: - return () => this.markKeyUseCase.enableJumpMode(); - case operations.FOCUS_INPUT: - return () => this.focusUseCase.focusFirstInput(); - case operations.URLS_YANK: - return () => this.clipbaordUseCase.yankCurrentURL(); - case operations.URLS_PASTE: - return () => this.clipbaordUseCase.openOrSearch( - op.newTab ? op.newTab : false, - ); - default: - return null; + case operations.ADDON_ENABLE: + return () => this.addonEnabledUseCase.enable(); + case operations.ADDON_DISABLE: + return () => this.addonEnabledUseCase.disable(); + case operations.ADDON_TOGGLE_ENABLED: + return () => this.addonEnabledUseCase.toggle(); + case operations.FIND_NEXT: + return () => this.findSlaveUseCase.findNext(); + case operations.FIND_PREV: + return () => this.findSlaveUseCase.findPrev(); + case operations.SCROLL_VERTICALLY: + return () => this.scrollUseCase.scrollVertically(op.count); + case operations.SCROLL_HORIZONALLY: + return () => this.scrollUseCase.scrollHorizonally(op.count); + case operations.SCROLL_PAGES: + return () => this.scrollUseCase.scrollPages(op.count); + case operations.SCROLL_TOP: + return () => this.scrollUseCase.scrollToTop(); + case operations.SCROLL_BOTTOM: + return () => this.scrollUseCase.scrollToBottom(); + case operations.SCROLL_HOME: + return () => this.scrollUseCase.scrollToHome(); + case operations.SCROLL_END: + return () => this.scrollUseCase.scrollToEnd(); + case operations.FOLLOW_START: + return () => + this.followMasterClient.startFollow(op.newTab, op.background); + case operations.MARK_SET_PREFIX: + return () => this.markKeyUseCase.enableSetMode(); + case operations.MARK_JUMP_PREFIX: + return () => this.markKeyUseCase.enableJumpMode(); + case operations.FOCUS_INPUT: + return () => this.focusUseCase.focusFirstInput(); + case operations.URLS_YANK: + return () => this.clipbaordUseCase.yankCurrentURL(); + case operations.URLS_PASTE: + return () => + this.clipbaordUseCase.openOrSearch(op.newTab ? op.newTab : false); + default: + return null; } })(nextOp.op); diff --git a/src/content/controllers/MarkController.ts b/src/content/controllers/MarkController.ts index 5eb898a..05a0c75 100644 --- a/src/content/controllers/MarkController.ts +++ b/src/content/controllers/MarkController.ts @@ -1,13 +1,10 @@ -import { injectable } from 'tsyringe'; -import * as messages from '../../shared/messages'; -import MarkUseCase from '../usecases/MarkUseCase'; +import { injectable } from "tsyringe"; +import * as messages from "../../shared/messages"; +import MarkUseCase from "../usecases/MarkUseCase"; @injectable() export default class MarkController { - constructor( - private markUseCase: MarkUseCase, - ) { - } + constructor(private markUseCase: MarkUseCase) {} scrollTo(message: messages.TabScrollToMessage) { this.markUseCase.scroll(message.x, message.y); diff --git a/src/content/controllers/MarkKeyController.ts b/src/content/controllers/MarkKeyController.ts index e7653ee..a011af1 100644 --- a/src/content/controllers/MarkKeyController.ts +++ b/src/content/controllers/MarkKeyController.ts @@ -1,15 +1,14 @@ -import { injectable } from 'tsyringe'; -import MarkUseCase from '../usecases/MarkUseCase'; -import MarkKeyyUseCase from '../usecases/MarkKeyUseCase'; -import Key from '../../shared/settings/Key'; +import { injectable } from "tsyringe"; +import MarkUseCase from "../usecases/MarkUseCase"; +import MarkKeyyUseCase from "../usecases/MarkKeyUseCase"; +import Key from "../../shared/settings/Key"; @injectable() export default class MarkKeyController { constructor( private markUseCase: MarkUseCase, - private markKeyUseCase: MarkKeyyUseCase, - ) { - } + private markKeyUseCase: MarkKeyyUseCase + ) {} press(key: Key): boolean { if (this.markKeyUseCase.isSetMode()) { diff --git a/src/content/controllers/NavigateController.ts b/src/content/controllers/NavigateController.ts index 3f2df7a..5b66a39 100644 --- a/src/content/controllers/NavigateController.ts +++ b/src/content/controllers/NavigateController.ts @@ -1,13 +1,10 @@ -import { injectable } from 'tsyringe'; -import { Message } from '../../shared/messages'; -import NavigateUseCase from '../usecases/NavigateUseCase'; +import { injectable } from "tsyringe"; +import { Message } from "../../shared/messages"; +import NavigateUseCase from "../usecases/NavigateUseCase"; @injectable() export default class NavigateController { - constructor( - private navigateUseCase: NavigateUseCase, - ) { - } + constructor(private navigateUseCase: NavigateUseCase) {} openHistoryNext(_m: Message): Promise<void> { this.navigateUseCase.openHistoryNext(); diff --git a/src/content/controllers/SettingController.ts b/src/content/controllers/SettingController.ts index 2d32c09..72d484c 100644 --- a/src/content/controllers/SettingController.ts +++ b/src/content/controllers/SettingController.ts @@ -1,16 +1,14 @@ -import { injectable } from 'tsyringe'; -import AddonEnabledUseCase from '../usecases/AddonEnabledUseCase'; -import SettingUseCase from '../usecases/SettingUseCase'; -import * as messages from '../../shared/messages'; +import { injectable } from "tsyringe"; +import AddonEnabledUseCase from "../usecases/AddonEnabledUseCase"; +import SettingUseCase from "../usecases/SettingUseCase"; +import * as messages from "../../shared/messages"; @injectable() export default class SettingController { - constructor( private addonEnabledUseCase: AddonEnabledUseCase, - private settingUseCase: SettingUseCase, - ) { - } + private settingUseCase: SettingUseCase + ) {} async initSettings(): Promise<void> { try { diff --git a/src/content/di.ts b/src/content/di.ts index 63103a1..cc10c78 100644 --- a/src/content/di.ts +++ b/src/content/di.ts @@ -1,58 +1,78 @@ /* eslint-disable max-len */ -import { AddonEnabledRepositoryImpl } from './repositories/AddonEnabledRepository'; -import { AddonIndicatorClientImpl } from './client/AddonIndicatorClient'; -import { AddressRepositoryImpl } from './repositories/AddressRepository'; -import { ClipboardRepositoryImpl } from './repositories/ClipboardRepository'; -import { ConsoleClientImpl } from './client/ConsoleClient'; -import { ConsoleFramePresenterImpl } from './presenters/ConsoleFramePresenter'; -import { FindClientImpl } from './client/FindClient'; -import { FindMasterClientImpl } from './client/FindMasterClient'; -import { FindPresenterImpl } from './presenters/FindPresenter'; -import { FindRepositoryImpl } from './repositories/FindRepository'; -import { FocusPresenterImpl } from './presenters/FocusPresenter'; -import { FollowKeyRepositoryImpl } from './repositories/FollowKeyRepository'; -import { FollowMasterClientImpl } from './client/FollowMasterClient'; -import { FollowMasterRepositoryImpl } from './repositories/FollowMasterRepository'; -import { FollowPresenterImpl } from './presenters/FollowPresenter'; -import { FollowSlaveClientFactoryImpl } from './client/FollowSlaveClientFactory'; -import { FollowSlaveRepositoryImpl } from './repositories/FollowSlaveRepository'; -import { KeymapRepositoryImpl } from './repositories/KeymapRepository'; -import { MarkClientImpl } from './client/MarkClient'; -import { MarkKeyRepositoryImpl } from './repositories/MarkKeyRepository'; -import { MarkRepositoryImpl } from './repositories/MarkRepository'; -import { NavigationPresenterImpl } from './presenters/NavigationPresenter'; -import { OperationClientImpl } from './client/OperationClient'; -import { ScrollPresenterImpl } from './presenters/ScrollPresenter'; -import { SettingClientImpl } from './client/SettingClient'; -import { SettingRepositoryImpl } from './repositories/SettingRepository'; -import { TabsClientImpl } from './client/TabsClient'; -import { container } from 'tsyringe'; +import { AddonEnabledRepositoryImpl } from "./repositories/AddonEnabledRepository"; +import { AddonIndicatorClientImpl } from "./client/AddonIndicatorClient"; +import { AddressRepositoryImpl } from "./repositories/AddressRepository"; +import { ClipboardRepositoryImpl } from "./repositories/ClipboardRepository"; +import { ConsoleClientImpl } from "./client/ConsoleClient"; +import { ConsoleFramePresenterImpl } from "./presenters/ConsoleFramePresenter"; +import { FindClientImpl } from "./client/FindClient"; +import { FindMasterClientImpl } from "./client/FindMasterClient"; +import { FindPresenterImpl } from "./presenters/FindPresenter"; +import { FindRepositoryImpl } from "./repositories/FindRepository"; +import { FocusPresenterImpl } from "./presenters/FocusPresenter"; +import { FollowKeyRepositoryImpl } from "./repositories/FollowKeyRepository"; +import { FollowMasterClientImpl } from "./client/FollowMasterClient"; +import { FollowMasterRepositoryImpl } from "./repositories/FollowMasterRepository"; +import { FollowPresenterImpl } from "./presenters/FollowPresenter"; +import { FollowSlaveClientFactoryImpl } from "./client/FollowSlaveClientFactory"; +import { FollowSlaveRepositoryImpl } from "./repositories/FollowSlaveRepository"; +import { KeymapRepositoryImpl } from "./repositories/KeymapRepository"; +import { MarkClientImpl } from "./client/MarkClient"; +import { MarkKeyRepositoryImpl } from "./repositories/MarkKeyRepository"; +import { MarkRepositoryImpl } from "./repositories/MarkRepository"; +import { NavigationPresenterImpl } from "./presenters/NavigationPresenter"; +import { OperationClientImpl } from "./client/OperationClient"; +import { ScrollPresenterImpl } from "./presenters/ScrollPresenter"; +import { SettingClientImpl } from "./client/SettingClient"; +import { SettingRepositoryImpl } from "./repositories/SettingRepository"; +import { TabsClientImpl } from "./client/TabsClient"; +import { container } from "tsyringe"; -container.register('FollowMasterClient', { useValue: new FollowMasterClientImpl(window.top) }); -container.register('AddonEnabledRepository', { useClass: AddonEnabledRepositoryImpl }); -container.register('AddonIndicatorClient', { useClass: AddonIndicatorClientImpl }); -container.register('AddressRepository', { useClass: AddressRepositoryImpl }); -container.register('ClipboardRepository', { useClass: ClipboardRepositoryImpl }); -container.register('ConsoleClient', { useClass: ConsoleClientImpl }); -container.register('ConsoleFramePresenter', { useClass: ConsoleFramePresenterImpl }); -container.register('FindClient', { useClass: FindClientImpl }); -container.register('FindMasterClient', { useClass: FindMasterClientImpl }); -container.register('FindPresenter', { useClass: FindPresenterImpl }); -container.register('FindRepository', { useClass: FindRepositoryImpl }); -container.register('FocusPresenter', { useClass: FocusPresenterImpl }); -container.register('FollowKeyRepository', { useClass: FollowKeyRepositoryImpl }); -container.register('FollowMasterRepository', { useClass: FollowMasterRepositoryImpl }); -container.register('FollowPresenter', { useClass: FollowPresenterImpl }); -container.register('FollowSlaveClientFactory', { useClass: FollowSlaveClientFactoryImpl }); -container.register('FollowSlaveRepository', { useClass: FollowSlaveRepositoryImpl }); -container.register('KeymapRepository', { useClass: KeymapRepositoryImpl }); -container.register('MarkClient', { useClass: MarkClientImpl }); -container.register('MarkKeyRepository', { useClass: MarkKeyRepositoryImpl }); -container.register('MarkRepository', { useClass: MarkRepositoryImpl }); -container.register('NavigationPresenter', { useClass: NavigationPresenterImpl }); -container.register('OperationClient', { useClass: OperationClientImpl }); -container.register('ScrollPresenter', { useClass: ScrollPresenterImpl }); -container.register('SettingClient', { useClass: SettingClientImpl }); -container.register('SettingRepository', { useClass: SettingRepositoryImpl }); -container.register('TabsClient', { useClass: TabsClientImpl }); +container.register("FollowMasterClient", { + useValue: new FollowMasterClientImpl(window.top), +}); +container.register("AddonEnabledRepository", { + useClass: AddonEnabledRepositoryImpl, +}); +container.register("AddonIndicatorClient", { + useClass: AddonIndicatorClientImpl, +}); +container.register("AddressRepository", { useClass: AddressRepositoryImpl }); +container.register("ClipboardRepository", { + useClass: ClipboardRepositoryImpl, +}); +container.register("ConsoleClient", { useClass: ConsoleClientImpl }); +container.register("ConsoleFramePresenter", { + useClass: ConsoleFramePresenterImpl, +}); +container.register("FindClient", { useClass: FindClientImpl }); +container.register("FindMasterClient", { useClass: FindMasterClientImpl }); +container.register("FindPresenter", { useClass: FindPresenterImpl }); +container.register("FindRepository", { useClass: FindRepositoryImpl }); +container.register("FocusPresenter", { useClass: FocusPresenterImpl }); +container.register("FollowKeyRepository", { + useClass: FollowKeyRepositoryImpl, +}); +container.register("FollowMasterRepository", { + useClass: FollowMasterRepositoryImpl, +}); +container.register("FollowPresenter", { useClass: FollowPresenterImpl }); +container.register("FollowSlaveClientFactory", { + useClass: FollowSlaveClientFactoryImpl, +}); +container.register("FollowSlaveRepository", { + useClass: FollowSlaveRepositoryImpl, +}); +container.register("KeymapRepository", { useClass: KeymapRepositoryImpl }); +container.register("MarkClient", { useClass: MarkClientImpl }); +container.register("MarkKeyRepository", { useClass: MarkKeyRepositoryImpl }); +container.register("MarkRepository", { useClass: MarkRepositoryImpl }); +container.register("NavigationPresenter", { + useClass: NavigationPresenterImpl, +}); +container.register("OperationClient", { useClass: OperationClientImpl }); +container.register("ScrollPresenter", { useClass: ScrollPresenterImpl }); +container.register("SettingClient", { useClass: SettingClientImpl }); +container.register("SettingRepository", { useClass: SettingRepositoryImpl }); +container.register("TabsClient", { useClass: TabsClientImpl }); diff --git a/src/content/domains/KeySequence.ts b/src/content/domains/KeySequence.ts index cf59125..5819fc5 100644 --- a/src/content/domains/KeySequence.ts +++ b/src/content/domains/KeySequence.ts @@ -1,10 +1,7 @@ -import Key from '../../shared/settings/Key'; +import Key from "../../shared/settings/Key"; export default class KeySequence { - constructor( - public readonly keys: Key[], - ) { - } + constructor(public readonly keys: Key[]) {} push(key: Key): number { return this.keys.push(key); @@ -27,25 +24,26 @@ export default class KeySequence { } isDigitOnly(): boolean { - return this.keys.every(key => key.isDigit()); + return this.keys.every((key) => key.isDigit()); } repeatCount(): number { - let nonDigitAt = this.keys.findIndex(key => !key.isDigit()); + let nonDigitAt = this.keys.findIndex((key) => !key.isDigit()); if (this.keys.length === 0 || nonDigitAt === 0) { return 1; } if (nonDigitAt === -1) { nonDigitAt = this.keys.length; } - const digits = this.keys.slice(0, nonDigitAt) - .map(key => key.key) - .join(''); + const digits = this.keys + .slice(0, nonDigitAt) + .map((key) => key.key) + .join(""); return Number(digits); } trimNumericPrefix(): KeySequence { - let nonDigitAt = this.keys.findIndex(key => !key.isDigit()); + let nonDigitAt = this.keys.findIndex((key) => !key.isDigit()); if (nonDigitAt === -1) { nonDigitAt = this.keys.length; } @@ -53,7 +51,7 @@ export default class KeySequence { } splitNumericPrefix(): [KeySequence, KeySequence] { - const nonDigitIndex = this.keys.findIndex(key => !key.isDigit()); + const nonDigitIndex = this.keys.findIndex((key) => !key.isDigit()); if (nonDigitIndex === -1) { return [this, new KeySequence([])]; } @@ -65,15 +63,16 @@ export default class KeySequence { static fromMapKeys(keys: string): KeySequence { const fromMapKeysRecursive = ( - remaining: string, mappedKeys: Key[], + remaining: string, + mappedKeys: Key[] ): Key[] => { if (remaining.length === 0) { return mappedKeys; } let nextPos = 1; - if (remaining.startsWith('<')) { - const ltPos = remaining.indexOf('>'); + if (remaining.startsWith("<")) { + const ltPos = remaining.indexOf(">"); if (ltPos > 0) { nextPos = ltPos + 1; } diff --git a/src/content/domains/Mark.ts b/src/content/domains/Mark.ts index 0c40988..68ed226 100644 --- a/src/content/domains/Mark.ts +++ b/src/content/domains/Mark.ts @@ -2,4 +2,3 @@ export default interface Mark { x: number; y: number; } - diff --git a/src/content/hint-key-producer.ts b/src/content/hint-key-producer.ts index 3c9482f..a5e2877 100644 --- a/src/content/hint-key-producer.ts +++ b/src/content/hint-key-producer.ts @@ -5,7 +5,7 @@ export default class HintKeyProducer { constructor(charset: string) { if (charset.length === 0) { - throw new TypeError('charset is empty'); + throw new TypeError("charset is empty"); } this.charset = charset; @@ -15,12 +15,12 @@ export default class HintKeyProducer { produce(): string { this.increment(); - return this.counter.map(x => this.charset[x]).join(''); + return this.counter.map((x) => this.charset[x]).join(""); } private increment(): void { const max = this.charset.length - 1; - if (this.counter.every(x => x === max)) { + if (this.counter.every((x) => x === max)) { this.counter = new Array(this.counter.length + 1).fill(0); return; } diff --git a/src/content/index.ts b/src/content/index.ts index 176a157..b575e0d 100644 --- a/src/content/index.ts +++ b/src/content/index.ts @@ -1,10 +1,10 @@ -import 'reflect-metadata'; +import "reflect-metadata"; -import Application from './Application'; -import consoleFrameStyle from './site-style'; -import { ConsoleFramePresenterImpl } from './presenters/ConsoleFramePresenter'; -import { container } from 'tsyringe'; -import './di'; +import Application from "./Application"; +import consoleFrameStyle from "./site-style"; +import { ConsoleFramePresenterImpl } from "./presenters/ConsoleFramePresenter"; +import { container } from "tsyringe"; +import "./di"; if (window.self === window.top) { new ConsoleFramePresenterImpl().initialize(); @@ -13,8 +13,10 @@ if (window.self === window.top) { try { const app = container.resolve(Application); app.run(); -} catch (e) { console.error(e); } +} catch (e) { + console.error(e); +} -const style = window.document.createElement('style'); +const style = window.document.createElement("style"); style.textContent = consoleFrameStyle; window.document.head.appendChild(style); diff --git a/src/content/presenters/ConsoleFramePresenter.ts b/src/content/presenters/ConsoleFramePresenter.ts index 63c78fb..26522c4 100644 --- a/src/content/presenters/ConsoleFramePresenter.ts +++ b/src/content/presenters/ConsoleFramePresenter.ts @@ -6,17 +6,17 @@ export default interface ConsoleFramePresenter { export class ConsoleFramePresenterImpl implements ConsoleFramePresenter { initialize(): void { - const iframe = document.createElement('iframe'); - iframe.src = browser.runtime.getURL('build/console.html'); - iframe.id = 'vimvixen-console-frame'; - iframe.className = 'vimvixen-console-frame'; + const iframe = document.createElement("iframe"); + iframe.src = browser.runtime.getURL("build/console.html"); + iframe.id = "vimvixen-console-frame"; + iframe.className = "vimvixen-console-frame"; document.body.append(iframe); } blur(): void { - const ele = document.getElementById('vimvixen-console-frame'); + const ele = document.getElementById("vimvixen-console-frame"); if (!ele) { - throw new Error('console frame not created'); + throw new Error("console frame not created"); } ele.blur(); } diff --git a/src/content/presenters/FindPresenter.ts b/src/content/presenters/FindPresenter.ts index 98d8088..117142c 100644 --- a/src/content/presenters/FindPresenter.ts +++ b/src/content/presenters/FindPresenter.ts @@ -1,4 +1,3 @@ - export default interface FindPresenter { find(keyword: string, backwards: boolean): boolean; @@ -18,7 +17,8 @@ interface MyWindow extends Window { aWrapAround?: boolean, aWholeWord?: boolean, aSearchInFrames?: boolean, - aShowDialog?: boolean): boolean; + aShowDialog?: boolean + ): boolean; } // eslint-disable-next-line no-var, vars-on-top, init-declarations @@ -29,7 +29,6 @@ export class FindPresenterImpl implements FindPresenter { const caseSensitive = false; const wrapScan = true; - // NOTE: aWholeWord dows not implemented, and aSearchInFrames does not work // because of same origin policy const found = window.find(keyword, caseSensitive, backwards, wrapScan); diff --git a/src/content/presenters/FocusPresenter.ts b/src/content/presenters/FocusPresenter.ts index 842c41e..4d70a6e 100644 --- a/src/content/presenters/FocusPresenter.ts +++ b/src/content/presenters/FocusPresenter.ts @@ -1,4 +1,4 @@ -import * as doms from '../../shared/utils/dom'; +import * as doms from "../../shared/utils/dom"; export default interface FocusPresenter { focusFirstElement(): boolean; @@ -6,9 +6,13 @@ export default interface FocusPresenter { export class FocusPresenterImpl implements FocusPresenter { focusFirstElement(): boolean { - const inputTypes = ['email', 'number', 'search', 'tel', 'text', 'url']; - const inputSelector = inputTypes.map(type => `input[type=${type}]`).join(','); - const targets = window.document.querySelectorAll(inputSelector + ',textarea'); + const inputTypes = ["email", "number", "search", "tel", "text", "url"]; + const inputSelector = inputTypes + .map((type) => `input[type=${type}]`) + .join(","); + const targets = window.document.querySelectorAll( + inputSelector + ",textarea" + ); const target = Array.from(targets).find(doms.isVisible); if (target instanceof HTMLInputElement) { target.focus(); @@ -20,4 +24,3 @@ export class FocusPresenterImpl implements FocusPresenter { return false; } } - diff --git a/src/content/presenters/FollowPresenter.ts b/src/content/presenters/FollowPresenter.ts index fef8140..8aef819 100644 --- a/src/content/presenters/FollowPresenter.ts +++ b/src/content/presenters/FollowPresenter.ts @@ -1,11 +1,18 @@ -import Hint, { InputHint, LinkHint } from './Hint'; -import * as doms from '../../shared/utils/dom'; +import Hint, { InputHint, LinkHint } from "./Hint"; +import * as doms from "../../shared/utils/dom"; const TARGET_SELECTOR = [ - 'a', 'button', 'input', 'textarea', 'area', - '[contenteditable=true]', '[contenteditable=""]', '[tabindex]', - '[role="button"]', 'summary' -].join(','); + "a", + "button", + "input", + "textarea", + "area", + "[contenteditable=true]", + '[contenteditable=""]', + "[tabindex]", + '[role="button"]', + "summary", +].join(","); interface Size { width: number; @@ -21,11 +28,9 @@ const inViewport = ( win: Window, element: Element, viewSize: Size, - framePosition: Point, + framePosition: Point ): boolean => { - const { - top, left, bottom, right - } = doms.viewportRect(element); + const { top, left, bottom, right } = doms.viewportRect(element); const doc = win.document; const frameWidth = doc.documentElement.clientWidth; const frameHeight = doc.documentElement.clientHeight; @@ -34,9 +39,12 @@ const inViewport = ( // out of frame return false; } - if (right + framePosition.x < 0 || bottom + framePosition.y < 0 || - left + framePosition.x > viewSize.width || - top + framePosition.y > viewSize.height) { + if ( + right + framePosition.x < 0 || + bottom + framePosition.y < 0 || + left + framePosition.x > viewSize.width || + top + framePosition.y > viewSize.height + ) { // out of viewport return false; } @@ -47,11 +55,11 @@ const isAriaHiddenOrAriaDisabled = (win: Window, element: Element): boolean => { if (!element || win.document.documentElement === element) { return false; } - for (const attr of ['aria-hidden', 'aria-disabled']) { + for (const attr of ["aria-hidden", "aria-disabled"]) { const value = element.getAttribute(attr); if (value !== null) { const hidden = value.toLowerCase(); - if (hidden === '' || hidden === 'true') { + if (hidden === "" || hidden === "true") { return true; } } @@ -88,8 +96,10 @@ export class FollowPresenterImpl implements FollowPresenter { const min = Math.min(targets.length, tags.length); for (let i = 0; i < min; ++i) { const target = targets[i]; - if (target instanceof HTMLAnchorElement || - target instanceof HTMLAreaElement) { + if ( + target instanceof HTMLAnchorElement || + target instanceof HTMLAreaElement + ) { this.hints.push(new LinkHint(target, tags[i])); } else { this.hints.push(new InputHint(target, tags[i])); @@ -98,35 +108,40 @@ export class FollowPresenterImpl implements FollowPresenter { } filterHints(prefix: string): void { - const shown = this.hints.filter(h => h.getTag().startsWith(prefix)); - const hidden = this.hints.filter(h => !h.getTag().startsWith(prefix)); + const shown = this.hints.filter((h) => h.getTag().startsWith(prefix)); + const hidden = this.hints.filter((h) => !h.getTag().startsWith(prefix)); - shown.forEach(h => h.show()); - hidden.forEach(h => h.hide()); + shown.forEach((h) => h.show()); + hidden.forEach((h) => h.hide()); } clearHints(): void { - this.hints.forEach(h => h.remove()); + this.hints.forEach((h) => h.remove()); this.hints = []; } getHint(tag: string): Hint | undefined { - return this.hints.find(h => h.getTag() === tag); + return this.hints.find((h) => h.getTag() === tag); } private getTargets(viewSize: Size, framePosition: Point): HTMLElement[] { const all = window.document.querySelectorAll(TARGET_SELECTOR); - const filtered = Array.prototype.filter.call(all, (element: HTMLElement) => { - const style = window.getComputedStyle(element); - - // AREA's 'display' in Browser style is 'none' - return (element.tagName === 'AREA' || style.display !== 'none') && - style.visibility !== 'hidden' && - (element as HTMLInputElement).type !== 'hidden' && - element.offsetHeight > 0 && - !isAriaHiddenOrAriaDisabled(window, element) && - inViewport(window, element, viewSize, framePosition); - }); + const filtered = Array.prototype.filter.call( + all, + (element: HTMLElement) => { + const style = window.getComputedStyle(element); + + // AREA's 'display' in Browser style is 'none' + return ( + (element.tagName === "AREA" || style.display !== "none") && + style.visibility !== "hidden" && + (element as HTMLInputElement).type !== "hidden" && + element.offsetHeight > 0 && + !isAriaHiddenOrAriaDisabled(window, element) && + inViewport(window, element, viewSize, framePosition) + ); + } + ); return filtered; } } diff --git a/src/content/presenters/Hint.ts b/src/content/presenters/Hint.ts index 44b8185..3f39060 100644 --- a/src/content/presenters/Hint.ts +++ b/src/content/presenters/Hint.ts @@ -1,4 +1,4 @@ -import * as doms from '../../shared/utils/dom'; +import * as doms from "../../shared/utils/dom"; interface Point { x: number; @@ -8,7 +8,7 @@ interface Point { const hintPosition = (element: Element): Point => { const { left, top, right, bottom } = doms.viewportRect(element); - if (element.tagName !== 'AREA') { + if (element.tagName !== "AREA") { return { x: left, y: top }; } @@ -28,17 +28,17 @@ export default abstract class Hint { const doc = target.ownerDocument; if (doc === null) { - throw new TypeError('ownerDocument is null'); + throw new TypeError("ownerDocument is null"); } const { x, y } = hintPosition(target); const { scrollX, scrollY } = window; - const hint = doc.createElement('span'); - hint.className = 'vimvixen-hint'; + const hint = doc.createElement("span"); + hint.className = "vimvixen-hint"; hint.textContent = tag; - hint.style.left = x + scrollX + 'px'; - hint.style.top = y + scrollY + 'px'; + hint.style.left = x + scrollX + "px"; + hint.style.top = y + scrollY + "px"; doc.body.append(hint); @@ -47,11 +47,11 @@ export default abstract class Hint { } show(): void { - this.hint.style.display = 'inline'; + this.hint.style.display = "inline"; } hide(): void { - this.hint.style.display = 'none'; + this.hint.style.display = "none"; } remove(): void { @@ -77,7 +77,7 @@ export class LinkHint extends Hint { } getLinkTarget(): string | null { - return this.target.getAttribute('target'); + return this.target.getAttribute("target"); } click(): void { @@ -97,31 +97,31 @@ export class InputHint extends Hint { activate(): void { const target = this.target; switch (target.tagName.toLowerCase()) { - case 'input': - switch ((target as HTMLInputElement).type) { - case 'file': - case 'checkbox': - case 'radio': - case 'submit': - case 'reset': - case 'button': - case 'image': - case 'color': - return target.click(); - default: + case "input": + switch ((target as HTMLInputElement).type) { + case "file": + case "checkbox": + case "radio": + case "submit": + case "reset": + case "button": + case "image": + case "color": + return target.click(); + default: + return target.focus(); + } + case "textarea": return target.focus(); - } - case 'textarea': - return target.focus(); - case 'button': - case 'summary': - return target.click(); - default: - if (doms.isContentEditable(target)) { - return target.focus(); - } else if (target.hasAttribute('tabindex')) { + case "button": + case "summary": return target.click(); - } + default: + if (doms.isContentEditable(target)) { + return target.focus(); + } else if (target.hasAttribute("tabindex")) { + return target.click(); + } } } } diff --git a/src/content/presenters/NavigationPresenter.ts b/src/content/presenters/NavigationPresenter.ts index 951e62a..3edcd12 100644 --- a/src/content/presenters/NavigationPresenter.ts +++ b/src/content/presenters/NavigationPresenter.ts @@ -8,7 +8,7 @@ export default interface NavigationPresenter { openLinkNext(): void; } -const REL_PATTERN: {[key: string]: RegExp} = { +const REL_PATTERN: { [key: string]: RegExp } = { prev: /^(?:prev(?:ious)?|older)\b|\u2039|\u2190|\xab|\u226a|<</i, next: /^(?:next|newer)\b|\u203a|\u2192|\xbb|\u226b|>>/i, }; @@ -18,7 +18,7 @@ const REL_PATTERN: {[key: string]: RegExp} = { // eslint-disable-next-line func-style function selectLast<E extends Element>( selector: string, - filter?: (e: E) => boolean, + filter?: (e: E) => boolean ): E | null { let nodes = Array.from( window.document.querySelectorAll(selector) as NodeListOf<E> @@ -40,15 +40,15 @@ export class NavigationPresenterImpl implements NavigationPresenter { } openLinkPrev(): void { - this.linkRel('prev'); + this.linkRel("prev"); } openLinkNext(): void { - this.linkRel('next'); + this.linkRel("next"); } // Code common to linkPrev and linkNext which navigates to the specified page. - private linkRel(rel: 'prev' | 'next'): void { + private linkRel(rel: "prev" | "next"): void { const link = selectLast<HTMLLinkElement>(`link[rel~=${rel}][href]`); if (link) { window.location.href = link.href; @@ -57,10 +57,11 @@ export class NavigationPresenterImpl implements NavigationPresenter { const pattern = REL_PATTERN[rel]; - const a = selectLast<HTMLAnchorElement>(`a[rel~=${rel}][href]`) || - // `innerText` is much slower than `textContent`, but produces much better - // (i.e. less unexpected) results - selectLast('a[href]', lnk => pattern.test(lnk.innerText)); + const a = + selectLast<HTMLAnchorElement>(`a[rel~=${rel}][href]`) || + // `innerText` is much slower than `textContent`, but produces much better + // (i.e. less unexpected) results + selectLast("a[href]", (lnk) => pattern.test(lnk.innerText)); if (a) { a.click(); diff --git a/src/content/presenters/ScrollPresenter.ts b/src/content/presenters/ScrollPresenter.ts index 387ab62..f1a6402 100644 --- a/src/content/presenters/ScrollPresenter.ts +++ b/src/content/presenters/ScrollPresenter.ts @@ -1,4 +1,4 @@ -import * as doms from '../../shared/utils/dom'; +import * as doms from "../../shared/utils/dom"; const SCROLL_DELTA_X = 64; const SCROLL_DELTA_Y = 64; @@ -9,13 +9,19 @@ let lastTimeoutId: number | null = null; const isScrollableStyle = (element: Element): boolean => { const { overflowX, overflowY } = window.getComputedStyle(element); - return !(overflowX !== 'scroll' && overflowX !== 'auto' && - overflowY !== 'scroll' && overflowY !== 'auto'); + return !( + overflowX !== "scroll" && + overflowX !== "auto" && + overflowY !== "scroll" && + overflowY !== "auto" + ); }; const isOverflowed = (element: Element): boolean => { - return element.scrollWidth > element.clientWidth || - element.scrollHeight > element.clientHeight; + return ( + element.scrollWidth > element.clientWidth || + element.scrollHeight > element.clientHeight + ); }; // Find a visiable and scrollable element by depth-first search. Currently @@ -73,7 +79,7 @@ class Scroller { this.element.scrollTo({ left: x, top: y, - behavior: 'smooth', + behavior: "smooth", }); this.prepareReset(); } @@ -94,7 +100,7 @@ class Scroller { } } -export type Point = { x: number, y: number }; +export type Point = { x: number; y: number }; export default interface ScrollPresenter { getScroll(): Point; diff --git a/src/content/repositories/AddressRepository.ts b/src/content/repositories/AddressRepository.ts index 6f9487b..f200bf2 100644 --- a/src/content/repositories/AddressRepository.ts +++ b/src/content/repositories/AddressRepository.ts @@ -1,5 +1,5 @@ export default interface AddressRepository { - getCurrentURL(): URL + getCurrentURL(): URL; } export class AddressRepositoryImpl implements AddressRepository { diff --git a/src/content/repositories/ClipboardRepository.ts b/src/content/repositories/ClipboardRepository.ts index 8219835..a700543 100644 --- a/src/content/repositories/ClipboardRepository.ts +++ b/src/content/repositories/ClipboardRepository.ts @@ -6,39 +6,39 @@ export default interface ClipboardRepository { export class ClipboardRepositoryImpl { read(): string { - const textarea = window.document.createElement('textarea'); + const textarea = window.document.createElement("textarea"); window.document.body.append(textarea); - textarea.style.position = 'fixed'; - textarea.style.top = '-100px'; - textarea.contentEditable = 'true'; + textarea.style.position = "fixed"; + textarea.style.top = "-100px"; + textarea.contentEditable = "true"; textarea.focus(); - const ok = window.document.execCommand('paste'); + const ok = window.document.execCommand("paste"); const value = textarea.textContent!!; textarea.remove(); if (!ok) { - throw new Error('failed to access clipbaord'); + throw new Error("failed to access clipbaord"); } return value; } write(text: string): void { - const input = window.document.createElement('input'); + const input = window.document.createElement("input"); window.document.body.append(input); - input.style.position = 'fixed'; - input.style.top = '-100px'; + input.style.position = "fixed"; + input.style.top = "-100px"; input.value = text; input.select(); - const ok = window.document.execCommand('copy'); + const ok = window.document.execCommand("copy"); input.remove(); if (!ok) { - throw new Error('failed to access clipbaord'); + throw new Error("failed to access clipbaord"); } } } diff --git a/src/content/repositories/FollowMasterRepository.ts b/src/content/repositories/FollowMasterRepository.ts index da2402c..cc49e5f 100644 --- a/src/content/repositories/FollowMasterRepository.ts +++ b/src/content/repositories/FollowMasterRepository.ts @@ -35,7 +35,7 @@ export class FollowMasterRepositoryImpl implements FollowMasterRepository { } getTagsByPrefix(prefix: string): string[] { - return current.tags.filter(t => t.startsWith(prefix)); + return current.tags.filter((t) => t.startsWith(prefix)); } addTag(tag: string): void { @@ -54,4 +54,3 @@ export class FollowMasterRepositoryImpl implements FollowMasterRepository { return current.background; } } - diff --git a/src/content/repositories/FollowSlaveRepository.ts b/src/content/repositories/FollowSlaveRepository.ts index 42a0710..0dc9e89 100644 --- a/src/content/repositories/FollowSlaveRepository.ts +++ b/src/content/repositories/FollowSlaveRepository.ts @@ -25,5 +25,3 @@ export class FollowSlaveRepositoryImpl implements FollowSlaveRepository { return current.enabled; } } - - diff --git a/src/content/repositories/KeymapRepository.ts b/src/content/repositories/KeymapRepository.ts index 2944723..6a7d656 100644 --- a/src/content/repositories/KeymapRepository.ts +++ b/src/content/repositories/KeymapRepository.ts @@ -1,5 +1,5 @@ -import Key from '../../shared/settings/Key'; -import KeySequence from '../domains/KeySequence'; +import Key from "../../shared/settings/Key"; +import KeySequence from "../domains/KeySequence"; export default interface KeymapRepository { enqueueKey(key: Key): KeySequence; @@ -10,7 +10,6 @@ export default interface KeymapRepository { let current: KeySequence = new KeySequence([]); export class KeymapRepositoryImpl { - enqueueKey(key: Key): KeySequence { current.push(key); return current; diff --git a/src/content/repositories/MarkKeyRepository.ts b/src/content/repositories/MarkKeyRepository.ts index 18c3e23..c351c13 100644 --- a/src/content/repositories/MarkKeyRepository.ts +++ b/src/content/repositories/MarkKeyRepository.ts @@ -23,7 +23,6 @@ const current: Mode = { }; export class MarkKeyRepositoryImpl implements MarkKeyRepository { - isSetMode(): boolean { return current.setMode; } diff --git a/src/content/repositories/MarkRepository.ts b/src/content/repositories/MarkRepository.ts index afa980a..e48db25 100644 --- a/src/content/repositories/MarkRepository.ts +++ b/src/content/repositories/MarkRepository.ts @@ -1,4 +1,4 @@ -import Mark from '../domains/Mark'; +import Mark from "../domains/Mark"; export default interface MarkRepository { set(key: string, mark: Mark): void; @@ -6,7 +6,7 @@ export default interface MarkRepository { get(key: string): Mark | null; } -const saved: {[key: string]: Mark} = {}; +const saved: { [key: string]: Mark } = {}; export class MarkRepositoryImpl implements MarkRepository { set(key: string, mark: Mark): void { diff --git a/src/content/repositories/SettingRepository.ts b/src/content/repositories/SettingRepository.ts index 4ba26e0..1e393cd 100644 --- a/src/content/repositories/SettingRepository.ts +++ b/src/content/repositories/SettingRepository.ts @@ -1,4 +1,4 @@ -import Settings, { DefaultSetting } from '../../shared/settings/Settings'; +import Settings, { DefaultSetting } from "../../shared/settings/Settings"; let current: Settings = DefaultSetting; diff --git a/src/content/usecases/AddonEnabledUseCase.ts b/src/content/usecases/AddonEnabledUseCase.ts index 608a401..f7e78c5 100644 --- a/src/content/usecases/AddonEnabledUseCase.ts +++ b/src/content/usecases/AddonEnabledUseCase.ts @@ -1,18 +1,16 @@ -import { injectable, inject } from 'tsyringe'; -import AddonIndicatorClient from '../client/AddonIndicatorClient'; -import AddonEnabledRepository from '../repositories/AddonEnabledRepository'; +import { injectable, inject } from "tsyringe"; +import AddonIndicatorClient from "../client/AddonIndicatorClient"; +import AddonEnabledRepository from "../repositories/AddonEnabledRepository"; @injectable() export default class AddonEnabledUseCase { - constructor( - @inject('AddonIndicatorClient') + @inject("AddonIndicatorClient") private indicator: AddonIndicatorClient, - @inject('AddonEnabledRepository') - private repository: AddonEnabledRepository, - ) { - } + @inject("AddonEnabledRepository") + private repository: AddonEnabledRepository + ) {} async enable(): Promise<void> { await this.setEnabled(true); diff --git a/src/content/usecases/ClipboardUseCase.ts b/src/content/usecases/ClipboardUseCase.ts index 7f16f68..875fc11 100644 --- a/src/content/usecases/ClipboardUseCase.ts +++ b/src/content/usecases/ClipboardUseCase.ts @@ -1,24 +1,23 @@ -import { injectable, inject } from 'tsyringe'; -import * as urls from '../../shared/urls'; -import ClipboardRepository from '../repositories/ClipboardRepository'; -import SettingRepository from '../repositories/SettingRepository'; -import ConsoleClient from '../client/ConsoleClient'; -import OperationClient from '../client/OperationClient'; +import { injectable, inject } from "tsyringe"; +import * as urls from "../../shared/urls"; +import ClipboardRepository from "../repositories/ClipboardRepository"; +import SettingRepository from "../repositories/SettingRepository"; +import ConsoleClient from "../client/ConsoleClient"; +import OperationClient from "../client/OperationClient"; @injectable() export default class ClipboardUseCase { constructor( - @inject('ClipboardRepository') private repository: ClipboardRepository, - @inject('SettingRepository') private settingRepository: SettingRepository, - @inject('ConsoleClient') private consoleClient: ConsoleClient, - @inject('OperationClient') private operationClinet: OperationClient, - ) { - } + @inject("ClipboardRepository") private repository: ClipboardRepository, + @inject("SettingRepository") private settingRepository: SettingRepository, + @inject("ConsoleClient") private consoleClient: ConsoleClient, + @inject("OperationClient") private operationClinet: OperationClient + ) {} async yankCurrentURL(): Promise<string> { const url = window.location.href; this.repository.write(url); - await this.consoleClient.info('Yanked ' + url); + await this.consoleClient.info("Yanked " + url); return Promise.resolve(url); } diff --git a/src/content/usecases/ConsoleFrameUseCase.ts b/src/content/usecases/ConsoleFrameUseCase.ts index 3c4b0a1..b118c7f 100644 --- a/src/content/usecases/ConsoleFrameUseCase.ts +++ b/src/content/usecases/ConsoleFrameUseCase.ts @@ -1,13 +1,12 @@ -import { injectable, inject } from 'tsyringe'; -import ConsoleFramePresenter from '../presenters/ConsoleFramePresenter'; +import { injectable, inject } from "tsyringe"; +import ConsoleFramePresenter from "../presenters/ConsoleFramePresenter"; @injectable() export default class ConsoleFrameUseCase { constructor( - @inject('ConsoleFramePresenter') - private consoleFramePresenter: ConsoleFramePresenter, - ) { - } + @inject("ConsoleFramePresenter") + private consoleFramePresenter: ConsoleFramePresenter + ) {} unfocus() { window.focus(); diff --git a/src/content/usecases/FindSlaveUseCase.ts b/src/content/usecases/FindSlaveUseCase.ts index 0a5c2ce..3b8c4b4 100644 --- a/src/content/usecases/FindSlaveUseCase.ts +++ b/src/content/usecases/FindSlaveUseCase.ts @@ -1,12 +1,11 @@ -import { injectable, inject } from 'tsyringe'; -import FindMasterClient from '../client/FindMasterClient'; +import { injectable, inject } from "tsyringe"; +import FindMasterClient from "../client/FindMasterClient"; @injectable() export default class FindSlaveUseCase { constructor( - @inject('FindMasterClient') private findMasterClient: FindMasterClient, - ) { - } + @inject("FindMasterClient") private findMasterClient: FindMasterClient + ) {} findNext() { this.findMasterClient.findNext(); diff --git a/src/content/usecases/FindUseCase.ts b/src/content/usecases/FindUseCase.ts index c6a478f..bff0eee 100644 --- a/src/content/usecases/FindUseCase.ts +++ b/src/content/usecases/FindUseCase.ts @@ -1,18 +1,17 @@ -import { injectable, inject } from 'tsyringe'; -import FindPresenter from '../presenters/FindPresenter'; -import FindRepository from '../repositories/FindRepository'; -import FindClient from '../client/FindClient'; -import ConsoleClient from '../client/ConsoleClient'; +import { injectable, inject } from "tsyringe"; +import FindPresenter from "../presenters/FindPresenter"; +import FindRepository from "../repositories/FindRepository"; +import FindClient from "../client/FindClient"; +import ConsoleClient from "../client/ConsoleClient"; @injectable() export default class FindUseCase { constructor( - @inject('FindPresenter') private presenter: FindPresenter, - @inject('FindRepository') private repository: FindRepository, - @inject('FindClient') private client: FindClient, - @inject('ConsoleClient') private consoleClient: ConsoleClient, - ) { - } + @inject("FindPresenter") private presenter: FindPresenter, + @inject("FindRepository") private repository: FindRepository, + @inject("FindClient") private client: FindClient, + @inject("ConsoleClient") private consoleClient: ConsoleClient + ) {} async startFind(keyword?: string): Promise<void> { this.presenter.clearSelection(); @@ -36,18 +35,16 @@ export default class FindUseCase { return this.findNextPrev(true); } - private async findNextPrev( - backwards: boolean, - ): Promise<void> { + private async findNextPrev(backwards: boolean): Promise<void> { const keyword = await this.getKeyword(); if (!keyword) { return this.showNoLastKeywordError(); } const found = this.presenter.find(keyword, backwards); if (found) { - this.consoleClient.info('Pattern found: ' + keyword); + this.consoleClient.info("Pattern found: " + keyword); } else { - this.consoleClient.error('Pattern not found: ' + keyword); + this.consoleClient.error("Pattern not found: " + keyword); } } @@ -65,6 +62,6 @@ export default class FindUseCase { } private async showNoLastKeywordError(): Promise<void> { - await this.consoleClient.error('No previous search keywords'); + await this.consoleClient.error("No previous search keywords"); } } diff --git a/src/content/usecases/FocusUseCase.ts b/src/content/usecases/FocusUseCase.ts index 0158672..8c62003 100644 --- a/src/content/usecases/FocusUseCase.ts +++ b/src/content/usecases/FocusUseCase.ts @@ -1,12 +1,9 @@ -import { injectable, inject } from 'tsyringe'; -import FocusPresenter from '../presenters/FocusPresenter'; +import { injectable, inject } from "tsyringe"; +import FocusPresenter from "../presenters/FocusPresenter"; @injectable() export default class FocusUseCases { - constructor( - @inject('FocusPresenter') private presenter: FocusPresenter, - ) { - } + constructor(@inject("FocusPresenter") private presenter: FocusPresenter) {} focusFirstInput() { this.presenter.focusFirstElement(); diff --git a/src/content/usecases/FollowMasterUseCase.ts b/src/content/usecases/FollowMasterUseCase.ts index 0e7f394..329f05a 100644 --- a/src/content/usecases/FollowMasterUseCase.ts +++ b/src/content/usecases/FollowMasterUseCase.ts @@ -1,10 +1,10 @@ -import { injectable, inject } from 'tsyringe'; -import FollowKeyRepository from '../repositories/FollowKeyRepository'; -import FollowMasterRepository from '../repositories/FollowMasterRepository'; -import FollowSlaveClient from '../client/FollowSlaveClient'; -import FollowSlaveClientFactory from '../client/FollowSlaveClientFactory'; -import SettingRepository from '../repositories/SettingRepository'; -import HintKeyProducer from './HintKeyProducer'; +import { injectable, inject } from "tsyringe"; +import FollowKeyRepository from "../repositories/FollowKeyRepository"; +import FollowMasterRepository from "../repositories/FollowMasterRepository"; +import FollowSlaveClient from "../client/FollowSlaveClient"; +import FollowSlaveClientFactory from "../client/FollowSlaveClientFactory"; +import SettingRepository from "../repositories/SettingRepository"; +import HintKeyProducer from "./HintKeyProducer"; @injectable() export default class FollowMasterUseCase { @@ -12,17 +12,17 @@ export default class FollowMasterUseCase { private producer: HintKeyProducer | null; constructor( - @inject('FollowKeyRepository') + @inject("FollowKeyRepository") private followKeyRepository: FollowKeyRepository, - @inject('FollowMasterRepository') + @inject("FollowMasterRepository") private followMasterRepository: FollowMasterRepository, - @inject('SettingRepository') + @inject("SettingRepository") private settingRepository: SettingRepository, - @inject('FollowSlaveClientFactory') - private followSlaveClientFactory: FollowSlaveClientFactory, + @inject("FollowSlaveClientFactory") + private followSlaveClientFactory: FollowSlaveClientFactory ) { this.producer = null; } @@ -36,19 +36,21 @@ export default class FollowMasterUseCase { const viewWidth = window.top.innerWidth; const viewHeight = window.top.innerHeight; - this.followSlaveClientFactory.create(window.top).requestHintCount( - { width: viewWidth, height: viewHeight }, - { x: 0, y: 0 }, - ); + this.followSlaveClientFactory + .create(window.top) + .requestHintCount( + { width: viewWidth, height: viewHeight }, + { x: 0, y: 0 } + ); - const frameElements = window.document.querySelectorAll('iframe'); + const frameElements = window.document.querySelectorAll("iframe"); for (let i = 0; i < frameElements.length; ++i) { const ele = frameElements[i] as HTMLFrameElement | HTMLIFrameElement; const { left: frameX, top: frameY } = ele.getBoundingClientRect(); const client = this.followSlaveClientFactory.create(ele.contentWindow!!); client.requestHintCount( { width: viewWidth, height: viewHeight }, - { x: frameX, y: frameY }, + { x: frameX, y: frameY } ); } } @@ -67,8 +69,10 @@ export default class FollowMasterUseCase { const viewHeight = window.innerHeight || doc.documentElement.clientHeight; let pos = { x: 0, y: 0 }; if (sender !== window) { - const frameElements = window.document.querySelectorAll('iframe'); - const ele = Array.from(frameElements).find(e => e.contentWindow === sender); + const frameElements = window.document.querySelectorAll("iframe"); + const ele = Array.from(frameElements).find( + (e) => e.contentWindow === sender + ); if (!ele) { // elements of the sender is gone return; @@ -77,11 +81,7 @@ export default class FollowMasterUseCase { pos = { x: frameX, y: frameY }; } const client = this.followSlaveClientFactory.create(sender); - client.createHints( - { width: viewWidth, height: viewHeight }, - pos, - produced, - ); + client.createHints({ width: viewWidth, height: viewHeight }, pos, produced); } cancelFollow(): void { @@ -110,17 +110,17 @@ export default class FollowMasterUseCase { enqueue(key: string): void { switch (key) { - case 'Enter': - this.activate(this.getCurrentTag()); - return; - case 'Esc': - this.cancelFollow(); - return; - case 'Backspace': - case 'Delete': - this.followKeyRepository.popKey(); - this.filter(this.getCurrentTag()); - return; + case "Enter": + this.activate(this.getCurrentTag()); + return; + case "Esc": + this.cancelFollow(); + return; + case "Backspace": + case "Delete": + this.followKeyRepository.popKey(); + this.filter(this.getCurrentTag()); + return; } this.followKeyRepository.pushKey(key); @@ -138,13 +138,15 @@ export default class FollowMasterUseCase { private broadcastToSlaves(handler: (client: FollowSlaveClient) => void) { const allFrames = [window.self].concat(Array.from(window.frames as any)); - const clients = allFrames.map(w => this.followSlaveClientFactory.create(w)); + const clients = allFrames.map((w) => + this.followSlaveClientFactory.create(w) + ); for (const client of clients) { handler(client); } } private getCurrentTag(): string { - return this.followKeyRepository.getKeys().join(''); + return this.followKeyRepository.getKeys().join(""); } } diff --git a/src/content/usecases/FollowSlaveUseCase.ts b/src/content/usecases/FollowSlaveUseCase.ts index fb805b9..971ecee 100644 --- a/src/content/usecases/FollowSlaveUseCase.ts +++ b/src/content/usecases/FollowSlaveUseCase.ts @@ -1,10 +1,10 @@ -import { injectable, inject } from 'tsyringe'; -import FollowSlaveRepository from '../repositories/FollowSlaveRepository'; -import FollowPresenter from '../presenters/FollowPresenter'; -import TabsClient from '../client/TabsClient'; -import FollowMasterClient from '../client/FollowMasterClient'; -import { LinkHint, InputHint } from '../presenters/Hint'; -import Key from '../../shared/settings/Key'; +import { injectable, inject } from "tsyringe"; +import FollowSlaveRepository from "../repositories/FollowSlaveRepository"; +import FollowPresenter from "../presenters/FollowPresenter"; +import TabsClient from "../client/TabsClient"; +import FollowMasterClient from "../client/FollowMasterClient"; +import { LinkHint, InputHint } from "../presenters/Hint"; +import Key from "../../shared/settings/Key"; interface Size { width: number; @@ -19,19 +19,18 @@ interface Point { @injectable() export default class FollowSlaveUseCase { constructor( - @inject('FollowPresenter') + @inject("FollowPresenter") private presenter: FollowPresenter, - @inject('TabsClient') + @inject("TabsClient") private tabsClient: TabsClient, - @inject('FollowMasterClient') + @inject("FollowMasterClient") private followMasterClient: FollowMasterClient, - @inject('FollowSlaveRepository') - private followSlaveRepository: FollowSlaveRepository, - ) { - } + @inject("FollowSlaveRepository") + private followSlaveRepository: FollowSlaveRepository + ) {} countTargets(viewSize: Size, framePosition: Point): void { const count = this.presenter.getTargetCount(viewSize, framePosition); @@ -65,11 +64,11 @@ export default class FollowSlaveUseCase { const url = hint.getLink(); let openNewTab = newTab; // Open link by background script in order to prevent a popup block - if (hint.getLinkTarget() === '_blank') { + if (hint.getLinkTarget() === "_blank") { openNewTab = true; } // eslint-disable-next-line no-script-url - if (!url || url === '#' || url.toLowerCase().startsWith('javascript:')) { + if (!url || url === "#" || url.toLowerCase().startsWith("javascript:")) { return; } await this.tabsClient.openUrl(url, openNewTab, background); diff --git a/src/content/usecases/HintKeyProducer.ts b/src/content/usecases/HintKeyProducer.ts index 68f3fbd..a5e2877 100644 --- a/src/content/usecases/HintKeyProducer.ts +++ b/src/content/usecases/HintKeyProducer.ts @@ -5,7 +5,7 @@ export default class HintKeyProducer { constructor(charset: string) { if (charset.length === 0) { - throw new TypeError('charset is empty'); + throw new TypeError("charset is empty"); } this.charset = charset; @@ -15,12 +15,12 @@ export default class HintKeyProducer { produce(): string { this.increment(); - return this.counter.map(x => this.charset[x]).join(''); + return this.counter.map((x) => this.charset[x]).join(""); } private increment(): void { const max = this.charset.length - 1; - if (this.counter.every(x => x === max)) { + if (this.counter.every((x) => x === max)) { this.counter = new Array(this.counter.length + 1).fill(0); return; } @@ -35,4 +35,3 @@ export default class HintKeyProducer { this.counter.reverse(); } } - diff --git a/src/content/usecases/KeymapUseCase.ts b/src/content/usecases/KeymapUseCase.ts index e02bc48..3cbadcb 100644 --- a/src/content/usecases/KeymapUseCase.ts +++ b/src/content/usecases/KeymapUseCase.ts @@ -1,16 +1,16 @@ -import { injectable, inject } from 'tsyringe'; -import KeymapRepository from '../repositories/KeymapRepository'; -import SettingRepository from '../repositories/SettingRepository'; -import AddonEnabledRepository from '../repositories/AddonEnabledRepository'; -import * as operations from '../../shared/operations'; -import Keymaps from '../../shared/settings/Keymaps'; -import Key from '../../shared/settings/Key'; -import KeySequence from '../domains/KeySequence'; -import AddressRepository from '../repositories/AddressRepository'; +import { injectable, inject } from "tsyringe"; +import KeymapRepository from "../repositories/KeymapRepository"; +import SettingRepository from "../repositories/SettingRepository"; +import AddonEnabledRepository from "../repositories/AddonEnabledRepository"; +import * as operations from "../../shared/operations"; +import Keymaps from "../../shared/settings/Keymaps"; +import Key from "../../shared/settings/Key"; +import KeySequence from "../domains/KeySequence"; +import AddressRepository from "../repositories/AddressRepository"; const reservedKeymaps = Keymaps.fromJSON({ - '<Esc>': { type: operations.CANCEL }, - '<C-[>': { type: operations.CANCEL }, + "<Esc>": { type: operations.CANCEL }, + "<C-[>": { type: operations.CANCEL }, }); const enableAddonOps = [ @@ -21,22 +21,21 @@ const enableAddonOps = [ @injectable() export default class KeymapUseCase { constructor( - @inject('KeymapRepository') + @inject("KeymapRepository") private repository: KeymapRepository, - @inject('SettingRepository') + @inject("SettingRepository") private settingRepository: SettingRepository, - @inject('AddonEnabledRepository') + @inject("AddonEnabledRepository") private addonEnabledRepository: AddonEnabledRepository, - @inject('AddressRepository') - private addressRepository: AddressRepository, - ) { - } + @inject("AddressRepository") + private addressRepository: AddressRepository + ) {} // eslint-disable-next-line max-statements - nextOps(key: Key): { repeat: number, op: operations.Operation } | null { + nextOps(key: Key): { repeat: number; op: operations.Operation } | null { const sequence = this.repository.enqueueKey(key); const baseSequence = sequence.trimNumericPrefix(); const keymaps = this.keymapEntityMap(); @@ -49,14 +48,14 @@ export default class KeymapUseCase { return null; } - if (matched.length === 1 && - sequence.length() === matched[0][0].length()) { + if (matched.length === 1 && sequence.length() === matched[0][0].length()) { // keys are matched with an operation this.repository.clear(); return { repeat: 1, op: matched[0][1] }; } else if ( baseMatched.length === 1 && - baseSequence.length() === baseMatched[0][0].length()) { + baseSequence.length() === baseMatched[0][0].length() + ) { // keys are matched with an operation with a numeric prefix this.repository.clear(); return { repeat: sequence.repeatCount(), op: baseMatched[0][1] }; @@ -75,15 +74,20 @@ export default class KeymapUseCase { } private keymapEntityMap(): [KeySequence, operations.Operation][] { - const keymaps = this.settingRepository.get().keymaps.combine(reservedKeymaps); - let entries = keymaps.entries().map( - ([keys, op]) => [KeySequence.fromMapKeys(keys), op] - ) as [KeySequence, operations.Operation][]; + const keymaps = this.settingRepository + .get() + .keymaps.combine(reservedKeymaps); + let entries = keymaps + .entries() + .map(([keys, op]) => [KeySequence.fromMapKeys(keys), op]) as [ + KeySequence, + operations.Operation + ][]; if (!this.addonEnabledRepository.get()) { // available keymaps are only ADDON_ENABLE and ADDON_TOGGLE_ENABLED if // the addon disabled - entries = entries.filter( - ([_seq, { type }]) => enableAddonOps.includes(type) + entries = entries.filter(([_seq, { type }]) => + enableAddonOps.includes(type) ); } return entries; diff --git a/src/content/usecases/MarkKeyUseCase.ts b/src/content/usecases/MarkKeyUseCase.ts index 6cef6f2..b807c74 100644 --- a/src/content/usecases/MarkKeyUseCase.ts +++ b/src/content/usecases/MarkKeyUseCase.ts @@ -1,12 +1,11 @@ -import { injectable, inject } from 'tsyringe'; -import MarkKeyRepository from '../repositories/MarkKeyRepository'; +import { injectable, inject } from "tsyringe"; +import MarkKeyRepository from "../repositories/MarkKeyRepository"; @injectable() export default class MarkKeyUseCase { constructor( - @inject('MarkKeyRepository') private repository: MarkKeyRepository, - ) { - } + @inject("MarkKeyRepository") private repository: MarkKeyRepository + ) {} isSetMode(): boolean { return this.repository.isSetMode(); diff --git a/src/content/usecases/MarkUseCase.ts b/src/content/usecases/MarkUseCase.ts index 8cd0c72..002fdee 100644 --- a/src/content/usecases/MarkUseCase.ts +++ b/src/content/usecases/MarkUseCase.ts @@ -1,20 +1,19 @@ -import { injectable, inject } from 'tsyringe'; -import ScrollPresenter from '../presenters/ScrollPresenter'; -import MarkClient from '../client/MarkClient'; -import MarkRepository from '../repositories/MarkRepository'; -import SettingRepository from '../repositories/SettingRepository'; -import ConsoleClient from '../client/ConsoleClient'; +import { injectable, inject } from "tsyringe"; +import ScrollPresenter from "../presenters/ScrollPresenter"; +import MarkClient from "../client/MarkClient"; +import MarkRepository from "../repositories/MarkRepository"; +import SettingRepository from "../repositories/SettingRepository"; +import ConsoleClient from "../client/ConsoleClient"; @injectable() export default class MarkUseCase { constructor( - @inject('ScrollPresenter') private scrollPresenter: ScrollPresenter, - @inject('MarkClient') private client: MarkClient, - @inject('MarkRepository') private repository: MarkRepository, - @inject('SettingRepository') private settingRepository: SettingRepository, - @inject('ConsoleClient') private consoleClient: ConsoleClient, - ) { - } + @inject("ScrollPresenter") private scrollPresenter: ScrollPresenter, + @inject("MarkClient") private client: MarkClient, + @inject("MarkRepository") private repository: MarkRepository, + @inject("SettingRepository") private settingRepository: SettingRepository, + @inject("ConsoleClient") private consoleClient: ConsoleClient + ) {} async set(key: string): Promise<void> { const pos = this.scrollPresenter.getScroll(); @@ -33,7 +32,7 @@ export default class MarkUseCase { } else { const pos = this.repository.get(key); if (!pos) { - throw new Error('Mark is not set'); + throw new Error("Mark is not set"); } this.scroll(pos.x, pos.y); } @@ -45,6 +44,6 @@ export default class MarkUseCase { } private globalKey(key: string) { - return (/^[A-Z0-9]$/).test(key); + return /^[A-Z0-9]$/.test(key); } } diff --git a/src/content/usecases/NavigateUseCase.ts b/src/content/usecases/NavigateUseCase.ts index 7adccfd..c704980 100644 --- a/src/content/usecases/NavigateUseCase.ts +++ b/src/content/usecases/NavigateUseCase.ts @@ -1,13 +1,12 @@ -import { injectable, inject } from 'tsyringe'; -import NavigationPresenter from '../presenters/NavigationPresenter'; +import { injectable, inject } from "tsyringe"; +import NavigationPresenter from "../presenters/NavigationPresenter"; @injectable() export default class NavigateUseCase { constructor( - @inject('NavigationPresenter') - private navigationPresenter: NavigationPresenter, - ) { - } + @inject("NavigationPresenter") + private navigationPresenter: NavigationPresenter + ) {} openHistoryPrev(): void { this.navigationPresenter.openHistoryPrev(); diff --git a/src/content/usecases/ScrollUseCase.ts b/src/content/usecases/ScrollUseCase.ts index c68c889..319c8b4 100644 --- a/src/content/usecases/ScrollUseCase.ts +++ b/src/content/usecases/ScrollUseCase.ts @@ -1,14 +1,13 @@ -import { injectable, inject } from 'tsyringe'; -import ScrollPresenter from '../presenters/ScrollPresenter'; -import SettingRepository from '../repositories/SettingRepository'; +import { injectable, inject } from "tsyringe"; +import ScrollPresenter from "../presenters/ScrollPresenter"; +import SettingRepository from "../repositories/SettingRepository"; @injectable() export default class ScrollUseCase { constructor( - @inject('ScrollPresenter') private presenter: ScrollPresenter, - @inject('SettingRepository') private settingRepository: SettingRepository, - ) { - } + @inject("ScrollPresenter") private presenter: ScrollPresenter, + @inject("SettingRepository") private settingRepository: SettingRepository + ) {} scrollVertically(count: number): void { const smooth = this.getSmoothScroll(); diff --git a/src/content/usecases/SettingUseCase.ts b/src/content/usecases/SettingUseCase.ts index 67d1be6..b2b24aa 100644 --- a/src/content/usecases/SettingUseCase.ts +++ b/src/content/usecases/SettingUseCase.ts @@ -1,15 +1,14 @@ -import { injectable, inject } from 'tsyringe'; -import SettingRepository from '../repositories/SettingRepository'; -import SettingClient from '../client/SettingClient'; -import Settings from '../../shared/settings/Settings'; +import { injectable, inject } from "tsyringe"; +import SettingRepository from "../repositories/SettingRepository"; +import SettingClient from "../client/SettingClient"; +import Settings from "../../shared/settings/Settings"; @injectable() export default class SettingUseCase { constructor( - @inject('SettingRepository') private repository: SettingRepository, - @inject('SettingClient') private client: SettingClient, - ) { - } + @inject("SettingRepository") private repository: SettingRepository, + @inject("SettingClient") private client: SettingClient + ) {} async reload(): Promise<Settings> { const settings = await this.client.load(); diff --git a/src/settings/actions/index.ts b/src/settings/actions/index.ts index dfa41c4..6b06ef8 100644 --- a/src/settings/actions/index.ts +++ b/src/settings/actions/index.ts @@ -1,12 +1,14 @@ import { - JSONTextSettings, FormSettings, SettingSource, -} from '../../shared/SettingData'; + JSONTextSettings, + FormSettings, + SettingSource, +} from "../../shared/SettingData"; // Settings -export const SETTING_SET_SETTINGS = 'setting.set.settings'; -export const SETTING_SHOW_ERROR = 'setting.show.error'; -export const SETTING_SWITCH_TO_FORM = 'setting.switch.to.form'; -export const SETTING_SWITCH_TO_JSON = 'setting.switch.to.json'; +export const SETTING_SET_SETTINGS = "setting.set.settings"; +export const SETTING_SHOW_ERROR = "setting.show.error"; +export const SETTING_SWITCH_TO_FORM = "setting.switch.to.form"; +export const SETTING_SWITCH_TO_JSON = "setting.switch.to.json"; interface SettingSetSettingsAcion { type: typeof SETTING_SET_SETTINGS; @@ -23,14 +25,16 @@ interface SettingShowErrorAction { interface SettingSwitchToFormAction { type: typeof SETTING_SWITCH_TO_FORM; - form: FormSettings, + form: FormSettings; } interface SettingSwitchToJsonAction { type: typeof SETTING_SWITCH_TO_JSON; - json: JSONTextSettings, + json: JSONTextSettings; } export type SettingAction = - SettingSetSettingsAcion | SettingShowErrorAction | - SettingSwitchToFormAction | SettingSwitchToJsonAction; + | SettingSetSettingsAcion + | SettingShowErrorAction + | SettingSwitchToFormAction + | SettingSwitchToJsonAction; diff --git a/src/settings/actions/setting.ts b/src/settings/actions/setting.ts index 93ca5f8..e880ae4 100644 --- a/src/settings/actions/setting.ts +++ b/src/settings/actions/setting.ts @@ -1,15 +1,17 @@ -import * as actions from './index'; -import * as storages from '../storage'; +import * as actions from "./index"; +import * as storages from "../storage"; import SettingData, { - JSONTextSettings, FormSettings, SettingSource, -} from '../../shared/SettingData'; + JSONTextSettings, + FormSettings, + SettingSource, +} from "../../shared/SettingData"; -const load = async(): Promise<actions.SettingAction> => { +const load = async (): Promise<actions.SettingAction> => { const data = await storages.load(); return set(data); }; -const save = async(data: SettingData): Promise<actions.SettingAction> => { +const save = async (data: SettingData): Promise<actions.SettingAction> => { try { if (data.getSource() === SettingSource.JSON) { // toSettings exercise validation @@ -26,7 +28,6 @@ const save = async(data: SettingData): Promise<actions.SettingAction> => { return set(data); }; - const switchToForm = (json: JSONTextSettings): actions.SettingAction => { try { // toSettings exercise validation @@ -55,18 +56,18 @@ const switchToJson = (form: FormSettings): actions.SettingAction => { const set = (data: SettingData): actions.SettingAction => { const source = data.getSource(); switch (source) { - case SettingSource.JSON: - return { - type: actions.SETTING_SET_SETTINGS, - source: source, - json: data.getJSON(), - }; - case SettingSource.Form: - return { - type: actions.SETTING_SET_SETTINGS, - source: source, - form: data.getForm(), - }; + case SettingSource.JSON: + return { + type: actions.SETTING_SET_SETTINGS, + source: source, + json: data.getJSON(), + }; + case SettingSource.Form: + return { + type: actions.SETTING_SET_SETTINGS, + source: source, + form: data.getForm(), + }; } throw new Error(`unknown source: ${source}`); }; diff --git a/src/settings/components/form/BlacklistForm.tsx b/src/settings/components/form/BlacklistForm.tsx index 51c32f4..859cb9f 100644 --- a/src/settings/components/form/BlacklistForm.tsx +++ b/src/settings/components/form/BlacklistForm.tsx @@ -1,8 +1,8 @@ -import './BlacklistForm.scss'; -import AddButton from '../ui/AddButton'; -import DeleteButton from '../ui/DeleteButton'; -import React from 'react'; -import Blacklist, { BlacklistItem } from '../../../shared/settings/Blacklist'; +import "./BlacklistForm.scss"; +import AddButton from "../ui/AddButton"; +import DeleteButton from "../ui/DeleteButton"; +import React from "react"; +import Blacklist, { BlacklistItem } from "../../../shared/settings/Blacklist"; interface Props { value: Blacklist; @@ -18,45 +18,56 @@ class BlacklistForm extends React.Component<Props> { }; render() { - return <div className='form-blacklist-form'> - { - this.props.value.items.map((item, index) => { + return ( + <div className="form-blacklist-form"> + {this.props.value.items.map((item, index) => { if (item.partial) { return null; } - return <div key={index} className='form-blacklist-form-row'> - <input data-index={index} type='text' name='url' - className='column-url' value={item.pattern} - onChange={this.bindValue.bind(this)} - onBlur={this.props.onBlur} - /> - <DeleteButton data-index={index} name='delete' - onClick={this.bindValue.bind(this)} - onBlur={this.props.onBlur} - /> - </div>; - }) - } - <AddButton name='add' style={{ float: 'right' }} - onClick={this.bindValue.bind(this)} /> - </div>; + return ( + <div key={index} className="form-blacklist-form-row"> + <input + data-index={index} + type="text" + name="url" + className="column-url" + value={item.pattern} + onChange={this.bindValue.bind(this)} + onBlur={this.props.onBlur} + /> + <DeleteButton + data-index={index} + name="delete" + onClick={this.bindValue.bind(this)} + onBlur={this.props.onBlur} + /> + </div> + ); + })} + <AddButton + name="add" + style={{ float: "right" }} + onClick={this.bindValue.bind(this)} + /> + </div> + ); } bindValue(e: any) { const name = e.target.name; - const index = e.target.getAttribute('data-index'); + const index = e.target.getAttribute("data-index"); const items = this.props.value.items; - if (name === 'url') { + if (name === "url") { items[index] = new BlacklistItem(e.target.value, false, []); - } else if (name === 'add') { - items.push(new BlacklistItem('', false, [])); - } else if (name === 'delete') { + } else if (name === "add") { + items.push(new BlacklistItem("", false, [])); + } else if (name === "delete") { items.splice(index, 1); } this.props.onChange(new Blacklist(items)); - if (name === 'delete') { + if (name === "delete") { this.props.onBlur(); } } diff --git a/src/settings/components/form/KeymapsForm.tsx b/src/settings/components/form/KeymapsForm.tsx index dc74de3..b9af0df 100644 --- a/src/settings/components/form/KeymapsForm.tsx +++ b/src/settings/components/form/KeymapsForm.tsx @@ -1,8 +1,8 @@ -import './KeymapsForm.scss'; -import React from 'react'; -import Input from '../ui/Input'; -import keymaps from '../../keymaps'; -import { FormKeymaps } from '../../../shared/SettingData'; +import "./KeymapsForm.scss"; +import React from "react"; +import Input from "../ui/Input"; +import keymaps from "../../keymaps"; +import { FormKeymaps } from "../../../shared/SettingData"; interface Props { value: FormKeymaps; @@ -19,25 +19,31 @@ class KeymapsForm extends React.Component<Props> { render() { const values = this.props.value.toJSON(); - return <div className='form-keymaps-form'> - { - keymaps.fields.map((group, index) => { - return <div key={index} className='form-keymaps-form-field-group'> - { - group.map(([name, label]) => { - const value = values[name] || ''; - return <Input - type='text' id={name} name={name} key={name} - label={label} value={value} - onValueChange={this.bindValue.bind(this)} - onBlur={this.props.onBlur} - />; - }) - } - </div>; - }) - } - </div>; + return ( + <div className="form-keymaps-form"> + {keymaps.fields.map((group, index) => { + return ( + <div key={index} className="form-keymaps-form-field-group"> + {group.map(([name, label]) => { + const value = values[name] || ""; + return ( + <Input + type="text" + id={name} + name={name} + key={name} + label={label} + value={value} + onValueChange={this.bindValue.bind(this)} + onBlur={this.props.onBlur} + /> + ); + })} + </div> + ); + })} + </div> + ); } bindValue(name: string, value: string) { diff --git a/src/settings/components/form/PartialBlacklistForm.tsx b/src/settings/components/form/PartialBlacklistForm.tsx index 1807e28..95beee8 100644 --- a/src/settings/components/form/PartialBlacklistForm.tsx +++ b/src/settings/components/form/PartialBlacklistForm.tsx @@ -1,8 +1,8 @@ -import './PartialBlacklistForm.scss'; -import AddButton from '../ui/AddButton'; -import DeleteButton from '../ui/DeleteButton'; -import React from 'react'; -import Blacklist, { BlacklistItem } from '../../../shared/settings/Blacklist'; +import "./PartialBlacklistForm.scss"; +import AddButton from "../ui/AddButton"; +import DeleteButton from "../ui/DeleteButton"; +import React from "react"; +import Blacklist, { BlacklistItem } from "../../../shared/settings/Blacklist"; interface Props { value: Blacklist; @@ -18,59 +18,77 @@ class PartialBlacklistForm extends React.Component<Props> { }; render() { - return <div className='form-partial-blacklist-form'> - <div className='form-partial-blacklist-form-header'> - <div className='column-url'>URL</div> - <div className='column-keys'>Keys</div> - </div> - { - this.props.value.items.map((item, index) => { + return ( + <div className="form-partial-blacklist-form"> + <div className="form-partial-blacklist-form-header"> + <div className="column-url">URL</div> + <div className="column-keys">Keys</div> + </div> + {this.props.value.items.map((item, index) => { if (!item.partial) { return null; } - return <div key={index} className='form-partial-blacklist-form-row'> - <input data-index={index} type='text' name='url' - className='column-url' value={item.pattern} - onChange={this.bindValue.bind(this)} - onBlur={this.props.onBlur} - /> - <input data-index={index} type='text' name='keys' - className='column-keys' value={item.keys.join(',')} - onChange={this.bindValue.bind(this)} - onBlur={this.props.onBlur} - /> - <DeleteButton data-index={index} name='delete' - onClick={this.bindValue.bind(this)} - onBlur={this.props.onBlur} - /> - </div>; - }) - } - <AddButton name='add' style={{ float: 'right' }} - onClick={this.bindValue.bind(this)} /> - </div>; + return ( + <div key={index} className="form-partial-blacklist-form-row"> + <input + data-index={index} + type="text" + name="url" + className="column-url" + value={item.pattern} + onChange={this.bindValue.bind(this)} + onBlur={this.props.onBlur} + /> + <input + data-index={index} + type="text" + name="keys" + className="column-keys" + value={item.keys.join(",")} + onChange={this.bindValue.bind(this)} + onBlur={this.props.onBlur} + /> + <DeleteButton + data-index={index} + name="delete" + onClick={this.bindValue.bind(this)} + onBlur={this.props.onBlur} + /> + </div> + ); + })} + <AddButton + name="add" + style={{ float: "right" }} + onClick={this.bindValue.bind(this)} + /> + </div> + ); } bindValue(e: any) { const name = e.target.name; - const index = e.target.getAttribute('data-index'); + const index = e.target.getAttribute("data-index"); const items = this.props.value.items; - if (name === 'url') { + if (name === "url") { const current = items[index]; items[index] = new BlacklistItem(e.target.value, true, current.keys); - } else if (name === 'keys') { + } else if (name === "keys") { const current = items[index]; items[index] = new BlacklistItem( - current.pattern, true, e.target.value.split(',')); - } else if (name === 'add') { - items.push(new BlacklistItem('', true, [])); - } else if (name === 'delete') { + current.pattern, + true, + e.target.value.split(",") + ); + } else if (name === "add") { + items.push(new BlacklistItem("", true, [])); + } else if (name === "delete") { items.splice(index, 1); } this.props.onChange(new Blacklist(items)); - if (name === 'delete') { + if (name === "delete") { this.props.onBlur(); } } diff --git a/src/settings/components/form/PropertiesForm.tsx b/src/settings/components/form/PropertiesForm.tsx index e648971..aebd9b1 100644 --- a/src/settings/components/form/PropertiesForm.tsx +++ b/src/settings/components/form/PropertiesForm.tsx @@ -1,9 +1,9 @@ -import './PropertiesForm.scss'; -import React from 'react'; +import "./PropertiesForm.scss"; +import React from "react"; interface Props { - types: {[key: string]: string}; - value: {[key: string]: any}; + types: { [key: string]: string }; + value: { [key: string]: any }; onChange: (value: any) => void; onBlur: () => void; } @@ -20,18 +20,18 @@ class PropertiesForm extends React.Component<Props> { const types = this.props.types; const values = this.props.value; - return <div className='form-properties-form'> - { - Object.keys(types).map((name) => { + return ( + <div className="form-properties-form"> + {Object.keys(types).map((name) => { const type = types[name]; - let inputType = ''; + let inputType = ""; let onChange = this.bindValue.bind(this); - if (type === 'string') { - inputType = 'text'; - } else if (type === 'number') { - inputType = 'number'; - } else if (type === 'boolean') { - inputType = 'checkbox'; + if (type === "string") { + inputType = "text"; + } else if (type === "number") { + inputType = "number"; + } else if (type === "boolean") { + inputType = "checkbox"; // Settings are saved onBlur, but checkbox does not fire it onChange = (e) => { @@ -41,29 +41,33 @@ class PropertiesForm extends React.Component<Props> { } else { return null; } - return <div key={name} className='form-properties-form-row'> - <label> - <span className='column-name'>{name}</span> - <input type={inputType} name={name} - className='column-input' - value={values[name] ? values[name] : ''} - onChange={onChange} - onBlur={this.props.onBlur} - checked={values[name]} - /> - </label> - </div>; - }) - } - </div>; + return ( + <div key={name} className="form-properties-form-row"> + <label> + <span className="column-name">{name}</span> + <input + type={inputType} + name={name} + className="column-input" + value={values[name] ? values[name] : ""} + onChange={onChange} + onBlur={this.props.onBlur} + checked={values[name]} + /> + </label> + </div> + ); + })} + </div> + ); } bindValue(e: React.ChangeEvent<HTMLInputElement>) { const name = e.target.name; const next = { ...this.props.value }; - if (e.target.type.toLowerCase() === 'checkbox') { + if (e.target.type.toLowerCase() === "checkbox") { next[name] = e.target.checked; - } else if (e.target.type.toLowerCase() === 'number') { + } else if (e.target.type.toLowerCase() === "number") { next[name] = Number(e.target.value); } else { next[name] = e.target.value; diff --git a/src/settings/components/form/SearchForm.tsx b/src/settings/components/form/SearchForm.tsx index 5dc786b..a4d923d 100644 --- a/src/settings/components/form/SearchForm.tsx +++ b/src/settings/components/form/SearchForm.tsx @@ -1,8 +1,8 @@ -import './SearchForm.scss'; -import React from 'react'; -import AddButton from '../ui/AddButton'; -import DeleteButton from '../ui/DeleteButton'; -import { FormSearch } from '../../../shared/SettingData'; +import "./SearchForm.scss"; +import React from "react"; +import AddButton from "../ui/AddButton"; +import DeleteButton from "../ui/DeleteButton"; +import { FormSearch } from "../../../shared/SettingData"; interface Props { value: FormSearch; @@ -12,68 +12,88 @@ interface Props { class SearchForm extends React.Component<Props> { public static defaultProps: Props = { - value: FormSearch.fromJSON({ default: '', engines: []}), + value: FormSearch.fromJSON({ default: "", engines: [] }), onChange: () => {}, onBlur: () => {}, }; render() { const value = this.props.value.toJSON(); - return <div className='form-search-form'> - <div className='form-search-form-header'> - <div className='column-name'>Name</div> - <div className='column-url'>URL</div> - <div className='column-option'>Default</div> - </div> - { - value.engines.map((engine, index) => { - return <div key={index} className='form-search-form-row'> - <input data-index={index} type='text' name='name' - className='column-name' value={engine[0]} - onChange={this.bindValue.bind(this)} - onBlur={this.props.onBlur} - /> - <input data-index={index} type='text' name='url' - placeholder='http://example.com/?q={}' - className='column-url' value={engine[1]} - onChange={this.bindValue.bind(this)} - onBlur={this.props.onBlur} - /> - <div className='column-option'> - <input data-index={index} type='radio' name='default' - checked={value.default === engine[0]} - onChange={this.bindValue.bind(this)} /> - <DeleteButton data-index={index} name='delete' - onClick={this.bindValue.bind(this)} /> + return ( + <div className="form-search-form"> + <div className="form-search-form-header"> + <div className="column-name">Name</div> + <div className="column-url">URL</div> + <div className="column-option">Default</div> + </div> + {value.engines.map((engine, index) => { + return ( + <div key={index} className="form-search-form-row"> + <input + data-index={index} + type="text" + name="name" + className="column-name" + value={engine[0]} + onChange={this.bindValue.bind(this)} + onBlur={this.props.onBlur} + /> + <input + data-index={index} + type="text" + name="url" + placeholder="http://example.com/?q={}" + className="column-url" + value={engine[1]} + onChange={this.bindValue.bind(this)} + onBlur={this.props.onBlur} + /> + <div className="column-option"> + <input + data-index={index} + type="radio" + name="default" + checked={value.default === engine[0]} + onChange={this.bindValue.bind(this)} + /> + <DeleteButton + data-index={index} + name="delete" + onClick={this.bindValue.bind(this)} + /> + </div> </div> - </div>; - }) - } - <AddButton name='add' style={{ float: 'right' }} - onClick={this.bindValue.bind(this)} /> - </div>; + ); + })} + <AddButton + name="add" + style={{ float: "right" }} + onClick={this.bindValue.bind(this)} + /> + </div> + ); } // eslint-disable-next-line max-statements bindValue(e: any) { const value = this.props.value.toJSON(); const name = e.target.name; - const index = Number(e.target.getAttribute('data-index')); + const index = Number(e.target.getAttribute("data-index")); const next: typeof value = { default: value.default, engines: value.engines.slice(), }; - if (name === 'name') { + if (name === "name") { next.engines[index][0] = e.target.value; next.default = value.engines[index][0]; - } else if (name === 'url') { + } else if (name === "url") { next.engines[index][1] = e.target.value; - } else if (name === 'default') { + } else if (name === "default") { next.default = value.engines[index][0]; - } else if (name === 'add') { - next.engines.push(['', '']); - } else if (name === 'delete' && value.engines.length > 1) { + } else if (name === "add") { + next.engines.push(["", ""]); + } else if (name === "delete" && value.engines.length > 1) { next.engines.splice(index, 1); if (value.engines[index][0] === value.default) { const nextIndex = Math.min(index, next.engines.length - 1); @@ -82,7 +102,7 @@ class SearchForm extends React.Component<Props> { } this.props.onChange(FormSearch.fromJSON(next)); - if (name === 'delete' || name === 'default') { + if (name === "delete" || name === "default") { this.props.onBlur(); } } diff --git a/src/settings/components/index.tsx b/src/settings/components/index.tsx index f4f0326..5793a8f 100644 --- a/src/settings/components/index.tsx +++ b/src/settings/components/index.tsx @@ -1,32 +1,36 @@ -import './site.scss'; -import React from 'react'; -import { connect } from 'react-redux'; -import Input from './ui/Input'; -import SearchForm from './form/SearchForm'; -import KeymapsForm from './form/KeymapsForm'; -import BlacklistForm from './form/BlacklistForm'; -import PropertiesForm from './form/PropertiesForm'; -import PartialBlacklistForm from './form/PartialBlacklistForm'; -import * as settingActions from '../../settings/actions/setting'; +import "./site.scss"; +import React from "react"; +import { connect } from "react-redux"; +import Input from "./ui/Input"; +import SearchForm from "./form/SearchForm"; +import KeymapsForm from "./form/KeymapsForm"; +import BlacklistForm from "./form/BlacklistForm"; +import PropertiesForm from "./form/PropertiesForm"; +import PartialBlacklistForm from "./form/PartialBlacklistForm"; +import * as settingActions from "../../settings/actions/setting"; import SettingData, { - FormKeymaps, FormSearch, FormSettings, JSONTextSettings, -} from '../../shared/SettingData'; -import { State as AppState } from '../reducers/setting'; -import Properties from '../../shared/settings/Properties'; -import Blacklist from '../../shared/settings/Blacklist'; + FormKeymaps, + FormSearch, + FormSettings, + JSONTextSettings, +} from "../../shared/SettingData"; +import { State as AppState } from "../reducers/setting"; +import Properties from "../../shared/settings/Properties"; +import Blacklist from "../../shared/settings/Blacklist"; const DO_YOU_WANT_TO_CONTINUE = - 'Some settings in JSON can be lost when migrating. ' + - 'Do you want to continue?'; + "Some settings in JSON can be lost when migrating. " + + "Do you want to continue?"; type StateProps = ReturnType<typeof mapStateToProps>; interface DispatchProps { - dispatch: (action: any) => void, + dispatch: (action: any) => void; } -type Props = StateProps & DispatchProps & { - // FIXME - store: any; -}; +type Props = StateProps & + DispatchProps & { + // FIXME + store: any; + }; class SettingsComponent extends React.Component<Props> { componentDidMount() { @@ -34,97 +38,103 @@ class SettingsComponent extends React.Component<Props> { } renderFormFields(form: FormSettings) { - return <div> - <fieldset> - <legend>Keybindings</legend> - <KeymapsForm - value={form.keymaps} - onChange={this.bindKeymapsForm.bind(this)} - onBlur={this.save.bind(this)} - /> - </fieldset> - <fieldset> - <legend>Search Engines</legend> - <SearchForm - value={form.search} - onChange={this.bindSearchForm.bind(this)} - onBlur={this.save.bind(this)} - /> - </fieldset> - <fieldset> - <legend>Blacklist</legend> - <BlacklistForm - value={form.blacklist} - onChange={this.bindBlacklistForm.bind(this)} - onBlur={this.save.bind(this)} - /> - </fieldset> - <fieldset> - <legend>Partial blacklist</legend> - <PartialBlacklistForm - value={form.blacklist} - onChange={this.bindBlacklistForm.bind(this)} - onBlur={this.save.bind(this)} - /> - </fieldset> - <fieldset> - <legend>Properties</legend> - <PropertiesForm - types={Properties.types()} - value={form.properties.toJSON()} - onChange={this.bindPropertiesForm.bind(this)} - onBlur={this.save.bind(this)} - /> - </fieldset> - </div>; + return ( + <div> + <fieldset> + <legend>Keybindings</legend> + <KeymapsForm + value={form.keymaps} + onChange={this.bindKeymapsForm.bind(this)} + onBlur={this.save.bind(this)} + /> + </fieldset> + <fieldset> + <legend>Search Engines</legend> + <SearchForm + value={form.search} + onChange={this.bindSearchForm.bind(this)} + onBlur={this.save.bind(this)} + /> + </fieldset> + <fieldset> + <legend>Blacklist</legend> + <BlacklistForm + value={form.blacklist} + onChange={this.bindBlacklistForm.bind(this)} + onBlur={this.save.bind(this)} + /> + </fieldset> + <fieldset> + <legend>Partial blacklist</legend> + <PartialBlacklistForm + value={form.blacklist} + onChange={this.bindBlacklistForm.bind(this)} + onBlur={this.save.bind(this)} + /> + </fieldset> + <fieldset> + <legend>Properties</legend> + <PropertiesForm + types={Properties.types()} + value={form.properties.toJSON()} + onChange={this.bindPropertiesForm.bind(this)} + onBlur={this.save.bind(this)} + /> + </fieldset> + </div> + ); } renderJsonFields(json: JSONTextSettings, error: string) { - return <div> - <Input - type='textarea' - name='json' - label='Plain JSON' - spellCheck={false} - error={error} - onValueChange={this.bindJson.bind(this)} - onBlur={this.save.bind(this)} - value={json.toJSONText()} - /> - </div>; + return ( + <div> + <Input + type="textarea" + name="json" + label="Plain JSON" + spellCheck={false} + error={error} + onValueChange={this.bindJson.bind(this)} + onBlur={this.save.bind(this)} + value={json.toJSONText()} + /> + </div> + ); } render() { let fields = null; const disabled = this.props.error.length > 0; - if (this.props.source === 'form') { + if (this.props.source === "form") { fields = this.renderFormFields(this.props.form!!); - } else if (this.props.source === 'json') { + } else if (this.props.source === "json") { fields = this.renderJsonFields(this.props.json!!, this.props.error); } return ( <div> <h1>Configure Vim-Vixen</h1> - <form className='vimvixen-settings-form'> + <form className="vimvixen-settings-form"> <Input - type='radio' - id='setting-source-form' - name='source' - label='Use form' - checked={this.props.source === 'form'} - value='form' + type="radio" + id="setting-source-form" + name="source" + label="Use form" + checked={this.props.source === "form"} + value="form" onValueChange={this.bindSource.bind(this)} - disabled={disabled} /> + disabled={disabled} + /> <Input - type='radio' - name='source' - label='Use plain JSON' - checked={this.props.source === 'json'} - value='json' + type="radio" + name="source" + label="Use plain JSON" + checked={this.props.source === "json"} + value="json" onValueChange={this.bindSource.bind(this)} - disabled={disabled} /> - { fields } + disabled={disabled} + /> + {fields} </form> </div> ); @@ -142,7 +152,8 @@ class SettingsComponent extends React.Component<Props> { const data = new SettingData({ source: this.props.source, form: (this.props.form as FormSettings).buildWithSearch( - FormSearch.fromJSON(value)), + FormSearch.fromJSON(value) + ), }); this.props.dispatch(settingActions.set(data)); } @@ -159,7 +170,8 @@ class SettingsComponent extends React.Component<Props> { const data = new SettingData({ source: this.props.source, form: (this.props.form as FormSettings).buildWithProperties( - Properties.fromJSON(value)) + Properties.fromJSON(value) + ), }); this.props.dispatch(settingActions.set(data)); } @@ -174,27 +186,29 @@ class SettingsComponent extends React.Component<Props> { bindSource(_name: string, value: string) { const from = this.props.source; - if (from === 'form' && value === 'json') { - this.props.dispatch(settingActions.switchToJson( - this.props.form as FormSettings)); + if (from === "form" && value === "json") { + this.props.dispatch( + settingActions.switchToJson(this.props.form as FormSettings) + ); this.save(); - } else if (from === 'json' && value === 'form') { + } else if (from === "json" && value === "form") { const b = window.confirm(DO_YOU_WANT_TO_CONTINUE); if (!b) { this.forceUpdate(); return; } this.props.dispatch( - settingActions.switchToForm(this.props.json as JSONTextSettings)); + settingActions.switchToForm(this.props.json as JSONTextSettings) + ); this.save(); } } save() { const { source, json, form } = this.props.store.getState(); - this.props.dispatch(settingActions.save( - new SettingData({ source, json, form }), - )); + this.props.dispatch( + settingActions.save(new SettingData({ source, json, form })) + ); } } diff --git a/src/settings/components/ui/AddButton.tsx b/src/settings/components/ui/AddButton.tsx index bb76d08..c15a732 100644 --- a/src/settings/components/ui/AddButton.tsx +++ b/src/settings/components/ui/AddButton.tsx @@ -1,13 +1,18 @@ -import './AddButton.scss'; -import React from 'react'; +import "./AddButton.scss"; +import React from "react"; type Props = React.AllHTMLAttributes<HTMLInputElement>; class AddButton extends React.Component<Props> { render() { - return <input - className='ui-add-button' type='button' value='✚' - {...this.props} />; + return ( + <input + className="ui-add-button" + type="button" + value="✚" + {...this.props} + /> + ); } } diff --git a/src/settings/components/ui/DeleteButton.tsx b/src/settings/components/ui/DeleteButton.tsx index e666426..df8976e 100644 --- a/src/settings/components/ui/DeleteButton.tsx +++ b/src/settings/components/ui/DeleteButton.tsx @@ -1,13 +1,18 @@ -import './DeleteButton.scss'; -import React from 'react'; +import "./DeleteButton.scss"; +import React from "react"; type Props = React.AllHTMLAttributes<HTMLInputElement>; class DeleteButton extends React.Component<Props> { render() { - return <input - className='ui-delete-button' type='button' value='✖' - {...this.props} />; + return ( + <input + className="ui-delete-button" + type="button" + value="✖" + {...this.props} + /> + ); } } diff --git a/src/settings/components/ui/Input.tsx b/src/settings/components/ui/Input.tsx index 69c14b3..6819ddb 100644 --- a/src/settings/components/ui/Input.tsx +++ b/src/settings/components/ui/Input.tsx @@ -1,5 +1,5 @@ -import React from 'react'; -import './Input.scss'; +import React from "react"; +import "./Input.scss"; interface Props extends React.AllHTMLAttributes<HTMLElement> { name: string; @@ -13,66 +13,75 @@ interface Props extends React.AllHTMLAttributes<HTMLElement> { class Input extends React.Component<Props> { renderText(props: Props) { - const inputClassName = props.error ? 'input-error' : ''; + const inputClassName = props.error ? "input-error" : ""; const pp = { ...props }; delete pp.onValueChange; - return <div className='settings-ui-input'> - <label htmlFor={props.id}>{ props.label }</label> - <input - type='text' className={inputClassName} - onChange={this.bindOnChange.bind(this)} - { ...pp } /> - </div>; + return ( + <div className="settings-ui-input"> + <label htmlFor={props.id}>{props.label}</label> + <input + type="text" + className={inputClassName} + onChange={this.bindOnChange.bind(this)} + {...pp} + /> + </div> + ); } renderRadio(props: Props) { - const inputClassName = props.error ? 'input-error' : ''; + const inputClassName = props.error ? "input-error" : ""; const pp = { ...props }; delete pp.onValueChange; - return <div className='settings-ui-input'> - <label> - <input - type='radio' className={inputClassName} - onChange={this.bindOnChange.bind(this)} - { ...pp } /> - { props.label } - </label> - </div>; + return ( + <div className="settings-ui-input"> + <label> + <input + type="radio" + className={inputClassName} + onChange={this.bindOnChange.bind(this)} + {...pp} + /> + {props.label} + </label> + </div> + ); } renderTextArea(props: Props) { - const inputClassName = props.error ? 'input-error' : ''; + const inputClassName = props.error ? "input-error" : ""; const pp = { ...props }; delete pp.onValueChange; - return <div className='settings-ui-input'> - <label - htmlFor={props.id} - >{ props.label }</label> - <textarea - className={inputClassName} - onChange={this.bindOnChange.bind(this)} - { ...pp } /> - <p className='settings-ui-input-error'>{ this.props.error }</p> - </div>; + return ( + <div className="settings-ui-input"> + <label htmlFor={props.id}>{props.label}</label> + <textarea + className={inputClassName} + onChange={this.bindOnChange.bind(this)} + {...pp} + /> + <p className="settings-ui-input-error">{this.props.error}</p> + </div> + ); } render() { const { type } = this.props; switch (this.props.type) { - case 'text': - return this.renderText(this.props); - case 'radio': - return this.renderRadio(this.props); - case 'textarea': - return this.renderTextArea(this.props); - default: - console.warn(`Unsupported input type ${type}`); + case "text": + return this.renderText(this.props); + case "radio": + return this.renderRadio(this.props); + case "textarea": + return this.renderTextArea(this.props); + default: + console.warn(`Unsupported input type ${type}`); } return null; } - bindOnChange(e: React.ChangeEvent<HTMLInputElement|HTMLTextAreaElement>) { + bindOnChange(e: React.ChangeEvent<HTMLInputElement | HTMLTextAreaElement>) { if (this.props.onValueChange) { this.props.onValueChange(e.target.name, e.target.value); } diff --git a/src/settings/index.tsx b/src/settings/index.tsx index cde4488..0d3364b 100644 --- a/src/settings/index.tsx +++ b/src/settings/index.tsx @@ -1,18 +1,15 @@ -import React from 'react'; -import ReactDOM from 'react-dom'; -import SettingsComponent from './components'; -import reducer from './reducers/setting'; -import { Provider } from 'react-redux'; -import promise from 'redux-promise'; -import { createStore, applyMiddleware } from 'redux'; +import React from "react"; +import ReactDOM from "react-dom"; +import SettingsComponent from "./components"; +import reducer from "./reducers/setting"; +import { Provider } from "react-redux"; +import promise from "redux-promise"; +import { createStore, applyMiddleware } from "redux"; -const store = createStore( - reducer, - applyMiddleware(promise), -); +const store = createStore(reducer, applyMiddleware(promise)); -document.addEventListener('DOMContentLoaded', () => { - const wrapper = document.getElementById('vimvixen-settings'); +document.addEventListener("DOMContentLoaded", () => { + const wrapper = document.getElementById("vimvixen-settings"); ReactDOM.render( <Provider store={store}> <SettingsComponent store={store} /> diff --git a/src/settings/keymaps.ts b/src/settings/keymaps.ts index 24ba1a5..25c7a51 100644 --- a/src/settings/keymaps.ts +++ b/src/settings/keymaps.ts @@ -2,70 +2,79 @@ const fields = [ [ - ['scroll.vertically?{"count":1}', 'Scroll down'], - ['scroll.vertically?{"count":-1}', 'Scroll up'], - ['scroll.horizonally?{"count":-1}', 'Scroll left'], - ['scroll.horizonally?{"count":1}', 'Scroll right'], - ['scroll.home', 'Scroll to leftmost'], - ['scroll.end', 'Scroll to rightmost'], - ['scroll.top', 'Scroll to top'], - ['scroll.bottom', 'Scroll to bottom'], - ['scroll.pages?{"count":-0.5}', 'Scroll up by half of screen'], - ['scroll.pages?{"count":0.5}', 'Scroll down by half of screen'], - ['scroll.pages?{"count":-1}', 'Scroll up by a screen'], - ['scroll.pages?{"count":1}', 'Scroll down by a screen'], - ], [ - ['mark.set.prefix', 'Set mark at current position'], - ['mark.jump.prefix', 'Jump to the mark'], - ], [ - ['tabs.close?{"select":"right"}', 'Close a tab'], - ['tabs.close.right', 'Close all tabs to the right'], - ['tabs.reopen', 'Reopen closed tab'], - ['tabs.next', 'Select next tab'], - ['tabs.prev', 'Select prev tab'], - ['tabs.first', 'Select first tab'], - ['tabs.last', 'Select last tab'], - ['tabs.reload?{"cache":false}', 'Reload current tab'], - ['tabs.reload?{"cache":true}', 'Reload with no caches'], - ['tabs.pin.toggle', 'Toggle pinned state'], - ['tabs.duplicate', 'Duplicate a tab'], - ], [ - ['follow.start?{"newTab":false,"background":false}', 'Follow a link'], - ['follow.start?{"newTab":true,"background":false}', 'Follow a link in new tab'], - ['navigate.history.prev', 'Go back in histories'], - ['navigate.history.next', 'Go forward in histories'], - ['navigate.link.next', 'Open next link'], - ['navigate.link.prev', 'Open previous link'], - ['navigate.parent', 'Go to parent directory'], - ['navigate.root', 'Go to root directory'], - ['page.source', 'Open page source'], - ['page.home?{"newTab":false}', 'Open start page to current tab'], - ['page.home?{"newTab":true}', 'Open start page in new tab'], - ['focus.input', 'Focus input'], - ], [ - ['find.start', 'Start find mode'], - ['find.next', 'Find next word'], - ['find.prev', 'Find previous word'], - ], [ - ['command.show', 'Open console'], - ['command.show.open?{"alter":false}', 'Open URL'], - ['command.show.open?{"alter":true}', 'Alter URL'], - ['command.show.tabopen?{"alter":false}', 'Open URL in new tab'], - ['command.show.tabopen?{"alter":true}', 'Alter URL in new tab'], - ['command.show.winopen?{"alter":false}', 'Open URL in new window'], - ['command.show.winopen?{"alter":true}', 'Alter URL in new window'], - ['command.show.buffer', 'Open buffer command'], - ['command.show.addbookmark?{"alter":true}', 'Open addbookmark command'], - ], [ - ['addon.toggle.enabled', 'Enable or disable'], - ['urls.yank', 'Copy current URL'], - ['urls.paste?{"newTab":false}', 'Open clipboard\'s URL in current tab'], - ['urls.paste?{"newTab":true}', 'Open clipboard\'s URL in new tab'], - ['zoom.in', 'Zoom-in'], - ['zoom.out', 'Zoom-out'], - ['zoom.neutral', 'Reset zoom level'], - ['repeat.last', 'Repeat last change'], - ] + ['scroll.vertically?{"count":1}', "Scroll down"], + ['scroll.vertically?{"count":-1}', "Scroll up"], + ['scroll.horizonally?{"count":-1}', "Scroll left"], + ['scroll.horizonally?{"count":1}', "Scroll right"], + ["scroll.home", "Scroll to leftmost"], + ["scroll.end", "Scroll to rightmost"], + ["scroll.top", "Scroll to top"], + ["scroll.bottom", "Scroll to bottom"], + ['scroll.pages?{"count":-0.5}', "Scroll up by half of screen"], + ['scroll.pages?{"count":0.5}', "Scroll down by half of screen"], + ['scroll.pages?{"count":-1}', "Scroll up by a screen"], + ['scroll.pages?{"count":1}', "Scroll down by a screen"], + ], + [ + ["mark.set.prefix", "Set mark at current position"], + ["mark.jump.prefix", "Jump to the mark"], + ], + [ + ['tabs.close?{"select":"right"}', "Close a tab"], + ["tabs.close.right", "Close all tabs to the right"], + ["tabs.reopen", "Reopen closed tab"], + ["tabs.next", "Select next tab"], + ["tabs.prev", "Select prev tab"], + ["tabs.first", "Select first tab"], + ["tabs.last", "Select last tab"], + ['tabs.reload?{"cache":false}', "Reload current tab"], + ['tabs.reload?{"cache":true}', "Reload with no caches"], + ["tabs.pin.toggle", "Toggle pinned state"], + ["tabs.duplicate", "Duplicate a tab"], + ], + [ + ['follow.start?{"newTab":false,"background":false}', "Follow a link"], + [ + 'follow.start?{"newTab":true,"background":false}', + "Follow a link in new tab", + ], + ["navigate.history.prev", "Go back in histories"], + ["navigate.history.next", "Go forward in histories"], + ["navigate.link.next", "Open next link"], + ["navigate.link.prev", "Open previous link"], + ["navigate.parent", "Go to parent directory"], + ["navigate.root", "Go to root directory"], + ["page.source", "Open page source"], + ['page.home?{"newTab":false}', "Open start page to current tab"], + ['page.home?{"newTab":true}', "Open start page in new tab"], + ["focus.input", "Focus input"], + ], + [ + ["find.start", "Start find mode"], + ["find.next", "Find next word"], + ["find.prev", "Find previous word"], + ], + [ + ["command.show", "Open console"], + ['command.show.open?{"alter":false}', "Open URL"], + ['command.show.open?{"alter":true}', "Alter URL"], + ['command.show.tabopen?{"alter":false}', "Open URL in new tab"], + ['command.show.tabopen?{"alter":true}', "Alter URL in new tab"], + ['command.show.winopen?{"alter":false}', "Open URL in new window"], + ['command.show.winopen?{"alter":true}', "Alter URL in new window"], + ["command.show.buffer", "Open buffer command"], + ['command.show.addbookmark?{"alter":true}', "Open addbookmark command"], + ], + [ + ["addon.toggle.enabled", "Enable or disable"], + ["urls.yank", "Copy current URL"], + ['urls.paste?{"newTab":false}', "Open clipboard's URL in current tab"], + ['urls.paste?{"newTab":true}', "Open clipboard's URL in new tab"], + ["zoom.in", "Zoom-in"], + ["zoom.out", "Zoom-out"], + ["zoom.neutral", "Reset zoom level"], + ["repeat.last", "Repeat last change"], + ], ]; export default { diff --git a/src/settings/reducers/setting.ts b/src/settings/reducers/setting.ts index 804853f..31544bb 100644 --- a/src/settings/reducers/setting.ts +++ b/src/settings/reducers/setting.ts @@ -1,8 +1,10 @@ -import * as actions from '../actions'; +import * as actions from "../actions"; import { - JSONTextSettings, FormSettings, SettingSource, -} from '../../shared/SettingData'; -import { DefaultSetting } from '../../shared/settings/Settings'; + JSONTextSettings, + FormSettings, + SettingSource, +} from "../../shared/SettingData"; +import { DefaultSetting } from "../../shared/settings/Settings"; export interface State { source: SettingSource; @@ -13,37 +15,41 @@ export interface State { const defaultState: State = { source: SettingSource.JSON, - json: JSONTextSettings.fromText(''), + json: JSONTextSettings.fromText(""), form: FormSettings.fromSettings(DefaultSetting), - error: '', + error: "", }; export default function reducer( state = defaultState, - action: actions.SettingAction, + action: actions.SettingAction ): State { switch (action.type) { - case actions.SETTING_SET_SETTINGS: - return { ...state, - source: action.source, - json: action.json, - form: action.form, - error: '', }; - case actions.SETTING_SHOW_ERROR: - return { ...state, - error: action.error, - json: action.json, }; - case actions.SETTING_SWITCH_TO_FORM: - return { ...state, - error: '', - source: SettingSource.Form, - form: action.form, }; - case actions.SETTING_SWITCH_TO_JSON: - return { ...state, - error: '', - source: SettingSource.JSON, - json: action.json, }; - default: - return state; + case actions.SETTING_SET_SETTINGS: + return { + ...state, + source: action.source, + json: action.json, + form: action.form, + error: "", + }; + case actions.SETTING_SHOW_ERROR: + return { ...state, error: action.error, json: action.json }; + case actions.SETTING_SWITCH_TO_FORM: + return { + ...state, + error: "", + source: SettingSource.Form, + form: action.form, + }; + case actions.SETTING_SWITCH_TO_JSON: + return { + ...state, + error: "", + source: SettingSource.JSON, + json: action.json, + }; + default: + return state; } } diff --git a/src/settings/storage.ts b/src/settings/storage.ts index 55cca96..da67ecc 100644 --- a/src/settings/storage.ts +++ b/src/settings/storage.ts @@ -1,22 +1,24 @@ -import SettingData, { DefaultSettingData } from '../shared/SettingData'; +import SettingData, { DefaultSettingData } from "../shared/SettingData"; -const loadSettingData = async(): Promise<SettingData> => { - const { settings: syncSettings } = await browser.storage.sync.get('settings'); +const loadSettingData = async (): Promise<SettingData> => { + const { settings: syncSettings } = await browser.storage.sync.get("settings"); if (syncSettings) { return SettingData.fromJSON(syncSettings as any); } - const { settings: localSettings } = await browser.storage.local.get('settings'); + const { settings: localSettings } = await browser.storage.local.get( + "settings" + ); if (localSettings) { return SettingData.fromJSON(localSettings as any); } - return DefaultSettingData + return DefaultSettingData; }; -export const load = async(): Promise<SettingData> => { +export const load = async (): Promise<SettingData> => { try { return loadSettingData(); } catch (e) { - console.error('unable to load settings', e); + console.error("unable to load settings", e); return DefaultSettingData; } }; diff --git a/src/shared/Command.ts b/src/shared/Command.ts index b8c21ce..05b8b83 100644 --- a/src/shared/Command.ts +++ b/src/shared/Command.ts @@ -1,40 +1,40 @@ export enum Command { - Open = "open", - TabOpen = "tabopen", - WindowOpen = "winopen", - Buffer = "buffer", - BufferDelete = "bdelete", - BufferDeleteForce = "bdelete!", - BuffersDelete = "bdeletes", - BuffersDeleteForce = "bdeletes!", - AddBookmark = "addbookmark", - Quit = "quit", - QuitAll = "quitall", - Set = "set", - Help = "help", + Open = "open", + TabOpen = "tabopen", + WindowOpen = "winopen", + Buffer = "buffer", + BufferDelete = "bdelete", + BufferDeleteForce = "bdelete!", + BuffersDelete = "bdeletes", + BuffersDeleteForce = "bdeletes!", + AddBookmark = "addbookmark", + Quit = "quit", + QuitAll = "quitall", + Set = "set", + Help = "help", } export namespace Command { export function members(): Command[] { return [ - Command.Open , - Command.TabOpen , - Command.WindowOpen , - Command.Buffer , - Command.BufferDelete , - Command.BufferDeleteForce , - Command.BuffersDelete , - Command.BuffersDeleteForce , - Command.AddBookmark , - Command.Quit , - Command.QuitAll , - Command.Set , - Command.Help , - ] + Command.Open, + Command.TabOpen, + Command.WindowOpen, + Command.Buffer, + Command.BufferDelete, + Command.BufferDeleteForce, + Command.BuffersDelete, + Command.BuffersDeleteForce, + Command.AddBookmark, + Command.Quit, + Command.QuitAll, + Command.Set, + Command.Help, + ]; } export function valueOf(value: string): Command { - const map = new Map(members().map(cmd => [cmd.toString(), cmd])); + const map = new Map(members().map((cmd) => [cmd.toString(), cmd])); const cmd = map.get(value); if (!cmd) { throw new Error(`unknown command '${value}`); diff --git a/src/shared/CompletionType.ts b/src/shared/CompletionType.ts index e104455..8ca04a7 100644 --- a/src/shared/CompletionType.ts +++ b/src/shared/CompletionType.ts @@ -4,4 +4,4 @@ enum CompletionType { Bookmarks, } -export default CompletionType;
\ No newline at end of file +export default CompletionType; diff --git a/src/shared/SettingData.ts b/src/shared/SettingData.ts index 5ad360e..a7bdf80 100644 --- a/src/shared/SettingData.ts +++ b/src/shared/SettingData.ts @@ -1,21 +1,21 @@ -import * as operations from './operations'; -import Settings, { DefaultSettingJSONText } from './settings/Settings'; -import Keymaps from './settings/Keymaps'; -import Search from './settings/Search'; -import Properties from './settings/Properties'; -import Blacklist from './settings/Blacklist'; +import * as operations from "./operations"; +import Settings, { DefaultSettingJSONText } from "./settings/Settings"; +import Keymaps from "./settings/Keymaps"; +import Search from "./settings/Search"; +import Properties from "./settings/Properties"; +import Blacklist from "./settings/Blacklist"; export class FormKeymaps { - private readonly data: {[op: string]: string}; + private readonly data: { [op: string]: string }; - private constructor(data: {[op: string]: string}) { + private constructor(data: { [op: string]: string }) { this.data = data; } toKeymaps(): Keymaps { const keymaps: { [key: string]: operations.Operation } = {}; for (const name of Object.keys(this.data)) { - const [type, argStr] = name.split('?'); + const [type, argStr] = name.split("?"); let args = {}; if (argStr) { args = JSON.parse(argStr); @@ -26,7 +26,7 @@ export class FormKeymaps { return Keymaps.fromJSON(keymaps); } - toJSON(): {[op: string]: string} { + toJSON(): { [op: string]: string } { return this.data; } @@ -38,8 +38,8 @@ export class FormKeymaps { return new FormKeymaps(newData); } - static fromJSON(o: ReturnType<FormKeymaps['toJSON']>): FormKeymaps { - const data: {[op: string]: string} = {}; + static fromJSON(o: ReturnType<FormKeymaps["toJSON"]>): FormKeymaps { + const data: { [op: string]: string } = {}; for (const op of Object.keys(o)) { data[op] = o[op] as string; } @@ -48,7 +48,7 @@ export class FormKeymaps { static fromKeymaps(keymaps: Keymaps): FormKeymaps { const json = keymaps.toJSON(); - const data: {[op: string]: string} = {}; + const data: { [op: string]: string } = {}; for (const key of Object.keys(json)) { const op = json[key]; const args = { ...op }; @@ -56,7 +56,7 @@ export class FormKeymaps { let name = op.type; if (Object.keys(args).length > 0) { - name += '?' + JSON.stringify(args); + name += "?" + JSON.stringify(args); } data[name] = key; } @@ -85,18 +85,18 @@ export class FormSearch { toJSON(): { default: string; engines: string[][]; - } { + } { return { default: this.default, engines: this.engines, }; } - static fromJSON(o: ReturnType<FormSearch['toJSON']>): FormSearch { - if (!Object.prototype.hasOwnProperty.call(o, 'default')) { + static fromJSON(o: ReturnType<FormSearch["toJSON"]>): FormSearch { + if (!Object.prototype.hasOwnProperty.call(o, "default")) { throw new TypeError(`"default" field not set`); } - if (!Object.prototype.hasOwnProperty.call(o, 'engines')) { + if (!Object.prototype.hasOwnProperty.call(o, "engines")) { throw new TypeError(`"engines" field not set`); } return new FormSearch(o.default, o.engines); @@ -106,16 +106,15 @@ export class FormSearch { const engines = Object.entries(search.engines).reduce( (o: string[][], [name, url]) => { return o.concat([[name, url]]); - }, []); + }, + [] + ); return new FormSearch(search.defaultEngine, engines); } } export class JSONTextSettings { - constructor( - private json: string, - ) { - } + constructor(private json: string) {} toSettings(): Settings { return Settings.fromJSON(JSON.parse(this.json)); @@ -153,7 +152,7 @@ export class FormSettings { keymaps: FormKeymaps, search: FormSearch, properties: Properties, - blacklist: Blacklist, + blacklist: Blacklist ) { this.keymaps = keymaps; this.search = search; @@ -166,7 +165,7 @@ export class FormSettings { keymaps, this.search, this.properties, - this.blacklist, + this.blacklist ); } @@ -175,17 +174,12 @@ export class FormSettings { this.keymaps, search, this.properties, - this.blacklist, + this.blacklist ); } buildWithProperties(props: Properties): FormSettings { - return new FormSettings( - this.keymaps, - this.search, - props, - this.blacklist, - ); + return new FormSettings(this.keymaps, this.search, props, this.blacklist); } buildWithBlacklist(blacklist: Blacklist): FormSettings { @@ -193,7 +187,7 @@ export class FormSettings { this.keymaps, this.search, this.properties, - blacklist, + blacklist ); } @@ -207,11 +201,11 @@ export class FormSettings { } toJSON(): { - keymaps: ReturnType<FormKeymaps['toJSON']>; - search: ReturnType<FormSearch['toJSON']>; - properties: ReturnType<Properties['toJSON']>; - blacklist: ReturnType<Blacklist['toJSON']>; - } { + keymaps: ReturnType<FormKeymaps["toJSON"]>; + search: ReturnType<FormSearch["toJSON"]>; + properties: ReturnType<Properties["toJSON"]>; + blacklist: ReturnType<Blacklist["toJSON"]>; + } { return { keymaps: this.keymaps.toJSON(), search: this.search.toJSON(), @@ -220,8 +214,8 @@ export class FormSettings { }; } - static fromJSON(o: ReturnType<FormSettings['toJSON']>): FormSettings { - for (const name of ['keymaps', 'search', 'properties', 'blacklist']) { + static fromJSON(o: ReturnType<FormSettings["toJSON"]>): FormSettings { + for (const name of ["keymaps", "search", "properties", "blacklist"]) { if (!Object.prototype.hasOwnProperty.call(o, name)) { throw new Error(`"${name}" field not set`); } @@ -230,7 +224,7 @@ export class FormSettings { FormKeymaps.fromJSON(o.keymaps), FormSearch.fromJSON(o.search), Properties.fromJSON(o.properties), - Blacklist.fromJSON(o.blacklist), + Blacklist.fromJSON(o.blacklist) ); } @@ -239,13 +233,14 @@ export class FormSettings { FormKeymaps.fromKeymaps(data.keymaps), FormSearch.fromSearch(data.search), data.properties, - data.blacklist); + data.blacklist + ); } } export enum SettingSource { - JSON = 'json', - Form = 'form', + JSON = "json", + Form = "form", } export default class SettingData { @@ -256,11 +251,13 @@ export default class SettingData { private form?: FormSettings; constructor({ - source, json, form + source, + json, + form, }: { - source: SettingSource, - json?: JSONTextSettings, - form?: FormSettings, + source: SettingSource; + json?: JSONTextSettings; + form?: FormSettings; }) { this.source = source; this.json = json; @@ -273,40 +270,40 @@ export default class SettingData { getJSON(): JSONTextSettings { if (!this.json) { - throw new TypeError('json settings not set'); + throw new TypeError("json settings not set"); } return this.json; } getForm(): FormSettings { if (!this.form) { - throw new TypeError('form settings not set'); + throw new TypeError("form settings not set"); } return this.form; } toJSON(): any { switch (this.source) { - case SettingSource.JSON: - return { - source: this.source, - json: (this.json as JSONTextSettings).toJSONText(), - }; - case SettingSource.Form: - return { - source: this.source, - form: (this.form as FormSettings).toJSON(), - }; + case SettingSource.JSON: + return { + source: this.source, + json: (this.json as JSONTextSettings).toJSONText(), + }; + case SettingSource.Form: + return { + source: this.source, + form: (this.form as FormSettings).toJSON(), + }; } throw new Error(`unknown settings source: ${this.source}`); } toSettings(): Settings { switch (this.source) { - case SettingSource.JSON: - return this.getJSON().toSettings(); - case SettingSource.Form: - return this.getForm().toSettings(); + case SettingSource.JSON: + return this.getJSON().toSettings(); + case SettingSource.Form: + return this.getForm().toSettings(); } throw new Error(`unknown settings source: ${this.source}`); } @@ -314,27 +311,29 @@ export default class SettingData { static fromJSON(o: { source: string; json?: string; - form?: ReturnType<FormSettings['toJSON']>; + form?: ReturnType<FormSettings["toJSON"]>; }): SettingData { switch (o.source) { - case SettingSource.JSON: - return new SettingData({ - source: o.source, - json: JSONTextSettings.fromText( - o.json as ReturnType<JSONTextSettings['toJSONText']>), - }); - case SettingSource.Form: - return new SettingData({ - source: o.source, - form: FormSettings.fromJSON( - o.form as ReturnType<FormSettings['toJSON']>), - }); + case SettingSource.JSON: + return new SettingData({ + source: o.source, + json: JSONTextSettings.fromText( + o.json as ReturnType<JSONTextSettings["toJSONText"]> + ), + }); + case SettingSource.Form: + return new SettingData({ + source: o.source, + form: FormSettings.fromJSON( + o.form as ReturnType<FormSettings["toJSON"]> + ), + }); } throw new Error(`unknown settings source: ${o.source}`); } } export const DefaultSettingData: SettingData = SettingData.fromJSON({ - source: 'json', + source: "json", json: DefaultSettingJSONText, }); diff --git a/src/shared/TabFlag.ts b/src/shared/TabFlag.ts index b10d5c6..eb4e116 100644 --- a/src/shared/TabFlag.ts +++ b/src/shared/TabFlag.ts @@ -1,7 +1,7 @@ enum TabFlag { - CurrentTab = '%', - LastTab = '#', - None = '', + CurrentTab = "%", + LastTab = "#", + None = "", } -export default TabFlag
\ No newline at end of file +export default TabFlag; diff --git a/src/shared/messages.ts b/src/shared/messages.ts index edb7935..f876b99 100644 --- a/src/shared/messages.ts +++ b/src/shared/messages.ts @@ -1,58 +1,59 @@ -import * as operations from './operations'; +import * as operations from "./operations"; import CompletionType from "./CompletionType"; import TabFlag from "./TabFlag"; -export const BACKGROUND_OPERATION = 'background.operation'; - -export const CONSOLE_UNFOCUS = 'console.unfocus'; -export const CONSOLE_ENTER_COMMAND = 'console.enter.command'; -export const CONSOLE_ENTER_FIND = 'console.enter.find'; -export const CONSOLE_SHOW_COMMAND = 'console.show.command'; -export const CONSOLE_SHOW_ERROR = 'console.show.error'; -export const CONSOLE_SHOW_INFO = 'console.show.info'; -export const CONSOLE_SHOW_FIND = 'console.show.find'; -export const CONSOLE_HIDE = 'console.hide'; -export const CONSOLE_GET_COMPLETION_TYPES = 'console.get.completion.types'; -export const CONSOLE_REQUEST_SEARCH_ENGINES_MESSAGE = 'console.qresut.searchEngines'; -export const CONSOLE_REQUEST_BOOKMARKS = 'console.request.bookmarks'; -export const CONSOLE_REQUEST_HISTORY = 'console.request.history'; -export const CONSOLE_REQUEST_TABS = 'console.request.tabs'; -export const CONSOLE_GET_PROPERTIES = 'console.get.properties'; - -export const FOLLOW_START = 'follow.start'; -export const FOLLOW_REQUEST_COUNT_TARGETS = 'follow.request.count.targets'; -export const FOLLOW_RESPONSE_COUNT_TARGETS = 'follow.response.count.targets'; -export const FOLLOW_CREATE_HINTS = 'follow.create.hints'; -export const FOLLOW_SHOW_HINTS = 'follow.update.hints'; -export const FOLLOW_REMOVE_HINTS = 'follow.remove.hints'; -export const FOLLOW_ACTIVATE = 'follow.activate'; -export const FOLLOW_KEY_PRESS = 'follow.key.press'; - -export const MARK_SET_GLOBAL = 'mark.set.global'; -export const MARK_JUMP_GLOBAL = 'mark.jump.global'; - -export const TAB_SCROLL_TO = 'tab.scroll.to'; - -export const FIND_NEXT = 'find.next'; -export const FIND_PREV = 'find.prev'; -export const FIND_GET_KEYWORD = 'find.get.keyword'; -export const FIND_SET_KEYWORD = 'find.set.keyword'; - -export const ADDON_ENABLED_QUERY = 'addon.enabled.query'; -export const ADDON_ENABLED_RESPONSE = 'addon.enabled.response'; -export const ADDON_TOGGLE_ENABLED = 'addon.toggle.enabled'; - -export const OPEN_URL = 'open.url'; - -export const SETTINGS_CHANGED = 'settings.changed'; -export const SETTINGS_QUERY = 'settings.query'; - -export const CONSOLE_FRAME_MESSAGE = 'console.frame.message'; - -export const NAVIGATE_HISTORY_NEXT = 'navigate.history.next'; -export const NAVIGATE_HISTORY_PREV = 'navigate.history.prev'; -export const NAVIGATE_LINK_NEXT = 'navigate.link.next'; -export const NAVIGATE_LINK_PREV = 'navigate.link.prev'; +export const BACKGROUND_OPERATION = "background.operation"; + +export const CONSOLE_UNFOCUS = "console.unfocus"; +export const CONSOLE_ENTER_COMMAND = "console.enter.command"; +export const CONSOLE_ENTER_FIND = "console.enter.find"; +export const CONSOLE_SHOW_COMMAND = "console.show.command"; +export const CONSOLE_SHOW_ERROR = "console.show.error"; +export const CONSOLE_SHOW_INFO = "console.show.info"; +export const CONSOLE_SHOW_FIND = "console.show.find"; +export const CONSOLE_HIDE = "console.hide"; +export const CONSOLE_GET_COMPLETION_TYPES = "console.get.completion.types"; +export const CONSOLE_REQUEST_SEARCH_ENGINES_MESSAGE = + "console.qresut.searchEngines"; +export const CONSOLE_REQUEST_BOOKMARKS = "console.request.bookmarks"; +export const CONSOLE_REQUEST_HISTORY = "console.request.history"; +export const CONSOLE_REQUEST_TABS = "console.request.tabs"; +export const CONSOLE_GET_PROPERTIES = "console.get.properties"; + +export const FOLLOW_START = "follow.start"; +export const FOLLOW_REQUEST_COUNT_TARGETS = "follow.request.count.targets"; +export const FOLLOW_RESPONSE_COUNT_TARGETS = "follow.response.count.targets"; +export const FOLLOW_CREATE_HINTS = "follow.create.hints"; +export const FOLLOW_SHOW_HINTS = "follow.update.hints"; +export const FOLLOW_REMOVE_HINTS = "follow.remove.hints"; +export const FOLLOW_ACTIVATE = "follow.activate"; +export const FOLLOW_KEY_PRESS = "follow.key.press"; + +export const MARK_SET_GLOBAL = "mark.set.global"; +export const MARK_JUMP_GLOBAL = "mark.jump.global"; + +export const TAB_SCROLL_TO = "tab.scroll.to"; + +export const FIND_NEXT = "find.next"; +export const FIND_PREV = "find.prev"; +export const FIND_GET_KEYWORD = "find.get.keyword"; +export const FIND_SET_KEYWORD = "find.set.keyword"; + +export const ADDON_ENABLED_QUERY = "addon.enabled.query"; +export const ADDON_ENABLED_RESPONSE = "addon.enabled.response"; +export const ADDON_TOGGLE_ENABLED = "addon.toggle.enabled"; + +export const OPEN_URL = "open.url"; + +export const SETTINGS_CHANGED = "settings.changed"; +export const SETTINGS_QUERY = "settings.query"; + +export const CONSOLE_FRAME_MESSAGE = "console.frame.message"; + +export const NAVIGATE_HISTORY_NEXT = "navigate.history.next"; +export const NAVIGATE_HISTORY_PREV = "navigate.history.prev"; +export const NAVIGATE_LINK_NEXT = "navigate.link.next"; +export const NAVIGATE_LINK_PREV = "navigate.link.prev"; export interface BackgroundOperationMessage { type: typeof BACKGROUND_OPERATION; @@ -103,7 +104,7 @@ export interface ConsoleGetCompletionTypesMessage { export interface ConsoleRequestSearchEnginesMessage { type: typeof CONSOLE_REQUEST_SEARCH_ENGINES_MESSAGE; - query: string + query: string; } export interface ConsoleRequestBookmarksMessage { @@ -127,33 +128,33 @@ export interface ConsoleGetPropertiesMessage { } export type ConsoleRequesttabsResponse = { - index: number - flag: TabFlag - title: string - url: string - faviconUrl?: string -}[] + index: number; + flag: TabFlag; + title: string; + url: string; + faviconUrl?: string; +}[]; export type ConsoleGetCompletionTypesResponse = CompletionType[]; export type ConsoleRequestSearchEnginesResponse = { title: string; -}[] +}[]; export type ConsoleRequestBookmarksResponse = { - title: string; - url: string; -}[] + title: string; + url: string; +}[]; export type ConsoleRequestHistoryResponse = { title: string; url: string; -}[] +}[]; export type ConsoleGetPropertiesResponse = { - name: string - type: 'string' | 'boolean' | 'number' -}[] + name: string; + type: "string" | "boolean" | "number"; +}[]; export interface FollowStartMessage { type: typeof FOLLOW_START; @@ -163,8 +164,8 @@ export interface FollowStartMessage { export interface FollowRequestCountTargetsMessage { type: typeof FOLLOW_REQUEST_COUNT_TARGETS; - viewSize: { width: number, height: number }; - framePosition: { x: number, y: number }; + viewSize: { width: number; height: number }; + framePosition: { x: number; y: number }; } export interface FollowResponseCountTargetsMessage { @@ -175,8 +176,8 @@ export interface FollowResponseCountTargetsMessage { export interface FollowCreateHintsMessage { type: typeof FOLLOW_CREATE_HINTS; tags: string[]; - viewSize: { width: number, height: number }; - framePosition: { x: number, y: number }; + viewSize: { width: number; height: number }; + framePosition: { x: number; y: number }; } export interface FollowShowHintsMessage { @@ -287,86 +288,86 @@ export interface NavigateLinkPrev { } export type Message = - BackgroundOperationMessage | - ConsoleUnfocusMessage | - ConsoleEnterCommandMessage | - ConsoleEnterFindMessage | - ConsoleShowCommandMessage | - ConsoleShowErrorMessage | - ConsoleShowInfoMessage | - ConsoleShowFindMessage | - ConsoleHideMessage | - ConsoleRequestBookmarksMessage | - ConsoleRequestHistoryMessage | - ConsoleRequestTabsMessage | - ConsoleGetPropertiesMessage | - ConsoleGetCompletionTypesMessage | - ConsoleRequestSearchEnginesMessage | - FollowStartMessage | - FollowRequestCountTargetsMessage | - FollowResponseCountTargetsMessage | - FollowCreateHintsMessage | - FollowShowHintsMessage | - FollowRemoveHintsMessage | - FollowActivateMessage | - FollowKeyPressMessage | - MarkSetGlobalMessage | - MarkJumpGlobalMessage | - TabScrollToMessage | - FindNextMessage | - FindPrevMessage | - FindGetKeywordMessage | - FindSetKeywordMessage | - AddonEnabledQueryMessage | - AddonEnabledResponseMessage | - AddonToggleEnabledMessage | - OpenUrlMessage | - SettingsChangedMessage | - SettingsQueryMessage | - ConsoleFrameMessageMessage | - NavigateHistoryNextMessage | - NavigateHistoryPrevMessage | - NavigateLinkNext | - NavigateLinkPrev; + | BackgroundOperationMessage + | ConsoleUnfocusMessage + | ConsoleEnterCommandMessage + | ConsoleEnterFindMessage + | ConsoleShowCommandMessage + | ConsoleShowErrorMessage + | ConsoleShowInfoMessage + | ConsoleShowFindMessage + | ConsoleHideMessage + | ConsoleRequestBookmarksMessage + | ConsoleRequestHistoryMessage + | ConsoleRequestTabsMessage + | ConsoleGetPropertiesMessage + | ConsoleGetCompletionTypesMessage + | ConsoleRequestSearchEnginesMessage + | FollowStartMessage + | FollowRequestCountTargetsMessage + | FollowResponseCountTargetsMessage + | FollowCreateHintsMessage + | FollowShowHintsMessage + | FollowRemoveHintsMessage + | FollowActivateMessage + | FollowKeyPressMessage + | MarkSetGlobalMessage + | MarkJumpGlobalMessage + | TabScrollToMessage + | FindNextMessage + | FindPrevMessage + | FindGetKeywordMessage + | FindSetKeywordMessage + | AddonEnabledQueryMessage + | AddonEnabledResponseMessage + | AddonToggleEnabledMessage + | OpenUrlMessage + | SettingsChangedMessage + | SettingsQueryMessage + | ConsoleFrameMessageMessage + | NavigateHistoryNextMessage + | NavigateHistoryPrevMessage + | NavigateLinkNext + | NavigateLinkPrev; // eslint-disable-next-line complexity export const valueOf = (o: any): Message => { switch (o.type) { - case CONSOLE_UNFOCUS: - case CONSOLE_ENTER_COMMAND: - case CONSOLE_ENTER_FIND: - case CONSOLE_SHOW_COMMAND: - case CONSOLE_SHOW_ERROR: - case CONSOLE_SHOW_INFO: - case CONSOLE_SHOW_FIND: - case CONSOLE_HIDE: - case FOLLOW_START: - case FOLLOW_REQUEST_COUNT_TARGETS: - case FOLLOW_RESPONSE_COUNT_TARGETS: - case FOLLOW_CREATE_HINTS: - case FOLLOW_SHOW_HINTS: - case FOLLOW_REMOVE_HINTS: - case FOLLOW_ACTIVATE: - case FOLLOW_KEY_PRESS: - case MARK_SET_GLOBAL: - case MARK_JUMP_GLOBAL: - case TAB_SCROLL_TO: - case FIND_NEXT: - case FIND_PREV: - case FIND_GET_KEYWORD: - case FIND_SET_KEYWORD: - case ADDON_ENABLED_QUERY: - case ADDON_ENABLED_RESPONSE: - case ADDON_TOGGLE_ENABLED: - case OPEN_URL: - case SETTINGS_CHANGED: - case SETTINGS_QUERY: - case CONSOLE_FRAME_MESSAGE: - case NAVIGATE_HISTORY_NEXT: - case NAVIGATE_HISTORY_PREV: - case NAVIGATE_LINK_NEXT: - case NAVIGATE_LINK_PREV: - return o; + case CONSOLE_UNFOCUS: + case CONSOLE_ENTER_COMMAND: + case CONSOLE_ENTER_FIND: + case CONSOLE_SHOW_COMMAND: + case CONSOLE_SHOW_ERROR: + case CONSOLE_SHOW_INFO: + case CONSOLE_SHOW_FIND: + case CONSOLE_HIDE: + case FOLLOW_START: + case FOLLOW_REQUEST_COUNT_TARGETS: + case FOLLOW_RESPONSE_COUNT_TARGETS: + case FOLLOW_CREATE_HINTS: + case FOLLOW_SHOW_HINTS: + case FOLLOW_REMOVE_HINTS: + case FOLLOW_ACTIVATE: + case FOLLOW_KEY_PRESS: + case MARK_SET_GLOBAL: + case MARK_JUMP_GLOBAL: + case TAB_SCROLL_TO: + case FIND_NEXT: + case FIND_PREV: + case FIND_GET_KEYWORD: + case FIND_SET_KEYWORD: + case ADDON_ENABLED_QUERY: + case ADDON_ENABLED_RESPONSE: + case ADDON_TOGGLE_ENABLED: + case OPEN_URL: + case SETTINGS_CHANGED: + case SETTINGS_QUERY: + case CONSOLE_FRAME_MESSAGE: + case NAVIGATE_HISTORY_NEXT: + case NAVIGATE_HISTORY_PREV: + case NAVIGATE_LINK_NEXT: + case NAVIGATE_LINK_PREV: + return o; } - throw new Error('unknown operation type: ' + o.type); + throw new Error("unknown operation type: " + o.type); }; diff --git a/src/shared/operations.ts b/src/shared/operations.ts index beca7b9..3544502 100644 --- a/src/shared/operations.ts +++ b/src/shared/operations.ts @@ -1,85 +1,85 @@ // Hide console; or cancel some user actions -export const CANCEL = 'cancel'; +export const CANCEL = "cancel"; // Addons -export const ADDON_ENABLE = 'addon.enable'; -export const ADDON_DISABLE = 'addon.disable'; -export const ADDON_TOGGLE_ENABLED = 'addon.toggle.enabled'; +export const ADDON_ENABLE = "addon.enable"; +export const ADDON_DISABLE = "addon.disable"; +export const ADDON_TOGGLE_ENABLED = "addon.toggle.enabled"; // Command -export const COMMAND_SHOW = 'command.show'; -export const COMMAND_SHOW_OPEN = 'command.show.open'; -export const COMMAND_SHOW_TABOPEN = 'command.show.tabopen'; -export const COMMAND_SHOW_WINOPEN = 'command.show.winopen'; -export const COMMAND_SHOW_BUFFER = 'command.show.buffer'; -export const COMMAND_SHOW_ADDBOOKMARK = 'command.show.addbookmark'; +export const COMMAND_SHOW = "command.show"; +export const COMMAND_SHOW_OPEN = "command.show.open"; +export const COMMAND_SHOW_TABOPEN = "command.show.tabopen"; +export const COMMAND_SHOW_WINOPEN = "command.show.winopen"; +export const COMMAND_SHOW_BUFFER = "command.show.buffer"; +export const COMMAND_SHOW_ADDBOOKMARK = "command.show.addbookmark"; // Scrolls -export const SCROLL_VERTICALLY = 'scroll.vertically'; -export const SCROLL_HORIZONALLY = 'scroll.horizonally'; -export const SCROLL_PAGES = 'scroll.pages'; -export const SCROLL_TOP = 'scroll.top'; -export const SCROLL_BOTTOM = 'scroll.bottom'; -export const SCROLL_HOME = 'scroll.home'; -export const SCROLL_END = 'scroll.end'; +export const SCROLL_VERTICALLY = "scroll.vertically"; +export const SCROLL_HORIZONALLY = "scroll.horizonally"; +export const SCROLL_PAGES = "scroll.pages"; +export const SCROLL_TOP = "scroll.top"; +export const SCROLL_BOTTOM = "scroll.bottom"; +export const SCROLL_HOME = "scroll.home"; +export const SCROLL_END = "scroll.end"; // Follows -export const FOLLOW_START = 'follow.start'; +export const FOLLOW_START = "follow.start"; // Navigations -export const NAVIGATE_HISTORY_PREV = 'navigate.history.prev'; -export const NAVIGATE_HISTORY_NEXT = 'navigate.history.next'; -export const NAVIGATE_LINK_PREV = 'navigate.link.prev'; -export const NAVIGATE_LINK_NEXT = 'navigate.link.next'; -export const NAVIGATE_PARENT = 'navigate.parent'; -export const NAVIGATE_ROOT = 'navigate.root'; +export const NAVIGATE_HISTORY_PREV = "navigate.history.prev"; +export const NAVIGATE_HISTORY_NEXT = "navigate.history.next"; +export const NAVIGATE_LINK_PREV = "navigate.link.prev"; +export const NAVIGATE_LINK_NEXT = "navigate.link.next"; +export const NAVIGATE_PARENT = "navigate.parent"; +export const NAVIGATE_ROOT = "navigate.root"; // Focus -export const FOCUS_INPUT = 'focus.input'; +export const FOCUS_INPUT = "focus.input"; // Page -export const PAGE_SOURCE = 'page.source'; -export const PAGE_HOME = 'page.home'; +export const PAGE_SOURCE = "page.source"; +export const PAGE_HOME = "page.home"; // Tabs -export const TAB_CLOSE = 'tabs.close'; -export const TAB_CLOSE_FORCE = 'tabs.close.force'; -export const TAB_CLOSE_RIGHT = 'tabs.close.right'; -export const TAB_REOPEN = 'tabs.reopen'; -export const TAB_PREV = 'tabs.prev'; -export const TAB_NEXT = 'tabs.next'; -export const TAB_FIRST = 'tabs.first'; -export const TAB_LAST = 'tabs.last'; -export const TAB_PREV_SEL = 'tabs.prevsel'; -export const TAB_RELOAD = 'tabs.reload'; -export const TAB_PIN = 'tabs.pin'; -export const TAB_UNPIN = 'tabs.unpin'; -export const TAB_TOGGLE_PINNED = 'tabs.pin.toggle'; -export const TAB_DUPLICATE = 'tabs.duplicate'; +export const TAB_CLOSE = "tabs.close"; +export const TAB_CLOSE_FORCE = "tabs.close.force"; +export const TAB_CLOSE_RIGHT = "tabs.close.right"; +export const TAB_REOPEN = "tabs.reopen"; +export const TAB_PREV = "tabs.prev"; +export const TAB_NEXT = "tabs.next"; +export const TAB_FIRST = "tabs.first"; +export const TAB_LAST = "tabs.last"; +export const TAB_PREV_SEL = "tabs.prevsel"; +export const TAB_RELOAD = "tabs.reload"; +export const TAB_PIN = "tabs.pin"; +export const TAB_UNPIN = "tabs.unpin"; +export const TAB_TOGGLE_PINNED = "tabs.pin.toggle"; +export const TAB_DUPLICATE = "tabs.duplicate"; // Zooms -export const ZOOM_IN = 'zoom.in'; -export const ZOOM_OUT = 'zoom.out'; -export const ZOOM_NEUTRAL = 'zoom.neutral'; +export const ZOOM_IN = "zoom.in"; +export const ZOOM_OUT = "zoom.out"; +export const ZOOM_NEUTRAL = "zoom.neutral"; // Url yank/paste -export const URLS_YANK = 'urls.yank'; -export const URLS_PASTE = 'urls.paste'; +export const URLS_YANK = "urls.yank"; +export const URLS_PASTE = "urls.paste"; // Find -export const FIND_START = 'find.start'; -export const FIND_NEXT = 'find.next'; -export const FIND_PREV = 'find.prev'; +export const FIND_START = "find.start"; +export const FIND_NEXT = "find.next"; +export const FIND_PREV = "find.prev"; // Mark -export const MARK_SET_PREFIX = 'mark.set.prefix'; -export const MARK_JUMP_PREFIX = 'mark.jump.prefix'; +export const MARK_SET_PREFIX = "mark.set.prefix"; +export const MARK_JUMP_PREFIX = "mark.jump.prefix"; // Repeat -export const REPEAT_LAST = 'repeat.last'; +export const REPEAT_LAST = "repeat.last"; // Internal -export const INTERNAL_OPEN_URL = 'internal.open.url'; +export const INTERNAL_OPEN_URL = "internal.open.url"; export interface CancelOperation { type: typeof CANCEL; @@ -201,7 +201,7 @@ export interface PageHomeOperation { export interface TabCloseOperation { type: typeof TAB_CLOSE; - select?: 'left' | 'right'; + select?: "left" | "right"; } export interface TabCloseForceOperation { @@ -311,65 +311,67 @@ export interface InternalOpenUrl { } export type Operation = - CancelOperation | - AddonEnableOperation | - AddonDisableOperation | - AddonToggleEnabledOperation | - CommandShowOperation | - CommandShowOpenOperation | - CommandShowTabopenOperation | - CommandShowWinopenOperation | - CommandShowBufferOperation | - CommandShowAddbookmarkOperation | - ScrollVerticallyOperation | - ScrollHorizonallyOperation | - ScrollPagesOperation | - ScrollTopOperation | - ScrollBottomOperation | - ScrollHomeOperation | - ScrollEndOperation | - FollowStartOperation | - NavigateHistoryPrevOperation | - NavigateHistoryNextOperation | - NavigateLinkPrevOperation | - NavigateLinkNextOperation | - NavigateParentOperation | - NavigateRootOperation | - FocusInputOperation | - PageSourceOperation | - PageHomeOperation | - TabCloseOperation | - TabCloseForceOperation | - TabCloseRightOperation | - TabReopenOperation | - TabPrevOperation | - TabNextOperation | - TabFirstOperation | - TabLastOperation | - TabPrevSelOperation | - TabReloadOperation | - TabPinOperation | - TabUnpinOperation | - TabTogglePinnedOperation | - TabDuplicateOperation | - ZoomInOperation | - ZoomOutOperation | - ZoomNeutralOperation | - UrlsYankOperation | - UrlsPasteOperation | - FindStartOperation | - FindNextOperation | - FindPrevOperation | - MarkSetPrefixOperation | - MarkJumpPrefixOperation | - RepeatLastOperation | - InternalOpenUrl; + | CancelOperation + | AddonEnableOperation + | AddonDisableOperation + | AddonToggleEnabledOperation + | CommandShowOperation + | CommandShowOpenOperation + | CommandShowTabopenOperation + | CommandShowWinopenOperation + | CommandShowBufferOperation + | CommandShowAddbookmarkOperation + | ScrollVerticallyOperation + | ScrollHorizonallyOperation + | ScrollPagesOperation + | ScrollTopOperation + | ScrollBottomOperation + | ScrollHomeOperation + | ScrollEndOperation + | FollowStartOperation + | NavigateHistoryPrevOperation + | NavigateHistoryNextOperation + | NavigateLinkPrevOperation + | NavigateLinkNextOperation + | NavigateParentOperation + | NavigateRootOperation + | FocusInputOperation + | PageSourceOperation + | PageHomeOperation + | TabCloseOperation + | TabCloseForceOperation + | TabCloseRightOperation + | TabReopenOperation + | TabPrevOperation + | TabNextOperation + | TabFirstOperation + | TabLastOperation + | TabPrevSelOperation + | TabReloadOperation + | TabPinOperation + | TabUnpinOperation + | TabTogglePinnedOperation + | TabDuplicateOperation + | ZoomInOperation + | ZoomOutOperation + | ZoomNeutralOperation + | UrlsYankOperation + | UrlsPasteOperation + | FindStartOperation + | FindNextOperation + | FindPrevOperation + | MarkSetPrefixOperation + | MarkJumpPrefixOperation + | RepeatLastOperation + | InternalOpenUrl; const assertOptionalBoolean = (obj: any, name: string) => { - if (Object.prototype.hasOwnProperty.call(obj, name) && - typeof obj[name] !== 'boolean') { + if ( + Object.prototype.hasOwnProperty.call(obj, name) && + typeof obj[name] !== "boolean" + ) { throw new TypeError( - `Not a boolean parameter: '${name} (${typeof obj[name]})'`, + `Not a boolean parameter: '${name} (${typeof obj[name]})'` ); } }; @@ -377,9 +379,9 @@ const assertOptionalBoolean = (obj: any, name: string) => { const assertOptionalString = (obj: any, name: string, values?: string[]) => { if (Object.prototype.hasOwnProperty.call(obj, name)) { const value = obj[name]; - if (typeof value !== 'string') { + if (typeof value !== "string") { throw new TypeError( - `Not a string parameter: '${name}' (${typeof value})`, + `Not a string parameter: '${name}' (${typeof value})` ); } if (values && values.length && values.indexOf(value) === -1) { @@ -390,147 +392,157 @@ const assertOptionalString = (obj: any, name: string, values?: string[]) => { }; const assertRequiredNumber = (obj: any, name: string) => { - if (!Object.prototype.hasOwnProperty.call(obj, name) || - typeof obj[name] !== 'number') { + if ( + !Object.prototype.hasOwnProperty.call(obj, name) || + typeof obj[name] !== "number" + ) { throw new TypeError(`Missing number parameter: '${name}`); } }; const assertRequiredString = (obj: any, name: string) => { - if (!Object.prototype.hasOwnProperty.call(obj, name) || - typeof obj[name] !== 'string') { + if ( + !Object.prototype.hasOwnProperty.call(obj, name) || + typeof obj[name] !== "string" + ) { throw new TypeError(`Missing string parameter: '${name}`); } }; // eslint-disable-next-line complexity, max-lines-per-function export const valueOf = (o: any): Operation => { - if (!Object.prototype.hasOwnProperty.call(o, 'type')) { + if (!Object.prototype.hasOwnProperty.call(o, "type")) { throw new TypeError(`Missing 'type' field`); } switch (o.type) { - case COMMAND_SHOW_OPEN: - case COMMAND_SHOW_TABOPEN: - case COMMAND_SHOW_WINOPEN: - case COMMAND_SHOW_ADDBOOKMARK: - assertOptionalBoolean(o, 'alter'); - return { type: o.type, alter: Boolean(o.alter) }; - case SCROLL_VERTICALLY: - case SCROLL_HORIZONALLY: - case SCROLL_PAGES: - assertRequiredNumber(o, 'count'); - return { type: o.type, count: Number(o.count) }; - case FOLLOW_START: - assertOptionalBoolean(o, 'newTab'); - assertOptionalBoolean(o, 'background'); - return { - type: FOLLOW_START, - newTab: Boolean(typeof o.newTab === 'undefined' ? false : o.newTab), - background: Boolean(typeof o.background === 'undefined' ? true : o.background), // eslint-disable-line max-len - }; - case PAGE_HOME: - assertOptionalBoolean(o, 'newTab'); - return { - type: PAGE_HOME, - newTab: Boolean(typeof o.newTab === 'undefined' ? false : o.newTab), - }; - case TAB_CLOSE: - assertOptionalString(o, 'select', ['left', 'right']); - return { - type: TAB_CLOSE, - select: (typeof o.select === 'undefined' ? 'right' : o.select), - }; - case TAB_RELOAD: - assertOptionalBoolean(o, 'cache'); - return { - type: TAB_RELOAD, - cache: Boolean(typeof o.cache === 'undefined' ? false : o.cache), - }; - case URLS_PASTE: - assertOptionalBoolean(o, 'newTab'); - return { - type: URLS_PASTE, - newTab: Boolean(typeof o.newTab === 'undefined' ? false : o.newTab), - }; - case INTERNAL_OPEN_URL: - assertOptionalBoolean(o, 'newTab'); - assertOptionalBoolean(o, 'newWindow'); - assertOptionalBoolean(o, 'background'); - assertRequiredString(o, 'url'); - return { - type: INTERNAL_OPEN_URL, - url: o.url, - newTab: Boolean(typeof o.newTab === 'undefined' ? false : o.newTab), - newWindow: Boolean(typeof o.newWindow === 'undefined' ? false : o.newWindow), // eslint-disable-line max-len - background: Boolean(typeof o.background === 'undefined' ? true : o.background), // eslint-disable-line max-len - }; - case CANCEL: - case ADDON_ENABLE: - case ADDON_DISABLE: - case ADDON_TOGGLE_ENABLED: - case COMMAND_SHOW: - case COMMAND_SHOW_BUFFER: - case SCROLL_TOP: - case SCROLL_BOTTOM: - case SCROLL_HOME: - case SCROLL_END: - case NAVIGATE_HISTORY_PREV: - case NAVIGATE_HISTORY_NEXT: - case NAVIGATE_LINK_PREV: - case NAVIGATE_LINK_NEXT: - case NAVIGATE_PARENT: - case NAVIGATE_ROOT: - case FOCUS_INPUT: - case PAGE_SOURCE: - case TAB_CLOSE_FORCE: - case TAB_CLOSE_RIGHT: - case TAB_REOPEN: - case TAB_PREV: - case TAB_NEXT: - case TAB_FIRST: - case TAB_LAST: - case TAB_PREV_SEL: - case TAB_PIN: - case TAB_UNPIN: - case TAB_TOGGLE_PINNED: - case TAB_DUPLICATE: - case ZOOM_IN: - case ZOOM_OUT: - case ZOOM_NEUTRAL: - case URLS_YANK: - case FIND_START: - case FIND_NEXT: - case FIND_PREV: - case MARK_SET_PREFIX: - case MARK_JUMP_PREFIX: - case REPEAT_LAST: - return { type: o.type }; + case COMMAND_SHOW_OPEN: + case COMMAND_SHOW_TABOPEN: + case COMMAND_SHOW_WINOPEN: + case COMMAND_SHOW_ADDBOOKMARK: + assertOptionalBoolean(o, "alter"); + return { type: o.type, alter: Boolean(o.alter) }; + case SCROLL_VERTICALLY: + case SCROLL_HORIZONALLY: + case SCROLL_PAGES: + assertRequiredNumber(o, "count"); + return { type: o.type, count: Number(o.count) }; + case FOLLOW_START: + assertOptionalBoolean(o, "newTab"); + assertOptionalBoolean(o, "background"); + return { + type: FOLLOW_START, + newTab: Boolean(typeof o.newTab === "undefined" ? false : o.newTab), + background: Boolean( + typeof o.background === "undefined" ? true : o.background + ), // eslint-disable-line max-len + }; + case PAGE_HOME: + assertOptionalBoolean(o, "newTab"); + return { + type: PAGE_HOME, + newTab: Boolean(typeof o.newTab === "undefined" ? false : o.newTab), + }; + case TAB_CLOSE: + assertOptionalString(o, "select", ["left", "right"]); + return { + type: TAB_CLOSE, + select: typeof o.select === "undefined" ? "right" : o.select, + }; + case TAB_RELOAD: + assertOptionalBoolean(o, "cache"); + return { + type: TAB_RELOAD, + cache: Boolean(typeof o.cache === "undefined" ? false : o.cache), + }; + case URLS_PASTE: + assertOptionalBoolean(o, "newTab"); + return { + type: URLS_PASTE, + newTab: Boolean(typeof o.newTab === "undefined" ? false : o.newTab), + }; + case INTERNAL_OPEN_URL: + assertOptionalBoolean(o, "newTab"); + assertOptionalBoolean(o, "newWindow"); + assertOptionalBoolean(o, "background"); + assertRequiredString(o, "url"); + return { + type: INTERNAL_OPEN_URL, + url: o.url, + newTab: Boolean(typeof o.newTab === "undefined" ? false : o.newTab), + newWindow: Boolean( + typeof o.newWindow === "undefined" ? false : o.newWindow + ), // eslint-disable-line max-len + background: Boolean( + typeof o.background === "undefined" ? true : o.background + ), // eslint-disable-line max-len + }; + case CANCEL: + case ADDON_ENABLE: + case ADDON_DISABLE: + case ADDON_TOGGLE_ENABLED: + case COMMAND_SHOW: + case COMMAND_SHOW_BUFFER: + case SCROLL_TOP: + case SCROLL_BOTTOM: + case SCROLL_HOME: + case SCROLL_END: + case NAVIGATE_HISTORY_PREV: + case NAVIGATE_HISTORY_NEXT: + case NAVIGATE_LINK_PREV: + case NAVIGATE_LINK_NEXT: + case NAVIGATE_PARENT: + case NAVIGATE_ROOT: + case FOCUS_INPUT: + case PAGE_SOURCE: + case TAB_CLOSE_FORCE: + case TAB_CLOSE_RIGHT: + case TAB_REOPEN: + case TAB_PREV: + case TAB_NEXT: + case TAB_FIRST: + case TAB_LAST: + case TAB_PREV_SEL: + case TAB_PIN: + case TAB_UNPIN: + case TAB_TOGGLE_PINNED: + case TAB_DUPLICATE: + case ZOOM_IN: + case ZOOM_OUT: + case ZOOM_NEUTRAL: + case URLS_YANK: + case FIND_START: + case FIND_NEXT: + case FIND_PREV: + case MARK_SET_PREFIX: + case MARK_JUMP_PREFIX: + case REPEAT_LAST: + return { type: o.type }; } - throw new TypeError('Unknown operation type: ' + o.type); + throw new TypeError("Unknown operation type: " + o.type); }; export const isNRepeatable = (type: string): boolean => { switch (type) { - case SCROLL_VERTICALLY: - case SCROLL_HORIZONALLY: - case SCROLL_PAGES: - case NAVIGATE_HISTORY_PREV: - case NAVIGATE_HISTORY_NEXT: - case NAVIGATE_PARENT: - case TAB_CLOSE: - case TAB_CLOSE_FORCE: - case TAB_CLOSE_RIGHT: - case TAB_REOPEN: - case TAB_PREV: - case TAB_NEXT: - case TAB_DUPLICATE: - case ZOOM_IN: - case ZOOM_OUT: - case URLS_PASTE: - case FIND_NEXT: - case FIND_PREV: - case REPEAT_LAST: - return true; + case SCROLL_VERTICALLY: + case SCROLL_HORIZONALLY: + case SCROLL_PAGES: + case NAVIGATE_HISTORY_PREV: + case NAVIGATE_HISTORY_NEXT: + case NAVIGATE_PARENT: + case TAB_CLOSE: + case TAB_CLOSE_FORCE: + case TAB_CLOSE_RIGHT: + case TAB_REOPEN: + case TAB_PREV: + case TAB_NEXT: + case TAB_DUPLICATE: + case ZOOM_IN: + case ZOOM_OUT: + case URLS_PASTE: + case FIND_NEXT: + case FIND_PREV: + case REPEAT_LAST: + return true; } return false; }; diff --git a/src/shared/settings/Blacklist.ts b/src/shared/settings/Blacklist.ts index 6c54d73..278dbd6 100644 --- a/src/shared/settings/Blacklist.ts +++ b/src/shared/settings/Blacklist.ts @@ -1,14 +1,16 @@ -import Key from './Key'; +import Key from "./Key"; -export type BlacklistItemJSON = string | { - url: string, - keys: string[], -}; +export type BlacklistItemJSON = + | string + | { + url: string; + keys: string[]; + }; export type BlacklistJSON = BlacklistItemJSON[]; const regexFromWildcard = (pattern: string): RegExp => { - const regexStr = '^' + pattern.replace(/\*/g, '.*') + '$'; + const regexStr = "^" + pattern.replace(/\*/g, ".*") + "$"; return new RegExp(regexStr); }; @@ -23,11 +25,7 @@ export class BlacklistItem { private readonly keyEntities: Key[]; - constructor( - pattern: string, - partial: boolean, - keys: string[] - ) { + constructor(pattern: string, partial: boolean, keys: string[]) { this.pattern = pattern; this.regex = regexFromWildcard(pattern); this.partial = partial; @@ -36,7 +34,7 @@ export class BlacklistItem { } static fromJSON(json: BlacklistItemJSON): BlacklistItem { - return typeof json === 'string' + return typeof json === "string" ? new BlacklistItem(json, false, []) : new BlacklistItem(json.url, true, json.keys); } @@ -49,7 +47,7 @@ export class BlacklistItem { } matches(url: URL): boolean { - return this.pattern.includes('/') + return this.pattern.includes("/") ? this.regex.test(url.host + url.pathname) : this.regex.test(url.host); } @@ -58,30 +56,27 @@ export class BlacklistItem { if (!this.matches(url) || !this.partial) { return false; } - return this.keyEntities.some(k => k.equals(key)); + return this.keyEntities.some((k) => k.equals(key)); } } export default class Blacklist { - constructor( - public readonly items: BlacklistItem[], - ) { - } + constructor(public readonly items: BlacklistItem[]) {} static fromJSON(json: BlacklistJSON): Blacklist { - const items = json.map(o => BlacklistItem.fromJSON(o)); + const items = json.map((o) => BlacklistItem.fromJSON(o)); return new Blacklist(items); } toJSON(): BlacklistJSON { - return this.items.map(item => item.toJSON()); + return this.items.map((item) => item.toJSON()); } includesEntireBlacklist(url: URL): boolean { - return this.items.some(item => !item.partial && item.matches(url)); + return this.items.some((item) => !item.partial && item.matches(url)); } includeKey(url: URL, key: Key) { - return this.items.some(item => item.includeKey(url, key)); + return this.items.some((item) => item.includeKey(url, key)); } } diff --git a/src/shared/settings/Key.ts b/src/shared/settings/Key.ts index 1464e57..2f47aff 100644 --- a/src/shared/settings/Key.ts +++ b/src/shared/settings/Key.ts @@ -1,4 +1,4 @@ -const digits = ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9']; +const digits = ["0", "1", "2", "3", "4", "5", "6", "7", "8", "9"]; export default class Key { public readonly key: string; @@ -32,10 +32,10 @@ export default class Key { } static fromMapKey(str: string): Key { - if (str.startsWith('<') && str.endsWith('>')) { + if (str.startsWith("<") && str.endsWith(">")) { const inner = str.slice(1, -1); - const shift = inner.includes('S-'); - let base = inner.slice(inner.lastIndexOf('-') + 1); + const shift = inner.includes("S-"); + let base = inner.slice(inner.lastIndexOf("-") + 1); if (shift && base.length === 1) { base = base.toUpperCase(); } else if (!shift && base.length === 1) { @@ -44,9 +44,9 @@ export default class Key { return new Key({ key: base, shift: shift, - ctrl: inner.includes('C-'), - alt: inner.includes('A-'), - meta: inner.includes('M-'), + ctrl: inner.includes("C-"), + alt: inner.includes("A-"), + meta: inner.includes("M-"), }); } @@ -64,10 +64,12 @@ export default class Key { } equals(key: Key) { - return this.key === key.key && + return ( + this.key === key.key && this.ctrl === key.ctrl && this.meta === key.meta && this.alt === key.alt && - this.shift === key.shift; + this.shift === key.shift + ); } } diff --git a/src/shared/settings/Keymaps.ts b/src/shared/settings/Keymaps.ts index 3880654..718427e 100644 --- a/src/shared/settings/Keymaps.ts +++ b/src/shared/settings/Keymaps.ts @@ -1,18 +1,17 @@ -import * as operations from '../operations'; +import * as operations from "../operations"; -type OperationJson = { - type: string -} | { - type: string; - [prop: string]: string | number | boolean; -}; +type OperationJson = + | { + type: string; + } + | { + type: string; + [prop: string]: string | number | boolean; + }; export type KeymapsJSON = { [key: string]: OperationJson }; export default class Keymaps { - constructor( - private readonly data: { [key: string]: operations.Operation }, - ) { - } + constructor(private readonly data: { [key: string]: operations.Operation }) {} static fromJSON(json: KeymapsJSON): Keymaps { const entries: { [key: string]: operations.Operation } = {}; diff --git a/src/shared/settings/Properties.ts b/src/shared/settings/Properties.ts index 27fb62e..cf10d61 100644 --- a/src/shared/settings/Properties.ts +++ b/src/shared/settings/Properties.ts @@ -1,4 +1,3 @@ - export type PropertiesJSON = { hintchars?: string; smoothscroll?: boolean; @@ -11,38 +10,40 @@ export type PropertyTypes = { complete: string; }; -type PropertyName = 'hintchars' | 'smoothscroll' | 'complete'; +type PropertyName = "hintchars" | "smoothscroll" | "complete"; type PropertyDef = { name: PropertyName; description: string; defaultValue: string | number | boolean; - type: 'string' | 'number' | 'boolean'; + type: "string" | "number" | "boolean"; }; const defs: PropertyDef[] = [ { - name: 'hintchars', - description: 'hint characters on follow mode', - defaultValue: 'abcdefghijklmnopqrstuvwxyz', - type: 'string', - }, { - name: 'smoothscroll', - description: 'smooth scroll', + name: "hintchars", + description: "hint characters on follow mode", + defaultValue: "abcdefghijklmnopqrstuvwxyz", + type: "string", + }, + { + name: "smoothscroll", + description: "smooth scroll", defaultValue: false, - type: 'boolean', - }, { - name: 'complete', - description: 'which are completed at the open page', - defaultValue: 'sbh', - type: 'string', - } + type: "boolean", + }, + { + name: "complete", + description: "which are completed at the open page", + defaultValue: "sbh", + type: "string", + }, ]; const defaultValues = { - hintchars: 'abcdefghijklmnopqrstuvwxyz', + hintchars: "abcdefghijklmnopqrstuvwxyz", smoothscroll: false, - complete: 'sbh', + complete: "sbh", }; export default class Properties { @@ -72,14 +73,14 @@ export default class Properties { static types(): PropertyTypes { return { - hintchars: 'string', - smoothscroll: 'boolean', - complete: 'string', + hintchars: "string", + smoothscroll: "boolean", + complete: "string", }; } static def(name: string): PropertyDef | undefined { - return defs.find(p => p.name === name); + return defs.find((p) => p.name === name); } static defs(): PropertyDef[] { diff --git a/src/shared/settings/Search.ts b/src/shared/settings/Search.ts index 7de03de..b25aa78 100644 --- a/src/shared/settings/Search.ts +++ b/src/shared/settings/Search.ts @@ -6,16 +6,12 @@ export type SearchJSON = { }; export default class Search { - constructor( - public defaultEngine: string, - public engines: Entries, - ) { - } + constructor(public defaultEngine: string, public engines: Entries) {} static fromJSON(json: SearchJSON): Search { for (const [name, url] of Object.entries(json.engines)) { - if (!(/^[a-zA-Z0-9]+$/).test(name)) { - throw new TypeError('Search engine\'s name must be [a-zA-Z0-9]+'); + if (!/^[a-zA-Z0-9]+$/.test(name)) { + throw new TypeError("Search engine's name must be [a-zA-Z0-9]+"); } const matches = url.match(/{}/g); if (matches === null) { diff --git a/src/shared/settings/Settings.ts b/src/shared/settings/Settings.ts index add5389..1bb9249 100644 --- a/src/shared/settings/Settings.ts +++ b/src/shared/settings/Settings.ts @@ -1,16 +1,16 @@ -import Ajv from 'ajv'; +import Ajv from "ajv"; -import Keymaps, { KeymapsJSON } from './Keymaps'; -import Search, { SearchJSON } from './Search'; -import Properties, { PropertiesJSON } from './Properties'; -import Blacklist, { BlacklistJSON } from './Blacklist'; -import validate from './validate'; +import Keymaps, { KeymapsJSON } from "./Keymaps"; +import Search, { SearchJSON } from "./Search"; +import Properties, { PropertiesJSON } from "./Properties"; +import Blacklist, { BlacklistJSON } from "./Blacklist"; +import validate from "./validate"; export type SettingsJSON = { - keymaps?: KeymapsJSON, - search?: SearchJSON, - properties?: PropertiesJSON, - blacklist?: BlacklistJSON, + keymaps?: KeymapsJSON; + search?: SearchJSON; + properties?: PropertiesJSON; + blacklist?: BlacklistJSON; }; export default class Settings { @@ -42,11 +42,11 @@ export default class Settings { static fromJSON(json: unknown): Settings { const valid = validate(json); if (!valid) { - const message = (validate as any).errors!! - .map((err: Ajv.ErrorObject) => { + const message = (validate as any) + .errors!!.map((err: Ajv.ErrorObject) => { return `'${err.dataPath}' ${err.message}`; }) - .join('; '); + .join("; "); throw new TypeError(message); } @@ -162,5 +162,6 @@ export const DefaultSettingJSONText = `{ ] }`; -export const DefaultSetting: Settings = - Settings.fromJSON(JSON.parse(DefaultSettingJSONText)); +export const DefaultSetting: Settings = Settings.fromJSON( + JSON.parse(DefaultSettingJSONText) +); diff --git a/src/shared/urls.ts b/src/shared/urls.ts index bac929e..2bfa44b 100644 --- a/src/shared/urls.ts +++ b/src/shared/urls.ts @@ -1,28 +1,28 @@ -import Search from './settings/Search'; +import Search from "./settings/Search"; const trimStart = (str: string): string => { // NOTE String.trimStart is available on Firefox 61 - return str.replace(/^\s+/, ''); + return str.replace(/^\s+/, ""); }; -const SUPPORTED_PROTOCOLS = ['http:', 'https:', 'ftp:', 'mailto:', 'about:']; +const SUPPORTED_PROTOCOLS = ["http:", "https:", "ftp:", "mailto:", "about:"]; const isLocalhost = (url: string): boolean => { - if (url === 'localhost') { + if (url === "localhost") { return true; } - const [host, port] = url.split(':', 2); - return host === 'localhost' && !isNaN(Number(port)); + const [host, port] = url.split(":", 2); + return host === "localhost" && !isNaN(Number(port)); }; const isMissingHttp = (keywords: string): boolean => { - if (keywords.includes('.') && !keywords.includes(' ')) { + if (keywords.includes(".") && !keywords.includes(" ")) { return true; } try { - const u = new URL('http://' + keywords); + const u = new URL("http://" + keywords); return isLocalhost(u.host); } catch (e) { // fallthrough @@ -41,18 +41,18 @@ const searchUrl = (keywords: string, search: Search): string => { } if (isMissingHttp(keywords)) { - return 'http://' + keywords; + return "http://" + keywords; } let template = search.engines[search.defaultEngine]; let query = keywords; - const first = trimStart(keywords).split(' ')[0]; + const first = trimStart(keywords).split(" ")[0]; if (Object.keys(search.engines).includes(first)) { template = search.engines[first]; query = trimStart(trimStart(keywords).slice(first.length)); } - return template.replace('{}', encodeURIComponent(query)); + return template.replace("{}", encodeURIComponent(query)); }; const normalizeUrl = (url: string): string => { @@ -64,7 +64,7 @@ const normalizeUrl = (url: string): string => { } catch (e) { // fallthrough } - return 'http://' + url; + return "http://" + url; }; export { searchUrl, normalizeUrl }; diff --git a/src/shared/utils/dom.ts b/src/shared/utils/dom.ts index a6186cb..0cf2ee8 100644 --- a/src/shared/utils/dom.ts +++ b/src/shared/utils/dom.ts @@ -1,9 +1,9 @@ const isContentEditable = (element: Element): boolean => { - const value = element.getAttribute('contenteditable'); + const value = element.getAttribute("contenteditable"); if (value === null) { return false; } - return value.toLowerCase() === 'true' || value.toLowerCase() === ''; + return value.toLowerCase() === "true" || value.toLowerCase() === ""; }; interface Rect { @@ -14,12 +14,12 @@ interface Rect { } const rectangleCoordsRect = (coords: string): Rect => { - const [left, top, right, bottom] = coords.split(',').map(n => Number(n)); + const [left, top, right, bottom] = coords.split(",").map((n) => Number(n)); return { left, top, right, bottom }; }; const circleCoordsRect = (coords: string): Rect => { - const [x, y, r] = coords.split(',').map(n => Number(n)); + const [x, y, r] = coords.split(",").map((n) => Number(n)); return { left: x - r, top: y - r, @@ -29,7 +29,7 @@ const circleCoordsRect = (coords: string): Rect => { }; const polygonCoordsRect = (coords: string): Rect => { - const params = coords.split(','); + const params = coords.split(","); let minx = Number(params[0]), maxx = Number(params[0]), miny = Number(params[1]), @@ -55,7 +55,7 @@ const polygonCoordsRect = (coords: string): Rect => { }; const viewportRect = (e: Element): Rect => { - if (e.tagName !== 'AREA') { + if (e.tagName !== "AREA") { return e.getBoundingClientRect(); } @@ -63,29 +63,26 @@ const viewportRect = (e: Element): Rect => { const imgElement = document.querySelector( `img[usemap="#${mapElement.name}"]` ) as HTMLImageElement; - const { - left: mapLeft, - top: mapTop - } = imgElement.getBoundingClientRect(); - const coords = e.getAttribute('coords'); + const { left: mapLeft, top: mapTop } = imgElement.getBoundingClientRect(); + const coords = e.getAttribute("coords"); if (!coords) { return e.getBoundingClientRect(); } let rect = { left: 0, top: 0, right: 0, bottom: 0 }; - switch (e.getAttribute('shape')) { - case 'rect': - case 'rectangle': - rect = rectangleCoordsRect(coords); - break; - case 'circ': - case 'circle': - rect = circleCoordsRect(coords); - break; - case 'poly': - case 'polygon': - rect = polygonCoordsRect(coords); - break; + switch (e.getAttribute("shape")) { + case "rect": + case "rectangle": + rect = rectangleCoordsRect(coords); + break; + case "circ": + case "circle": + rect = circleCoordsRect(coords); + break; + case "poly": + case "polygon": + rect = polygonCoordsRect(coords); + break; } return { left: rect.left + mapLeft, @@ -99,7 +96,7 @@ const isVisible = (element: Element): boolean => { const rect = element.getBoundingClientRect(); const style = window.getComputedStyle(element); - if (style.overflow !== 'visible' && (rect.width === 0 || rect.height === 0)) { + if (style.overflow !== "visible" && (rect.width === 0 || rect.height === 0)) { return false; } if (rect.right < 0 && rect.bottom < 0) { @@ -108,13 +105,15 @@ const isVisible = (element: Element): boolean => { if (window.innerWidth < rect.left && window.innerHeight < rect.top) { return false; } - if (element instanceof HTMLInputElement && - element.type.toLowerCase() === 'hidden') { + if ( + element instanceof HTMLInputElement && + element.type.toLowerCase() === "hidden" + ) { return false; } const { display, visibility } = window.getComputedStyle(element); - if (display === 'none' || visibility === 'hidden') { + if (display === "none" || visibility === "hidden") { return false; } return true; |