diff --git a/src/background/controllers/OperationController.js b/src/background/controllers/OperationController.js index 609599e..416aa9c 100644 --- a/src/background/controllers/OperationController.js +++ b/src/background/controllers/OperationController.js @@ -1,68 +1,76 @@ import operations from '../../shared/operations'; -import OperationUseCase from '../usecases/OperationUseCase'; +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'; export default class OperationController { constructor() { - this.operationUseCase = new OperationUseCase(); + this.findUseCase = new FindUseCase(); + this.consoleUseCase = new ConsoleUseCase(); + this.tabUseCase = new TabUseCase(); + this.tabSelectUseCase = new TabSelectUseCase(); + this.zoomUseCase = new ZoomUseCase(); } // eslint-disable-next-line complexity, max-lines-per-function exec(operation) { switch (operation.type) { case operations.TAB_CLOSE: - return this.operationUseCase.close(false); + return this.tabUseCase.close(false); case operations.TAB_CLOSE_RIGHT: - return this.operationUseCase.closeRight(); + return this.tabUseCase.closeRight(); case operations.TAB_CLOSE_FORCE: - return this.operationUseCase.close(true); + return this.tabUseCase.close(true); case operations.TAB_REOPEN: - return this.operationUseCase.reopen(); + return this.tabUseCase.reopen(); case operations.TAB_PREV: - return this.operationUseCase.selectPrev(1); + return this.tabSelectUseCase.selectPrev(1); case operations.TAB_NEXT: - return this.operationUseCase.selectNext(1); + return this.tabSelectUseCase.selectNext(1); case operations.TAB_FIRST: - return this.operationUseCase.selectFirst(); + return this.tabSelectUseCase.selectFirst(); case operations.TAB_LAST: - return this.operationUseCase.selectLast(); + return this.tabSelectUseCase.selectLast(); case operations.TAB_PREV_SEL: - return this.operationUseCase.selectPrevSelected(); + return this.tabSelectUseCase.selectPrevSelected(); case operations.TAB_RELOAD: - return this.operationUseCase.reload(operation.cache); + return this.tabUseCase.reload(operation.cache); case operations.TAB_PIN: - return this.operationUseCase.setPinned(true); + return this.tabUseCase.setPinned(true); case operations.TAB_UNPIN: - return this.operationUseCase.setPinned(false); + return this.tabUseCase.setPinned(false); case operations.TAB_TOGGLE_PINNED: - return this.operationUseCase.togglePinned(); + return this.tabUseCase.togglePinned(); case operations.TAB_DUPLICATE: - return this.operationUseCase.duplicate(); + return this.tabUseCase.duplicate(); case operations.PAGE_SOURCE: - return this.operationUseCase.openPageSource(); + return this.tabUseCase.openPageSource(); case operations.PAGE_HOME: - return this.operationUseCase.openHome(operation.newTab); + return this.tabUseCase.openHome(operation.newTab); case operations.ZOOM_IN: - return this.operationUseCase.zoomIn(); + return this.zoomUseCase.zoomIn(); case operations.ZOOM_OUT: - return this.operationUseCase.zoomOut(); + return this.zoomUseCase.zoomOut(); case operations.ZOOM_NEUTRAL: - return this.operationUseCase.zoomNutoral(); + return this.zoomUseCase.zoomNutoral(); case operations.COMMAND_SHOW: - return this.operationUseCase.showCommand(); + return this.consoleUseCase.showCommand(); case operations.COMMAND_SHOW_OPEN: - return this.operationUseCase.showOpenCommand(operation.alter); + return this.consoleUseCase.showOpenCommand(operation.alter); case operations.COMMAND_SHOW_TABOPEN: - return this.operationUseCase.showTabopenCommand(operation.alter); + return this.consoleUseCase.showTabopenCommand(operation.alter); case operations.COMMAND_SHOW_WINOPEN: - return this.operationUseCase.showWinopenCommand(operation.alter); + return this.consoleUseCase.showWinopenCommand(operation.alter); case operations.COMMAND_SHOW_BUFFER: - return this.operationUseCase.showBufferCommand(); + return this.consoleUseCase.showBufferCommand(); case operations.COMMAND_SHOW_ADDBOOKMARK: - return this.operationUseCase.showAddbookmarkCommand(operation.alter); + return this.consoleUseCase.showAddbookmarkCommand(operation.alter); case operations.FIND_START: - return this.operationUseCase.findStart(); + return this.findUseCase.findStart(); case operations.CANCEL: - return this.operationUseCase.hideConsole(); + return this.consoleUseCase.hideConsole(); } } } diff --git a/src/background/repositories/BrowserSettingRepository.js b/src/background/repositories/BrowserSettingRepository.js new file mode 100644 index 0000000..a9d2c06 --- /dev/null +++ b/src/background/repositories/BrowserSettingRepository.js @@ -0,0 +1,8 @@ +import * as urls from '../../shared/urls'; + +export default class BrowserSettingRepository { + async getHomepageUrls() { + let { value } = await browser.browserSettings.homepageOverride.get({}); + return value.split('|').map(urls.normalizeUrl); + } +} diff --git a/src/background/usecases/ConsoleUseCase.js b/src/background/usecases/ConsoleUseCase.js new file mode 100644 index 0000000..e8e5d4a --- /dev/null +++ b/src/background/usecases/ConsoleUseCase.js @@ -0,0 +1,61 @@ +import TabPresenter from '../presenters/TabPresenter'; +import ConsoleClient from '../infrastructures/ConsoleClient'; + +export default class ConsoleUseCase { + constructor() { + this.tabPresenter = new TabPresenter(); + this.consoleClient = new ConsoleClient(); + } + + async showCommand() { + let tab = await this.tabPresenter.getCurrent(); + return this.consoleClient.showCommand(tab.id, ''); + } + + async showOpenCommand(alter) { + let tab = await this.tabPresenter.getCurrent(); + let command = 'open '; + if (alter) { + command += tab.url; + } + return this.consoleClient.showCommand(tab.id, command); + } + + async showTabopenCommand(alter) { + let tab = await this.tabPresenter.getCurrent(); + let command = 'tabopen '; + if (alter) { + command += tab.url; + } + return this.consoleClient.showCommand(tab.id, command); + } + + async showWinopenCommand(alter) { + let tab = await this.tabPresenter.getCurrent(); + let command = 'winopen '; + if (alter) { + command += tab.url; + } + return this.consoleClient.showCommand(tab.id, command); + } + + async showBufferCommand() { + let tab = await this.tabPresenter.getCurrent(); + let command = 'buffer '; + return this.consoleClient.showCommand(tab.id, command); + } + + async showAddbookmarkCommand(alter) { + let tab = await this.tabPresenter.getCurrent(); + let command = 'addbookmark '; + if (alter) { + command += tab.title; + } + return this.consoleClient.showCommand(tab.id, command); + } + + async hideConsole() { + let tab = await this.tabPresenter.getCurrent(); + return this.consoleClient.hide(tab.id); + } +} diff --git a/src/background/usecases/FindUseCase.js b/src/background/usecases/FindUseCase.js index d6b0323..224e4a9 100644 --- a/src/background/usecases/FindUseCase.js +++ b/src/background/usecases/FindUseCase.js @@ -1,8 +1,12 @@ import FindRepository from '../repositories/FindRepository'; +import TabPresenter from '../presenters/TabPresenter'; +import ConsoleClient from '../infrastructures/ConsoleClient'; export default class FindUseCase { constructor() { + this.tabPresenter = new TabPresenter(); this.findRepository = new FindRepository(); + this.consoleClient = new ConsoleClient(); } getKeyword() { @@ -12,4 +16,9 @@ export default class FindUseCase { setKeyword(keyword) { return this.findRepository.setKeyword(keyword); } + + async findStart() { + let tab = await this.tabPresenter.getCurrent(); + return this.consoleClient.showFind(tab.id); + } } diff --git a/src/background/usecases/OperationUseCase.js b/src/background/usecases/OperationUseCase.js deleted file mode 100644 index 1d75d1a..0000000 --- a/src/background/usecases/OperationUseCase.js +++ /dev/null @@ -1,208 +0,0 @@ -import TabPresenter from '../presenters/TabPresenter'; -import ConsoleClient from '../infrastructures/ConsoleClient'; -import * as urls from '../../shared/urls'; - -const ZOOM_SETTINGS = [ - 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 -]; - -export default class OperationUseCase { - constructor() { - this.tabPresenter = new TabPresenter(); - this.consoleClient = new ConsoleClient(); - } - - async close(force) { - let tab = await this.tabPresenter.getCurrent(); - if (!force && tab.pinned) { - return; - } - return this.tabPresenter.remove([tab.id]); - } - - async closeRight() { - let tabs = await this.tabPresenter.getAll(); - tabs.sort((t1, t2) => t1.index - t2.index); - let index = tabs.findIndex(t => t.active); - if (index < 0) { - return; - } - for (let i = index + 1; i < tabs.length; ++i) { - let tab = tabs[i]; - if (!tab.pinned) { - this.tabPresenter.remove(tab.id); - } - } - } - - reopen() { - return this.tabPresenter.reopen(); - } - - async selectPrev(count) { - let tabs = await this.tabPresenter.getAll(); - if (tabs.length < 2) { - return; - } - let tab = tabs.find(t => t.active); - if (!tab) { - return; - } - let select = (tab.index - count + tabs.length) % tabs.length; - return this.tabPresenter.select(tabs[select].id); - } - - async selectNext(count) { - let tabs = await this.tabPresenter.getAll(); - if (tabs.length < 2) { - return; - } - let tab = tabs.find(t => t.active); - if (!tab) { - return; - } - let select = (tab.index + count) % tabs.length; - return this.tabPresenter.select(tabs[select].id); - } - - async selectFirst() { - let tabs = await this.tabPresenter.getAll(); - return this.tabPresenter.select(tabs[0].id); - } - - async selectLast() { - let tabs = await this.tabPresenter.getAll(); - return this.tabPresenter.select(tabs[tabs.length - 1].id); - } - - async selectPrevSelected() { - let tabId = await this.tabPresenter.getLastSelectedId(); - if (tabId === null || typeof tabId === 'undefined') { - return; - } - this.tabPresenter.select(tabId); - } - - async reload(cache) { - let tab = await this.tabPresenter.getCurrent(); - return this.tabPresenter.reload(tab.id, cache); - } - - async setPinned(pinned) { - let tab = await this.tabPresenter.getCurrent(); - return this.tabPresenter.setPinned(tab.id, pinned); - } - - async togglePinned() { - let tab = await this.tabPresenter.getCurrent(); - return this.tabPresenter.setPinned(tab.id, !tab.pinned); - } - - async duplicate() { - let tab = await this.tabPresenter.getCurrent(); - return this.tabPresenter.duplicate(tab.id); - } - - async openPageSource() { - let tab = await this.tabPresenter.getCurrent(); - let url = 'view-source:' + tab.url; - return this.tabPresenter.create(url); - } - - async zoomIn(tabId) { - let tab = await this.tabPresenter.getCurrent(); - let current = await this.tabPresenter.getZoom(tab.id); - let factor = ZOOM_SETTINGS.find(f => f > current); - if (factor) { - return this.tabPresenter.setZoom(tabId, factor); - } - } - - async zoomOut(tabId) { - let tab = await this.tabPresenter.getCurrent(); - let current = await this.tabPresenter.getZoom(tab.id); - let factor = [].concat(ZOOM_SETTINGS).reverse().find(f => f < current); - if (factor) { - return this.tabPresenter.setZoom(tabId, factor); - } - } - - zoomNutoral(tabId) { - return this.tabPresenter.setZoom(tabId, 1); - } - - async showCommand() { - let tab = await this.tabPresenter.getCurrent(); - return this.consoleClient.showCommand(tab.id, ''); - } - - async showOpenCommand(alter) { - let tab = await this.tabPresenter.getCurrent(); - let command = 'open '; - if (alter) { - command += tab.url; - } - return this.consoleClient.showCommand(tab.id, command); - } - - async showTabopenCommand(alter) { - let tab = await this.tabPresenter.getCurrent(); - let command = 'tabopen '; - if (alter) { - command += tab.url; - } - return this.consoleClient.showCommand(tab.id, command); - } - - async showWinopenCommand(alter) { - let tab = await this.tabPresenter.getCurrent(); - let command = 'winopen '; - if (alter) { - command += tab.url; - } - return this.consoleClient.showCommand(tab.id, command); - } - - async showBufferCommand() { - let tab = await this.tabPresenter.getCurrent(); - let command = 'buffer '; - return this.consoleClient.showCommand(tab.id, command); - } - - async showAddbookmarkCommand(alter) { - let tab = await this.tabPresenter.getCurrent(); - let command = 'addbookmark '; - if (alter) { - command += tab.title; - } - return this.consoleClient.showCommand(tab.id, command); - } - - async findStart() { - let tab = await this.tabPresenter.getCurrent(); - return this.consoleClient.showFind(tab.id); - } - - async hideConsole() { - let tab = await this.tabPresenter.getCurrent(); - return this.consoleClient.hide(tab.id); - } - - async openHome(newTab) { - let tab = await this.tabPresenter.getCurrent(); - let result = await browser.browserSettings.homepageOverride.get({}); - let us = urls.homepageUrls(result.value); - if (us.length === 1 && us[0] === 'about:home') { - // eslint-disable-next-line max-len - throw new Error('Cannot open Firefox Home (about:home) by WebExtensions, set your custom URLs'); - } - if (us.length === 1 && !newTab) { - return this.tabPresenter.open(us[0], tab.id); - } - for (let u of us) { - this.tabPresenter.create(u); - } - } -} - diff --git a/src/background/usecases/TabSelectUseCase.js b/src/background/usecases/TabSelectUseCase.js new file mode 100644 index 0000000..16b3e14 --- /dev/null +++ b/src/background/usecases/TabSelectUseCase.js @@ -0,0 +1,51 @@ +import TabPresenter from '../presenters/TabPresenter'; + +export default class TabSelectUseCase { + constructor() { + this.tabPresenter = new TabPresenter(); + } + + async selectPrev(count) { + let tabs = await this.tabPresenter.getAll(); + if (tabs.length < 2) { + return; + } + let tab = tabs.find(t => t.active); + if (!tab) { + return; + } + let select = (tab.index - count + tabs.length) % tabs.length; + return this.tabPresenter.select(tabs[select].id); + } + + async selectNext(count) { + let tabs = await this.tabPresenter.getAll(); + if (tabs.length < 2) { + return; + } + let tab = tabs.find(t => t.active); + if (!tab) { + return; + } + let select = (tab.index + count) % tabs.length; + return this.tabPresenter.select(tabs[select].id); + } + + async selectFirst() { + let tabs = await this.tabPresenter.getAll(); + return this.tabPresenter.select(tabs[0].id); + } + + async selectLast() { + let tabs = await this.tabPresenter.getAll(); + return this.tabPresenter.select(tabs[tabs.length - 1].id); + } + + async selectPrevSelected() { + let tabId = await this.tabPresenter.getLastSelectedId(); + if (tabId === null || typeof tabId === 'undefined') { + return; + } + this.tabPresenter.select(tabId); + } +} diff --git a/src/background/usecases/TabUseCase.js b/src/background/usecases/TabUseCase.js new file mode 100644 index 0000000..d930842 --- /dev/null +++ b/src/background/usecases/TabUseCase.js @@ -0,0 +1,77 @@ +import TabPresenter from '../presenters/TabPresenter'; +import BrowserSettingRepository from '../repositories/BrowserSettingRepository'; + +export default class TabUseCase { + constructor() { + this.tabPresenter = new TabPresenter(); + this.browserSettingRepository = new BrowserSettingRepository(); + } + + async close(force) { + let tab = await this.tabPresenter.getCurrent(); + if (!force && tab.pinned) { + return; + } + return this.tabPresenter.remove([tab.id]); + } + + async closeRight() { + let tabs = await this.tabPresenter.getAll(); + tabs.sort((t1, t2) => t1.index - t2.index); + let index = tabs.findIndex(t => t.active); + if (index < 0) { + return; + } + for (let i = index + 1; i < tabs.length; ++i) { + let tab = tabs[i]; + if (!tab.pinned) { + this.tabPresenter.remove(tab.id); + } + } + } + + reopen() { + return this.tabPresenter.reopen(); + } + + async reload(cache) { + let tab = await this.tabPresenter.getCurrent(); + return this.tabPresenter.reload(tab.id, cache); + } + + async setPinned(pinned) { + let tab = await this.tabPresenter.getCurrent(); + return this.tabPresenter.setPinned(tab.id, pinned); + } + + async togglePinned() { + let tab = await this.tabPresenter.getCurrent(); + return this.tabPresenter.setPinned(tab.id, !tab.pinned); + } + + async duplicate() { + let tab = await this.tabPresenter.getCurrent(); + return this.tabPresenter.duplicate(tab.id); + } + + async openPageSource() { + let tab = await this.tabPresenter.getCurrent(); + let url = 'view-source:' + tab.url; + return this.tabPresenter.create(url); + } + + async openHome(newTab) { + let tab = await this.tabPresenter.getCurrent(); + let urls = await this.browserSettingRepository.getHomepageUrls(); + 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'); + } + if (urls.length === 1 && !newTab) { + return this.tabPresenter.open(urls[0], tab.id); + } + for (let url of urls) { + this.tabPresenter.create(url); + } + } +} diff --git a/src/background/usecases/ZoomUseCase.js b/src/background/usecases/ZoomUseCase.js new file mode 100644 index 0000000..692d6d9 --- /dev/null +++ b/src/background/usecases/ZoomUseCase.js @@ -0,0 +1,35 @@ +import TabPresenter from '../presenters/TabPresenter'; + +const ZOOM_SETTINGS = [ + 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 +]; + +export default class ZoomUseCase { + constructor() { + this.tabPresenter = new TabPresenter(); + } + + async zoomIn(tabId) { + let tab = await this.tabPresenter.getCurrent(); + let current = await this.tabPresenter.getZoom(tab.id); + let factor = ZOOM_SETTINGS.find(f => f > current); + if (factor) { + return this.tabPresenter.setZoom(tabId, factor); + } + } + + async zoomOut(tabId) { + let tab = await this.tabPresenter.getCurrent(); + let current = await this.tabPresenter.getZoom(tab.id); + let factor = [].concat(ZOOM_SETTINGS).reverse().find(f => f < current); + if (factor) { + return this.tabPresenter.setZoom(tabId, factor); + } + } + + zoomNutoral(tabId) { + return this.tabPresenter.setZoom(tabId, 1); + } + +} diff --git a/src/shared/urls.js b/src/shared/urls.js index f7e917d..94b1220 100644 --- a/src/shared/urls.js +++ b/src/shared/urls.js @@ -40,8 +40,4 @@ const normalizeUrl = (url) => { return 'http://' + url; }; -const homepageUrls = (value) => { - return value.split('|').map(normalizeUrl); -}; - -export { searchUrl, normalizeUrl, homepageUrls }; +export { searchUrl, normalizeUrl }; diff --git a/test/shared/urls.test.js b/test/shared/urls.test.js index f004b3d..f2950b6 100644 --- a/test/shared/urls.test.js +++ b/test/shared/urls.test.js @@ -44,14 +44,5 @@ describe("shared/commands/parsers", () => { .to.equal('http://google.com'); }); }); - - describe('#homepageUrls', () => { - it('split urls', () => { - expect(parsers.homepageUrls('https://google.com/')) - .to.deep.equal(['https://google.com/']); - expect(parsers.homepageUrls('yahoo.com|https://i-beam.org/')) - .to.deep.equal(['http://yahoo.com', 'https://i-beam.org/']); - }); - }); });