diff options
| author | Shin'ya Ueoka <ueokande@i-beam.org> | 2019-05-16 21:35:58 +0900 | 
|---|---|---|
| committer | Shin'ya Ueoka <ueokande@i-beam.org> | 2019-05-17 23:06:27 +0900 | 
| commit | fb8b4d28ce47171a83a7bf5148293fd2318cc02f (patch) | |
| tree | 02e23efe01d38adeb6dafb6794bc1d3e4866a055 /src/content/components | |
| parent | 8cef5981b808bc1713170627c88dc26ca81063c1 (diff) | |
Hints as a classes
Diffstat (limited to 'src/content/components')
| -rw-r--r-- | src/content/components/common/follow.ts | 79 | ||||
| -rw-r--r-- | src/content/components/common/hint.ts | 62 | 
2 files changed, 25 insertions, 116 deletions
diff --git a/src/content/components/common/follow.ts b/src/content/components/common/follow.ts index 67f2dd9..a30a3d5 100644 --- a/src/content/components/common/follow.ts +++ b/src/content/components/common/follow.ts @@ -1,8 +1,11 @@  import MessageListener from '../../MessageListener'; -import Hint from './hint'; +import Hint, { LinkHint, InputHint } from '../../presenters/Hint';  import * as dom from '../../../shared/utils/dom';  import * as messages from '../../../shared/messages';  import * as keyUtils from '../../../shared/utils/keys'; +import TabsClient, { TabsClientImpl } from '../../client/TabsClient'; + +let tabsClient: TabsClient = new TabsClientImpl();  const TARGET_SELECTOR = [    'a', 'button', 'input', 'textarea', 'area', @@ -95,27 +98,6 @@ export default class Follow {      return true;    } -  openLink(element: HTMLAreaElement|HTMLAnchorElement) { -    // Browser prevent new tab by link with target='_blank' -    if (!this.newTab && element.getAttribute('target') !== '_blank') { -      element.click(); -      return; -    } - -    let href = element.getAttribute('href'); - -    // eslint-disable-next-line no-script-url -    if (!href || href === '#' || href.toLowerCase().startsWith('javascript:')) { -      return; -    } -    return browser.runtime.sendMessage({ -      type: messages.OPEN_URL, -      url: element.href, -      newTab: true, -      background: this.background, -    }); -  } -    countHints(sender: any, viewSize: Size, framePosition: Point) {      this.targets = Follow.getTargetElements(this.win, viewSize, framePosition);      sender.postMessage(JSON.stringify({ @@ -134,8 +116,13 @@ export default class Follow {      this.hints = {};      for (let i = 0; i < keysArray.length; ++i) {        let keys = keysArray[i]; -      let hint = new Hint(this.targets[i], keys); -      this.hints[keys] = hint; +      let target = this.targets[i]; +      if (target instanceof HTMLAnchorElement || +        target instanceof HTMLAreaElement) { +        this.hints[keys] = new LinkHint(target, keys); +      } else { +        this.hints[keys] = new InputHint(target, keys); +      }      }    } @@ -154,42 +141,26 @@ export default class Follow {      this.targets = [];    } -  activateHints(keys: string) { +  async activateHints(keys: string): Promise<void> {      let hint = this.hints[keys];      if (!hint) {        return;      } -    let element = hint.getTarget(); -    switch (element.tagName.toLowerCase()) { -    case 'a': -      return this.openLink(element as HTMLAnchorElement); -    case 'area': -      return this.openLink(element as HTMLAreaElement); -    case 'input': -      switch ((element as HTMLInputElement).type) { -      case 'file': -      case 'checkbox': -      case 'radio': -      case 'submit': -      case 'reset': -      case 'button': -      case 'image': -      case 'color': -        return element.click(); -      default: -        return element.focus(); + +    if (hint instanceof LinkHint) { +      let url = hint.getLink(); +      // ignore taget='_blank' +      if (!this.newTab && hint.getLinkTarget() !== '_blank') { +        hint.click(); +        return;        } -    case 'textarea': -      return element.focus(); -    case 'button': -    case 'summary': -      return element.click(); -    default: -      if (dom.isContentEditable(element)) { -        return element.focus(); -      } else if (element.hasAttribute('tabindex')) { -        return element.click(); +      // eslint-disable-next-line no-script-url +      if (!url || url === '#' || url.toLowerCase().startsWith('javascript:')) { +        return;        } +      await tabsClient.openUrl(url, this.newTab, this.background); +    } else if (hint instanceof InputHint) { +      hint.activate();      }    } diff --git a/src/content/components/common/hint.ts b/src/content/components/common/hint.ts deleted file mode 100644 index 2fcbb0f..0000000 --- a/src/content/components/common/hint.ts +++ /dev/null @@ -1,62 +0,0 @@ -import * as dom from '../../../shared/utils/dom'; - -interface Point { -  x: number; -  y: number; -} - -const hintPosition = (element: Element): Point => { -  let { left, top, right, bottom } = dom.viewportRect(element); - -  if (element.tagName !== 'AREA') { -    return { x: left, y: top }; -  } - -  return { -    x: (left + right) / 2, -    y: (top + bottom) / 2, -  }; -}; - -export default class Hint { -  private target: HTMLElement; - -  private element: HTMLElement; - -  constructor(target: HTMLElement, tag: string) { -    let doc = target.ownerDocument; -    if (doc === null) { -      throw new TypeError('ownerDocument is null'); -    } - -    let { x, y } = hintPosition(target); -    let { scrollX, scrollY } = window; - -    this.target = target; - -    this.element = doc.createElement('span'); -    this.element.className = 'vimvixen-hint'; -    this.element.textContent = tag; -    this.element.style.left = x + scrollX + 'px'; -    this.element.style.top = y + scrollY + 'px'; - -    this.show(); -    doc.body.append(this.element); -  } - -  show(): void { -    this.element.style.display = 'inline'; -  } - -  hide(): void { -    this.element.style.display = 'none'; -  } - -  remove(): void { -    this.element.remove(); -  } - -  getTarget(): HTMLElement { -    return this.target; -  } -}  | 
