Remove unused components
This commit is contained in:
		
							parent
							
								
									e0c4182f14
								
							
						
					
					
						commit
						4be04628e1
					
				
					 27 changed files with 1 additions and 1083 deletions
				
			
		| 
						 | 
				
			
			@ -1,32 +0,0 @@
 | 
			
		|||
import * as actions from './index';
 | 
			
		||||
 | 
			
		||||
const enable = (
 | 
			
		||||
  newTab: boolean, background: boolean,
 | 
			
		||||
): actions.FollowAction => {
 | 
			
		||||
  return {
 | 
			
		||||
    type: actions.FOLLOW_CONTROLLER_ENABLE,
 | 
			
		||||
    newTab,
 | 
			
		||||
    background,
 | 
			
		||||
  };
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
const disable = (): actions.FollowAction => {
 | 
			
		||||
  return {
 | 
			
		||||
    type: actions.FOLLOW_CONTROLLER_DISABLE,
 | 
			
		||||
  };
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
const keyPress = (key: string): actions.FollowAction => {
 | 
			
		||||
  return {
 | 
			
		||||
    type: actions.FOLLOW_CONTROLLER_KEY_PRESS,
 | 
			
		||||
    key: key
 | 
			
		||||
  };
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
const backspace = (): actions.FollowAction => {
 | 
			
		||||
  return {
 | 
			
		||||
    type: actions.FOLLOW_CONTROLLER_BACKSPACE,
 | 
			
		||||
  };
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
export { enable, disable, keyPress, backspace };
 | 
			
		||||
| 
						 | 
				
			
			@ -1,81 +0,0 @@
 | 
			
		|||
import Redux from 'redux';
 | 
			
		||||
import Key from '../domains/Key';
 | 
			
		||||
 | 
			
		||||
// User input
 | 
			
		||||
export const INPUT_KEY_PRESS = 'input.key.press';
 | 
			
		||||
export const INPUT_CLEAR_KEYS = 'input.clear.keys';
 | 
			
		||||
 | 
			
		||||
// Completion
 | 
			
		||||
export const COMPLETION_SET_ITEMS = 'completion.set.items';
 | 
			
		||||
export const COMPLETION_SELECT_NEXT = 'completions.select.next';
 | 
			
		||||
export const COMPLETION_SELECT_PREV = 'completions.select.prev';
 | 
			
		||||
 | 
			
		||||
// Follow
 | 
			
		||||
export const FOLLOW_CONTROLLER_ENABLE = 'follow.controller.enable';
 | 
			
		||||
export const FOLLOW_CONTROLLER_DISABLE = 'follow.controller.disable';
 | 
			
		||||
export const FOLLOW_CONTROLLER_KEY_PRESS = 'follow.controller.key.press';
 | 
			
		||||
export const FOLLOW_CONTROLLER_BACKSPACE = 'follow.controller.backspace';
 | 
			
		||||
 | 
			
		||||
// Mark
 | 
			
		||||
export const MARK_START_SET = 'mark.start.set';
 | 
			
		||||
export const MARK_START_JUMP = 'mark.start.jump';
 | 
			
		||||
export const MARK_CANCEL = 'mark.cancel';
 | 
			
		||||
 | 
			
		||||
export const NOOP = 'noop';
 | 
			
		||||
 | 
			
		||||
export interface InputKeyPressAction extends Redux.Action {
 | 
			
		||||
  type: typeof INPUT_KEY_PRESS;
 | 
			
		||||
  key: Key;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export interface InputClearKeysAction extends Redux.Action {
 | 
			
		||||
  type: typeof INPUT_CLEAR_KEYS;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export interface FollowControllerEnableAction extends Redux.Action {
 | 
			
		||||
  type: typeof FOLLOW_CONTROLLER_ENABLE;
 | 
			
		||||
  newTab: boolean;
 | 
			
		||||
  background: boolean;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export interface FollowControllerDisableAction extends Redux.Action {
 | 
			
		||||
  type: typeof FOLLOW_CONTROLLER_DISABLE;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export interface FollowControllerKeyPressAction extends Redux.Action {
 | 
			
		||||
  type: typeof FOLLOW_CONTROLLER_KEY_PRESS;
 | 
			
		||||
  key: string;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export interface FollowControllerBackspaceAction extends Redux.Action {
 | 
			
		||||
  type: typeof FOLLOW_CONTROLLER_BACKSPACE;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export interface MarkStartSetAction extends Redux.Action {
 | 
			
		||||
  type: typeof MARK_START_SET;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export interface MarkStartJumpAction extends Redux.Action {
 | 
			
		||||
  type: typeof MARK_START_JUMP;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export interface MarkCancelAction extends Redux.Action {
 | 
			
		||||
  type: typeof MARK_CANCEL;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export interface NoopAction extends Redux.Action {
 | 
			
		||||
  type: typeof NOOP;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export type InputAction = InputKeyPressAction | InputClearKeysAction;
 | 
			
		||||
export type FollowAction =
 | 
			
		||||
  FollowControllerEnableAction | FollowControllerDisableAction |
 | 
			
		||||
  FollowControllerKeyPressAction | FollowControllerBackspaceAction;
 | 
			
		||||
export type MarkAction =
 | 
			
		||||
  MarkStartSetAction | MarkStartJumpAction | MarkCancelAction | NoopAction;
 | 
			
		||||
 | 
			
		||||
export type Action =
 | 
			
		||||
  InputAction |
 | 
			
		||||
  FollowAction |
 | 
			
		||||
  MarkAction |
 | 
			
		||||
  NoopAction;
 | 
			
		||||
| 
						 | 
				
			
			@ -1,17 +0,0 @@
 | 
			
		|||
import * as actions from './index';
 | 
			
		||||
import Key from '../domains/Key';
 | 
			
		||||
 | 
			
		||||
const keyPress = (key: Key): actions.InputAction => {
 | 
			
		||||
  return {
 | 
			
		||||
    type: actions.INPUT_KEY_PRESS,
 | 
			
		||||
    key,
 | 
			
		||||
  };
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
const clearKeys = (): actions.InputAction => {
 | 
			
		||||
  return {
 | 
			
		||||
    type: actions.INPUT_CLEAR_KEYS
 | 
			
		||||
  };
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
export { keyPress, clearKeys };
 | 
			
		||||
| 
						 | 
				
			
			@ -1,17 +0,0 @@
 | 
			
		|||
import * as actions from './index';
 | 
			
		||||
 | 
			
		||||
const startSet = (): actions.MarkAction => {
 | 
			
		||||
  return { type: actions.MARK_START_SET };
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
const startJump = (): actions.MarkAction => {
 | 
			
		||||
  return { type: actions.MARK_START_JUMP };
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
const cancel = (): actions.MarkAction => {
 | 
			
		||||
  return { type: actions.MARK_CANCEL };
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
export {
 | 
			
		||||
  startSet, startJump, cancel,
 | 
			
		||||
};
 | 
			
		||||
| 
						 | 
				
			
			@ -1,112 +0,0 @@
 | 
			
		|||
import * as operations from '../../shared/operations';
 | 
			
		||||
import * as actions from './index';
 | 
			
		||||
import * as messages from '../../shared/messages';
 | 
			
		||||
import * as navigates from '../navigates';
 | 
			
		||||
import * as focuses from '../focuses';
 | 
			
		||||
import * as markActions from './mark';
 | 
			
		||||
 | 
			
		||||
import AddonEnabledUseCase from '../usecases/AddonEnabledUseCase';
 | 
			
		||||
import ClipboardUseCase from '../usecases/ClipboardUseCase';
 | 
			
		||||
import { SettingRepositoryImpl } from '../repositories/SettingRepository';
 | 
			
		||||
import { ScrollPresenterImpl } from '../presenters/ScrollPresenter';
 | 
			
		||||
import { FollowMasterClientImpl } from '../client/FollowMasterClient';
 | 
			
		||||
 | 
			
		||||
let addonEnabledUseCase = new AddonEnabledUseCase();
 | 
			
		||||
let clipbaordUseCase = new ClipboardUseCase();
 | 
			
		||||
let settingRepository = new SettingRepositoryImpl();
 | 
			
		||||
let scrollPresenter = new ScrollPresenterImpl();
 | 
			
		||||
let followMasterClient = new FollowMasterClientImpl(window.top);
 | 
			
		||||
 | 
			
		||||
// eslint-disable-next-line complexity, max-lines-per-function
 | 
			
		||||
const exec = async(
 | 
			
		||||
  operation: operations.Operation,
 | 
			
		||||
): Promise<actions.Action> => {
 | 
			
		||||
  let settings = settingRepository.get();
 | 
			
		||||
  let smoothscroll = settings.properties.smoothscroll;
 | 
			
		||||
  switch (operation.type) {
 | 
			
		||||
  case operations.ADDON_ENABLE:
 | 
			
		||||
    await addonEnabledUseCase.enable();
 | 
			
		||||
    return { type: actions.NOOP };
 | 
			
		||||
  case operations.ADDON_DISABLE:
 | 
			
		||||
    await addonEnabledUseCase.disable();
 | 
			
		||||
    return { type: actions.NOOP };
 | 
			
		||||
  case operations.ADDON_TOGGLE_ENABLED:
 | 
			
		||||
    await addonEnabledUseCase.toggle();
 | 
			
		||||
    return { type: actions.NOOP };
 | 
			
		||||
  case operations.FIND_NEXT:
 | 
			
		||||
    window.top.postMessage(JSON.stringify({
 | 
			
		||||
      type: messages.FIND_NEXT,
 | 
			
		||||
    }), '*');
 | 
			
		||||
    break;
 | 
			
		||||
  case operations.FIND_PREV:
 | 
			
		||||
    window.top.postMessage(JSON.stringify({
 | 
			
		||||
      type: messages.FIND_PREV,
 | 
			
		||||
    }), '*');
 | 
			
		||||
    break;
 | 
			
		||||
  case operations.SCROLL_VERTICALLY:
 | 
			
		||||
    scrollPresenter.scrollVertically(operation.count, smoothscroll);
 | 
			
		||||
    break;
 | 
			
		||||
  case operations.SCROLL_HORIZONALLY:
 | 
			
		||||
    scrollPresenter.scrollHorizonally(operation.count, smoothscroll);
 | 
			
		||||
    break;
 | 
			
		||||
  case operations.SCROLL_PAGES:
 | 
			
		||||
    scrollPresenter.scrollPages(operation.count, smoothscroll);
 | 
			
		||||
    break;
 | 
			
		||||
  case operations.SCROLL_TOP:
 | 
			
		||||
    scrollPresenter.scrollToTop(smoothscroll);
 | 
			
		||||
    break;
 | 
			
		||||
  case operations.SCROLL_BOTTOM:
 | 
			
		||||
    scrollPresenter.scrollToBottom(smoothscroll);
 | 
			
		||||
    break;
 | 
			
		||||
  case operations.SCROLL_HOME:
 | 
			
		||||
    scrollPresenter.scrollToHome(smoothscroll);
 | 
			
		||||
    break;
 | 
			
		||||
  case operations.SCROLL_END:
 | 
			
		||||
    scrollPresenter.scrollToEnd(smoothscroll);
 | 
			
		||||
    break;
 | 
			
		||||
  case operations.FOLLOW_START:
 | 
			
		||||
    followMasterClient.startFollow(operation.newTab, operation.background);
 | 
			
		||||
    break;
 | 
			
		||||
  case operations.MARK_SET_PREFIX:
 | 
			
		||||
    return markActions.startSet();
 | 
			
		||||
  case operations.MARK_JUMP_PREFIX:
 | 
			
		||||
    return markActions.startJump();
 | 
			
		||||
  case operations.NAVIGATE_HISTORY_PREV:
 | 
			
		||||
    navigates.historyPrev(window);
 | 
			
		||||
    break;
 | 
			
		||||
  case operations.NAVIGATE_HISTORY_NEXT:
 | 
			
		||||
    navigates.historyNext(window);
 | 
			
		||||
    break;
 | 
			
		||||
  case operations.NAVIGATE_LINK_PREV:
 | 
			
		||||
    navigates.linkPrev(window);
 | 
			
		||||
    break;
 | 
			
		||||
  case operations.NAVIGATE_LINK_NEXT:
 | 
			
		||||
    navigates.linkNext(window);
 | 
			
		||||
    break;
 | 
			
		||||
  case operations.NAVIGATE_PARENT:
 | 
			
		||||
    navigates.parent(window);
 | 
			
		||||
    break;
 | 
			
		||||
  case operations.NAVIGATE_ROOT:
 | 
			
		||||
    navigates.root(window);
 | 
			
		||||
    break;
 | 
			
		||||
  case operations.FOCUS_INPUT:
 | 
			
		||||
    focuses.focusInput();
 | 
			
		||||
    break;
 | 
			
		||||
  case operations.URLS_YANK:
 | 
			
		||||
    await clipbaordUseCase.yankCurrentURL();
 | 
			
		||||
    break;
 | 
			
		||||
  case operations.URLS_PASTE:
 | 
			
		||||
    await clipbaordUseCase.openOrSearch(
 | 
			
		||||
      operation.newTab ? operation.newTab : false,
 | 
			
		||||
    );
 | 
			
		||||
    break;
 | 
			
		||||
  default:
 | 
			
		||||
    browser.runtime.sendMessage({
 | 
			
		||||
      type: messages.BACKGROUND_OPERATION,
 | 
			
		||||
      operation,
 | 
			
		||||
    });
 | 
			
		||||
  }
 | 
			
		||||
  return { type: actions.NOOP };
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
export { exec };
 | 
			
		||||
| 
						 | 
				
			
			@ -1,104 +0,0 @@
 | 
			
		|||
import MessageListener from '../../MessageListener';
 | 
			
		||||
import { LinkHint, InputHint } from '../../presenters/Hint';
 | 
			
		||||
import * as messages from '../../../shared/messages';
 | 
			
		||||
import Key from '../../domains/Key';
 | 
			
		||||
import TabsClient, { TabsClientImpl } from '../../client/TabsClient';
 | 
			
		||||
import FollowMasterClient, { FollowMasterClientImpl }
 | 
			
		||||
  from '../../client/FollowMasterClient';
 | 
			
		||||
import FollowPresenter, { FollowPresenterImpl }
 | 
			
		||||
  from '../../presenters/FollowPresenter';
 | 
			
		||||
 | 
			
		||||
let tabsClient: TabsClient = new TabsClientImpl();
 | 
			
		||||
let followMasterClient: FollowMasterClient =
 | 
			
		||||
  new FollowMasterClientImpl(window.top);
 | 
			
		||||
let followPresenter: FollowPresenter =
 | 
			
		||||
  new FollowPresenterImpl();
 | 
			
		||||
 | 
			
		||||
interface Size {
 | 
			
		||||
  width: number;
 | 
			
		||||
  height: number;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
interface Point {
 | 
			
		||||
  x: number;
 | 
			
		||||
  y: number;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export default class Follow {
 | 
			
		||||
  private enabled: boolean;
 | 
			
		||||
 | 
			
		||||
  constructor() {
 | 
			
		||||
    this.enabled = false;
 | 
			
		||||
 | 
			
		||||
    new MessageListener().onWebMessage(this.onMessage.bind(this));
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  key(key: Key): boolean {
 | 
			
		||||
    if (!this.enabled) {
 | 
			
		||||
      return false;
 | 
			
		||||
    }
 | 
			
		||||
    followMasterClient.sendKey(key);
 | 
			
		||||
    return true;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  countHints(viewSize: Size, framePosition: Point) {
 | 
			
		||||
    let count = followPresenter.getTargetCount(viewSize, framePosition);
 | 
			
		||||
    followMasterClient.responseHintCount(count);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  createHints(viewSize: Size, framePosition: Point, tags: string[]) {
 | 
			
		||||
    this.enabled = true;
 | 
			
		||||
    followPresenter.createHints(viewSize, framePosition, tags);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  showHints(prefix: string) {
 | 
			
		||||
    followPresenter.filterHints(prefix);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  removeHints() {
 | 
			
		||||
    followPresenter.clearHints();
 | 
			
		||||
    this.enabled = false;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  async activateHints(
 | 
			
		||||
    tag: string, newTab: boolean, background: boolean,
 | 
			
		||||
  ): Promise<void> {
 | 
			
		||||
    let hint = followPresenter.getHint(tag);
 | 
			
		||||
    if (!hint) {
 | 
			
		||||
      return;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (hint instanceof LinkHint) {
 | 
			
		||||
      let url = hint.getLink();
 | 
			
		||||
      // ignore taget='_blank'
 | 
			
		||||
      if (!newTab && hint.getLinkTarget() !== '_blank') {
 | 
			
		||||
        hint.click();
 | 
			
		||||
        return;
 | 
			
		||||
      }
 | 
			
		||||
      // eslint-disable-next-line no-script-url
 | 
			
		||||
      if (!url || url === '#' || url.toLowerCase().startsWith('javascript:')) {
 | 
			
		||||
        return;
 | 
			
		||||
      }
 | 
			
		||||
      await tabsClient.openUrl(url, newTab, background);
 | 
			
		||||
    } else if (hint instanceof InputHint) {
 | 
			
		||||
      hint.activate();
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  onMessage(message: messages.Message, _sender: Window) {
 | 
			
		||||
    switch (message.type) {
 | 
			
		||||
    case messages.FOLLOW_REQUEST_COUNT_TARGETS:
 | 
			
		||||
      return this.countHints(message.viewSize, message.framePosition);
 | 
			
		||||
    case messages.FOLLOW_CREATE_HINTS:
 | 
			
		||||
      return this.createHints(
 | 
			
		||||
        message.viewSize, message.framePosition, message.tags);
 | 
			
		||||
    case messages.FOLLOW_SHOW_HINTS:
 | 
			
		||||
      return this.showHints(message.prefix);
 | 
			
		||||
    case messages.FOLLOW_ACTIVATE:
 | 
			
		||||
      return this.activateHints(
 | 
			
		||||
        message.tag, message.newTab, message.background);
 | 
			
		||||
    case messages.FOLLOW_REMOVE_HINTS:
 | 
			
		||||
      return this.removeHints();
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -1,59 +0,0 @@
 | 
			
		|||
import InputDriver from './../../InputDriver';
 | 
			
		||||
import FollowComponent from './follow';
 | 
			
		||||
import MarkComponent from './mark';
 | 
			
		||||
// import KeymapperComponent from './keymapper';
 | 
			
		||||
import * as messages from '../../../shared/messages';
 | 
			
		||||
import MessageListener from '../../MessageListener';
 | 
			
		||||
import * as blacklists from '../../../shared/blacklists';
 | 
			
		||||
import Key from '../../domains/Key';
 | 
			
		||||
 | 
			
		||||
import AddonEnabledUseCase from '../../usecases/AddonEnabledUseCase';
 | 
			
		||||
import SettingUseCase from '../../usecases/SettingUseCase';
 | 
			
		||||
 | 
			
		||||
let addonEnabledUseCase = new AddonEnabledUseCase();
 | 
			
		||||
let settingUseCase = new SettingUseCase();
 | 
			
		||||
 | 
			
		||||
export default class Common {
 | 
			
		||||
  constructor(win: Window, store: any) {
 | 
			
		||||
    const input = new InputDriver(win.document.body);
 | 
			
		||||
    const follow = new FollowComponent();
 | 
			
		||||
    const mark = new MarkComponent(store);
 | 
			
		||||
    // const keymapper = new KeymapperComponent(store);
 | 
			
		||||
 | 
			
		||||
    input.onKey((key: Key) => follow.key(key));
 | 
			
		||||
    input.onKey((key: Key) => mark.key(key));
 | 
			
		||||
    // input.onKey((key: Key) => keymapper.key(key));
 | 
			
		||||
 | 
			
		||||
    this.reloadSettings();
 | 
			
		||||
 | 
			
		||||
    new MessageListener().onBackgroundMessage(this.onMessage.bind(this));
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  onMessage(message: messages.Message) {
 | 
			
		||||
    switch (message.type) {
 | 
			
		||||
    case messages.SETTINGS_CHANGED:
 | 
			
		||||
      return this.reloadSettings();
 | 
			
		||||
    case messages.ADDON_TOGGLE_ENABLED:
 | 
			
		||||
      return addonEnabledUseCase.toggle();
 | 
			
		||||
    }
 | 
			
		||||
    return undefined;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  async reloadSettings() {
 | 
			
		||||
    try {
 | 
			
		||||
      let current = await settingUseCase.reload();
 | 
			
		||||
      let disabled = blacklists.includes(
 | 
			
		||||
        current.blacklist, window.location.href,
 | 
			
		||||
      );
 | 
			
		||||
      if (disabled) {
 | 
			
		||||
        addonEnabledUseCase.disable();
 | 
			
		||||
      } else {
 | 
			
		||||
        addonEnabledUseCase.enable();
 | 
			
		||||
      }
 | 
			
		||||
    } catch (e) {
 | 
			
		||||
      // Sometime sendMessage fails when background script is not ready.
 | 
			
		||||
      console.warn(e);
 | 
			
		||||
      setTimeout(() => this.reloadSettings(), 500);
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -1,44 +0,0 @@
 | 
			
		|||
import * as markActions from '../../actions/mark';
 | 
			
		||||
import * as consoleFrames from '../..//console-frames';
 | 
			
		||||
import Key from '../../domains/Key';
 | 
			
		||||
 | 
			
		||||
import MarkUseCase from '../../usecases/MarkUseCase';
 | 
			
		||||
 | 
			
		||||
let markUseCase = new MarkUseCase();
 | 
			
		||||
 | 
			
		||||
const cancelKey = (key: Key): boolean => {
 | 
			
		||||
  return key.key === 'Esc' || key.key === '[' && Boolean(key.ctrlKey);
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
export default class MarkComponent {
 | 
			
		||||
  private store: any;
 | 
			
		||||
 | 
			
		||||
  constructor(store: any) {
 | 
			
		||||
    this.store = store;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  // eslint-disable-next-line max-statements
 | 
			
		||||
  key(key: Key) {
 | 
			
		||||
    let { mark: markState } = this.store.getState();
 | 
			
		||||
 | 
			
		||||
    if (!markState.setMode && !markState.jumpMode) {
 | 
			
		||||
      return false;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (cancelKey(key)) {
 | 
			
		||||
      this.store.dispatch(markActions.cancel());
 | 
			
		||||
      return true;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (key.ctrlKey || key.metaKey || key.altKey) {
 | 
			
		||||
      consoleFrames.postError('Unknown mark');
 | 
			
		||||
    } else if (markState.setMode) {
 | 
			
		||||
      markUseCase.set(key.key);
 | 
			
		||||
    } else if (markState.jumpMode) {
 | 
			
		||||
      markUseCase.jump(key.key);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    this.store.dispatch(markActions.cancel());
 | 
			
		||||
    return true;
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -1,3 +0,0 @@
 | 
			
		|||
import CommonComponent from './common';
 | 
			
		||||
 | 
			
		||||
export default CommonComponent;
 | 
			
		||||
| 
						 | 
				
			
			@ -1,181 +0,0 @@
 | 
			
		|||
import * as followControllerActions from '../../actions/follow-controller';
 | 
			
		||||
import * as messages from '../../../shared/messages';
 | 
			
		||||
import MessageListener from '../../MessageListener';
 | 
			
		||||
import HintKeyProducer from '../../hint-key-producer';
 | 
			
		||||
 | 
			
		||||
import { SettingRepositoryImpl } from '../../repositories/SettingRepository';
 | 
			
		||||
import FollowSlaveClient, { FollowSlaveClientImpl }
 | 
			
		||||
  from '../../client/FollowSlaveClient';
 | 
			
		||||
 | 
			
		||||
let settingRepository = new SettingRepositoryImpl();
 | 
			
		||||
 | 
			
		||||
export default class FollowController {
 | 
			
		||||
  private win: Window;
 | 
			
		||||
 | 
			
		||||
  private store: any;
 | 
			
		||||
 | 
			
		||||
  private state: {
 | 
			
		||||
    enabled?: boolean;
 | 
			
		||||
    newTab?: boolean;
 | 
			
		||||
    background?: boolean;
 | 
			
		||||
    keys?: string,
 | 
			
		||||
  };
 | 
			
		||||
 | 
			
		||||
  private keys: string[];
 | 
			
		||||
 | 
			
		||||
  private producer: HintKeyProducer | null;
 | 
			
		||||
 | 
			
		||||
  constructor(win: Window, store: any) {
 | 
			
		||||
    this.win = win;
 | 
			
		||||
    this.store = store;
 | 
			
		||||
    this.state = {};
 | 
			
		||||
    this.keys = [];
 | 
			
		||||
    this.producer = null;
 | 
			
		||||
 | 
			
		||||
    new MessageListener().onWebMessage(this.onMessage.bind(this));
 | 
			
		||||
 | 
			
		||||
    store.subscribe(() => {
 | 
			
		||||
      this.update();
 | 
			
		||||
    });
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  onMessage(message: messages.Message, sender: Window) {
 | 
			
		||||
    switch (message.type) {
 | 
			
		||||
    case messages.FOLLOW_START:
 | 
			
		||||
      return this.store.dispatch(
 | 
			
		||||
        followControllerActions.enable(message.newTab, message.background));
 | 
			
		||||
    case messages.FOLLOW_RESPONSE_COUNT_TARGETS:
 | 
			
		||||
      return this.create(message.count, sender);
 | 
			
		||||
    case messages.FOLLOW_KEY_PRESS:
 | 
			
		||||
      return this.keyPress(message.key, message.ctrlKey);
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  update(): void {
 | 
			
		||||
    let prevState = this.state;
 | 
			
		||||
    this.state = this.store.getState().followController;
 | 
			
		||||
 | 
			
		||||
    if (!prevState.enabled && this.state.enabled) {
 | 
			
		||||
      this.count();
 | 
			
		||||
    } else if (prevState.enabled && !this.state.enabled) {
 | 
			
		||||
      this.remove();
 | 
			
		||||
    } else if (prevState.keys !== this.state.keys) {
 | 
			
		||||
      this.updateHints();
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  updateHints(): void {
 | 
			
		||||
    let shown = this.keys.filter((key) => {
 | 
			
		||||
      return key.startsWith(this.state.keys as string);
 | 
			
		||||
    });
 | 
			
		||||
    if (shown.length === 1) {
 | 
			
		||||
      this.activate();
 | 
			
		||||
      this.store.dispatch(followControllerActions.disable());
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    this.broadcastMessage((c: FollowSlaveClient) => {
 | 
			
		||||
      c.filterHints(this.state.keys!!);
 | 
			
		||||
    });
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  activate(): void {
 | 
			
		||||
    this.broadcastMessage((c: FollowSlaveClient) => {
 | 
			
		||||
      c.activateIfExists(
 | 
			
		||||
        this.state.keys!!,
 | 
			
		||||
        this.state.newTab!!,
 | 
			
		||||
        this.state.background!!);
 | 
			
		||||
    });
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  keyPress(key: string, ctrlKey: boolean): boolean {
 | 
			
		||||
    if (key === '[' && ctrlKey) {
 | 
			
		||||
      this.store.dispatch(followControllerActions.disable());
 | 
			
		||||
      return true;
 | 
			
		||||
    }
 | 
			
		||||
    switch (key) {
 | 
			
		||||
    case 'Enter':
 | 
			
		||||
      this.activate();
 | 
			
		||||
      this.store.dispatch(followControllerActions.disable());
 | 
			
		||||
      break;
 | 
			
		||||
    case 'Esc':
 | 
			
		||||
      this.store.dispatch(followControllerActions.disable());
 | 
			
		||||
      break;
 | 
			
		||||
    case 'Backspace':
 | 
			
		||||
    case 'Delete':
 | 
			
		||||
      this.store.dispatch(followControllerActions.backspace());
 | 
			
		||||
      break;
 | 
			
		||||
    default:
 | 
			
		||||
      if (this.hintchars().includes(key)) {
 | 
			
		||||
        this.store.dispatch(followControllerActions.keyPress(key));
 | 
			
		||||
      }
 | 
			
		||||
      break;
 | 
			
		||||
    }
 | 
			
		||||
    return true;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  count() {
 | 
			
		||||
    this.producer = new HintKeyProducer(this.hintchars());
 | 
			
		||||
    let doc = this.win.document;
 | 
			
		||||
    let viewWidth = this.win.innerWidth || doc.documentElement.clientWidth;
 | 
			
		||||
    let viewHeight = this.win.innerHeight || doc.documentElement.clientHeight;
 | 
			
		||||
    let frameElements = this.win.document.querySelectorAll('iframe');
 | 
			
		||||
 | 
			
		||||
    new FollowSlaveClientImpl(this.win).requestHintCount(
 | 
			
		||||
      { width: viewWidth, height: viewHeight },
 | 
			
		||||
      { x: 0, y: 0 });
 | 
			
		||||
 | 
			
		||||
    for (let ele of Array.from(frameElements)) {
 | 
			
		||||
      let { left: frameX, top: frameY } = ele.getBoundingClientRect();
 | 
			
		||||
      new FollowSlaveClientImpl(ele.contentWindow!!).requestHintCount(
 | 
			
		||||
        { width: viewWidth, height: viewHeight },
 | 
			
		||||
        { x: frameX, y: frameY },
 | 
			
		||||
      );
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  create(count: number, sender: Window) {
 | 
			
		||||
    let produced = [];
 | 
			
		||||
    for (let i = 0; i < count; ++i) {
 | 
			
		||||
      produced.push((this.producer as HintKeyProducer).produce());
 | 
			
		||||
    }
 | 
			
		||||
    this.keys = this.keys.concat(produced);
 | 
			
		||||
 | 
			
		||||
    let doc = this.win.document;
 | 
			
		||||
    let viewWidth = this.win.innerWidth || doc.documentElement.clientWidth;
 | 
			
		||||
    let viewHeight = this.win.innerHeight || doc.documentElement.clientHeight;
 | 
			
		||||
    let pos = { x: 0, y: 0 };
 | 
			
		||||
    if (sender !== window) {
 | 
			
		||||
      let frameElements = this.win.document.querySelectorAll('iframe');
 | 
			
		||||
      let ele = Array.from(frameElements).find(e => e.contentWindow === sender);
 | 
			
		||||
      if (!ele) {
 | 
			
		||||
        // elements of the sender is gone
 | 
			
		||||
        return;
 | 
			
		||||
      }
 | 
			
		||||
      let { left: frameX, top: frameY } = ele.getBoundingClientRect();
 | 
			
		||||
      pos = { x: frameX, y: frameY };
 | 
			
		||||
    }
 | 
			
		||||
    new FollowSlaveClientImpl(sender).createHints(
 | 
			
		||||
      { width: viewWidth, height: viewHeight },
 | 
			
		||||
      pos,
 | 
			
		||||
      produced,
 | 
			
		||||
    );
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  remove() {
 | 
			
		||||
    this.keys = [];
 | 
			
		||||
    this.broadcastMessage((c: FollowSlaveClient) => {
 | 
			
		||||
      c.clearHints();
 | 
			
		||||
    });
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  private hintchars() {
 | 
			
		||||
    return settingRepository.get().properties.hintchars;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  private broadcastMessage(f: (clinet: FollowSlaveClient) => void) {
 | 
			
		||||
    let windows = [window.self].concat(Array.from(window.frames as any));
 | 
			
		||||
    windows
 | 
			
		||||
      .map(w => new FollowSlaveClientImpl(w))
 | 
			
		||||
      .forEach(c => f(c));
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -1,47 +0,0 @@
 | 
			
		|||
import CommonComponent from '../common';
 | 
			
		||||
import FollowController from './follow-controller';
 | 
			
		||||
import * as consoleFrames from '../../console-frames';
 | 
			
		||||
import * as messages from '../../../shared/messages';
 | 
			
		||||
import MessageListener from '../../MessageListener';
 | 
			
		||||
import AddonEnabledUseCase from '../../usecases/AddonEnabledUseCase';
 | 
			
		||||
import { ScrollPresenterImpl } from '../../presenters/ScrollPresenter';
 | 
			
		||||
 | 
			
		||||
let addonEnabledUseCase = new AddonEnabledUseCase();
 | 
			
		||||
let scrollPresenter = new ScrollPresenterImpl();
 | 
			
		||||
 | 
			
		||||
export default class TopContent {
 | 
			
		||||
  private win: Window;
 | 
			
		||||
 | 
			
		||||
  constructor(win: Window, store: any) {
 | 
			
		||||
    this.win = win;
 | 
			
		||||
 | 
			
		||||
    new CommonComponent(win, store); // eslint-disable-line no-new
 | 
			
		||||
    new FollowController(win, store); // eslint-disable-line no-new
 | 
			
		||||
 | 
			
		||||
    // TODO make component
 | 
			
		||||
    consoleFrames.initialize(this.win.document);
 | 
			
		||||
 | 
			
		||||
    new MessageListener().onWebMessage(this.onWebMessage.bind(this));
 | 
			
		||||
    new MessageListener().onBackgroundMessage(
 | 
			
		||||
      this.onBackgroundMessage.bind(this));
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  onWebMessage(message: messages.Message) {
 | 
			
		||||
    switch (message.type) {
 | 
			
		||||
    case messages.CONSOLE_UNFOCUS:
 | 
			
		||||
      this.win.focus();
 | 
			
		||||
      consoleFrames.blur(window.document);
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  onBackgroundMessage(message: messages.Message) {
 | 
			
		||||
    let addonEnabled = addonEnabledUseCase.getEnabled();
 | 
			
		||||
 | 
			
		||||
    switch (message.type) {
 | 
			
		||||
    case messages.ADDON_ENABLED_QUERY:
 | 
			
		||||
      return Promise.resolve(addonEnabled);
 | 
			
		||||
    case messages.TAB_SCROLL_TO:
 | 
			
		||||
      return scrollPresenter.scrollTo(message.x, message.y, false);
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -1,5 +1,3 @@
 | 
			
		|||
import * as messages from '../shared/messages';
 | 
			
		||||
 | 
			
		||||
const initialize = (doc: Document): HTMLIFrameElement => {
 | 
			
		||||
  let iframe = doc.createElement('iframe');
 | 
			
		||||
  iframe.src = browser.runtime.getURL('build/console.html');
 | 
			
		||||
| 
						 | 
				
			
			@ -15,24 +13,4 @@ const blur = (doc: Document) => {
 | 
			
		|||
  ele.blur();
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
const postError = (text: string): Promise<any> => {
 | 
			
		||||
  return browser.runtime.sendMessage({
 | 
			
		||||
    type: messages.CONSOLE_FRAME_MESSAGE,
 | 
			
		||||
    message: {
 | 
			
		||||
      type: messages.CONSOLE_SHOW_ERROR,
 | 
			
		||||
      text,
 | 
			
		||||
    },
 | 
			
		||||
  });
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
const postInfo = (text: string): Promise<any> => {
 | 
			
		||||
  return browser.runtime.sendMessage({
 | 
			
		||||
    type: messages.CONSOLE_FRAME_MESSAGE,
 | 
			
		||||
    message: {
 | 
			
		||||
      type: messages.CONSOLE_SHOW_INFO,
 | 
			
		||||
      text,
 | 
			
		||||
    },
 | 
			
		||||
  });
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
export { initialize, blur, postError, postInfo };
 | 
			
		||||
export { initialize, blur };
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,15 +0,0 @@
 | 
			
		|||
import * as doms from '../shared/utils/dom';
 | 
			
		||||
 | 
			
		||||
const focusInput = (): void => {
 | 
			
		||||
  let inputTypes = ['email', 'number', 'search', 'tel', 'text', 'url'];
 | 
			
		||||
  let inputSelector = inputTypes.map(type => `input[type=${type}]`).join(',');
 | 
			
		||||
  let targets = window.document.querySelectorAll(inputSelector + ',textarea');
 | 
			
		||||
  let target = Array.from(targets).find(doms.isVisible);
 | 
			
		||||
  if (target instanceof HTMLInputElement) {
 | 
			
		||||
    target.focus();
 | 
			
		||||
  } else if (target instanceof HTMLTextAreaElement) {
 | 
			
		||||
    target.focus();
 | 
			
		||||
  }
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
export { focusInput };
 | 
			
		||||
| 
						 | 
				
			
			@ -1,8 +1,5 @@
 | 
			
		|||
// import TopContentComponent from './components/top-content';
 | 
			
		||||
// import FrameContentComponent from './components/frame-content';
 | 
			
		||||
import * as consoleFrames from './console-frames';
 | 
			
		||||
import consoleFrameStyle from './site-style';
 | 
			
		||||
// import { newStore } from './store';
 | 
			
		||||
import MessageListener from './MessageListener';
 | 
			
		||||
import FindController from './controllers/FindController';
 | 
			
		||||
import MarkController from './controllers/MarkController';
 | 
			
		||||
| 
						 | 
				
			
			@ -18,12 +15,8 @@ import * as blacklists from '../shared/blacklists';
 | 
			
		|||
import MarkKeyController from './controllers/MarkKeyController';
 | 
			
		||||
import AddonEnabledController from './controllers/AddonEnabledController';
 | 
			
		||||
 | 
			
		||||
// const store = newStore();
 | 
			
		||||
 | 
			
		||||
let listener = new MessageListener();
 | 
			
		||||
if (window.self === window.top) {
 | 
			
		||||
  // new TopContentComponent(window, store); // eslint-disable-line no-new
 | 
			
		||||
 | 
			
		||||
  let findController = new FindController();
 | 
			
		||||
 | 
			
		||||
  let followMasterController = new FollowMasterController();
 | 
			
		||||
| 
						 | 
				
			
			@ -63,8 +56,6 @@ if (window.self === window.top) {
 | 
			
		|||
  });
 | 
			
		||||
 | 
			
		||||
  consoleFrames.initialize(window.document);
 | 
			
		||||
} else {
 | 
			
		||||
  // new FrameContentComponent(window, store); // eslint-disable-line no-new
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
let followSlaveController = new FollowSlaveController();
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,40 +0,0 @@
 | 
			
		|||
import * as actions from '../actions';
 | 
			
		||||
 | 
			
		||||
export interface State {
 | 
			
		||||
  enabled: boolean;
 | 
			
		||||
  newTab: boolean;
 | 
			
		||||
  background: boolean;
 | 
			
		||||
  keys: string,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
const defaultState: State = {
 | 
			
		||||
  enabled: false,
 | 
			
		||||
  newTab: false,
 | 
			
		||||
  background: false,
 | 
			
		||||
  keys: '',
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
export default function reducer(
 | 
			
		||||
  state: State = defaultState,
 | 
			
		||||
  action: actions.FollowAction,
 | 
			
		||||
): State {
 | 
			
		||||
  switch (action.type) {
 | 
			
		||||
  case actions.FOLLOW_CONTROLLER_ENABLE:
 | 
			
		||||
    return { ...state,
 | 
			
		||||
      enabled: true,
 | 
			
		||||
      newTab: action.newTab,
 | 
			
		||||
      background: action.background,
 | 
			
		||||
      keys: '', };
 | 
			
		||||
  case actions.FOLLOW_CONTROLLER_DISABLE:
 | 
			
		||||
    return { ...state,
 | 
			
		||||
      enabled: false, };
 | 
			
		||||
  case actions.FOLLOW_CONTROLLER_KEY_PRESS:
 | 
			
		||||
    return { ...state,
 | 
			
		||||
      keys: state.keys + action.key, };
 | 
			
		||||
  case actions.FOLLOW_CONTROLLER_BACKSPACE:
 | 
			
		||||
    return { ...state,
 | 
			
		||||
      keys: state.keys.slice(0, -1), };
 | 
			
		||||
  default:
 | 
			
		||||
    return state;
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -1,15 +0,0 @@
 | 
			
		|||
import { combineReducers } from 'redux';
 | 
			
		||||
import input, { State as InputState } from './input';
 | 
			
		||||
import followController, { State as FollowControllerState }
 | 
			
		||||
  from './follow-controller';
 | 
			
		||||
import mark, { State as MarkState } from './mark';
 | 
			
		||||
 | 
			
		||||
export interface State {
 | 
			
		||||
  input: InputState;
 | 
			
		||||
  followController: FollowControllerState;
 | 
			
		||||
  mark: MarkState;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export default combineReducers({
 | 
			
		||||
  input, followController, mark,
 | 
			
		||||
});
 | 
			
		||||
| 
						 | 
				
			
			@ -1,26 +0,0 @@
 | 
			
		|||
import * as actions from '../actions';
 | 
			
		||||
import Key from '../domains/Key';
 | 
			
		||||
 | 
			
		||||
export interface State {
 | 
			
		||||
  keys: Key[],
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
const defaultState: State = {
 | 
			
		||||
  keys: []
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
export default function reducer(
 | 
			
		||||
  state: State = defaultState,
 | 
			
		||||
  action: actions.InputAction,
 | 
			
		||||
): State {
 | 
			
		||||
  switch (action.type) {
 | 
			
		||||
  case actions.INPUT_KEY_PRESS:
 | 
			
		||||
    return { ...state,
 | 
			
		||||
      keys: state.keys.concat([action.key]), };
 | 
			
		||||
  case actions.INPUT_CLEAR_KEYS:
 | 
			
		||||
    return { ...state,
 | 
			
		||||
      keys: [], };
 | 
			
		||||
  default:
 | 
			
		||||
    return state;
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -1,27 +0,0 @@
 | 
			
		|||
import * as actions from '../actions';
 | 
			
		||||
 | 
			
		||||
export interface State {
 | 
			
		||||
  setMode: boolean;
 | 
			
		||||
  jumpMode: boolean;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
const defaultState: State = {
 | 
			
		||||
  setMode: false,
 | 
			
		||||
  jumpMode: false,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
export default function reducer(
 | 
			
		||||
  state: State = defaultState,
 | 
			
		||||
  action: actions.MarkAction,
 | 
			
		||||
): State {
 | 
			
		||||
  switch (action.type) {
 | 
			
		||||
  case actions.MARK_START_SET:
 | 
			
		||||
    return { ...state, setMode: true };
 | 
			
		||||
  case actions.MARK_START_JUMP:
 | 
			
		||||
    return { ...state, jumpMode: true };
 | 
			
		||||
  case actions.MARK_CANCEL:
 | 
			
		||||
    return { ...state, setMode: false, jumpMode: false };
 | 
			
		||||
  default:
 | 
			
		||||
    return state;
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -1,8 +0,0 @@
 | 
			
		|||
import promise from 'redux-promise';
 | 
			
		||||
import reducers from '../reducers';
 | 
			
		||||
import { createStore, applyMiddleware } from 'redux';
 | 
			
		||||
 | 
			
		||||
export const newStore = () => createStore(
 | 
			
		||||
  reducers,
 | 
			
		||||
  applyMiddleware(promise),
 | 
			
		||||
);
 | 
			
		||||
| 
						 | 
				
			
			@ -1,34 +0,0 @@
 | 
			
		|||
import * as actions from 'content/actions';
 | 
			
		||||
import * as followControllerActions from 'content/actions/follow-controller';
 | 
			
		||||
 | 
			
		||||
describe('follow-controller actions', () => {
 | 
			
		||||
  describe('enable', () => {
 | 
			
		||||
    it('creates FOLLOW_CONTROLLER_ENABLE action', () => {
 | 
			
		||||
      let action = followControllerActions.enable(true);
 | 
			
		||||
      expect(action.type).to.equal(actions.FOLLOW_CONTROLLER_ENABLE);
 | 
			
		||||
      expect(action.newTab).to.equal(true);
 | 
			
		||||
    });
 | 
			
		||||
  });
 | 
			
		||||
 | 
			
		||||
  describe('disable', () => {
 | 
			
		||||
    it('creates FOLLOW_CONTROLLER_DISABLE action', () => {
 | 
			
		||||
      let action = followControllerActions.disable(true);
 | 
			
		||||
      expect(action.type).to.equal(actions.FOLLOW_CONTROLLER_DISABLE);
 | 
			
		||||
    });
 | 
			
		||||
  });
 | 
			
		||||
 | 
			
		||||
  describe('keyPress', () => {
 | 
			
		||||
    it('creates FOLLOW_CONTROLLER_KEY_PRESS action', () => {
 | 
			
		||||
      let action = followControllerActions.keyPress(100);
 | 
			
		||||
      expect(action.type).to.equal(actions.FOLLOW_CONTROLLER_KEY_PRESS);
 | 
			
		||||
      expect(action.key).to.equal(100);
 | 
			
		||||
    });
 | 
			
		||||
  });
 | 
			
		||||
 | 
			
		||||
  describe('backspace', () => {
 | 
			
		||||
    it('creates FOLLOW_CONTROLLER_BACKSPACE action', () => {
 | 
			
		||||
      let action = followControllerActions.backspace(100);
 | 
			
		||||
      expect(action.type).to.equal(actions.FOLLOW_CONTROLLER_BACKSPACE);
 | 
			
		||||
    });
 | 
			
		||||
  });
 | 
			
		||||
});
 | 
			
		||||
| 
						 | 
				
			
			@ -1,19 +0,0 @@
 | 
			
		|||
import * as actions from 'content/actions';
 | 
			
		||||
import * as inputActions from 'content/actions/input';
 | 
			
		||||
 | 
			
		||||
describe("input actions", () => {
 | 
			
		||||
  describe("keyPress", () => {
 | 
			
		||||
    it('create INPUT_KEY_PRESS action', () => {
 | 
			
		||||
      let action = inputActions.keyPress('a');
 | 
			
		||||
      expect(action.type).to.equal(actions.INPUT_KEY_PRESS);
 | 
			
		||||
      expect(action.key).to.equal('a');
 | 
			
		||||
    });
 | 
			
		||||
  });
 | 
			
		||||
 | 
			
		||||
  describe("clearKeys", () => {
 | 
			
		||||
    it('create INPUT_CLEAR_KEYSaction', () => {
 | 
			
		||||
      let action = inputActions.clearKeys();
 | 
			
		||||
      expect(action.type).to.equal(actions.INPUT_CLEAR_KEYS);
 | 
			
		||||
    });
 | 
			
		||||
  });
 | 
			
		||||
});
 | 
			
		||||
| 
						 | 
				
			
			@ -1,25 +0,0 @@
 | 
			
		|||
import * as actions from 'content/actions';
 | 
			
		||||
import * as markActions from 'content/actions/mark';
 | 
			
		||||
 | 
			
		||||
describe('mark actions', () => {
 | 
			
		||||
  describe('startSet', () => {
 | 
			
		||||
    it('create MARK_START_SET action', () => {
 | 
			
		||||
      let action = markActions.startSet();
 | 
			
		||||
      expect(action.type).to.equal(actions.MARK_START_SET);
 | 
			
		||||
    });
 | 
			
		||||
  });
 | 
			
		||||
 | 
			
		||||
  describe('startJump', () => {
 | 
			
		||||
    it('create MARK_START_JUMP action', () => {
 | 
			
		||||
      let action = markActions.startJump();
 | 
			
		||||
      expect(action.type).to.equal(actions.MARK_START_JUMP);
 | 
			
		||||
    });
 | 
			
		||||
  });
 | 
			
		||||
 | 
			
		||||
  describe('cancel', () => {
 | 
			
		||||
    it('create MARK_CANCEL action', () => {
 | 
			
		||||
      let action = markActions.cancel();
 | 
			
		||||
      expect(action.type).to.equal(actions.MARK_CANCEL);
 | 
			
		||||
    });
 | 
			
		||||
  });
 | 
			
		||||
});
 | 
			
		||||
| 
						 | 
				
			
			@ -1,17 +0,0 @@
 | 
			
		|||
<!DOCTYPE html>
 | 
			
		||||
<html>
 | 
			
		||||
  <body>
 | 
			
		||||
    <a id='visible_a' href='#' >link</a>
 | 
			
		||||
    <a href='#' style='display:none'>invisible 1</a>
 | 
			
		||||
    <a href='#' style='visibility:hidden'>invisible 2</a>
 | 
			
		||||
    <i>not link<i>
 | 
			
		||||
    <div id='editable_div_1' contenteditable>link</div>
 | 
			
		||||
    <div id='editable_div_2' contenteditable='true'>link</div>
 | 
			
		||||
    <div id='x' contenteditable='false'>link</div>
 | 
			
		||||
    <details>
 | 
			
		||||
      <summary id='summary_1'>summary link</summary>
 | 
			
		||||
      Some details
 | 
			
		||||
      <a href='#'>not visible</a>
 | 
			
		||||
    </details>
 | 
			
		||||
  </body>
 | 
			
		||||
</html>
 | 
			
		||||
| 
						 | 
				
			
			@ -1,25 +0,0 @@
 | 
			
		|||
import FollowComponent from 'content/components/common/follow';
 | 
			
		||||
 | 
			
		||||
describe('FollowComponent', () => {
 | 
			
		||||
  describe('#getTargetElements', () => {
 | 
			
		||||
    beforeEach(() => {
 | 
			
		||||
      document.body.innerHTML = __html__['test/content/components/common/follow.html'];
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
    it('returns visible links', () => {
 | 
			
		||||
      let targets = FollowComponent.getTargetElements(
 | 
			
		||||
        window,
 | 
			
		||||
        { width: window.innerWidth, height: window.innerHeight },
 | 
			
		||||
        { x: 0, y: 0 });
 | 
			
		||||
      expect(targets).to.have.lengthOf(4);
 | 
			
		||||
 | 
			
		||||
      let ids = Array.prototype.map.call(targets, (e) => e.id);
 | 
			
		||||
      expect(ids).to.include.members([
 | 
			
		||||
        'visible_a',
 | 
			
		||||
        'editable_div_1',
 | 
			
		||||
        'editable_div_2',
 | 
			
		||||
        'summary_1',
 | 
			
		||||
      ]);
 | 
			
		||||
    });
 | 
			
		||||
  });
 | 
			
		||||
});
 | 
			
		||||
| 
						 | 
				
			
			@ -1,47 +0,0 @@
 | 
			
		|||
import * as actions from 'content/actions';
 | 
			
		||||
import followControllerReducer from 'content/reducers/follow-controller';
 | 
			
		||||
 | 
			
		||||
describe('follow-controller reducer', () => {
 | 
			
		||||
  it ('returns the initial state', () => {
 | 
			
		||||
    let state = followControllerReducer(undefined, {});
 | 
			
		||||
    expect(state).to.have.property('enabled', false);
 | 
			
		||||
    expect(state).to.have.property('newTab');
 | 
			
		||||
    expect(state).to.have.deep.property('keys', '');
 | 
			
		||||
  });
 | 
			
		||||
 | 
			
		||||
  it ('returns next state for FOLLOW_CONTROLLER_ENABLE', () => {
 | 
			
		||||
    let action = { type: actions.FOLLOW_CONTROLLER_ENABLE, newTab: true };
 | 
			
		||||
    let state = followControllerReducer({ enabled: false, newTab: false }, action);
 | 
			
		||||
    expect(state).to.have.property('enabled', true);
 | 
			
		||||
    expect(state).to.have.property('newTab', true);
 | 
			
		||||
    expect(state).to.have.property('keys', '');
 | 
			
		||||
  });
 | 
			
		||||
 | 
			
		||||
  it ('returns next state for FOLLOW_CONTROLLER_DISABLE', () => {
 | 
			
		||||
    let action = { type: actions.FOLLOW_CONTROLLER_DISABLE };
 | 
			
		||||
    let state = followControllerReducer({ enabled: true }, action);
 | 
			
		||||
    expect(state).to.have.property('enabled', false);
 | 
			
		||||
  });
 | 
			
		||||
 | 
			
		||||
  it ('returns next state for FOLLOW_CONTROLLER_KEY_PRESS', () => {
 | 
			
		||||
    let action = { type: actions.FOLLOW_CONTROLLER_KEY_PRESS, key: 'a'};
 | 
			
		||||
    let state = followControllerReducer({ keys: '' }, action);
 | 
			
		||||
    expect(state).to.have.deep.property('keys', 'a');
 | 
			
		||||
 | 
			
		||||
    action = { type: actions.FOLLOW_CONTROLLER_KEY_PRESS, key: 'b'};
 | 
			
		||||
    state = followControllerReducer(state, action);
 | 
			
		||||
    expect(state).to.have.deep.property('keys', 'ab');
 | 
			
		||||
  });
 | 
			
		||||
 | 
			
		||||
  it ('returns next state for FOLLOW_CONTROLLER_BACKSPACE', () => {
 | 
			
		||||
    let action = { type: actions.FOLLOW_CONTROLLER_BACKSPACE };
 | 
			
		||||
    let state = followControllerReducer({ keys: 'ab' }, action);
 | 
			
		||||
    expect(state).to.have.deep.property('keys', 'a');
 | 
			
		||||
 | 
			
		||||
    state = followControllerReducer(state, action);
 | 
			
		||||
    expect(state).to.have.deep.property('keys', '');
 | 
			
		||||
 | 
			
		||||
    state = followControllerReducer(state, action);
 | 
			
		||||
    expect(state).to.have.deep.property('keys', '');
 | 
			
		||||
  });
 | 
			
		||||
});
 | 
			
		||||
| 
						 | 
				
			
			@ -1,25 +0,0 @@
 | 
			
		|||
import * as actions from 'content/actions';
 | 
			
		||||
import inputReducer from 'content/reducers/input';
 | 
			
		||||
 | 
			
		||||
describe("input reducer", () => {
 | 
			
		||||
  it('return the initial state', () => {
 | 
			
		||||
    let state = inputReducer(undefined, {});
 | 
			
		||||
    expect(state).to.have.deep.property('keys', []);
 | 
			
		||||
  });
 | 
			
		||||
 | 
			
		||||
  it('return next state for INPUT_KEY_PRESS', () => {
 | 
			
		||||
    let action = { type: actions.INPUT_KEY_PRESS, key: 'a' };
 | 
			
		||||
    let state = inputReducer(undefined, action);
 | 
			
		||||
    expect(state).to.have.deep.property('keys', ['a']);
 | 
			
		||||
 | 
			
		||||
    action = { type: actions.INPUT_KEY_PRESS, key: 'b' };
 | 
			
		||||
    state = inputReducer(state, action);
 | 
			
		||||
    expect(state).to.have.deep.property('keys', ['a', 'b']);
 | 
			
		||||
  });
 | 
			
		||||
 | 
			
		||||
  it('return next state for INPUT_CLEAR_KEYS', () => {
 | 
			
		||||
    let action = { type: actions.INPUT_CLEAR_KEYS };
 | 
			
		||||
    let state = inputReducer({ keys: [1, 2, 3] }, action);
 | 
			
		||||
    expect(state).to.have.deep.property('keys', []);
 | 
			
		||||
  });
 | 
			
		||||
});
 | 
			
		||||
| 
						 | 
				
			
			@ -1,31 +0,0 @@
 | 
			
		|||
import * as actions from 'content/actions';
 | 
			
		||||
import reducer from 'content/reducers/mark';
 | 
			
		||||
 | 
			
		||||
describe("mark reducer", () => {
 | 
			
		||||
  it('return the initial state', () => {
 | 
			
		||||
    let state = reducer(undefined, {});
 | 
			
		||||
    expect(state.setMode).to.be.false;
 | 
			
		||||
    expect(state.jumpMode).to.be.false;
 | 
			
		||||
  });
 | 
			
		||||
 | 
			
		||||
  it('starts set mode', () => {
 | 
			
		||||
    let action = { type: actions.MARK_START_SET };
 | 
			
		||||
    let state = reducer(undefined, action);
 | 
			
		||||
    expect(state.setMode).to.be.true;
 | 
			
		||||
  });
 | 
			
		||||
 | 
			
		||||
  it('starts jump mode', () => {
 | 
			
		||||
    let action = { type: actions.MARK_START_JUMP };
 | 
			
		||||
    let state = reducer(undefined, action);
 | 
			
		||||
    expect(state.jumpMode).to.be.true;
 | 
			
		||||
  });
 | 
			
		||||
 | 
			
		||||
  it('cancels set and jump mode', () => {
 | 
			
		||||
    let action = { type: actions.MARK_CANCEL };
 | 
			
		||||
    let state = reducer({ setMode: true }, action);
 | 
			
		||||
    expect(state.setMode).to.be.false;
 | 
			
		||||
 | 
			
		||||
    state = reducer({ jumpMode: true }, action);
 | 
			
		||||
    expect(state.jumpMode).to.be.false;
 | 
			
		||||
  });
 | 
			
		||||
});
 | 
			
		||||
		Reference in a new issue