From 809bdb11f3d213254c098411755631b1264c52f0 Mon Sep 17 00:00:00 2001 From: Shin'ya Ueoka Date: Sat, 28 Nov 2020 13:25:47 +0900 Subject: Make operators as a strategy pattern --- src/content/operators/Operator.ts | 5 + src/content/operators/OperatorFactory.ts | 6 + src/content/operators/OperatorFactoryChain.ts | 6 + .../operators/impls/BackgroundOperationOperator.ts | 15 ++ src/content/operators/impls/OperatorFactoryImpl.ts | 51 ++++++ src/content/operators/impls/RepeatOperator.ts | 14 ++ src/content/operators/impls/addons.ts | 74 +++++++++ src/content/operators/impls/clipboard.ts | 74 +++++++++ src/content/operators/impls/find.ts | 45 +++++ src/content/operators/impls/focus.ts | 29 ++++ src/content/operators/impls/follow.ts | 37 +++++ src/content/operators/impls/mark.ts | 39 +++++ src/content/operators/impls/scroll.ts | 183 +++++++++++++++++++++ 13 files changed, 578 insertions(+) create mode 100644 src/content/operators/Operator.ts create mode 100644 src/content/operators/OperatorFactory.ts create mode 100644 src/content/operators/OperatorFactoryChain.ts create mode 100644 src/content/operators/impls/BackgroundOperationOperator.ts create mode 100644 src/content/operators/impls/OperatorFactoryImpl.ts create mode 100644 src/content/operators/impls/RepeatOperator.ts create mode 100644 src/content/operators/impls/addons.ts create mode 100644 src/content/operators/impls/clipboard.ts create mode 100644 src/content/operators/impls/find.ts create mode 100644 src/content/operators/impls/focus.ts create mode 100644 src/content/operators/impls/follow.ts create mode 100644 src/content/operators/impls/mark.ts create mode 100644 src/content/operators/impls/scroll.ts (limited to 'src/content/operators') diff --git a/src/content/operators/Operator.ts b/src/content/operators/Operator.ts new file mode 100644 index 0000000..3b1fe03 --- /dev/null +++ b/src/content/operators/Operator.ts @@ -0,0 +1,5 @@ +interface Operator { + run(): Promise; +} + +export default Operator; diff --git a/src/content/operators/OperatorFactory.ts b/src/content/operators/OperatorFactory.ts new file mode 100644 index 0000000..f45973b --- /dev/null +++ b/src/content/operators/OperatorFactory.ts @@ -0,0 +1,6 @@ +import * as operations from "../../shared/operations"; +import Operator from "./Operator"; + +export default interface OperatorFactory { + create(op: operations.Operation, repeat: number): Operator; +} diff --git a/src/content/operators/OperatorFactoryChain.ts b/src/content/operators/OperatorFactoryChain.ts new file mode 100644 index 0000000..98dedb5 --- /dev/null +++ b/src/content/operators/OperatorFactoryChain.ts @@ -0,0 +1,6 @@ +import * as operations from "../../shared/operations"; +import Operator from "./Operator"; + +export default interface OperatorFactoryChain { + create(op: operations.Operation, repeat: number): Operator | null; +} diff --git a/src/content/operators/impls/BackgroundOperationOperator.ts b/src/content/operators/impls/BackgroundOperationOperator.ts new file mode 100644 index 0000000..dd86559 --- /dev/null +++ b/src/content/operators/impls/BackgroundOperationOperator.ts @@ -0,0 +1,15 @@ +import Operator from "../Operator"; +import OperationClient from "../../client/OperationClient"; +import * as operations from "../../../shared/operations"; + +export default class BackgroundOperationOperator implements Operator { + constructor( + private readonly operationClient: OperationClient, + private readonly repeat: number, + private readonly op: operations.Operation + ) {} + + async run(): Promise { + await this.operationClient.execBackgroundOp(this.repeat, this.op); + } +} diff --git a/src/content/operators/impls/OperatorFactoryImpl.ts b/src/content/operators/impls/OperatorFactoryImpl.ts new file mode 100644 index 0000000..f1aa3bc --- /dev/null +++ b/src/content/operators/impls/OperatorFactoryImpl.ts @@ -0,0 +1,51 @@ +import { inject, injectable } from "tsyringe"; +import OperatorFactory from "../OperatorFactory"; +import { AddonOperatorFactoryChain } from "./addons"; +import { ClipboardOperatorFactoryChain } from "./clipboard"; +import { FindOperatorFactoryChain } from "./find"; +import { FocusOperatorFactoryChain } from "./focus"; +import { MarkOperatorFactoryChain } from "./mark"; +import { ScrollOperatorFactoryChain } from "./scroll"; +import { FollowOperatorFactoryChain } from "./follow"; +import BackgroundOperationOperator from "./BackgroundOperationOperator"; +import Operator from "../Operator"; +import OperatorFactoryChain from "../OperatorFactoryChain"; +import { Operation } from "../../../shared/operations"; +import OperationClient from "../../client/OperationClient"; + +@injectable() +export default class OperatorFactoryImpl implements OperatorFactory { + private readonly factoryChains: OperatorFactoryChain[]; + + constructor( + addonOperatorFactoryChain: AddonOperatorFactoryChain, + clipboardOperatorFactoryChain: ClipboardOperatorFactoryChain, + findOperatorFactoryChain: FindOperatorFactoryChain, + focusOperatorFactoryChain: FocusOperatorFactoryChain, + followOperatorFactoryChain: FollowOperatorFactoryChain, + markOperatorFactoryChain: MarkOperatorFactoryChain, + scrollOperatorFactoryChain: ScrollOperatorFactoryChain, + @inject("OperationClient") + private readonly operationClient: OperationClient + ) { + this.factoryChains = [ + addonOperatorFactoryChain, + clipboardOperatorFactoryChain, + findOperatorFactoryChain, + focusOperatorFactoryChain, + followOperatorFactoryChain, + markOperatorFactoryChain, + scrollOperatorFactoryChain, + ]; + } + + create(op: Operation, repeat: number): Operator { + for (const chain of this.factoryChains) { + const operator = chain.create(op, repeat); + if (operator != null) { + return operator; + } + } + return new BackgroundOperationOperator(this.operationClient, repeat, op); + } +} diff --git a/src/content/operators/impls/RepeatOperator.ts b/src/content/operators/impls/RepeatOperator.ts new file mode 100644 index 0000000..efe2faf --- /dev/null +++ b/src/content/operators/impls/RepeatOperator.ts @@ -0,0 +1,14 @@ +import Operator from "../Operator"; + +export default class RepeatOperator implements Operator { + constructor( + private readonly operator: Operator, + private readonly repeat: number + ) {} + + async run(): Promise { + for (let i = 0; i < this.repeat; ++i) { + this.operator.run(); + } + } +} diff --git a/src/content/operators/impls/addons.ts b/src/content/operators/impls/addons.ts new file mode 100644 index 0000000..959da43 --- /dev/null +++ b/src/content/operators/impls/addons.ts @@ -0,0 +1,74 @@ +import { inject, injectable } from "tsyringe"; +import Operator from "../Operator"; +import OperatorFactoryChain from "../OperatorFactoryChain"; +import AddonIndicatorClient from "../../client/AddonIndicatorClient"; +import AddonEnabledRepository from "../../repositories/AddonEnabledRepository"; +import * as operations from "../../../shared/operations"; + +export class EnableAddonOperator implements Operator { + constructor( + private readonly indicator: AddonIndicatorClient, + private readonly repository: AddonEnabledRepository + ) {} + + async run(): Promise { + this.repository.set(true); + await this.indicator.setEnabled(true); + } +} + +export class DisableAddonOperator implements Operator { + constructor( + private readonly indicator: AddonIndicatorClient, + private readonly repository: AddonEnabledRepository + ) {} + + async run(): Promise { + this.repository.set(false); + await this.indicator.setEnabled(false); + } +} + +export class ToggleAddonOperator implements Operator { + constructor( + private readonly indicator: AddonIndicatorClient, + private readonly repository: AddonEnabledRepository + ) {} + + async run(): Promise { + const current = this.repository.get(); + this.repository.set(!current); + await this.indicator.setEnabled(!current); + } +} + +@injectable() +export class AddonOperatorFactoryChain implements OperatorFactoryChain { + constructor( + @inject("AddonIndicatorClient") + private readonly addonIndicatorClient: AddonIndicatorClient, + @inject("AddonEnabledRepository") + private readonly addonEnabledRepository: AddonEnabledRepository + ) {} + + create(op: operations.Operation, _repeat: number): Operator | null { + switch (op.type) { + case operations.ADDON_ENABLE: + return new EnableAddonOperator( + this.addonIndicatorClient, + this.addonEnabledRepository + ); + case operations.ADDON_DISABLE: + return new DisableAddonOperator( + this.addonIndicatorClient, + this.addonEnabledRepository + ); + case operations.ADDON_TOGGLE_ENABLED: + return new ToggleAddonOperator( + this.addonIndicatorClient, + this.addonEnabledRepository + ); + } + return null; + } +} diff --git a/src/content/operators/impls/clipboard.ts b/src/content/operators/impls/clipboard.ts new file mode 100644 index 0000000..26bdba0 --- /dev/null +++ b/src/content/operators/impls/clipboard.ts @@ -0,0 +1,74 @@ +import { inject, injectable } from "tsyringe"; +import Operator from "../Operator"; +import OperatorFactoryChain from "../OperatorFactoryChain"; +import ClipboardRepository from "../../repositories/ClipboardRepository"; +import SettingRepository from "../../repositories/SettingRepository"; +import ConsoleClient from "../../client/ConsoleClient"; +import OperationClient from "../../client/OperationClient"; +import * as urls from "../../../shared/urls"; +import * as operations from "../../../shared/operations"; + +export class YankURLOperator implements Operator { + constructor( + private readonly repository: ClipboardRepository, + private readonly consoleClient: ConsoleClient + ) {} + + async run(): Promise { + const url = window.location.href; + this.repository.write(url); + await this.consoleClient.info("Yanked " + url); + } +} + +export class PasteOperator implements Operator { + constructor( + private readonly repository: ClipboardRepository, + private readonly settingRepository: SettingRepository, + private readonly operationClient: OperationClient, + private readonly newTab: boolean + ) {} + + async run(): Promise { + const search = this.settingRepository.get().search; + const text = this.repository.read(); + const url = urls.searchUrl(text, search); + + // NOTE: Repeat pasting from clipboard instead of opening a certain url. + // 'Repeat last' command is implemented in the background script and cannot + // access to clipboard until Firefox 63. + await this.operationClient.internalOpenUrl(url, this.newTab); + } +} + +@injectable() +export class ClipboardOperatorFactoryChain implements OperatorFactoryChain { + constructor( + @inject("ClipboardRepository") + private readonly clipboardRepository: ClipboardRepository, + @inject("ConsoleClient") + private readonly consoleClient: ConsoleClient, + @inject("OperationClient") + private readonly operationClinet: OperationClient, + @inject("SettingRepository") + private readonly settingRepository: SettingRepository + ) {} + + create(op: operations.Operation, _repeat: number): Operator | null { + switch (op.type) { + case operations.URLS_YANK: + return new YankURLOperator( + this.clipboardRepository, + this.consoleClient + ); + case operations.URLS_PASTE: + return new PasteOperator( + this.clipboardRepository, + this.settingRepository, + this.operationClinet, + op.newTab + ); + } + return null; + } +} diff --git a/src/content/operators/impls/find.ts b/src/content/operators/impls/find.ts new file mode 100644 index 0000000..82310bc --- /dev/null +++ b/src/content/operators/impls/find.ts @@ -0,0 +1,45 @@ +import { inject, injectable } from "tsyringe"; +import RepeatOperator from "./RepeatOperator"; +import Operator from "../Operator"; +import OperatorFactoryChain from "../OperatorFactoryChain"; +import FindMasterClient from "../../client/FindMasterClient"; +import * as operations from "../../../shared/operations"; + +export class FindNextOperator implements Operator { + constructor(private readonly findMasterClient: FindMasterClient) {} + + async run(): Promise { + this.findMasterClient.findNext(); + } +} + +export class FindPrevOperator implements Operator { + constructor(private readonly findMasterClient: FindMasterClient) {} + + async run(): Promise { + this.findMasterClient.findPrev(); + } +} + +@injectable() +export class FindOperatorFactoryChain implements OperatorFactoryChain { + constructor( + @inject("FindMasterClient") + private readonly findMasterClient: FindMasterClient + ) {} + create(op: operations.Operation, repeat: number): Operator | null { + switch (op.type) { + case operations.FIND_NEXT: + return new RepeatOperator( + new FindNextOperator(this.findMasterClient), + repeat + ); + case operations.FIND_PREV: + return new RepeatOperator( + new FindPrevOperator(this.findMasterClient), + repeat + ); + } + return null; + } +} diff --git a/src/content/operators/impls/focus.ts b/src/content/operators/impls/focus.ts new file mode 100644 index 0000000..ea8e27d --- /dev/null +++ b/src/content/operators/impls/focus.ts @@ -0,0 +1,29 @@ +import { inject, injectable } from "tsyringe"; +import Operator from "../Operator"; +import OperatorFactoryChain from "../OperatorFactoryChain"; +import FocusPresenter from "../../presenters/FocusPresenter"; +import * as operations from "../../../shared/operations"; + +export class FocusOperator implements Operator { + constructor(private readonly presenter: FocusPresenter) {} + + async run(): Promise { + this.presenter.focusFirstElement(); + } +} + +@injectable() +export class FocusOperatorFactoryChain implements OperatorFactoryChain { + constructor( + @inject("FocusPresenter") + private readonly focusPresenter: FocusPresenter + ) {} + + create(op: operations.Operation, _repeat: number): Operator | null { + switch (op.type) { + case operations.FOCUS_INPUT: + return new FocusOperator(this.focusPresenter); + } + return null; + } +} diff --git a/src/content/operators/impls/follow.ts b/src/content/operators/impls/follow.ts new file mode 100644 index 0000000..6d3fadc --- /dev/null +++ b/src/content/operators/impls/follow.ts @@ -0,0 +1,37 @@ +import { inject, injectable } from "tsyringe"; +import Operator from "../Operator"; +import OperatorFactoryChain from "../OperatorFactoryChain"; +import FollowMasterClient from "../../client/FollowMasterClient"; +import * as operations from "../../../shared/operations"; + +export class StartFollowOperator implements Operator { + constructor( + private readonly followMasterClient: FollowMasterClient, + private readonly newTab: boolean, + private readonly background: boolean + ) {} + + async run(): Promise { + this.followMasterClient.startFollow(this.newTab, this.background); + } +} + +@injectable() +export class FollowOperatorFactoryChain implements OperatorFactoryChain { + constructor( + @inject("FollowMasterClient") + private followMasterClient: FollowMasterClient + ) {} + + create(op: operations.Operation, _repeat: number): Operator | null { + switch (op.type) { + case operations.FOLLOW_START: + return new StartFollowOperator( + this.followMasterClient, + op.newTab, + op.background + ); + } + return null; + } +} diff --git a/src/content/operators/impls/mark.ts b/src/content/operators/impls/mark.ts new file mode 100644 index 0000000..d90aba9 --- /dev/null +++ b/src/content/operators/impls/mark.ts @@ -0,0 +1,39 @@ +import { inject, injectable } from "tsyringe"; +import Operator from "../Operator"; +import OperatorFactoryChain from "../OperatorFactoryChain"; +import MarkKeyRepository from "../../repositories/MarkKeyRepository"; +import * as operations from "../../../shared/operations"; + +export class EnableSetMarkOperator implements Operator { + constructor(private readonly repository: MarkKeyRepository) {} + + async run(): Promise { + this.repository.enableSetMode(); + } +} + +export class EnableJumpMarkOperator implements Operator { + constructor(private readonly repository: MarkKeyRepository) {} + + async run(): Promise { + this.repository.enableJumpMode(); + } +} + +@injectable() +export class MarkOperatorFactoryChain implements OperatorFactoryChain { + constructor( + @inject("MarkKeyRepository") + private readonly markKeyRepository: MarkKeyRepository + ) {} + + create(op: operations.Operation, _repeat: number): Operator | null { + switch (op.type) { + case operations.MARK_SET_PREFIX: + return new EnableSetMarkOperator(this.markKeyRepository); + case operations.MARK_JUMP_PREFIX: + return new EnableJumpMarkOperator(this.markKeyRepository); + } + return null; + } +} diff --git a/src/content/operators/impls/scroll.ts b/src/content/operators/impls/scroll.ts new file mode 100644 index 0000000..96963be --- /dev/null +++ b/src/content/operators/impls/scroll.ts @@ -0,0 +1,183 @@ +import { inject, injectable } from "tsyringe"; +import Operator from "../Operator"; +import OperatorFactoryChain from "../OperatorFactoryChain"; +import ScrollPresenter from "../../presenters/ScrollPresenter"; +import SettingRepository from "../../repositories/SettingRepository"; +import * as operations from "../../../shared/operations"; + +class AbstractScrollOperator { + constructor(private readonly settingRepository: SettingRepository) {} + + protected getSmoothScroll(): boolean { + const settings = this.settingRepository.get(); + return settings.properties.smoothscroll; + } +} + +export class VerticalScrollOperator + extends AbstractScrollOperator + implements Operator { + constructor( + private readonly presenter: ScrollPresenter, + settingRepository: SettingRepository, + private readonly count: number + ) { + super(settingRepository); + } + + async run(): Promise { + const smooth = this.getSmoothScroll(); + this.presenter.scrollVertically(this.count, smooth); + } +} + +export class HorizonalScrollOperator + extends AbstractScrollOperator + implements Operator { + constructor( + private readonly presenter: ScrollPresenter, + settingRepository: SettingRepository, + private readonly count: number + ) { + super(settingRepository); + } + + async run(): Promise { + const smooth = this.getSmoothScroll(); + this.presenter.scrollHorizonally(this.count, smooth); + } +} + +export class PageScrollOperator + extends AbstractScrollOperator + implements Operator { + constructor( + private readonly presenter: ScrollPresenter, + settingRepository: SettingRepository, + private readonly count: number + ) { + super(settingRepository); + } + + async run(): Promise { + const smooth = this.getSmoothScroll(); + this.presenter.scrollPages(this.count, smooth); + } +} + +export class ScrollToTopOperator + extends AbstractScrollOperator + implements Operator { + constructor( + private readonly presenter: ScrollPresenter, + settingRepository: SettingRepository + ) { + super(settingRepository); + } + + async run(): Promise { + const smooth = this.getSmoothScroll(); + this.presenter.scrollToTop(smooth); + } +} + +export class ScrollToBottomOperator + extends AbstractScrollOperator + implements Operator { + constructor( + private readonly presenter: ScrollPresenter, + settingRepository: SettingRepository + ) { + super(settingRepository); + } + + async run(): Promise { + const smooth = this.getSmoothScroll(); + this.presenter.scrollToBottom(smooth); + } +} + +export class ScrollToHomeOperator + extends AbstractScrollOperator + implements Operator { + constructor( + private readonly presenter: ScrollPresenter, + settingRepository: SettingRepository + ) { + super(settingRepository); + } + + async run(): Promise { + const smooth = this.getSmoothScroll(); + this.presenter.scrollToHome(smooth); + } +} + +export class ScrollToEndOperator + extends AbstractScrollOperator + implements Operator { + constructor( + private readonly presenter: ScrollPresenter, + settingRepository: SettingRepository + ) { + super(settingRepository); + } + + async run(): Promise { + const smooth = this.getSmoothScroll(); + this.presenter.scrollToEnd(smooth); + } +} + +@injectable() +export class ScrollOperatorFactoryChain implements OperatorFactoryChain { + constructor( + @inject("ScrollPresenter") + private readonly scrollPresenter: ScrollPresenter, + @inject("SettingRepository") + private readonly settingRepository: SettingRepository + ) {} + create(op: operations.Operation, repeat: number): Operator | null { + switch (op.type) { + case operations.SCROLL_VERTICALLY: + return new VerticalScrollOperator( + this.scrollPresenter, + this.settingRepository, + op.count * repeat + ); + case operations.SCROLL_HORIZONALLY: + return new HorizonalScrollOperator( + this.scrollPresenter, + this.settingRepository, + op.count * repeat + ); + case operations.SCROLL_PAGES: + return new PageScrollOperator( + this.scrollPresenter, + this.settingRepository, + op.count * repeat + ); + case operations.SCROLL_TOP: + return new ScrollToTopOperator( + this.scrollPresenter, + this.settingRepository + ); + case operations.SCROLL_BOTTOM: + return new ScrollToBottomOperator( + this.scrollPresenter, + this.settingRepository + ); + case operations.SCROLL_HOME: + return new ScrollToHomeOperator( + this.scrollPresenter, + this.settingRepository + ); + case operations.SCROLL_END: + return new ScrollToEndOperator( + this.scrollPresenter, + this.settingRepository + ); + } + return null; + } +} -- cgit v1.2.3 From 36c28a538955c0cd9d94c210372337d7a5c2a01b Mon Sep 17 00:00:00 2001 From: Shin'ya Ueoka Date: Sun, 29 Nov 2020 09:31:45 +0900 Subject: extract independent classes --- .../operators/impls/AbstractScrollOperator.ts | 10 ++ .../operators/impls/AddonOperatorFactoryChain.ts | 40 +++++ .../impls/ClipboardOperatorFactoryChain.ts | 43 +++++ .../operators/impls/DisableAddonOperator.ts | 15 ++ src/content/operators/impls/EnableAddonOperator.ts | 15 ++ .../operators/impls/EnableJumpMarkOperator.ts | 10 ++ .../operators/impls/EnableSetMarkOperator.ts | 10 ++ src/content/operators/impls/FindNextOperator.ts | 10 ++ .../operators/impls/FindOperatorFactoryChain.ts | 32 ++++ src/content/operators/impls/FindPrevOperator.ts | 10 ++ src/content/operators/impls/FocusOperator.ts | 10 ++ .../operators/impls/FocusOperatorFactoryChain.ts | 22 +++ .../operators/impls/FollowOperatorFactoryChain.ts | 27 +++ .../operators/impls/HorizontalScrollOperator.ts | 21 +++ .../operators/impls/MarkOperatorFactoryChain.ts | 25 +++ src/content/operators/impls/OperatorFactoryImpl.ts | 14 +- src/content/operators/impls/PageScrollOperator.ts | 21 +++ src/content/operators/impls/PasteOperator.ts | 25 +++ .../operators/impls/ScrollOperatorFactoryChain.ts | 68 ++++++++ .../operators/impls/ScrollToBottomOperator.ts | 20 +++ src/content/operators/impls/ScrollToEndOperator.ts | 20 +++ .../operators/impls/ScrollToHomeOperator.ts | 20 +++ src/content/operators/impls/ScrollToTopOperator.ts | 20 +++ src/content/operators/impls/StartFollowOperator.ts | 14 ++ src/content/operators/impls/ToggleAddonOperator.ts | 16 ++ .../operators/impls/VerticalScrollOperator.ts | 21 +++ src/content/operators/impls/YankURLOperator.ts | 16 ++ src/content/operators/impls/addons.ts | 74 --------- src/content/operators/impls/clipboard.ts | 74 --------- src/content/operators/impls/find.ts | 45 ----- src/content/operators/impls/focus.ts | 29 ---- src/content/operators/impls/follow.ts | 37 ----- src/content/operators/impls/mark.ts | 39 ----- src/content/operators/impls/scroll.ts | 183 --------------------- 34 files changed, 568 insertions(+), 488 deletions(-) create mode 100644 src/content/operators/impls/AbstractScrollOperator.ts create mode 100644 src/content/operators/impls/AddonOperatorFactoryChain.ts create mode 100644 src/content/operators/impls/ClipboardOperatorFactoryChain.ts create mode 100644 src/content/operators/impls/DisableAddonOperator.ts create mode 100644 src/content/operators/impls/EnableAddonOperator.ts create mode 100644 src/content/operators/impls/EnableJumpMarkOperator.ts create mode 100644 src/content/operators/impls/EnableSetMarkOperator.ts create mode 100644 src/content/operators/impls/FindNextOperator.ts create mode 100644 src/content/operators/impls/FindOperatorFactoryChain.ts create mode 100644 src/content/operators/impls/FindPrevOperator.ts create mode 100644 src/content/operators/impls/FocusOperator.ts create mode 100644 src/content/operators/impls/FocusOperatorFactoryChain.ts create mode 100644 src/content/operators/impls/FollowOperatorFactoryChain.ts create mode 100644 src/content/operators/impls/HorizontalScrollOperator.ts create mode 100644 src/content/operators/impls/MarkOperatorFactoryChain.ts create mode 100644 src/content/operators/impls/PageScrollOperator.ts create mode 100644 src/content/operators/impls/PasteOperator.ts create mode 100644 src/content/operators/impls/ScrollOperatorFactoryChain.ts create mode 100644 src/content/operators/impls/ScrollToBottomOperator.ts create mode 100644 src/content/operators/impls/ScrollToEndOperator.ts create mode 100644 src/content/operators/impls/ScrollToHomeOperator.ts create mode 100644 src/content/operators/impls/ScrollToTopOperator.ts create mode 100644 src/content/operators/impls/StartFollowOperator.ts create mode 100644 src/content/operators/impls/ToggleAddonOperator.ts create mode 100644 src/content/operators/impls/VerticalScrollOperator.ts create mode 100644 src/content/operators/impls/YankURLOperator.ts delete mode 100644 src/content/operators/impls/addons.ts delete mode 100644 src/content/operators/impls/clipboard.ts delete mode 100644 src/content/operators/impls/find.ts delete mode 100644 src/content/operators/impls/focus.ts delete mode 100644 src/content/operators/impls/follow.ts delete mode 100644 src/content/operators/impls/mark.ts delete mode 100644 src/content/operators/impls/scroll.ts (limited to 'src/content/operators') diff --git a/src/content/operators/impls/AbstractScrollOperator.ts b/src/content/operators/impls/AbstractScrollOperator.ts new file mode 100644 index 0000000..f8d9f70 --- /dev/null +++ b/src/content/operators/impls/AbstractScrollOperator.ts @@ -0,0 +1,10 @@ +import SettingRepository from "../../repositories/SettingRepository"; + +export default class AbstractScrollOperator { + constructor(private readonly settingRepository: SettingRepository) {} + + protected getSmoothScroll(): boolean { + const settings = this.settingRepository.get(); + return settings.properties.smoothscroll; + } +} diff --git a/src/content/operators/impls/AddonOperatorFactoryChain.ts b/src/content/operators/impls/AddonOperatorFactoryChain.ts new file mode 100644 index 0000000..54880c4 --- /dev/null +++ b/src/content/operators/impls/AddonOperatorFactoryChain.ts @@ -0,0 +1,40 @@ +import { inject, injectable } from "tsyringe"; +import OperatorFactoryChain from "../OperatorFactoryChain"; +import AddonIndicatorClient from "../../client/AddonIndicatorClient"; +import AddonEnabledRepository from "../../repositories/AddonEnabledRepository"; +import * as operations from "../../../shared/operations"; +import Operator from "../Operator"; +import EnableAddonOperator from "./EnableAddonOperator"; +import DisableAddonOperator from "./DisableAddonOperator"; +import ToggleAddonOperator from "./ToggleAddonOperator"; + +@injectable() +export default class AddonOperatorFactoryChain implements OperatorFactoryChain { + constructor( + @inject("AddonIndicatorClient") + private readonly addonIndicatorClient: AddonIndicatorClient, + @inject("AddonEnabledRepository") + private readonly addonEnabledRepository: AddonEnabledRepository + ) {} + + create(op: operations.Operation, _repeat: number): Operator | null { + switch (op.type) { + case operations.ADDON_ENABLE: + return new EnableAddonOperator( + this.addonIndicatorClient, + this.addonEnabledRepository + ); + case operations.ADDON_DISABLE: + return new DisableAddonOperator( + this.addonIndicatorClient, + this.addonEnabledRepository + ); + case operations.ADDON_TOGGLE_ENABLED: + return new ToggleAddonOperator( + this.addonIndicatorClient, + this.addonEnabledRepository + ); + } + return null; + } +} diff --git a/src/content/operators/impls/ClipboardOperatorFactoryChain.ts b/src/content/operators/impls/ClipboardOperatorFactoryChain.ts new file mode 100644 index 0000000..fb12ae8 --- /dev/null +++ b/src/content/operators/impls/ClipboardOperatorFactoryChain.ts @@ -0,0 +1,43 @@ +import { inject, injectable } from "tsyringe"; +import YankURLOperator from "./YankURLOperator"; +import PasteOperator from "./PasteOperator"; +import Operator from "../Operator"; +import OperatorFactoryChain from "../OperatorFactoryChain"; +import ClipboardRepository from "../../repositories/ClipboardRepository"; +import ConsoleClient from "../../client/ConsoleClient"; +import OperationClient from "../../client/OperationClient"; +import SettingRepository from "../../repositories/SettingRepository"; +import * as operations from "../../../shared/operations"; + +@injectable() +export default class ClipboardOperatorFactoryChain + implements OperatorFactoryChain { + constructor( + @inject("ClipboardRepository") + private readonly clipboardRepository: ClipboardRepository, + @inject("ConsoleClient") + private readonly consoleClient: ConsoleClient, + @inject("OperationClient") + private readonly operationClinet: OperationClient, + @inject("SettingRepository") + private readonly settingRepository: SettingRepository + ) {} + + create(op: operations.Operation, _repeat: number): Operator | null { + switch (op.type) { + case operations.URLS_YANK: + return new YankURLOperator( + this.clipboardRepository, + this.consoleClient + ); + case operations.URLS_PASTE: + return new PasteOperator( + this.clipboardRepository, + this.settingRepository, + this.operationClinet, + op.newTab + ); + } + return null; + } +} diff --git a/src/content/operators/impls/DisableAddonOperator.ts b/src/content/operators/impls/DisableAddonOperator.ts new file mode 100644 index 0000000..28811fe --- /dev/null +++ b/src/content/operators/impls/DisableAddonOperator.ts @@ -0,0 +1,15 @@ +import Operator from "../Operator"; +import AddonIndicatorClient from "../../client/AddonIndicatorClient"; +import AddonEnabledRepository from "../../repositories/AddonEnabledRepository"; + +export default class DisableAddonOperator implements Operator { + constructor( + private readonly indicator: AddonIndicatorClient, + private readonly repository: AddonEnabledRepository + ) {} + + async run(): Promise { + this.repository.set(false); + await this.indicator.setEnabled(false); + } +} diff --git a/src/content/operators/impls/EnableAddonOperator.ts b/src/content/operators/impls/EnableAddonOperator.ts new file mode 100644 index 0000000..b5b1d79 --- /dev/null +++ b/src/content/operators/impls/EnableAddonOperator.ts @@ -0,0 +1,15 @@ +import Operator from "../Operator"; +import AddonIndicatorClient from "../../client/AddonIndicatorClient"; +import AddonEnabledRepository from "../../repositories/AddonEnabledRepository"; + +export default class EnableAddonOperator implements Operator { + constructor( + private readonly indicator: AddonIndicatorClient, + private readonly repository: AddonEnabledRepository + ) {} + + async run(): Promise { + this.repository.set(true); + await this.indicator.setEnabled(true); + } +} diff --git a/src/content/operators/impls/EnableJumpMarkOperator.ts b/src/content/operators/impls/EnableJumpMarkOperator.ts new file mode 100644 index 0000000..42ca8ee --- /dev/null +++ b/src/content/operators/impls/EnableJumpMarkOperator.ts @@ -0,0 +1,10 @@ +import Operator from "../Operator"; +import MarkKeyRepository from "../../repositories/MarkKeyRepository"; + +export default class EnableJumpMarkOperator implements Operator { + constructor(private readonly repository: MarkKeyRepository) {} + + async run(): Promise { + this.repository.enableJumpMode(); + } +} diff --git a/src/content/operators/impls/EnableSetMarkOperator.ts b/src/content/operators/impls/EnableSetMarkOperator.ts new file mode 100644 index 0000000..3d0daf4 --- /dev/null +++ b/src/content/operators/impls/EnableSetMarkOperator.ts @@ -0,0 +1,10 @@ +import Operator from "../Operator"; +import MarkKeyRepository from "../../repositories/MarkKeyRepository"; + +export default class EnableSetMarkOperator implements Operator { + constructor(private readonly repository: MarkKeyRepository) {} + + async run(): Promise { + this.repository.enableSetMode(); + } +} diff --git a/src/content/operators/impls/FindNextOperator.ts b/src/content/operators/impls/FindNextOperator.ts new file mode 100644 index 0000000..723db3d --- /dev/null +++ b/src/content/operators/impls/FindNextOperator.ts @@ -0,0 +1,10 @@ +import Operator from "../Operator"; +import FindMasterClient from "../../client/FindMasterClient"; + +export default class FindNextOperator implements Operator { + constructor(private readonly findMasterClient: FindMasterClient) {} + + async run(): Promise { + this.findMasterClient.findNext(); + } +} diff --git a/src/content/operators/impls/FindOperatorFactoryChain.ts b/src/content/operators/impls/FindOperatorFactoryChain.ts new file mode 100644 index 0000000..ef1c754 --- /dev/null +++ b/src/content/operators/impls/FindOperatorFactoryChain.ts @@ -0,0 +1,32 @@ +import { inject, injectable } from "tsyringe"; +import Operator from "../Operator"; +import OperatorFactoryChain from "../OperatorFactoryChain"; +import RepeatOperator from "./RepeatOperator"; +import FindNextOperator from "./FindNextOperator"; +import FindPrevOperator from "./FindPrevOperator"; +import FindMasterClient from "../../client/FindMasterClient"; +import * as operations from "../../../shared/operations"; + +@injectable() +export default class FindOperatorFactoryChain implements OperatorFactoryChain { + constructor( + @inject("FindMasterClient") + private readonly findMasterClient: FindMasterClient + ) {} + + create(op: operations.Operation, repeat: number): Operator | null { + switch (op.type) { + case operations.FIND_NEXT: + return new RepeatOperator( + new FindNextOperator(this.findMasterClient), + repeat + ); + case operations.FIND_PREV: + return new RepeatOperator( + new FindPrevOperator(this.findMasterClient), + repeat + ); + } + return null; + } +} diff --git a/src/content/operators/impls/FindPrevOperator.ts b/src/content/operators/impls/FindPrevOperator.ts new file mode 100644 index 0000000..be6a01e --- /dev/null +++ b/src/content/operators/impls/FindPrevOperator.ts @@ -0,0 +1,10 @@ +import Operator from "../Operator"; +import FindMasterClient from "../../client/FindMasterClient"; + +export default class FindPrevOperator implements Operator { + constructor(private readonly findMasterClient: FindMasterClient) {} + + async run(): Promise { + this.findMasterClient.findPrev(); + } +} diff --git a/src/content/operators/impls/FocusOperator.ts b/src/content/operators/impls/FocusOperator.ts new file mode 100644 index 0000000..51d6fec --- /dev/null +++ b/src/content/operators/impls/FocusOperator.ts @@ -0,0 +1,10 @@ +import Operator from "../Operator"; +import FocusPresenter from "../../presenters/FocusPresenter"; + +export default class FocusOperator implements Operator { + constructor(private readonly presenter: FocusPresenter) {} + + async run(): Promise { + this.presenter.focusFirstElement(); + } +} diff --git a/src/content/operators/impls/FocusOperatorFactoryChain.ts b/src/content/operators/impls/FocusOperatorFactoryChain.ts new file mode 100644 index 0000000..c89c1e5 --- /dev/null +++ b/src/content/operators/impls/FocusOperatorFactoryChain.ts @@ -0,0 +1,22 @@ +import { inject, injectable } from "tsyringe"; +import OperatorFactoryChain from "../OperatorFactoryChain"; +import Operator from "../Operator"; +import FocusOperator from "./FocusOperator"; +import FocusPresenter from "../../presenters/FocusPresenter"; +import * as operations from "../../../shared/operations"; + +@injectable() +export default class FocusOperatorFactoryChain implements OperatorFactoryChain { + constructor( + @inject("FocusPresenter") + private readonly focusPresenter: FocusPresenter + ) {} + + create(op: operations.Operation, _repeat: number): Operator | null { + switch (op.type) { + case operations.FOCUS_INPUT: + return new FocusOperator(this.focusPresenter); + } + return null; + } +} diff --git a/src/content/operators/impls/FollowOperatorFactoryChain.ts b/src/content/operators/impls/FollowOperatorFactoryChain.ts new file mode 100644 index 0000000..588e1a4 --- /dev/null +++ b/src/content/operators/impls/FollowOperatorFactoryChain.ts @@ -0,0 +1,27 @@ +import { inject, injectable } from "tsyringe"; +import StartFollowOperator from "./StartFollowOperator"; +import Operator from "../Operator"; +import OperatorFactoryChain from "../OperatorFactoryChain"; +import FollowMasterClient from "../../client/FollowMasterClient"; +import * as operations from "../../../shared/operations"; + +@injectable() +export default class FollowOperatorFactoryChain + implements OperatorFactoryChain { + constructor( + @inject("FollowMasterClient") + private followMasterClient: FollowMasterClient + ) {} + + create(op: operations.Operation, _repeat: number): Operator | null { + switch (op.type) { + case operations.FOLLOW_START: + return new StartFollowOperator( + this.followMasterClient, + op.newTab, + op.background + ); + } + return null; + } +} diff --git a/src/content/operators/impls/HorizontalScrollOperator.ts b/src/content/operators/impls/HorizontalScrollOperator.ts new file mode 100644 index 0000000..f813f85 --- /dev/null +++ b/src/content/operators/impls/HorizontalScrollOperator.ts @@ -0,0 +1,21 @@ +import AbstractScrollOperator from "./AbstractScrollOperator"; +import Operator from "../Operator"; +import ScrollPresenter from "../../presenters/ScrollPresenter"; +import SettingRepository from "../../repositories/SettingRepository"; + +export default class HorizontalScrollOperator + extends AbstractScrollOperator + implements Operator { + constructor( + private readonly presenter: ScrollPresenter, + settingRepository: SettingRepository, + private readonly count: number + ) { + super(settingRepository); + } + + async run(): Promise { + const smooth = this.getSmoothScroll(); + this.presenter.scrollHorizonally(this.count, smooth); + } +} diff --git a/src/content/operators/impls/MarkOperatorFactoryChain.ts b/src/content/operators/impls/MarkOperatorFactoryChain.ts new file mode 100644 index 0000000..7e6c513 --- /dev/null +++ b/src/content/operators/impls/MarkOperatorFactoryChain.ts @@ -0,0 +1,25 @@ +import { inject, injectable } from "tsyringe"; +import EnableSetMarkOperator from "./EnableSetMarkOperator"; +import EnableJumpMarkOperator from "./EnableJumpMarkOperator"; +import Operator from "../Operator"; +import OperatorFactoryChain from "../OperatorFactoryChain"; +import MarkKeyRepository from "../../repositories/MarkKeyRepository"; +import * as operations from "../../../shared/operations"; + +@injectable() +export default class MarkOperatorFactoryChain implements OperatorFactoryChain { + constructor( + @inject("MarkKeyRepository") + private readonly markKeyRepository: MarkKeyRepository + ) {} + + create(op: operations.Operation, _repeat: number): Operator | null { + switch (op.type) { + case operations.MARK_SET_PREFIX: + return new EnableSetMarkOperator(this.markKeyRepository); + case operations.MARK_JUMP_PREFIX: + return new EnableJumpMarkOperator(this.markKeyRepository); + } + return null; + } +} diff --git a/src/content/operators/impls/OperatorFactoryImpl.ts b/src/content/operators/impls/OperatorFactoryImpl.ts index f1aa3bc..22b35c8 100644 --- a/src/content/operators/impls/OperatorFactoryImpl.ts +++ b/src/content/operators/impls/OperatorFactoryImpl.ts @@ -1,17 +1,17 @@ import { inject, injectable } from "tsyringe"; import OperatorFactory from "../OperatorFactory"; -import { AddonOperatorFactoryChain } from "./addons"; -import { ClipboardOperatorFactoryChain } from "./clipboard"; -import { FindOperatorFactoryChain } from "./find"; -import { FocusOperatorFactoryChain } from "./focus"; -import { MarkOperatorFactoryChain } from "./mark"; -import { ScrollOperatorFactoryChain } from "./scroll"; -import { FollowOperatorFactoryChain } from "./follow"; import BackgroundOperationOperator from "./BackgroundOperationOperator"; import Operator from "../Operator"; import OperatorFactoryChain from "../OperatorFactoryChain"; import { Operation } from "../../../shared/operations"; import OperationClient from "../../client/OperationClient"; +import AddonOperatorFactoryChain from "./AddonOperatorFactoryChain"; +import ClipboardOperatorFactoryChain from "./ClipboardOperatorFactoryChain"; +import FindOperatorFactoryChain from "./FindOperatorFactoryChain"; +import FocusOperatorFactoryChain from "./FocusOperatorFactoryChain"; +import FollowOperatorFactoryChain from "./FollowOperatorFactoryChain"; +import MarkOperatorFactoryChain from "./MarkOperatorFactoryChain"; +import ScrollOperatorFactoryChain from "./ScrollOperatorFactoryChain"; @injectable() export default class OperatorFactoryImpl implements OperatorFactory { diff --git a/src/content/operators/impls/PageScrollOperator.ts b/src/content/operators/impls/PageScrollOperator.ts new file mode 100644 index 0000000..377bf92 --- /dev/null +++ b/src/content/operators/impls/PageScrollOperator.ts @@ -0,0 +1,21 @@ +import AbstractScrollOperator from "./AbstractScrollOperator"; +import Operator from "../Operator"; +import ScrollPresenter from "../../presenters/ScrollPresenter"; +import SettingRepository from "../../repositories/SettingRepository"; + +export default class PageScrollOperator + extends AbstractScrollOperator + implements Operator { + constructor( + private readonly presenter: ScrollPresenter, + settingRepository: SettingRepository, + private readonly count: number + ) { + super(settingRepository); + } + + async run(): Promise { + const smooth = this.getSmoothScroll(); + this.presenter.scrollPages(this.count, smooth); + } +} diff --git a/src/content/operators/impls/PasteOperator.ts b/src/content/operators/impls/PasteOperator.ts new file mode 100644 index 0000000..592da66 --- /dev/null +++ b/src/content/operators/impls/PasteOperator.ts @@ -0,0 +1,25 @@ +import Operator from "../Operator"; +import ClipboardRepository from "../../repositories/ClipboardRepository"; +import SettingRepository from "../../repositories/SettingRepository"; +import OperationClient from "../../client/OperationClient"; +import * as urls from "../../../shared/urls"; + +export default class PasteOperator implements Operator { + constructor( + private readonly repository: ClipboardRepository, + private readonly settingRepository: SettingRepository, + private readonly operationClient: OperationClient, + private readonly newTab: boolean + ) {} + + async run(): Promise { + const search = this.settingRepository.get().search; + const text = this.repository.read(); + const url = urls.searchUrl(text, search); + + // NOTE: Repeat pasting from clipboard instead of opening a certain url. + // 'Repeat last' command is implemented in the background script and cannot + // access to clipboard until Firefox 63. + await this.operationClient.internalOpenUrl(url, this.newTab); + } +} diff --git a/src/content/operators/impls/ScrollOperatorFactoryChain.ts b/src/content/operators/impls/ScrollOperatorFactoryChain.ts new file mode 100644 index 0000000..6847aea --- /dev/null +++ b/src/content/operators/impls/ScrollOperatorFactoryChain.ts @@ -0,0 +1,68 @@ +import { inject, injectable } from "tsyringe"; +import OperatorFactoryChain from "../OperatorFactoryChain"; +import ScrollPresenter from "../../presenters/ScrollPresenter"; +import SettingRepository from "../../repositories/SettingRepository"; +import * as operations from "../../../shared/operations"; +import Operator from "../Operator"; +import VerticalScrollOperator from "./VerticalScrollOperator"; +import HorizontalScrollOperator from "./HorizontalScrollOperator"; +import PageScrollOperator from "./PageScrollOperator"; +import ScrollToTopOperator from "./ScrollToTopOperator"; +import ScrollToBottomOperator from "./ScrollToBottomOperator"; +import ScrollToHomeOperator from "./ScrollToHomeOperator"; +import ScrollToEndOperator from "./ScrollToEndOperator"; + +@injectable() +export default class ScrollOperatorFactoryChain + implements OperatorFactoryChain { + constructor( + @inject("ScrollPresenter") + private readonly scrollPresenter: ScrollPresenter, + @inject("SettingRepository") + private readonly settingRepository: SettingRepository + ) {} + + create(op: operations.Operation, repeat: number): Operator | null { + switch (op.type) { + case operations.SCROLL_VERTICALLY: + return new VerticalScrollOperator( + this.scrollPresenter, + this.settingRepository, + op.count * repeat + ); + case operations.SCROLL_HORIZONALLY: + return new HorizontalScrollOperator( + this.scrollPresenter, + this.settingRepository, + op.count * repeat + ); + case operations.SCROLL_PAGES: + return new PageScrollOperator( + this.scrollPresenter, + this.settingRepository, + op.count * repeat + ); + case operations.SCROLL_TOP: + return new ScrollToTopOperator( + this.scrollPresenter, + this.settingRepository + ); + case operations.SCROLL_BOTTOM: + return new ScrollToBottomOperator( + this.scrollPresenter, + this.settingRepository + ); + case operations.SCROLL_HOME: + return new ScrollToHomeOperator( + this.scrollPresenter, + this.settingRepository + ); + case operations.SCROLL_END: + return new ScrollToEndOperator( + this.scrollPresenter, + this.settingRepository + ); + } + return null; + } +} diff --git a/src/content/operators/impls/ScrollToBottomOperator.ts b/src/content/operators/impls/ScrollToBottomOperator.ts new file mode 100644 index 0000000..4db521b --- /dev/null +++ b/src/content/operators/impls/ScrollToBottomOperator.ts @@ -0,0 +1,20 @@ +import AbstractScrollOperator from "./AbstractScrollOperator"; +import Operator from "../Operator"; +import ScrollPresenter from "../../presenters/ScrollPresenter"; +import SettingRepository from "../../repositories/SettingRepository"; + +export default class ScrollToBottomOperator + extends AbstractScrollOperator + implements Operator { + constructor( + private readonly presenter: ScrollPresenter, + settingRepository: SettingRepository + ) { + super(settingRepository); + } + + async run(): Promise { + const smooth = this.getSmoothScroll(); + this.presenter.scrollToBottom(smooth); + } +} diff --git a/src/content/operators/impls/ScrollToEndOperator.ts b/src/content/operators/impls/ScrollToEndOperator.ts new file mode 100644 index 0000000..8217e15 --- /dev/null +++ b/src/content/operators/impls/ScrollToEndOperator.ts @@ -0,0 +1,20 @@ +import AbstractScrollOperator from "./AbstractScrollOperator"; +import Operator from "../Operator"; +import ScrollPresenter from "../../presenters/ScrollPresenter"; +import SettingRepository from "../../repositories/SettingRepository"; + +export default class ScrollToEndOperator + extends AbstractScrollOperator + implements Operator { + constructor( + private readonly presenter: ScrollPresenter, + settingRepository: SettingRepository + ) { + super(settingRepository); + } + + async run(): Promise { + const smooth = this.getSmoothScroll(); + this.presenter.scrollToEnd(smooth); + } +} diff --git a/src/content/operators/impls/ScrollToHomeOperator.ts b/src/content/operators/impls/ScrollToHomeOperator.ts new file mode 100644 index 0000000..a0d7701 --- /dev/null +++ b/src/content/operators/impls/ScrollToHomeOperator.ts @@ -0,0 +1,20 @@ +import AbstractScrollOperator from "./AbstractScrollOperator"; +import Operator from "../Operator"; +import ScrollPresenter from "../../presenters/ScrollPresenter"; +import SettingRepository from "../../repositories/SettingRepository"; + +export default class ScrollToHomeOperator + extends AbstractScrollOperator + implements Operator { + constructor( + private readonly presenter: ScrollPresenter, + settingRepository: SettingRepository + ) { + super(settingRepository); + } + + async run(): Promise { + const smooth = this.getSmoothScroll(); + this.presenter.scrollToHome(smooth); + } +} diff --git a/src/content/operators/impls/ScrollToTopOperator.ts b/src/content/operators/impls/ScrollToTopOperator.ts new file mode 100644 index 0000000..6075758 --- /dev/null +++ b/src/content/operators/impls/ScrollToTopOperator.ts @@ -0,0 +1,20 @@ +import AbstractScrollOperator from "./AbstractScrollOperator"; +import Operator from "../Operator"; +import ScrollPresenter from "../../presenters/ScrollPresenter"; +import SettingRepository from "../../repositories/SettingRepository"; + +export default class ScrollToTopOperator + extends AbstractScrollOperator + implements Operator { + constructor( + private readonly presenter: ScrollPresenter, + settingRepository: SettingRepository + ) { + super(settingRepository); + } + + async run(): Promise { + const smooth = this.getSmoothScroll(); + this.presenter.scrollToTop(smooth); + } +} diff --git a/src/content/operators/impls/StartFollowOperator.ts b/src/content/operators/impls/StartFollowOperator.ts new file mode 100644 index 0000000..6f30058 --- /dev/null +++ b/src/content/operators/impls/StartFollowOperator.ts @@ -0,0 +1,14 @@ +import Operator from "../Operator"; +import FollowMasterClient from "../../client/FollowMasterClient"; + +export default class StartFollowOperator implements Operator { + constructor( + private readonly followMasterClient: FollowMasterClient, + private readonly newTab: boolean, + private readonly background: boolean + ) {} + + async run(): Promise { + this.followMasterClient.startFollow(this.newTab, this.background); + } +} diff --git a/src/content/operators/impls/ToggleAddonOperator.ts b/src/content/operators/impls/ToggleAddonOperator.ts new file mode 100644 index 0000000..2a249d6 --- /dev/null +++ b/src/content/operators/impls/ToggleAddonOperator.ts @@ -0,0 +1,16 @@ +import Operator from "../Operator"; +import AddonIndicatorClient from "../../client/AddonIndicatorClient"; +import AddonEnabledRepository from "../../repositories/AddonEnabledRepository"; + +export default class ToggleAddonOperator implements Operator { + constructor( + private readonly indicator: AddonIndicatorClient, + private readonly repository: AddonEnabledRepository + ) {} + + async run(): Promise { + const current = this.repository.get(); + this.repository.set(!current); + await this.indicator.setEnabled(!current); + } +} diff --git a/src/content/operators/impls/VerticalScrollOperator.ts b/src/content/operators/impls/VerticalScrollOperator.ts new file mode 100644 index 0000000..4ab336c --- /dev/null +++ b/src/content/operators/impls/VerticalScrollOperator.ts @@ -0,0 +1,21 @@ +import AbstractScrollOperator from "./AbstractScrollOperator"; +import Operator from "../Operator"; +import ScrollPresenter from "../../presenters/ScrollPresenter"; +import SettingRepository from "../../repositories/SettingRepository"; + +export default class VerticalScrollOperator + extends AbstractScrollOperator + implements Operator { + constructor( + private readonly presenter: ScrollPresenter, + settingRepository: SettingRepository, + private readonly count: number + ) { + super(settingRepository); + } + + async run(): Promise { + const smooth = this.getSmoothScroll(); + this.presenter.scrollVertically(this.count, smooth); + } +} diff --git a/src/content/operators/impls/YankURLOperator.ts b/src/content/operators/impls/YankURLOperator.ts new file mode 100644 index 0000000..5e2ac60 --- /dev/null +++ b/src/content/operators/impls/YankURLOperator.ts @@ -0,0 +1,16 @@ +import Operator from "../Operator"; +import ClipboardRepository from "../../repositories/ClipboardRepository"; +import ConsoleClient from "../../client/ConsoleClient"; + +export default class YankURLOperator implements Operator { + constructor( + private readonly repository: ClipboardRepository, + private readonly consoleClient: ConsoleClient + ) {} + + async run(): Promise { + const url = window.location.href; + this.repository.write(url); + await this.consoleClient.info("Yanked " + url); + } +} diff --git a/src/content/operators/impls/addons.ts b/src/content/operators/impls/addons.ts deleted file mode 100644 index 959da43..0000000 --- a/src/content/operators/impls/addons.ts +++ /dev/null @@ -1,74 +0,0 @@ -import { inject, injectable } from "tsyringe"; -import Operator from "../Operator"; -import OperatorFactoryChain from "../OperatorFactoryChain"; -import AddonIndicatorClient from "../../client/AddonIndicatorClient"; -import AddonEnabledRepository from "../../repositories/AddonEnabledRepository"; -import * as operations from "../../../shared/operations"; - -export class EnableAddonOperator implements Operator { - constructor( - private readonly indicator: AddonIndicatorClient, - private readonly repository: AddonEnabledRepository - ) {} - - async run(): Promise { - this.repository.set(true); - await this.indicator.setEnabled(true); - } -} - -export class DisableAddonOperator implements Operator { - constructor( - private readonly indicator: AddonIndicatorClient, - private readonly repository: AddonEnabledRepository - ) {} - - async run(): Promise { - this.repository.set(false); - await this.indicator.setEnabled(false); - } -} - -export class ToggleAddonOperator implements Operator { - constructor( - private readonly indicator: AddonIndicatorClient, - private readonly repository: AddonEnabledRepository - ) {} - - async run(): Promise { - const current = this.repository.get(); - this.repository.set(!current); - await this.indicator.setEnabled(!current); - } -} - -@injectable() -export class AddonOperatorFactoryChain implements OperatorFactoryChain { - constructor( - @inject("AddonIndicatorClient") - private readonly addonIndicatorClient: AddonIndicatorClient, - @inject("AddonEnabledRepository") - private readonly addonEnabledRepository: AddonEnabledRepository - ) {} - - create(op: operations.Operation, _repeat: number): Operator | null { - switch (op.type) { - case operations.ADDON_ENABLE: - return new EnableAddonOperator( - this.addonIndicatorClient, - this.addonEnabledRepository - ); - case operations.ADDON_DISABLE: - return new DisableAddonOperator( - this.addonIndicatorClient, - this.addonEnabledRepository - ); - case operations.ADDON_TOGGLE_ENABLED: - return new ToggleAddonOperator( - this.addonIndicatorClient, - this.addonEnabledRepository - ); - } - return null; - } -} diff --git a/src/content/operators/impls/clipboard.ts b/src/content/operators/impls/clipboard.ts deleted file mode 100644 index 26bdba0..0000000 --- a/src/content/operators/impls/clipboard.ts +++ /dev/null @@ -1,74 +0,0 @@ -import { inject, injectable } from "tsyringe"; -import Operator from "../Operator"; -import OperatorFactoryChain from "../OperatorFactoryChain"; -import ClipboardRepository from "../../repositories/ClipboardRepository"; -import SettingRepository from "../../repositories/SettingRepository"; -import ConsoleClient from "../../client/ConsoleClient"; -import OperationClient from "../../client/OperationClient"; -import * as urls from "../../../shared/urls"; -import * as operations from "../../../shared/operations"; - -export class YankURLOperator implements Operator { - constructor( - private readonly repository: ClipboardRepository, - private readonly consoleClient: ConsoleClient - ) {} - - async run(): Promise { - const url = window.location.href; - this.repository.write(url); - await this.consoleClient.info("Yanked " + url); - } -} - -export class PasteOperator implements Operator { - constructor( - private readonly repository: ClipboardRepository, - private readonly settingRepository: SettingRepository, - private readonly operationClient: OperationClient, - private readonly newTab: boolean - ) {} - - async run(): Promise { - const search = this.settingRepository.get().search; - const text = this.repository.read(); - const url = urls.searchUrl(text, search); - - // NOTE: Repeat pasting from clipboard instead of opening a certain url. - // 'Repeat last' command is implemented in the background script and cannot - // access to clipboard until Firefox 63. - await this.operationClient.internalOpenUrl(url, this.newTab); - } -} - -@injectable() -export class ClipboardOperatorFactoryChain implements OperatorFactoryChain { - constructor( - @inject("ClipboardRepository") - private readonly clipboardRepository: ClipboardRepository, - @inject("ConsoleClient") - private readonly consoleClient: ConsoleClient, - @inject("OperationClient") - private readonly operationClinet: OperationClient, - @inject("SettingRepository") - private readonly settingRepository: SettingRepository - ) {} - - create(op: operations.Operation, _repeat: number): Operator | null { - switch (op.type) { - case operations.URLS_YANK: - return new YankURLOperator( - this.clipboardRepository, - this.consoleClient - ); - case operations.URLS_PASTE: - return new PasteOperator( - this.clipboardRepository, - this.settingRepository, - this.operationClinet, - op.newTab - ); - } - return null; - } -} diff --git a/src/content/operators/impls/find.ts b/src/content/operators/impls/find.ts deleted file mode 100644 index 82310bc..0000000 --- a/src/content/operators/impls/find.ts +++ /dev/null @@ -1,45 +0,0 @@ -import { inject, injectable } from "tsyringe"; -import RepeatOperator from "./RepeatOperator"; -import Operator from "../Operator"; -import OperatorFactoryChain from "../OperatorFactoryChain"; -import FindMasterClient from "../../client/FindMasterClient"; -import * as operations from "../../../shared/operations"; - -export class FindNextOperator implements Operator { - constructor(private readonly findMasterClient: FindMasterClient) {} - - async run(): Promise { - this.findMasterClient.findNext(); - } -} - -export class FindPrevOperator implements Operator { - constructor(private readonly findMasterClient: FindMasterClient) {} - - async run(): Promise { - this.findMasterClient.findPrev(); - } -} - -@injectable() -export class FindOperatorFactoryChain implements OperatorFactoryChain { - constructor( - @inject("FindMasterClient") - private readonly findMasterClient: FindMasterClient - ) {} - create(op: operations.Operation, repeat: number): Operator | null { - switch (op.type) { - case operations.FIND_NEXT: - return new RepeatOperator( - new FindNextOperator(this.findMasterClient), - repeat - ); - case operations.FIND_PREV: - return new RepeatOperator( - new FindPrevOperator(this.findMasterClient), - repeat - ); - } - return null; - } -} diff --git a/src/content/operators/impls/focus.ts b/src/content/operators/impls/focus.ts deleted file mode 100644 index ea8e27d..0000000 --- a/src/content/operators/impls/focus.ts +++ /dev/null @@ -1,29 +0,0 @@ -import { inject, injectable } from "tsyringe"; -import Operator from "../Operator"; -import OperatorFactoryChain from "../OperatorFactoryChain"; -import FocusPresenter from "../../presenters/FocusPresenter"; -import * as operations from "../../../shared/operations"; - -export class FocusOperator implements Operator { - constructor(private readonly presenter: FocusPresenter) {} - - async run(): Promise { - this.presenter.focusFirstElement(); - } -} - -@injectable() -export class FocusOperatorFactoryChain implements OperatorFactoryChain { - constructor( - @inject("FocusPresenter") - private readonly focusPresenter: FocusPresenter - ) {} - - create(op: operations.Operation, _repeat: number): Operator | null { - switch (op.type) { - case operations.FOCUS_INPUT: - return new FocusOperator(this.focusPresenter); - } - return null; - } -} diff --git a/src/content/operators/impls/follow.ts b/src/content/operators/impls/follow.ts deleted file mode 100644 index 6d3fadc..0000000 --- a/src/content/operators/impls/follow.ts +++ /dev/null @@ -1,37 +0,0 @@ -import { inject, injectable } from "tsyringe"; -import Operator from "../Operator"; -import OperatorFactoryChain from "../OperatorFactoryChain"; -import FollowMasterClient from "../../client/FollowMasterClient"; -import * as operations from "../../../shared/operations"; - -export class StartFollowOperator implements Operator { - constructor( - private readonly followMasterClient: FollowMasterClient, - private readonly newTab: boolean, - private readonly background: boolean - ) {} - - async run(): Promise { - this.followMasterClient.startFollow(this.newTab, this.background); - } -} - -@injectable() -export class FollowOperatorFactoryChain implements OperatorFactoryChain { - constructor( - @inject("FollowMasterClient") - private followMasterClient: FollowMasterClient - ) {} - - create(op: operations.Operation, _repeat: number): Operator | null { - switch (op.type) { - case operations.FOLLOW_START: - return new StartFollowOperator( - this.followMasterClient, - op.newTab, - op.background - ); - } - return null; - } -} diff --git a/src/content/operators/impls/mark.ts b/src/content/operators/impls/mark.ts deleted file mode 100644 index d90aba9..0000000 --- a/src/content/operators/impls/mark.ts +++ /dev/null @@ -1,39 +0,0 @@ -import { inject, injectable } from "tsyringe"; -import Operator from "../Operator"; -import OperatorFactoryChain from "../OperatorFactoryChain"; -import MarkKeyRepository from "../../repositories/MarkKeyRepository"; -import * as operations from "../../../shared/operations"; - -export class EnableSetMarkOperator implements Operator { - constructor(private readonly repository: MarkKeyRepository) {} - - async run(): Promise { - this.repository.enableSetMode(); - } -} - -export class EnableJumpMarkOperator implements Operator { - constructor(private readonly repository: MarkKeyRepository) {} - - async run(): Promise { - this.repository.enableJumpMode(); - } -} - -@injectable() -export class MarkOperatorFactoryChain implements OperatorFactoryChain { - constructor( - @inject("MarkKeyRepository") - private readonly markKeyRepository: MarkKeyRepository - ) {} - - create(op: operations.Operation, _repeat: number): Operator | null { - switch (op.type) { - case operations.MARK_SET_PREFIX: - return new EnableSetMarkOperator(this.markKeyRepository); - case operations.MARK_JUMP_PREFIX: - return new EnableJumpMarkOperator(this.markKeyRepository); - } - return null; - } -} diff --git a/src/content/operators/impls/scroll.ts b/src/content/operators/impls/scroll.ts deleted file mode 100644 index 96963be..0000000 --- a/src/content/operators/impls/scroll.ts +++ /dev/null @@ -1,183 +0,0 @@ -import { inject, injectable } from "tsyringe"; -import Operator from "../Operator"; -import OperatorFactoryChain from "../OperatorFactoryChain"; -import ScrollPresenter from "../../presenters/ScrollPresenter"; -import SettingRepository from "../../repositories/SettingRepository"; -import * as operations from "../../../shared/operations"; - -class AbstractScrollOperator { - constructor(private readonly settingRepository: SettingRepository) {} - - protected getSmoothScroll(): boolean { - const settings = this.settingRepository.get(); - return settings.properties.smoothscroll; - } -} - -export class VerticalScrollOperator - extends AbstractScrollOperator - implements Operator { - constructor( - private readonly presenter: ScrollPresenter, - settingRepository: SettingRepository, - private readonly count: number - ) { - super(settingRepository); - } - - async run(): Promise { - const smooth = this.getSmoothScroll(); - this.presenter.scrollVertically(this.count, smooth); - } -} - -export class HorizonalScrollOperator - extends AbstractScrollOperator - implements Operator { - constructor( - private readonly presenter: ScrollPresenter, - settingRepository: SettingRepository, - private readonly count: number - ) { - super(settingRepository); - } - - async run(): Promise { - const smooth = this.getSmoothScroll(); - this.presenter.scrollHorizonally(this.count, smooth); - } -} - -export class PageScrollOperator - extends AbstractScrollOperator - implements Operator { - constructor( - private readonly presenter: ScrollPresenter, - settingRepository: SettingRepository, - private readonly count: number - ) { - super(settingRepository); - } - - async run(): Promise { - const smooth = this.getSmoothScroll(); - this.presenter.scrollPages(this.count, smooth); - } -} - -export class ScrollToTopOperator - extends AbstractScrollOperator - implements Operator { - constructor( - private readonly presenter: ScrollPresenter, - settingRepository: SettingRepository - ) { - super(settingRepository); - } - - async run(): Promise { - const smooth = this.getSmoothScroll(); - this.presenter.scrollToTop(smooth); - } -} - -export class ScrollToBottomOperator - extends AbstractScrollOperator - implements Operator { - constructor( - private readonly presenter: ScrollPresenter, - settingRepository: SettingRepository - ) { - super(settingRepository); - } - - async run(): Promise { - const smooth = this.getSmoothScroll(); - this.presenter.scrollToBottom(smooth); - } -} - -export class ScrollToHomeOperator - extends AbstractScrollOperator - implements Operator { - constructor( - private readonly presenter: ScrollPresenter, - settingRepository: SettingRepository - ) { - super(settingRepository); - } - - async run(): Promise { - const smooth = this.getSmoothScroll(); - this.presenter.scrollToHome(smooth); - } -} - -export class ScrollToEndOperator - extends AbstractScrollOperator - implements Operator { - constructor( - private readonly presenter: ScrollPresenter, - settingRepository: SettingRepository - ) { - super(settingRepository); - } - - async run(): Promise { - const smooth = this.getSmoothScroll(); - this.presenter.scrollToEnd(smooth); - } -} - -@injectable() -export class ScrollOperatorFactoryChain implements OperatorFactoryChain { - constructor( - @inject("ScrollPresenter") - private readonly scrollPresenter: ScrollPresenter, - @inject("SettingRepository") - private readonly settingRepository: SettingRepository - ) {} - create(op: operations.Operation, repeat: number): Operator | null { - switch (op.type) { - case operations.SCROLL_VERTICALLY: - return new VerticalScrollOperator( - this.scrollPresenter, - this.settingRepository, - op.count * repeat - ); - case operations.SCROLL_HORIZONALLY: - return new HorizonalScrollOperator( - this.scrollPresenter, - this.settingRepository, - op.count * repeat - ); - case operations.SCROLL_PAGES: - return new PageScrollOperator( - this.scrollPresenter, - this.settingRepository, - op.count * repeat - ); - case operations.SCROLL_TOP: - return new ScrollToTopOperator( - this.scrollPresenter, - this.settingRepository - ); - case operations.SCROLL_BOTTOM: - return new ScrollToBottomOperator( - this.scrollPresenter, - this.settingRepository - ); - case operations.SCROLL_HOME: - return new ScrollToHomeOperator( - this.scrollPresenter, - this.settingRepository - ); - case operations.SCROLL_END: - return new ScrollToEndOperator( - this.scrollPresenter, - this.settingRepository - ); - } - return null; - } -} -- cgit v1.2.3 From c523d75472a16dc58e2e4c4ee51eb15efe6c11f9 Mon Sep 17 00:00:00 2001 From: Shin'ya Ueoka Date: Sun, 29 Nov 2020 13:55:26 +0900 Subject: Add operators' test --- src/content/di.ts | 2 + .../impls/ClipboardOperatorFactoryChain.ts | 8 +++- src/content/operators/impls/FindNextOperator.ts | 9 +++- .../operators/impls/FindOperatorFactoryChain.ts | 11 +---- src/content/operators/impls/FindPrevOperator.ts | 9 +++- src/content/operators/impls/RepeatOperator.ts | 14 ------ src/content/operators/impls/URLRepository.ts | 9 ++++ src/content/operators/impls/YankURLOperator.ts | 6 ++- test/content/mock/MockAddonEnabledRepository.ts | 18 ++++++++ test/content/mock/MockAddonIndicatorClient.ts | 13 ++++++ test/content/mock/MockClipboardRepository.ts | 16 +++++++ test/content/mock/MockFindMasterClient.ts | 11 +++++ test/content/mock/MockFocusPresenter.ts | 7 +++ test/content/mock/MockFollowMasterClient.ts | 16 +++++++ test/content/mock/MockMarkKeyRepository.ts | 43 ++++++++++++++++++ test/content/mock/MockOperationClient.ts | 16 +++++++ test/content/mock/MockScrollPresenter.ts | 6 +-- test/content/mock/MockSettingRepository.ts | 20 +++++++++ test/content/mock/MockURLRepository.ts | 9 ++++ .../impls/AddonOperatorFactoryChain.test.ts | 29 ++++++++++++ .../impls/BackgroundOperationOperator.test.ts | 38 ++++++++++++++++ .../impls/ClipboardOperatorFactoryChain.test.ts | 31 +++++++++++++ .../operators/impls/DisableAddonOperator.test.ts | 19 ++++++++ .../operators/impls/EnableAddonOperator.test.ts | 19 ++++++++ .../operators/impls/EnableJumpMarkOperator.test.ts | 19 ++++++++ .../operators/impls/EnableSetMarkOperator.test.ts | 19 ++++++++ .../operators/impls/FindNextOperator.test.ts | 17 ++++++++ .../impls/FindOperatorFactoryChain.test.ts | 21 +++++++++ .../operators/impls/FindPrevOperator.test.ts | 17 ++++++++ test/content/operators/impls/FocusOperator.test.ts | 17 ++++++++ .../impls/FocusOperatorFactoryChain.test.ts | 17 ++++++++ .../impls/FollowOperatorFactoryChain.test.ts | 20 +++++++++ .../impls/HorizontalScrollOperator.test.ts | 28 ++++++++++++ .../impls/MarkOperatorFactoryChain.test.ts | 21 +++++++++ .../operators/impls/PageScrollOperator.test.ts | 28 ++++++++++++ test/content/operators/impls/PasteOperator.test.ts | 51 ++++++++++++++++++++++ .../impls/ScrollOperatorFactoryChain.test.ts | 46 +++++++++++++++++++ .../operators/impls/ScrollToBottomOperator.test.ts | 18 ++++++++ .../operators/impls/ScrollToEndOperator.test.ts | 18 ++++++++ .../operators/impls/ScrollToHomeOperator.test.ts | 18 ++++++++ .../operators/impls/ScrollToTopOperator.test.ts | 18 ++++++++ .../operators/impls/StartFollowOperator.test.ts | 20 +++++++++ .../operators/impls/ToggleAddonOperator.test.ts | 24 ++++++++++ .../operators/impls/VerticalScrollOperator.test.ts | 28 ++++++++++++ .../operators/impls/YankURLOperator.test.ts | 26 +++++++++++ 45 files changed, 836 insertions(+), 34 deletions(-) delete mode 100644 src/content/operators/impls/RepeatOperator.ts create mode 100644 src/content/operators/impls/URLRepository.ts create mode 100644 test/content/mock/MockAddonEnabledRepository.ts create mode 100644 test/content/mock/MockAddonIndicatorClient.ts create mode 100644 test/content/mock/MockClipboardRepository.ts create mode 100644 test/content/mock/MockFindMasterClient.ts create mode 100644 test/content/mock/MockFocusPresenter.ts create mode 100644 test/content/mock/MockFollowMasterClient.ts create mode 100644 test/content/mock/MockMarkKeyRepository.ts create mode 100644 test/content/mock/MockOperationClient.ts create mode 100644 test/content/mock/MockSettingRepository.ts create mode 100644 test/content/mock/MockURLRepository.ts create mode 100644 test/content/operators/impls/AddonOperatorFactoryChain.test.ts create mode 100644 test/content/operators/impls/BackgroundOperationOperator.test.ts create mode 100644 test/content/operators/impls/ClipboardOperatorFactoryChain.test.ts create mode 100644 test/content/operators/impls/DisableAddonOperator.test.ts create mode 100644 test/content/operators/impls/EnableAddonOperator.test.ts create mode 100644 test/content/operators/impls/EnableJumpMarkOperator.test.ts create mode 100644 test/content/operators/impls/EnableSetMarkOperator.test.ts create mode 100644 test/content/operators/impls/FindNextOperator.test.ts create mode 100644 test/content/operators/impls/FindOperatorFactoryChain.test.ts create mode 100644 test/content/operators/impls/FindPrevOperator.test.ts create mode 100644 test/content/operators/impls/FocusOperator.test.ts create mode 100644 test/content/operators/impls/FocusOperatorFactoryChain.test.ts create mode 100644 test/content/operators/impls/FollowOperatorFactoryChain.test.ts create mode 100644 test/content/operators/impls/HorizontalScrollOperator.test.ts create mode 100644 test/content/operators/impls/MarkOperatorFactoryChain.test.ts create mode 100644 test/content/operators/impls/PageScrollOperator.test.ts create mode 100644 test/content/operators/impls/PasteOperator.test.ts create mode 100644 test/content/operators/impls/ScrollOperatorFactoryChain.test.ts create mode 100644 test/content/operators/impls/ScrollToBottomOperator.test.ts create mode 100644 test/content/operators/impls/ScrollToEndOperator.test.ts create mode 100644 test/content/operators/impls/ScrollToHomeOperator.test.ts create mode 100644 test/content/operators/impls/ScrollToTopOperator.test.ts create mode 100644 test/content/operators/impls/StartFollowOperator.test.ts create mode 100644 test/content/operators/impls/ToggleAddonOperator.test.ts create mode 100644 test/content/operators/impls/VerticalScrollOperator.test.ts create mode 100644 test/content/operators/impls/YankURLOperator.test.ts (limited to 'src/content/operators') diff --git a/src/content/di.ts b/src/content/di.ts index b39ce54..e74d7ac 100644 --- a/src/content/di.ts +++ b/src/content/di.ts @@ -30,6 +30,7 @@ import { SettingRepositoryImpl } from "./repositories/SettingRepository"; import { TabsClientImpl } from "./client/TabsClient"; import { container } from "tsyringe"; import OperatorFactoryImpl from "./operators/impls/OperatorFactoryImpl"; +import { URLRepositoryImpl } from "./operators/impls/URLRepository"; container.register("FollowMasterClient", { useValue: new FollowMasterClientImpl(window.top), @@ -80,5 +81,6 @@ container.register("OperationClient", { useClass: OperationClientImpl }); container.register("ScrollPresenter", { useClass: ScrollPresenterImpl }); container.register("SettingClient", { useClass: SettingClientImpl }); container.register("SettingRepository", { useClass: SettingRepositoryImpl }); +container.register("URLRepository", { useClass: URLRepositoryImpl }); container.register("TabsClient", { useClass: TabsClientImpl }); container.register("OperatorFactory", { useClass: OperatorFactoryImpl }); diff --git a/src/content/operators/impls/ClipboardOperatorFactoryChain.ts b/src/content/operators/impls/ClipboardOperatorFactoryChain.ts index fb12ae8..454aea1 100644 --- a/src/content/operators/impls/ClipboardOperatorFactoryChain.ts +++ b/src/content/operators/impls/ClipboardOperatorFactoryChain.ts @@ -8,6 +8,7 @@ import ConsoleClient from "../../client/ConsoleClient"; import OperationClient from "../../client/OperationClient"; import SettingRepository from "../../repositories/SettingRepository"; import * as operations from "../../../shared/operations"; +import URLRepository from "./URLRepository"; @injectable() export default class ClipboardOperatorFactoryChain @@ -20,7 +21,9 @@ export default class ClipboardOperatorFactoryChain @inject("OperationClient") private readonly operationClinet: OperationClient, @inject("SettingRepository") - private readonly settingRepository: SettingRepository + private readonly settingRepository: SettingRepository, + @inject("URLRepository") + private readonly urlRepository: URLRepository ) {} create(op: operations.Operation, _repeat: number): Operator | null { @@ -28,7 +31,8 @@ export default class ClipboardOperatorFactoryChain case operations.URLS_YANK: return new YankURLOperator( this.clipboardRepository, - this.consoleClient + this.consoleClient, + this.urlRepository ); case operations.URLS_PASTE: return new PasteOperator( diff --git a/src/content/operators/impls/FindNextOperator.ts b/src/content/operators/impls/FindNextOperator.ts index 723db3d..c67f6d9 100644 --- a/src/content/operators/impls/FindNextOperator.ts +++ b/src/content/operators/impls/FindNextOperator.ts @@ -2,9 +2,14 @@ import Operator from "../Operator"; import FindMasterClient from "../../client/FindMasterClient"; export default class FindNextOperator implements Operator { - constructor(private readonly findMasterClient: FindMasterClient) {} + constructor( + private readonly findMasterClient: FindMasterClient, + private readonly repeat: number + ) {} async run(): Promise { - this.findMasterClient.findNext(); + for (let i = 0; i < this.repeat; ++i) { + this.findMasterClient.findNext(); + } } } diff --git a/src/content/operators/impls/FindOperatorFactoryChain.ts b/src/content/operators/impls/FindOperatorFactoryChain.ts index ef1c754..b3524c1 100644 --- a/src/content/operators/impls/FindOperatorFactoryChain.ts +++ b/src/content/operators/impls/FindOperatorFactoryChain.ts @@ -1,7 +1,6 @@ import { inject, injectable } from "tsyringe"; import Operator from "../Operator"; import OperatorFactoryChain from "../OperatorFactoryChain"; -import RepeatOperator from "./RepeatOperator"; import FindNextOperator from "./FindNextOperator"; import FindPrevOperator from "./FindPrevOperator"; import FindMasterClient from "../../client/FindMasterClient"; @@ -17,15 +16,9 @@ export default class FindOperatorFactoryChain implements OperatorFactoryChain { create(op: operations.Operation, repeat: number): Operator | null { switch (op.type) { case operations.FIND_NEXT: - return new RepeatOperator( - new FindNextOperator(this.findMasterClient), - repeat - ); + return new FindNextOperator(this.findMasterClient, repeat); case operations.FIND_PREV: - return new RepeatOperator( - new FindPrevOperator(this.findMasterClient), - repeat - ); + return new FindPrevOperator(this.findMasterClient, repeat); } return null; } diff --git a/src/content/operators/impls/FindPrevOperator.ts b/src/content/operators/impls/FindPrevOperator.ts index be6a01e..f73e605 100644 --- a/src/content/operators/impls/FindPrevOperator.ts +++ b/src/content/operators/impls/FindPrevOperator.ts @@ -2,9 +2,14 @@ import Operator from "../Operator"; import FindMasterClient from "../../client/FindMasterClient"; export default class FindPrevOperator implements Operator { - constructor(private readonly findMasterClient: FindMasterClient) {} + constructor( + private readonly findMasterClient: FindMasterClient, + private readonly repeat: number + ) {} async run(): Promise { - this.findMasterClient.findPrev(); + for (let i = 0; i < this.repeat; ++i) { + this.findMasterClient.findPrev(); + } } } diff --git a/src/content/operators/impls/RepeatOperator.ts b/src/content/operators/impls/RepeatOperator.ts deleted file mode 100644 index efe2faf..0000000 --- a/src/content/operators/impls/RepeatOperator.ts +++ /dev/null @@ -1,14 +0,0 @@ -import Operator from "../Operator"; - -export default class RepeatOperator implements Operator { - constructor( - private readonly operator: Operator, - private readonly repeat: number - ) {} - - async run(): Promise { - for (let i = 0; i < this.repeat; ++i) { - this.operator.run(); - } - } -} diff --git a/src/content/operators/impls/URLRepository.ts b/src/content/operators/impls/URLRepository.ts new file mode 100644 index 0000000..a1efc2e --- /dev/null +++ b/src/content/operators/impls/URLRepository.ts @@ -0,0 +1,9 @@ +export default interface URLRepository { + getCurrentURL(): string; +} + +export class URLRepositoryImpl implements URLRepository { + getCurrentURL(): string { + return window.location.href; + } +} diff --git a/src/content/operators/impls/YankURLOperator.ts b/src/content/operators/impls/YankURLOperator.ts index 5e2ac60..2e774eb 100644 --- a/src/content/operators/impls/YankURLOperator.ts +++ b/src/content/operators/impls/YankURLOperator.ts @@ -1,15 +1,17 @@ import Operator from "../Operator"; import ClipboardRepository from "../../repositories/ClipboardRepository"; import ConsoleClient from "../../client/ConsoleClient"; +import URLRepository from "./URLRepository"; export default class YankURLOperator implements Operator { constructor( private readonly repository: ClipboardRepository, - private readonly consoleClient: ConsoleClient + private readonly consoleClient: ConsoleClient, + private readonly urlRepository: URLRepository ) {} async run(): Promise { - const url = window.location.href; + const url = this.urlRepository.getCurrentURL(); this.repository.write(url); await this.consoleClient.info("Yanked " + url); } diff --git a/test/content/mock/MockAddonEnabledRepository.ts b/test/content/mock/MockAddonEnabledRepository.ts new file mode 100644 index 0000000..cbe248b --- /dev/null +++ b/test/content/mock/MockAddonEnabledRepository.ts @@ -0,0 +1,18 @@ +import AddonEnabledRepository from "../../../src/content/repositories/AddonEnabledRepository"; + +export default class MockAddonEnabledRepository + implements AddonEnabledRepository { + public enabled: boolean; + + constructor(initialValue = false) { + this.enabled = initialValue; + } + + get(): boolean { + return this.enabled; + } + + set(on: boolean): void { + this.enabled = on; + } +} diff --git a/test/content/mock/MockAddonIndicatorClient.ts b/test/content/mock/MockAddonIndicatorClient.ts new file mode 100644 index 0000000..6ea9798 --- /dev/null +++ b/test/content/mock/MockAddonIndicatorClient.ts @@ -0,0 +1,13 @@ +import AddonIndicatorClient from "../../../src/content/client/AddonIndicatorClient"; + +export default class MockAddonIndicatorClient implements AddonIndicatorClient { + public enabled: boolean; + + constructor(initialValue = false) { + this.enabled = initialValue; + } + + async setEnabled(enabled: boolean): Promise { + this.enabled = enabled; + } +} diff --git a/test/content/mock/MockClipboardRepository.ts b/test/content/mock/MockClipboardRepository.ts new file mode 100644 index 0000000..c6e53bd --- /dev/null +++ b/test/content/mock/MockClipboardRepository.ts @@ -0,0 +1,16 @@ +import ClipboardRepository from "../../../src/content/repositories/ClipboardRepository"; + +export default class MockClipboardRepository implements ClipboardRepository { + private value: string; + + constructor(initValue = "") { + this.value = initValue; + } + read(): string { + return this.value; + } + + write(text: string): void { + this.value = text; + } +} diff --git a/test/content/mock/MockFindMasterClient.ts b/test/content/mock/MockFindMasterClient.ts new file mode 100644 index 0000000..a035cc5 --- /dev/null +++ b/test/content/mock/MockFindMasterClient.ts @@ -0,0 +1,11 @@ +import FindMasterClient from "../../../src/content/client/FindMasterClient"; + +export default class MockFindMasterClient implements FindMasterClient { + findNext(): void { + throw new Error("not implemented"); + } + + findPrev(): void { + throw new Error("not implemented"); + } +} diff --git a/test/content/mock/MockFocusPresenter.ts b/test/content/mock/MockFocusPresenter.ts new file mode 100644 index 0000000..43454d0 --- /dev/null +++ b/test/content/mock/MockFocusPresenter.ts @@ -0,0 +1,7 @@ +import FocusPresenter from "../../../src/content/presenters/FocusPresenter"; + +export default class MockFocusPresenter implements FocusPresenter { + focusFirstElement(): boolean { + throw new Error("not implemented"); + } +} diff --git a/test/content/mock/MockFollowMasterClient.ts b/test/content/mock/MockFollowMasterClient.ts new file mode 100644 index 0000000..fc660d5 --- /dev/null +++ b/test/content/mock/MockFollowMasterClient.ts @@ -0,0 +1,16 @@ +import FollowMasterClient from "../../../src/content/client/FollowMasterClient"; +import Key from "../../../src/shared/settings/Key"; + +export default class MockFollowMasterClient implements FollowMasterClient { + responseHintCount(_count: number): void { + throw new Error("not implemented"); + } + + sendKey(_key: Key): void { + throw new Error("not implemented"); + } + + startFollow(_newTab: boolean, _background: boolean): void { + throw new Error("not implemented"); + } +} diff --git a/test/content/mock/MockMarkKeyRepository.ts b/test/content/mock/MockMarkKeyRepository.ts new file mode 100644 index 0000000..12bc75c --- /dev/null +++ b/test/content/mock/MockMarkKeyRepository.ts @@ -0,0 +1,43 @@ +import MarkKeyRepository from "../../../src/content/repositories/MarkKeyRepository"; + +export default class MockMarkKeyRepository implements MarkKeyRepository { + public jumpMode: boolean; + public setMode: boolean; + + constructor( + initialValue: { + jumpMode: boolean; + setMode: boolean; + } = { + jumpMode: false, + setMode: false, + } + ) { + this.jumpMode = initialValue.jumpMode; + this.setMode = initialValue.setMode; + } + + disabeJumpMode(): void { + this.jumpMode = false; + } + + disabeSetMode(): void { + this.setMode = false; + } + + enableJumpMode(): void { + this.jumpMode = true; + } + + enableSetMode(): void { + this.setMode = true; + } + + isJumpMode(): boolean { + return this.jumpMode; + } + + isSetMode(): boolean { + return this.setMode; + } +} diff --git a/test/content/mock/MockOperationClient.ts b/test/content/mock/MockOperationClient.ts new file mode 100644 index 0000000..2f50f77 --- /dev/null +++ b/test/content/mock/MockOperationClient.ts @@ -0,0 +1,16 @@ +import OperationClient from "../../../src/content/client/OperationClient"; +import * as operations from "../../../src/shared/operations"; + +export default class MockOperationClient implements OperationClient { + execBackgroundOp(_repeat: number, _op: operations.Operation): Promise { + throw new Error("not implemented"); + } + + internalOpenUrl( + _url: string, + _newTab?: boolean, + _background?: boolean + ): Promise { + throw new Error("not implemented"); + } +} diff --git a/test/content/mock/MockScrollPresenter.ts b/test/content/mock/MockScrollPresenter.ts index c802227..8b4cf2a 100644 --- a/test/content/mock/MockScrollPresenter.ts +++ b/test/content/mock/MockScrollPresenter.ts @@ -3,10 +3,10 @@ import ScrollPresenter, { } from "../../../src/content/presenters/ScrollPresenter"; export default class MockScrollPresenter implements ScrollPresenter { - private pos: Point; + private readonly pos: Point; - constructor() { - this.pos = { x: 0, y: 0 }; + constructor(initX = 0, initY = 0) { + this.pos = { x: initX, y: initY }; } getScroll(): Point { diff --git a/test/content/mock/MockSettingRepository.ts b/test/content/mock/MockSettingRepository.ts new file mode 100644 index 0000000..5242713 --- /dev/null +++ b/test/content/mock/MockSettingRepository.ts @@ -0,0 +1,20 @@ +import SettingRepository from "../../../src/content/repositories/SettingRepository"; +import Settings, { + DefaultSetting, +} from "../../../src/shared/settings/Settings"; + +export default class MockSettingRepository implements SettingRepository { + private value: Settings; + + constructor(initValue: Settings = DefaultSetting) { + this.value = initValue; + } + + get(): Settings { + return this.value; + } + + set(setting: Settings): void { + this.value = setting; + } +} diff --git a/test/content/mock/MockURLRepository.ts b/test/content/mock/MockURLRepository.ts new file mode 100644 index 0000000..731a7fb --- /dev/null +++ b/test/content/mock/MockURLRepository.ts @@ -0,0 +1,9 @@ +import URLRepository from "../../../src/content/operators/impls/URLRepository"; + +export default class MockURLRepository implements URLRepository { + constructor(private url: string = "https://example.com/") {} + + getCurrentURL(): string { + return this.url; + } +} diff --git a/test/content/operators/impls/AddonOperatorFactoryChain.test.ts b/test/content/operators/impls/AddonOperatorFactoryChain.test.ts new file mode 100644 index 0000000..c064bb9 --- /dev/null +++ b/test/content/operators/impls/AddonOperatorFactoryChain.test.ts @@ -0,0 +1,29 @@ +import AddonOperatorFactoryChain from "../../../../src/content/operators/impls/AddonOperatorFactoryChain"; +import EnableAddonOperator from "../../../../src/content/operators/impls/EnableAddonOperator"; +import DisableAddonOperator from "../../../../src/content/operators/impls/DisableAddonOperator"; +import ToggleAddonOperator from "../../../../src/content/operators/impls/ToggleAddonOperator"; +import * as operations from "../../../../src/shared/operations"; +import { expect } from "chai"; +import MockAddonIndicatorClient from "../../mock/MockAddonIndicatorClient"; +import MockAddonEnabledRepository from "../../mock/MockAddonEnabledRepository"; + +describe("AddonOperatorFactoryChain", () => { + describe("#create", () => { + it("returns an operator", () => { + const sut = new AddonOperatorFactoryChain( + new MockAddonIndicatorClient(), + new MockAddonEnabledRepository() + ); + expect(sut.create({ type: operations.ADDON_ENABLE }, 0)).to.be.instanceOf( + EnableAddonOperator + ); + expect( + sut.create({ type: operations.ADDON_DISABLE }, 0) + ).to.be.instanceOf(DisableAddonOperator); + expect( + sut.create({ type: operations.ADDON_TOGGLE_ENABLED }, 0) + ).to.be.instanceOf(ToggleAddonOperator); + expect(sut.create({ type: operations.SCROLL_TOP }, 0)).to.be.null; + }); + }); +}); diff --git a/test/content/operators/impls/BackgroundOperationOperator.test.ts b/test/content/operators/impls/BackgroundOperationOperator.test.ts new file mode 100644 index 0000000..b8b1fbd --- /dev/null +++ b/test/content/operators/impls/BackgroundOperationOperator.test.ts @@ -0,0 +1,38 @@ +import * as operations from "../../../../src/shared/operations"; +import BackgroundOperationOperator from "../../../../src/content/operators/impls/BackgroundOperationOperator"; +import OperationClient from "../../../../src/content/client/OperationClient"; +import { expect } from "chai"; + +class MockOperationClient implements OperationClient { + public readonly executedOps: { + op: operations.Operation; + repeat: number; + }[] = []; + async execBackgroundOp( + repeat: number, + op: operations.Operation + ): Promise { + this.executedOps.push({ repeat, op }); + } + + internalOpenUrl(): Promise { + throw new Error("not implemented"); + } +} + +describe("BackgroundOperationOperator", () => { + describe("#run", () => { + it("returns an operator", async () => { + const client = new MockOperationClient(); + const sut = new BackgroundOperationOperator(client, 2, { + type: operations.TAB_CLOSE, + }); + + await sut.run(); + + expect(client.executedOps).to.deep.equal([ + { op: { type: operations.TAB_CLOSE }, repeat: 2 }, + ]); + }); + }); +}); diff --git a/test/content/operators/impls/ClipboardOperatorFactoryChain.test.ts b/test/content/operators/impls/ClipboardOperatorFactoryChain.test.ts new file mode 100644 index 0000000..9ddc229 --- /dev/null +++ b/test/content/operators/impls/ClipboardOperatorFactoryChain.test.ts @@ -0,0 +1,31 @@ +import * as operations from "../../../../src/shared/operations"; +import { expect } from "chai"; +import ClipboardOperatorFactoryChain from "../../../../src/content/operators/impls/ClipboardOperatorFactoryChain"; +import YankURLOperator from "../../../../src/content/operators/impls/YankURLOperator"; +import PasteOperator from "../../../../src/content/operators/impls/PasteOperator"; +import MockClipboardRepository from "../../mock/MockClipboardRepository"; +import MockOperationClient from "../../mock/MockOperationClient"; +import MockSettingRepository from "../../mock/MockSettingRepository"; +import MockConsoleClient from "../../mock/MockConsoleClient"; +import MockURLRepository from "../../mock/MockURLRepository"; + +describe("ClipboardOperatorFactoryChain", () => { + describe("#create", () => { + it("returns an operator", () => { + const sut = new ClipboardOperatorFactoryChain( + new MockClipboardRepository(), + new MockConsoleClient(), + new MockOperationClient(), + new MockSettingRepository(), + new MockURLRepository() + ); + expect(sut.create({ type: operations.URLS_YANK }, 0)).to.be.instanceOf( + YankURLOperator + ); + expect( + sut.create({ type: operations.URLS_PASTE, newTab: false }, 0) + ).to.be.instanceOf(PasteOperator); + expect(sut.create({ type: operations.SCROLL_TOP }, 0)).to.be.null; + }); + }); +}); diff --git a/test/content/operators/impls/DisableAddonOperator.test.ts b/test/content/operators/impls/DisableAddonOperator.test.ts new file mode 100644 index 0000000..358ae44 --- /dev/null +++ b/test/content/operators/impls/DisableAddonOperator.test.ts @@ -0,0 +1,19 @@ +import { expect } from "chai"; +import DisableAddonOperator from "../../../../src/content/operators/impls/DisableAddonOperator"; +import MockAddonIndicatorClient from "../../mock/MockAddonIndicatorClient"; +import MockAddonEnabledRepository from "../../mock/MockAddonEnabledRepository"; + +describe("DisableAddonOperator", () => { + describe("#run", () => { + it("disables addon", async () => { + const client = new MockAddonIndicatorClient(true); + const repository = new MockAddonEnabledRepository(true); + const sut = new DisableAddonOperator(client, repository); + + await sut.run(); + + expect(client.enabled).to.be.false; + expect(repository.enabled).to.be.false; + }); + }); +}); diff --git a/test/content/operators/impls/EnableAddonOperator.test.ts b/test/content/operators/impls/EnableAddonOperator.test.ts new file mode 100644 index 0000000..a6ca31b --- /dev/null +++ b/test/content/operators/impls/EnableAddonOperator.test.ts @@ -0,0 +1,19 @@ +import { expect } from "chai"; +import EnableAddonOperator from "../../../../src/content/operators/impls/EnableAddonOperator"; +import MockAddonIndicatorClient from "../../mock/MockAddonIndicatorClient"; +import MockAddonEnabledRepository from "../../mock/MockAddonEnabledRepository"; + +describe("EnableAddonOperator", () => { + describe("#run", () => { + it("enabled addon", async () => { + const client = new MockAddonIndicatorClient(false); + const repository = new MockAddonEnabledRepository(false); + const sut = new EnableAddonOperator(client, repository); + + await sut.run(); + + expect(client.enabled).to.be.true; + expect(repository.enabled).to.be.true; + }); + }); +}); diff --git a/test/content/operators/impls/EnableJumpMarkOperator.test.ts b/test/content/operators/impls/EnableJumpMarkOperator.test.ts new file mode 100644 index 0000000..66b4ecd --- /dev/null +++ b/test/content/operators/impls/EnableJumpMarkOperator.test.ts @@ -0,0 +1,19 @@ +import { expect } from "chai"; +import EnableJumpMarkOperator from "../../../../src/content/operators/impls/EnableJumpMarkOperator"; +import MockMarkKeyRepository from "../../mock/MockMarkKeyRepository"; + +describe("EnableJumpMarkOperator", () => { + describe("#run", () => { + it("starts mark jump mode", async () => { + const repository = new MockMarkKeyRepository({ + jumpMode: false, + setMode: false, + }); + const sut = new EnableJumpMarkOperator(repository); + + await sut.run(); + + expect(repository.jumpMode).to.be.true; + }); + }); +}); diff --git a/test/content/operators/impls/EnableSetMarkOperator.test.ts b/test/content/operators/impls/EnableSetMarkOperator.test.ts new file mode 100644 index 0000000..b28874d --- /dev/null +++ b/test/content/operators/impls/EnableSetMarkOperator.test.ts @@ -0,0 +1,19 @@ +import { expect } from "chai"; +import EnableSetMarkOperator from "../../../../src/content/operators/impls/EnableSetMarkOperator"; +import MockMarkKeyRepository from "../../mock/MockMarkKeyRepository"; + +describe("EnableSetMarkOperator", () => { + describe("#run", () => { + it("starts mark set mode", async () => { + const repository = new MockMarkKeyRepository({ + jumpMode: false, + setMode: false, + }); + const sut = new EnableSetMarkOperator(repository); + + await sut.run(); + + expect(repository.setMode).to.be.true; + }); + }); +}); diff --git a/test/content/operators/impls/FindNextOperator.test.ts b/test/content/operators/impls/FindNextOperator.test.ts new file mode 100644 index 0000000..d93d45e --- /dev/null +++ b/test/content/operators/impls/FindNextOperator.test.ts @@ -0,0 +1,17 @@ +import sinon from "sinon"; +import FindNextOperator from "../../../../src/content/operators/impls/FindNextOperator"; +import MockFindMasterClient from "../../mock/MockFindMasterClient"; + +describe("FindNextOperator", () => { + describe("#run", () => { + it("find next keyword", async () => { + const client = new MockFindMasterClient(); + const mock = sinon.mock(client).expects("findNext").exactly(3); + const sut = new FindNextOperator(client, 3); + + await sut.run(); + + mock.verify(); + }); + }); +}); diff --git a/test/content/operators/impls/FindOperatorFactoryChain.test.ts b/test/content/operators/impls/FindOperatorFactoryChain.test.ts new file mode 100644 index 0000000..6c599ae --- /dev/null +++ b/test/content/operators/impls/FindOperatorFactoryChain.test.ts @@ -0,0 +1,21 @@ +import * as operations from "../../../../src/shared/operations"; +import { expect } from "chai"; +import FindOperatorFactoryChain from "../../../../src/content/operators/impls/FindOperatorFactoryChain"; +import MockFindMasterClient from "../../mock/MockFindMasterClient"; +import FindNextOperator from "../../../../src/content/operators/impls/FindNextOperator"; +import FindPrevOperator from "../../../../src/content/operators/impls/FindPrevOperator"; + +describe("FindOperatorFactoryChain", () => { + describe("#create", () => { + it("returns an operator", () => { + const sut = new FindOperatorFactoryChain(new MockFindMasterClient()); + expect(sut.create({ type: operations.FIND_NEXT }, 0)).to.be.instanceOf( + FindNextOperator + ); + expect(sut.create({ type: operations.FIND_PREV }, 0)).to.be.instanceOf( + FindPrevOperator + ); + expect(sut.create({ type: operations.SCROLL_TOP }, 0)).to.be.null; + }); + }); +}); diff --git a/test/content/operators/impls/FindPrevOperator.test.ts b/test/content/operators/impls/FindPrevOperator.test.ts new file mode 100644 index 0000000..1ebde8d --- /dev/null +++ b/test/content/operators/impls/FindPrevOperator.test.ts @@ -0,0 +1,17 @@ +import sinon from "sinon"; +import FindPrevOperator from "../../../../src/content/operators/impls/FindPrevOperator"; +import MockFindMasterClient from "../../mock/MockFindMasterClient"; + +describe("FindPrevOperator", () => { + describe("#run", () => { + it("find previous keyword", async () => { + const client = new MockFindMasterClient(); + const mock = sinon.mock(client).expects("findPrev").exactly(3); + const sut = new FindPrevOperator(client, 3); + + await sut.run(); + + mock.verify(); + }); + }); +}); diff --git a/test/content/operators/impls/FocusOperator.test.ts b/test/content/operators/impls/FocusOperator.test.ts new file mode 100644 index 0000000..a0eb53b --- /dev/null +++ b/test/content/operators/impls/FocusOperator.test.ts @@ -0,0 +1,17 @@ +import sinon from "sinon"; +import FocusOperator from "../../../../src/content/operators/impls/FocusOperator"; +import MockFocusPresenter from "../../mock/MockFocusPresenter"; + +describe("FocusOperator", () => { + describe("#run", () => { + it("focus a first input", async () => { + const presenter = new MockFocusPresenter(); + const mock = sinon.mock(presenter).expects("focusFirstElement"); + const sut = new FocusOperator(presenter); + + await sut.run(); + + mock.verify(); + }); + }); +}); diff --git a/test/content/operators/impls/FocusOperatorFactoryChain.test.ts b/test/content/operators/impls/FocusOperatorFactoryChain.test.ts new file mode 100644 index 0000000..91f734b --- /dev/null +++ b/test/content/operators/impls/FocusOperatorFactoryChain.test.ts @@ -0,0 +1,17 @@ +import * as operations from "../../../../src/shared/operations"; +import { expect } from "chai"; +import FocusOperatorFactoryChain from "../../../../src/content/operators/impls/FocusOperatorFactoryChain"; +import FocusOperator from "../../../../src/content/operators/impls/FocusOperator"; +import MockFocusPresenter from "../../mock/MockFocusPresenter"; + +describe("FocusOperatorFactoryChain", () => { + describe("#create", () => { + it("returns an operator", () => { + const sut = new FocusOperatorFactoryChain(new MockFocusPresenter()); + expect(sut.create({ type: operations.FOCUS_INPUT }, 0)).to.be.instanceOf( + FocusOperator + ); + expect(sut.create({ type: operations.SCROLL_TOP }, 0)).to.be.null; + }); + }); +}); diff --git a/test/content/operators/impls/FollowOperatorFactoryChain.test.ts b/test/content/operators/impls/FollowOperatorFactoryChain.test.ts new file mode 100644 index 0000000..526a93c --- /dev/null +++ b/test/content/operators/impls/FollowOperatorFactoryChain.test.ts @@ -0,0 +1,20 @@ +import * as operations from "../../../../src/shared/operations"; +import { expect } from "chai"; +import FocusOperatorFactoryChain from "../../../../src/content/operators/impls/FocusOperatorFactoryChain"; +import FocusOperator from "../../../../src/content/operators/impls/FocusOperator"; +import MockFocusPresenter from "../../mock/MockFocusPresenter"; + +describe("FocusOperatorFactoryChain", () => { + describe("#create", () => { + it("returns an operator", () => { + const sut = new FocusOperatorFactoryChain(new MockFocusPresenter()); + expect( + sut.create( + { type: operations.FOCUS_INPUT, newTab: false, background: false }, + 0 + ) + ).to.be.instanceOf(FocusOperator); + expect(sut.create({ type: operations.SCROLL_TOP }, 0)).to.be.null; + }); + }); +}); diff --git a/test/content/operators/impls/HorizontalScrollOperator.test.ts b/test/content/operators/impls/HorizontalScrollOperator.test.ts new file mode 100644 index 0000000..f77a34e --- /dev/null +++ b/test/content/operators/impls/HorizontalScrollOperator.test.ts @@ -0,0 +1,28 @@ +import { expect } from "chai"; +import HorizontalScrollOperator from "../../../../src/content/operators/impls/HorizontalScrollOperator"; +import MockScrollPresenter from "../../mock/MockScrollPresenter"; +import MockSettingRepository from "../../mock/MockSettingRepository"; + +describe("HorizontalScrollOperator", () => { + describe("#run", () => { + it("scroll horizontally", async () => { + const presenter = new MockScrollPresenter(); + const settingRepository = new MockSettingRepository(); + const sut = new HorizontalScrollOperator(presenter, settingRepository, 1); + + await sut.run(); + + expect(presenter.getScroll()).to.deep.equal({ x: 1, y: 0 }); + }); + + it("scroll horizontally with repeats", async () => { + const presenter = new MockScrollPresenter(); + const settingRepository = new MockSettingRepository(); + const sut = new HorizontalScrollOperator(presenter, settingRepository, 5); + + await sut.run(); + + expect(presenter.getScroll()).to.deep.equal({ x: 5, y: 0 }); + }); + }); +}); diff --git a/test/content/operators/impls/MarkOperatorFactoryChain.test.ts b/test/content/operators/impls/MarkOperatorFactoryChain.test.ts new file mode 100644 index 0000000..1f094dd --- /dev/null +++ b/test/content/operators/impls/MarkOperatorFactoryChain.test.ts @@ -0,0 +1,21 @@ +import * as operations from "../../../../src/shared/operations"; +import { expect } from "chai"; +import MarkOperatorFactoryChain from "../../../../src/content/operators/impls/MarkOperatorFactoryChain"; +import MockMarkKeyRepository from "../../mock/MockMarkKeyRepository"; +import EnableSetMarkOperator from "../../../../src/content/operators/impls/EnableSetMarkOperator"; +import EnableJumpMarkOperator from "../../../../src/content/operators/impls/EnableJumpMarkOperator"; + +describe("MarkOperatorFactoryChain", () => { + describe("#create", () => { + it("returns an operator", () => { + const sut = new MarkOperatorFactoryChain(new MockMarkKeyRepository()); + expect( + sut.create({ type: operations.MARK_SET_PREFIX }, 0) + ).to.be.instanceOf(EnableSetMarkOperator); + expect( + sut.create({ type: operations.MARK_JUMP_PREFIX }, 0) + ).to.be.instanceOf(EnableJumpMarkOperator); + expect(sut.create({ type: operations.SCROLL_TOP }, 0)).to.be.null; + }); + }); +}); diff --git a/test/content/operators/impls/PageScrollOperator.test.ts b/test/content/operators/impls/PageScrollOperator.test.ts new file mode 100644 index 0000000..80c9185 --- /dev/null +++ b/test/content/operators/impls/PageScrollOperator.test.ts @@ -0,0 +1,28 @@ +import { expect } from "chai"; +import PageScrollOperator from "../../../../src/content/operators/impls/PageScrollOperator"; +import MockScrollPresenter from "../../mock/MockScrollPresenter"; +import MockSettingRepository from "../../mock/MockSettingRepository"; + +describe("PageScrollOperator", () => { + describe("#run", () => { + it("scroll by a page", async () => { + const presenter = new MockScrollPresenter(); + const settingRepository = new MockSettingRepository(); + const sut = new PageScrollOperator(presenter, settingRepository, 1); + + await sut.run(); + + expect(presenter.getScroll()).to.deep.equal({ x: 1, y: 0 }); + }); + + it("scroll by a page with repeats", async () => { + const presenter = new MockScrollPresenter(); + const settingRepository = new MockSettingRepository(); + const sut = new PageScrollOperator(presenter, settingRepository, 5); + + await sut.run(); + + expect(presenter.getScroll()).to.deep.equal({ x: 5, y: 0 }); + }); + }); +}); diff --git a/test/content/operators/impls/PasteOperator.test.ts b/test/content/operators/impls/PasteOperator.test.ts new file mode 100644 index 0000000..8a3a374 --- /dev/null +++ b/test/content/operators/impls/PasteOperator.test.ts @@ -0,0 +1,51 @@ +import sinon from "sinon"; +import PasteOperator from "../../../../src/content/operators/impls/PasteOperator"; +import MockClipboardRepository from "../../mock/MockClipboardRepository"; +import MockSettingRepository from "../../mock/MockSettingRepository"; +import MockOperationClient from "../../mock/MockOperationClient"; + +describe("PasteOperator", () => { + describe("#run", () => { + it("open a search url", async () => { + const clipboardRepository = new MockClipboardRepository("apple"); + const settingRepository = new MockSettingRepository(); + const operationClient = new MockOperationClient(); + const mockOperationClient = sinon + .mock(operationClient) + .expects("internalOpenUrl") + .withArgs("https://google.com/search?q=apple"); + const sut = new PasteOperator( + clipboardRepository, + settingRepository, + operationClient, + false + ); + + await sut.run(); + + mockOperationClient.verify(); + }); + + it("open a url", async () => { + const clipboardRepository = new MockClipboardRepository( + "https://example.com/" + ); + const settingRepository = new MockSettingRepository(); + const operationClient = new MockOperationClient(); + const mockOperationClient = sinon + .mock(operationClient) + .expects("internalOpenUrl") + .withArgs("https://example.com/"); + const sut = new PasteOperator( + clipboardRepository, + settingRepository, + operationClient, + false + ); + + await sut.run(); + + mockOperationClient.verify(); + }); + }); +}); diff --git a/test/content/operators/impls/ScrollOperatorFactoryChain.test.ts b/test/content/operators/impls/ScrollOperatorFactoryChain.test.ts new file mode 100644 index 0000000..08034cb --- /dev/null +++ b/test/content/operators/impls/ScrollOperatorFactoryChain.test.ts @@ -0,0 +1,46 @@ +import { expect } from "chai"; +import ScrollOperatorFactoryChain from "../../../../src/content/operators/impls/ScrollOperatorFactoryChain"; +import MockScrollPresenter from "../../mock/MockScrollPresenter"; +import MockSettingRepository from "../../mock/MockSettingRepository"; +import HorizontalScrollOperator from "../../../../src/content/operators/impls/HorizontalScrollOperator"; +import VerticalScrollOperator from "../../../../src/content/operators/impls/VerticalScrollOperator"; +import PageScrollOperator from "../../../../src/content/operators/impls/PageScrollOperator"; +import ScrollToTopOperator from "../../../../src/content/operators/impls/ScrollToTopOperator"; +import ScrollToBottomOperator from "../../../../src/content/operators/impls/ScrollToBottomOperator"; +import ScrollToHomeOperator from "../../../../src/content/operators/impls/ScrollToHomeOperator"; +import ScrollToEndOperator from "../../../../src/content/operators/impls/ScrollToEndOperator"; +import * as operations from "../../../../src/shared/operations"; + +describe("ScrollOperatorFactoryChain", () => { + describe("#create", () => { + it("returns an operator", () => { + const sut = new ScrollOperatorFactoryChain( + new MockScrollPresenter(), + new MockSettingRepository() + ); + expect( + sut.create({ type: operations.SCROLL_HORIZONALLY, count: 10 }, 0) + ).to.be.instanceOf(HorizontalScrollOperator); + expect( + sut.create({ type: operations.SCROLL_VERTICALLY, count: 10 }, 0) + ).to.be.instanceOf(VerticalScrollOperator); + expect( + sut.create({ type: operations.SCROLL_PAGES, count: 10 }, 0) + ).to.be.instanceOf(PageScrollOperator); + expect(sut.create({ type: operations.SCROLL_TOP }, 0)).to.be.instanceOf( + ScrollToTopOperator + ); + expect( + sut.create({ type: operations.SCROLL_BOTTOM }, 0) + ).to.be.instanceOf(ScrollToBottomOperator); + expect(sut.create({ type: operations.SCROLL_HOME }, 0)).to.be.instanceOf( + ScrollToHomeOperator + ); + expect(sut.create({ type: operations.SCROLL_END }, 0)).to.be.instanceOf( + ScrollToEndOperator + ); + expect(sut.create({ type: operations.PAGE_HOME, newTab: false }, 0)).to.be + .null; + }); + }); +}); diff --git a/test/content/operators/impls/ScrollToBottomOperator.test.ts b/test/content/operators/impls/ScrollToBottomOperator.test.ts new file mode 100644 index 0000000..500c8f2 --- /dev/null +++ b/test/content/operators/impls/ScrollToBottomOperator.test.ts @@ -0,0 +1,18 @@ +import { expect } from "chai"; +import ScrollToBottomOperator from "../../../../src/content/operators/impls/ScrollToBottomOperator"; +import MockScrollPresenter from "../../mock/MockScrollPresenter"; +import MockSettingRepository from "../../mock/MockSettingRepository"; + +describe("ScrollToBottomOperator", () => { + describe("#run", () => { + it("scroll to bottom", async () => { + const presenter = new MockScrollPresenter(); + const settingRepository = new MockSettingRepository(); + const sut = new ScrollToBottomOperator(presenter, settingRepository); + + await sut.run(); + + expect(presenter.getScroll()).to.deep.equal({ x: 0, y: Infinity }); + }); + }); +}); diff --git a/test/content/operators/impls/ScrollToEndOperator.test.ts b/test/content/operators/impls/ScrollToEndOperator.test.ts new file mode 100644 index 0000000..0c98c8d --- /dev/null +++ b/test/content/operators/impls/ScrollToEndOperator.test.ts @@ -0,0 +1,18 @@ +import { expect } from "chai"; +import ScrollToEndOperator from "../../../../src/content/operators/impls/ScrollToEndOperator"; +import MockScrollPresenter from "../../mock/MockScrollPresenter"; +import MockSettingRepository from "../../mock/MockSettingRepository"; + +describe("ScrollToEndOperator", () => { + describe("#run", () => { + it("scroll to rightmost", async () => { + const presenter = new MockScrollPresenter(); + const settingRepository = new MockSettingRepository(); + const sut = new ScrollToEndOperator(presenter, settingRepository); + + await sut.run(); + + expect(presenter.getScroll()).to.deep.equal({ x: Infinity, y: 0 }); + }); + }); +}); diff --git a/test/content/operators/impls/ScrollToHomeOperator.test.ts b/test/content/operators/impls/ScrollToHomeOperator.test.ts new file mode 100644 index 0000000..f8614d2 --- /dev/null +++ b/test/content/operators/impls/ScrollToHomeOperator.test.ts @@ -0,0 +1,18 @@ +import { expect } from "chai"; +import ScrollToHomeOperator from "../../../../src/content/operators/impls/ScrollToHomeOperator"; +import MockScrollPresenter from "../../mock/MockScrollPresenter"; +import MockSettingRepository from "../../mock/MockSettingRepository"; + +describe("ScrollToHomeOperator", () => { + describe("#run", () => { + it("scroll to leftmost", async () => { + const presenter = new MockScrollPresenter(10, 10); + const settingRepository = new MockSettingRepository(); + const sut = new ScrollToHomeOperator(presenter, settingRepository); + + await sut.run(); + + expect(presenter.getScroll()).to.deep.equal({ x: 0, y: 10 }); + }); + }); +}); diff --git a/test/content/operators/impls/ScrollToTopOperator.test.ts b/test/content/operators/impls/ScrollToTopOperator.test.ts new file mode 100644 index 0000000..25a84ba --- /dev/null +++ b/test/content/operators/impls/ScrollToTopOperator.test.ts @@ -0,0 +1,18 @@ +import { expect } from "chai"; +import ScrollToTopOperator from "../../../../src/content/operators/impls/ScrollToTopOperator"; +import MockScrollPresenter from "../../mock/MockScrollPresenter"; +import MockSettingRepository from "../../mock/MockSettingRepository"; + +describe("ScrollToTopOperator", () => { + describe("#run", () => { + it("scroll to top", async () => { + const presenter = new MockScrollPresenter(10, 10); + const settingRepository = new MockSettingRepository(); + const sut = new ScrollToTopOperator(presenter, settingRepository); + + await sut.run(); + + expect(presenter.getScroll()).to.deep.equal({ x: 10, y: 0 }); + }); + }); +}); diff --git a/test/content/operators/impls/StartFollowOperator.test.ts b/test/content/operators/impls/StartFollowOperator.test.ts new file mode 100644 index 0000000..8f9bd2d --- /dev/null +++ b/test/content/operators/impls/StartFollowOperator.test.ts @@ -0,0 +1,20 @@ +import sinon from "sinon"; +import StartFollowOperator from "../../../../src/content/operators/impls/StartFollowOperator"; +import MockFollowMasterClient from "../../mock/MockFollowMasterClient"; + +describe("StartFollowOperator", () => { + describe("#run", () => { + it("starts following links", async () => { + const client = new MockFollowMasterClient(); + const mock = sinon + .mock(client) + .expects("startFollow") + .withArgs(true, false); + const sut = new StartFollowOperator(client, true, false); + + await sut.run(); + + mock.verify(); + }); + }); +}); diff --git a/test/content/operators/impls/ToggleAddonOperator.test.ts b/test/content/operators/impls/ToggleAddonOperator.test.ts new file mode 100644 index 0000000..6026eb1 --- /dev/null +++ b/test/content/operators/impls/ToggleAddonOperator.test.ts @@ -0,0 +1,24 @@ +import { expect } from "chai"; +import ToggleAddonOperator from "../../../../src/content/operators/impls/ToggleAddonOperator"; +import MockAddonIndicatorClient from "../../mock/MockAddonIndicatorClient"; +import MockAddonEnabledRepository from "../../mock/MockAddonEnabledRepository"; + +describe("ToggleAddonOperator", () => { + describe("#run", () => { + it("toggles addon-enabled state", async () => { + const client = new MockAddonIndicatorClient(true); + const repository = new MockAddonEnabledRepository(true); + const sut = new ToggleAddonOperator(client, repository); + + await sut.run(); + + expect(client.enabled).to.be.false; + expect(repository.enabled).to.be.false; + + await sut.run(); + + expect(client.enabled).to.be.true; + expect(repository.enabled).to.be.true; + }); + }); +}); diff --git a/test/content/operators/impls/VerticalScrollOperator.test.ts b/test/content/operators/impls/VerticalScrollOperator.test.ts new file mode 100644 index 0000000..05b15d2 --- /dev/null +++ b/test/content/operators/impls/VerticalScrollOperator.test.ts @@ -0,0 +1,28 @@ +import { expect } from "chai"; +import VerticalScrollOperator from "../../../../src/content/operators/impls/VerticalScrollOperator"; +import MockScrollPresenter from "../../mock/MockScrollPresenter"; +import MockSettingRepository from "../../mock/MockSettingRepository"; + +describe("VerticalScrollOperator", () => { + describe("#run", () => { + it("scroll vertically", async () => { + const presenter = new MockScrollPresenter(); + const settingRepository = new MockSettingRepository(); + const sut = new VerticalScrollOperator(presenter, settingRepository, 1); + + await sut.run(); + + expect(presenter.getScroll()).to.deep.equal({ x: 0, y: 1 }); + }); + + it("scroll vertically with repeats", async () => { + const presenter = new MockScrollPresenter(); + const settingRepository = new MockSettingRepository(); + const sut = new VerticalScrollOperator(presenter, settingRepository, 5); + + await sut.run(); + + expect(presenter.getScroll()).to.deep.equal({ x: 0, y: 5 }); + }); + }); +}); diff --git a/test/content/operators/impls/YankURLOperator.test.ts b/test/content/operators/impls/YankURLOperator.test.ts new file mode 100644 index 0000000..46e3d06 --- /dev/null +++ b/test/content/operators/impls/YankURLOperator.test.ts @@ -0,0 +1,26 @@ +import { expect } from "chai"; +import MockClipboardRepository from "../../mock/MockClipboardRepository"; +import YankURLOperator from "../../../../src/content/operators/impls/YankURLOperator"; +import MockURLRepository from "../../mock/MockURLRepository"; +import MockConsoleClient from "../../mock/MockConsoleClient"; + +describe("YankOperation", () => { + describe("#run", () => { + it("copy current URL", async () => { + const clipboardRepository = new MockClipboardRepository(); + const consoleClient = new MockConsoleClient(); + const urlRepository = new MockURLRepository("https://example.com/"); + const sut = new YankURLOperator( + clipboardRepository, + consoleClient, + urlRepository + ); + + await sut.run(); + + expect(clipboardRepository.read()).to.equal("https://example.com/"); + expect(consoleClient.text).to.equal("Yanked https://example.com/"); + expect(consoleClient.isError).to.be.false; + }); + }); +}); -- cgit v1.2.3