diff options
| author | Shin'ya UEOKA <ueokande@i-beam.org> | 2019-10-06 12:39:56 +0000 | 
|---|---|---|
| committer | Shin'ya UEOKA <ueokande@i-beam.org> | 2019-10-08 11:43:10 +0000 | 
| commit | 7528fe831fa4e17e5c427e89025ac76b078a9313 (patch) | |
| tree | 9c40749b231ec1a8bdea3a9d720eb78b20ab7bab | |
| parent | 9ff80fcac3600401c9fed053cc8422f89c404940 (diff) | |
Ignore keys on partial blacklist
| -rw-r--r-- | src/content/di.ts | 2 | ||||
| -rw-r--r-- | src/content/repositories/AddressRepository.ts | 9 | ||||
| -rw-r--r-- | src/content/usecases/KeymapUseCase.ts | 15 | ||||
| -rw-r--r-- | test/content/usecases/KeymapUseCase.test.ts | 133 | 
4 files changed, 159 insertions, 0 deletions
diff --git a/src/content/di.ts b/src/content/di.ts index e18806a..63103a1 100644 --- a/src/content/di.ts +++ b/src/content/di.ts @@ -2,6 +2,7 @@  import { AddonEnabledRepositoryImpl } from './repositories/AddonEnabledRepository';  import { AddonIndicatorClientImpl } from './client/AddonIndicatorClient'; +import { AddressRepositoryImpl } from './repositories/AddressRepository';  import { ClipboardRepositoryImpl } from './repositories/ClipboardRepository';  import { ConsoleClientImpl } from './client/ConsoleClient';  import { ConsoleFramePresenterImpl } from './presenters/ConsoleFramePresenter'; @@ -31,6 +32,7 @@ import { container } from 'tsyringe';  container.register('FollowMasterClient', { useValue: new FollowMasterClientImpl(window.top) });  container.register('AddonEnabledRepository', { useClass: AddonEnabledRepositoryImpl });  container.register('AddonIndicatorClient', { useClass: AddonIndicatorClientImpl }); +container.register('AddressRepository', { useClass: AddressRepositoryImpl });  container.register('ClipboardRepository', { useClass: ClipboardRepositoryImpl });  container.register('ConsoleClient', { useClass: ConsoleClientImpl });  container.register('ConsoleFramePresenter', { useClass: ConsoleFramePresenterImpl }); diff --git a/src/content/repositories/AddressRepository.ts b/src/content/repositories/AddressRepository.ts new file mode 100644 index 0000000..6f9487b --- /dev/null +++ b/src/content/repositories/AddressRepository.ts @@ -0,0 +1,9 @@ +export default interface AddressRepository { +  getCurrentURL(): URL +} + +export class AddressRepositoryImpl implements AddressRepository { +  getCurrentURL(): URL { +    return new URL(window.location.href); +  } +} diff --git a/src/content/usecases/KeymapUseCase.ts b/src/content/usecases/KeymapUseCase.ts index 495f6d0..67d667d 100644 --- a/src/content/usecases/KeymapUseCase.ts +++ b/src/content/usecases/KeymapUseCase.ts @@ -6,6 +6,7 @@ import * as operations from '../../shared/operations';  import Keymaps from '../../shared/settings/Keymaps';  import Key from '../../shared/settings/Key';  import KeySequence from '../../shared/settings/KeySequence'; +import AddressRepository from '../repositories/AddressRepository';  type KeymapEntityMap = Map<KeySequence, operations.Operation>; @@ -25,11 +26,19 @@ export default class KeymapUseCase {      @inject('AddonEnabledRepository')      private addonEnabledRepository: AddonEnabledRepository, + +    @inject('AddressRepository') +    private addressRepository: AddressRepository,    ) {    }    nextOp(key: Key): operations.Operation | null {      let sequence = this.repository.enqueueKey(key); +    if (sequence.length() === 1 && this.blacklistKey(key)) { +      // ignore if the input starts with black list keys +      this.repository.clear(); +      return null; +    }      let keymaps = this.keymapEntityMap();      let matched = Array.from(keymaps.keys()).filter( @@ -71,4 +80,10 @@ export default class KeymapUseCase {      ) as [KeySequence, operations.Operation][];      return new Map<KeySequence, operations.Operation>(entries);    } + +  private blacklistKey(key: Key): boolean { +    let url = this.addressRepository.getCurrentURL(); +    let blacklist = this.settingRepository.get().blacklist; +    return blacklist.includeKey(url, key); +  }  } diff --git a/test/content/usecases/KeymapUseCase.test.ts b/test/content/usecases/KeymapUseCase.test.ts new file mode 100644 index 0000000..5f2feba --- /dev/null +++ b/test/content/usecases/KeymapUseCase.test.ts @@ -0,0 +1,133 @@ +import KeymapUseCase from '../../../src/content/usecases/KeymapUseCase'; +import {expect} from 'chai'; +import SettingRepository from "../../../src/content/repositories/SettingRepository"; +import Settings from "../../../src/shared/settings/Settings"; +import AddonEnabledRepository from "../../../src/content/repositories/AddonEnabledRepository"; +import {KeymapRepositoryImpl} from "../../../src/content/repositories/KeymapRepository"; +import Key from "../../../src/shared/settings/Key"; +import AddressRepository from "../../../src/content/repositories/AddressRepository"; + +class MockSettingRepository implements SettingRepository { +  constructor( +    private readonly settings: Settings, +  ) { +  } + +  get(): Settings { +    return this.settings; +  } + +  set(_setting: Settings): void { +    throw new Error('TODO'); +  } +} + +class MockAddonEnabledRepository implements AddonEnabledRepository { +  constructor( +    private readonly enabled: boolean, +  ) { +  } + +  get(): boolean { +    return this.enabled; +  } + +  set(_on: boolean): void { +    throw new Error('TODO'); +  } +} + +class MockAddressRepository implements AddressRepository { +  constructor( +    private url: URL, +  ) { +  } + +  getCurrentURL(): URL { +    return this.url; +  } +} + + +describe('KeymapUseCase', () => { +  it('returns matched operation', () => { +    let settings = Settings.fromJSON({ +      keymaps: { +        k: {type: 'scroll.vertically', count: -1}, +        j: {type: 'scroll.vertically', count: 1}, +        gg: {type: 'scroll.top'}, +      }, +    }); +    let sut = new KeymapUseCase( +      new KeymapRepositoryImpl(), +      new MockSettingRepository(settings), +      new MockAddonEnabledRepository(true), +      new MockAddressRepository(new URL('https://example.com')), +    ); + +    expect(sut.nextOp(Key.fromMapKey('k'))).to.deep.equal({type: 'scroll.vertically', count: -1}); +    expect(sut.nextOp(Key.fromMapKey('j'))).to.deep.equal({type: 'scroll.vertically', count: 1}); +    expect(sut.nextOp(Key.fromMapKey('g'))).to.be.null; +    expect(sut.nextOp(Key.fromMapKey('g'))).to.deep.equal({type: 'scroll.top'}); +    expect(sut.nextOp(Key.fromMapKey('z'))).to.be.null; +  }); + +  it('returns only ADDON_ENABLE and ADDON_TOGGLE_ENABLED operation', () => { +    let settings = Settings.fromJSON({ +      keymaps: { +        k: {type: 'scroll.vertically', count: -1}, +        a: {type: 'addon.enable'}, +        b: {type: 'addon.toggle.enabled'}, +      }, +    }); +    let sut = new KeymapUseCase( +      new KeymapRepositoryImpl(), +      new MockSettingRepository(settings), +      new MockAddonEnabledRepository(false), +      new MockAddressRepository(new URL('https://example.com')), +    ); + +    expect(sut.nextOp(Key.fromMapKey('k'))).to.be.null; +    expect(sut.nextOp(Key.fromMapKey('a'))).to.deep.equal({type: 'addon.enable'}); +    expect(sut.nextOp(Key.fromMapKey('b'))).to.deep.equal({type: 'addon.toggle.enabled'}); +  }); + +  it('blocks keys in the partial blacklist', () => { +    let settings = Settings.fromJSON({ +      keymaps: { +        k: {type: 'scroll.vertically', count: -1}, +        j: {type: 'scroll.vertically', count: 1}, +        gg: {"type": "scroll.top"}, +        G: {"type": "scroll.bottom"}, +      }, +      blacklist: [ +        { url: "example.com", keys: ['g'] }, +        { url: "example.org", keys: ['<S-G>'] } +      ], +    }); + +    let sut = new KeymapUseCase( +      new KeymapRepositoryImpl(), +      new MockSettingRepository(settings), +      new MockAddonEnabledRepository(true), +      new MockAddressRepository(new URL('https://example.com')), +    ); + +    expect(sut.nextOp(Key.fromMapKey('k'))).to.deep.equal({type: 'scroll.vertically', count: -1}); +    expect(sut.nextOp(Key.fromMapKey('j'))).to.deep.equal({type: 'scroll.vertically', count: 1}); +    expect(sut.nextOp(Key.fromMapKey('g'))).to.be.null; +    expect(sut.nextOp(Key.fromMapKey('g'))).to.be.null; +    expect(sut.nextOp(Key.fromMapKey('G'))).to.deep.equal({type: 'scroll.bottom'}); + +    sut = new KeymapUseCase( +      new KeymapRepositoryImpl(), +      new MockSettingRepository(settings), +      new MockAddonEnabledRepository(true), +      new MockAddressRepository(new URL('https://example.org')), +    ); + +    expect(sut.nextOp(Key.fromMapKey('g'))).to.be.null; +    expect(sut.nextOp(Key.fromMapKey('g'))).to.deep.equal({type: 'scroll.top'}); +    expect(sut.nextOp(Key.fromMapKey('G'))).to.be.null; +  }); +});  | 
