aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/content/actions/operation.ts12
-rw-r--r--src/content/client/TabsClient.ts18
-rw-r--r--src/content/repositories/ClipboardRepository.ts46
-rw-r--r--src/content/urls.ts41
-rw-r--r--src/content/usecases/ClipboardUseCase.ts44
-rw-r--r--src/shared/urls.ts10
-rw-r--r--test/content/usecases/ClipboardUseCase.test.ts76
7 files changed, 195 insertions, 52 deletions
diff --git a/src/content/actions/operation.ts b/src/content/actions/operation.ts
index b264e36..28192d7 100644
--- a/src/content/actions/operation.ts
+++ b/src/content/actions/operation.ts
@@ -3,15 +3,15 @@ import * as actions from './index';
import * as messages from '../../shared/messages';
import * as navigates from '../navigates';
import * as focuses from '../focuses';
-import * as urls from '../urls';
-import * as consoleFrames from '../console-frames';
import * as markActions from './mark';
import AddonEnabledUseCase from '../usecases/AddonEnabledUseCase';
+import ClipboardUseCase from '../usecases/ClipboardUseCase';
import { SettingRepositoryImpl } from '../repositories/SettingRepository';
import { ScrollPresenterImpl } from '../presenters/ScrollPresenter';
let addonEnabledUseCase = new AddonEnabledUseCase();
+let clipbaordUseCase = new ClipboardUseCase();
let settingRepository = new SettingRepositoryImpl();
let scrollPresenter = new ScrollPresenterImpl();
@@ -95,13 +95,11 @@ const exec = async(
focuses.focusInput();
break;
case operations.URLS_YANK:
- urls.yank(window);
- consoleFrames.postInfo('Yanked ' + window.location.href);
+ await clipbaordUseCase.yankCurrentURL();
break;
case operations.URLS_PASTE:
- urls.paste(
- window, operation.newTab ? operation.newTab : false,
- settings.search,
+ await clipbaordUseCase.openOrSearch(
+ operation.newTab ? operation.newTab : false,
);
break;
default:
diff --git a/src/content/client/TabsClient.ts b/src/content/client/TabsClient.ts
new file mode 100644
index 0000000..fe72e11
--- /dev/null
+++ b/src/content/client/TabsClient.ts
@@ -0,0 +1,18 @@
+import * as messages from '../../shared/messages';
+
+export default interface TabsClient {
+ openUrl(url: string, newTab: boolean): Promise<void>;
+
+ // eslint-disable-next-line semi
+}
+
+export class TabsClientImpl {
+ async openUrl(url: string, newTab: boolean): Promise<void> {
+ await browser.runtime.sendMessage({
+ type: messages.OPEN_URL,
+ url,
+ newTab,
+ });
+ }
+}
+
diff --git a/src/content/repositories/ClipboardRepository.ts b/src/content/repositories/ClipboardRepository.ts
new file mode 100644
index 0000000..747ae6a
--- /dev/null
+++ b/src/content/repositories/ClipboardRepository.ts
@@ -0,0 +1,46 @@
+export default interface ClipboardRepository {
+ read(): string;
+
+ write(text: string): void;
+
+ // eslint-disable-next-line semi
+}
+
+export class ClipboardRepositoryImpl {
+ read(): string {
+ let textarea = window.document.createElement('textarea');
+ window.document.body.append(textarea);
+
+ textarea.style.position = 'fixed';
+ textarea.style.top = '-100px';
+ textarea.contentEditable = 'true';
+ textarea.focus();
+
+ let ok = window.document.execCommand('paste');
+ let value = textarea.textContent!!;
+ textarea.remove();
+
+ if (!ok) {
+ throw new Error('failed to access clipbaord');
+ }
+
+ return value;
+ }
+
+ write(text: string): void {
+ let input = window.document.createElement('input');
+ window.document.body.append(input);
+
+ input.style.position = 'fixed';
+ input.style.top = '-100px';
+ input.value = text;
+ input.select();
+
+ let ok = window.document.execCommand('copy');
+ input.remove();
+
+ if (!ok) {
+ throw new Error('failed to access clipbaord');
+ }
+ }
+}
diff --git a/src/content/urls.ts b/src/content/urls.ts
deleted file mode 100644
index 035b9bb..0000000
--- a/src/content/urls.ts
+++ /dev/null
@@ -1,41 +0,0 @@
-import * as messages from '../shared/messages';
-import * as urls from '../shared/urls';
-import { Search } from '../shared/Settings';
-
-const yank = (win: Window) => {
- let input = win.document.createElement('input');
- win.document.body.append(input);
-
- input.style.position = 'fixed';
- input.style.top = '-100px';
- input.value = win.location.href;
- input.select();
-
- win.document.execCommand('copy');
-
- input.remove();
-};
-
-const paste = (win: Window, newTab: boolean, search: Search) => {
- let textarea = win.document.createElement('textarea');
- win.document.body.append(textarea);
-
- textarea.style.position = 'fixed';
- textarea.style.top = '-100px';
- textarea.contentEditable = 'true';
- textarea.focus();
-
- if (win.document.execCommand('paste')) {
- let value = textarea.textContent as string;
- let url = urls.searchUrl(value, search);
- browser.runtime.sendMessage({
- type: messages.OPEN_URL,
- url,
- newTab,
- });
- }
-
- textarea.remove();
-};
-
-export { yank, paste };
diff --git a/src/content/usecases/ClipboardUseCase.ts b/src/content/usecases/ClipboardUseCase.ts
new file mode 100644
index 0000000..b2ece2f
--- /dev/null
+++ b/src/content/usecases/ClipboardUseCase.ts
@@ -0,0 +1,44 @@
+import * as urls from '../../shared/urls';
+import ClipboardRepository, { ClipboardRepositoryImpl }
+ from '../repositories/ClipboardRepository';
+import SettingRepository, { SettingRepositoryImpl }
+ from '../repositories/SettingRepository';
+import TabsClient, { TabsClientImpl }
+ from '../client/TabsClient';
+import ConsoleClient, { ConsoleClientImpl } from '../client/ConsoleClient';
+
+export default class ClipboardUseCase {
+ private repository: ClipboardRepository;
+
+ private settingRepository: SettingRepository;
+
+ private client: TabsClient;
+
+ private consoleClient: ConsoleClient;
+
+ constructor({
+ repository = new ClipboardRepositoryImpl(),
+ settingRepository = new SettingRepositoryImpl(),
+ client = new TabsClientImpl(),
+ consoleClient = new ConsoleClientImpl(),
+ } = {}) {
+ this.repository = repository;
+ this.settingRepository = settingRepository;
+ this.client = client;
+ this.consoleClient = consoleClient;
+ }
+
+ async yankCurrentURL(): Promise<string> {
+ let url = window.location.href;
+ this.repository.write(url);
+ await this.consoleClient.info('Yanked ' + url);
+ return Promise.resolve(url);
+ }
+
+ async openOrSearch(newTab: boolean): Promise<void> {
+ let search = this.settingRepository.get().search;
+ let text = this.repository.read();
+ let url = urls.searchUrl(text, search);
+ await this.client.openUrl(url, newTab);
+ }
+}
diff --git a/src/shared/urls.ts b/src/shared/urls.ts
index 18349c8..bbdb1ea 100644
--- a/src/shared/urls.ts
+++ b/src/shared/urls.ts
@@ -1,3 +1,5 @@
+import { Search } from './Settings';
+
const trimStart = (str: string): string => {
// NOTE String.trimStart is available on Firefox 61
return str.replace(/^\s+/, '');
@@ -5,7 +7,7 @@ const trimStart = (str: string): string => {
const SUPPORTED_PROTOCOLS = ['http:', 'https:', 'ftp:', 'mailto:', 'about:'];
-const searchUrl = (keywords: string, searchSettings: any): string => {
+const searchUrl = (keywords: string, search: Search): string => {
try {
let u = new URL(keywords);
if (SUPPORTED_PROTOCOLS.includes(u.protocol.toLowerCase())) {
@@ -17,12 +19,12 @@ const searchUrl = (keywords: string, searchSettings: any): string => {
if (keywords.includes('.') && !keywords.includes(' ')) {
return 'http://' + keywords;
}
- let template = searchSettings.engines[searchSettings.default];
+ let template = search.engines[search.default];
let query = keywords;
let first = trimStart(keywords).split(' ')[0];
- if (Object.keys(searchSettings.engines).includes(first)) {
- template = searchSettings.engines[first];
+ if (Object.keys(search.engines).includes(first)) {
+ template = search.engines[first];
query = trimStart(trimStart(keywords).slice(first.length));
}
return template.replace('{}', encodeURIComponent(query));
diff --git a/test/content/usecases/ClipboardUseCase.test.ts b/test/content/usecases/ClipboardUseCase.test.ts
new file mode 100644
index 0000000..862ee8a
--- /dev/null
+++ b/test/content/usecases/ClipboardUseCase.test.ts
@@ -0,0 +1,76 @@
+import ClipboardRepository from '../../../src/content/repositories/ClipboardRepository';
+import TabsClient from '../../../src/content/client/TabsClient';
+import MockConsoleClient from '../mock/MockConsoleClient';
+import ClipboardUseCase from '../../../src/content/usecases/ClipboardUseCase';
+import { expect } from 'chai';
+
+class MockClipboardRepository implements ClipboardRepository {
+ public clipboard: string;
+
+ constructor() {
+ this.clipboard = '';
+ }
+
+ read(): string {
+ return this.clipboard;
+ }
+
+ write(text: string): void {
+ this.clipboard = text;
+ }
+}
+
+class MockTabsClient implements TabsClient {
+ public last: string;
+
+ constructor() {
+ this.last = '';
+ }
+
+ openUrl(url: string, _newTab: boolean): Promise<void> {
+ this.last = url;
+ return Promise.resolve();
+ }
+}
+
+describe('ClipboardUseCase', () => {
+ let repository: MockClipboardRepository;
+ let client: MockTabsClient;
+ let consoleClient: MockConsoleClient;
+ let sut: ClipboardUseCase;
+
+ beforeEach(() => {
+ repository = new MockClipboardRepository();
+ client = new MockTabsClient();
+ consoleClient = new MockConsoleClient();
+ sut = new ClipboardUseCase({ repository, client: client, consoleClient });
+ });
+
+ describe('#yankCurrentURL', () => {
+ it('yanks current url', async () => {
+ let yanked = await sut.yankCurrentURL();
+
+ expect(yanked).to.equal(window.location.href);
+ expect(repository.clipboard).to.equal(yanked);
+ expect(consoleClient.text).to.equal('Yanked ' + yanked);
+ });
+ });
+
+ describe('#openOrSearch', () => {
+ it('opens url from the clipboard', async () => {
+ let url = 'https://github.com/ueokande/vim-vixen'
+ repository.clipboard = url;
+ await sut.openOrSearch(true);
+
+ expect(client.last).to.equal(url);
+ });
+
+ it('opens search results from the clipboard', async () => {
+ repository.clipboard = 'banana';
+ await sut.openOrSearch(true);
+
+ expect(client.last).to.equal('https://google.com/search?q=banana');
+ });
+ });
+});
+