aboutsummaryrefslogtreecommitdiff
path: root/src/content/presenters
diff options
context:
space:
mode:
Diffstat (limited to 'src/content/presenters')
-rw-r--r--src/content/presenters/ConsoleFramePresenter.ts12
-rw-r--r--src/content/presenters/FindPresenter.ts5
-rw-r--r--src/content/presenters/FocusPresenter.ts13
-rw-r--r--src/content/presenters/FollowPresenter.ts83
-rw-r--r--src/content/presenters/Hint.ts66
-rw-r--r--src/content/presenters/NavigationPresenter.ts19
-rw-r--r--src/content/presenters/ScrollPresenter.ts20
7 files changed, 121 insertions, 97 deletions
diff --git a/src/content/presenters/ConsoleFramePresenter.ts b/src/content/presenters/ConsoleFramePresenter.ts
index 63c78fb..26522c4 100644
--- a/src/content/presenters/ConsoleFramePresenter.ts
+++ b/src/content/presenters/ConsoleFramePresenter.ts
@@ -6,17 +6,17 @@ export default interface ConsoleFramePresenter {
export class ConsoleFramePresenterImpl implements ConsoleFramePresenter {
initialize(): void {
- const iframe = document.createElement('iframe');
- iframe.src = browser.runtime.getURL('build/console.html');
- iframe.id = 'vimvixen-console-frame';
- iframe.className = 'vimvixen-console-frame';
+ const iframe = document.createElement("iframe");
+ iframe.src = browser.runtime.getURL("build/console.html");
+ iframe.id = "vimvixen-console-frame";
+ iframe.className = "vimvixen-console-frame";
document.body.append(iframe);
}
blur(): void {
- const ele = document.getElementById('vimvixen-console-frame');
+ const ele = document.getElementById("vimvixen-console-frame");
if (!ele) {
- throw new Error('console frame not created');
+ throw new Error("console frame not created");
}
ele.blur();
}
diff --git a/src/content/presenters/FindPresenter.ts b/src/content/presenters/FindPresenter.ts
index 98d8088..117142c 100644
--- a/src/content/presenters/FindPresenter.ts
+++ b/src/content/presenters/FindPresenter.ts
@@ -1,4 +1,3 @@
-
export default interface FindPresenter {
find(keyword: string, backwards: boolean): boolean;
@@ -18,7 +17,8 @@ interface MyWindow extends Window {
aWrapAround?: boolean,
aWholeWord?: boolean,
aSearchInFrames?: boolean,
- aShowDialog?: boolean): boolean;
+ aShowDialog?: boolean
+ ): boolean;
}
// eslint-disable-next-line no-var, vars-on-top, init-declarations
@@ -29,7 +29,6 @@ export class FindPresenterImpl implements FindPresenter {
const caseSensitive = false;
const wrapScan = true;
-
// NOTE: aWholeWord dows not implemented, and aSearchInFrames does not work
// because of same origin policy
const found = window.find(keyword, caseSensitive, backwards, wrapScan);
diff --git a/src/content/presenters/FocusPresenter.ts b/src/content/presenters/FocusPresenter.ts
index 842c41e..4d70a6e 100644
--- a/src/content/presenters/FocusPresenter.ts
+++ b/src/content/presenters/FocusPresenter.ts
@@ -1,4 +1,4 @@
-import * as doms from '../../shared/utils/dom';
+import * as doms from "../../shared/utils/dom";
export default interface FocusPresenter {
focusFirstElement(): boolean;
@@ -6,9 +6,13 @@ export default interface FocusPresenter {
export class FocusPresenterImpl implements FocusPresenter {
focusFirstElement(): boolean {
- const inputTypes = ['email', 'number', 'search', 'tel', 'text', 'url'];
- const inputSelector = inputTypes.map(type => `input[type=${type}]`).join(',');
- const targets = window.document.querySelectorAll(inputSelector + ',textarea');
+ const inputTypes = ["email", "number", "search", "tel", "text", "url"];
+ const inputSelector = inputTypes
+ .map((type) => `input[type=${type}]`)
+ .join(",");
+ const targets = window.document.querySelectorAll(
+ inputSelector + ",textarea"
+ );
const target = Array.from(targets).find(doms.isVisible);
if (target instanceof HTMLInputElement) {
target.focus();
@@ -20,4 +24,3 @@ export class FocusPresenterImpl implements FocusPresenter {
return false;
}
}
-
diff --git a/src/content/presenters/FollowPresenter.ts b/src/content/presenters/FollowPresenter.ts
index fef8140..8aef819 100644
--- a/src/content/presenters/FollowPresenter.ts
+++ b/src/content/presenters/FollowPresenter.ts
@@ -1,11 +1,18 @@
-import Hint, { InputHint, LinkHint } from './Hint';
-import * as doms from '../../shared/utils/dom';
+import Hint, { InputHint, LinkHint } from "./Hint";
+import * as doms from "../../shared/utils/dom";
const TARGET_SELECTOR = [
- 'a', 'button', 'input', 'textarea', 'area',
- '[contenteditable=true]', '[contenteditable=""]', '[tabindex]',
- '[role="button"]', 'summary'
-].join(',');
+ "a",
+ "button",
+ "input",
+ "textarea",
+ "area",
+ "[contenteditable=true]",
+ '[contenteditable=""]',
+ "[tabindex]",
+ '[role="button"]',
+ "summary",
+].join(",");
interface Size {
width: number;
@@ -21,11 +28,9 @@ const inViewport = (
win: Window,
element: Element,
viewSize: Size,
- framePosition: Point,
+ framePosition: Point
): boolean => {
- const {
- top, left, bottom, right
- } = doms.viewportRect(element);
+ const { top, left, bottom, right } = doms.viewportRect(element);
const doc = win.document;
const frameWidth = doc.documentElement.clientWidth;
const frameHeight = doc.documentElement.clientHeight;
@@ -34,9 +39,12 @@ const inViewport = (
// out of frame
return false;
}
- if (right + framePosition.x < 0 || bottom + framePosition.y < 0 ||
- left + framePosition.x > viewSize.width ||
- top + framePosition.y > viewSize.height) {
+ if (
+ right + framePosition.x < 0 ||
+ bottom + framePosition.y < 0 ||
+ left + framePosition.x > viewSize.width ||
+ top + framePosition.y > viewSize.height
+ ) {
// out of viewport
return false;
}
@@ -47,11 +55,11 @@ const isAriaHiddenOrAriaDisabled = (win: Window, element: Element): boolean => {
if (!element || win.document.documentElement === element) {
return false;
}
- for (const attr of ['aria-hidden', 'aria-disabled']) {
+ for (const attr of ["aria-hidden", "aria-disabled"]) {
const value = element.getAttribute(attr);
if (value !== null) {
const hidden = value.toLowerCase();
- if (hidden === '' || hidden === 'true') {
+ if (hidden === "" || hidden === "true") {
return true;
}
}
@@ -88,8 +96,10 @@ export class FollowPresenterImpl implements FollowPresenter {
const min = Math.min(targets.length, tags.length);
for (let i = 0; i < min; ++i) {
const target = targets[i];
- if (target instanceof HTMLAnchorElement ||
- target instanceof HTMLAreaElement) {
+ if (
+ target instanceof HTMLAnchorElement ||
+ target instanceof HTMLAreaElement
+ ) {
this.hints.push(new LinkHint(target, tags[i]));
} else {
this.hints.push(new InputHint(target, tags[i]));
@@ -98,35 +108,40 @@ export class FollowPresenterImpl implements FollowPresenter {
}
filterHints(prefix: string): void {
- const shown = this.hints.filter(h => h.getTag().startsWith(prefix));
- const hidden = this.hints.filter(h => !h.getTag().startsWith(prefix));
+ const shown = this.hints.filter((h) => h.getTag().startsWith(prefix));
+ const hidden = this.hints.filter((h) => !h.getTag().startsWith(prefix));
- shown.forEach(h => h.show());
- hidden.forEach(h => h.hide());
+ shown.forEach((h) => h.show());
+ hidden.forEach((h) => h.hide());
}
clearHints(): void {
- this.hints.forEach(h => h.remove());
+ this.hints.forEach((h) => h.remove());
this.hints = [];
}
getHint(tag: string): Hint | undefined {
- return this.hints.find(h => h.getTag() === tag);
+ return this.hints.find((h) => h.getTag() === tag);
}
private getTargets(viewSize: Size, framePosition: Point): HTMLElement[] {
const all = window.document.querySelectorAll(TARGET_SELECTOR);
- const filtered = Array.prototype.filter.call(all, (element: HTMLElement) => {
- const style = window.getComputedStyle(element);
-
- // AREA's 'display' in Browser style is 'none'
- return (element.tagName === 'AREA' || style.display !== 'none') &&
- style.visibility !== 'hidden' &&
- (element as HTMLInputElement).type !== 'hidden' &&
- element.offsetHeight > 0 &&
- !isAriaHiddenOrAriaDisabled(window, element) &&
- inViewport(window, element, viewSize, framePosition);
- });
+ const filtered = Array.prototype.filter.call(
+ all,
+ (element: HTMLElement) => {
+ const style = window.getComputedStyle(element);
+
+ // AREA's 'display' in Browser style is 'none'
+ return (
+ (element.tagName === "AREA" || style.display !== "none") &&
+ style.visibility !== "hidden" &&
+ (element as HTMLInputElement).type !== "hidden" &&
+ element.offsetHeight > 0 &&
+ !isAriaHiddenOrAriaDisabled(window, element) &&
+ inViewport(window, element, viewSize, framePosition)
+ );
+ }
+ );
return filtered;
}
}
diff --git a/src/content/presenters/Hint.ts b/src/content/presenters/Hint.ts
index 44b8185..3f39060 100644
--- a/src/content/presenters/Hint.ts
+++ b/src/content/presenters/Hint.ts
@@ -1,4 +1,4 @@
-import * as doms from '../../shared/utils/dom';
+import * as doms from "../../shared/utils/dom";
interface Point {
x: number;
@@ -8,7 +8,7 @@ interface Point {
const hintPosition = (element: Element): Point => {
const { left, top, right, bottom } = doms.viewportRect(element);
- if (element.tagName !== 'AREA') {
+ if (element.tagName !== "AREA") {
return { x: left, y: top };
}
@@ -28,17 +28,17 @@ export default abstract class Hint {
const doc = target.ownerDocument;
if (doc === null) {
- throw new TypeError('ownerDocument is null');
+ throw new TypeError("ownerDocument is null");
}
const { x, y } = hintPosition(target);
const { scrollX, scrollY } = window;
- const hint = doc.createElement('span');
- hint.className = 'vimvixen-hint';
+ const hint = doc.createElement("span");
+ hint.className = "vimvixen-hint";
hint.textContent = tag;
- hint.style.left = x + scrollX + 'px';
- hint.style.top = y + scrollY + 'px';
+ hint.style.left = x + scrollX + "px";
+ hint.style.top = y + scrollY + "px";
doc.body.append(hint);
@@ -47,11 +47,11 @@ export default abstract class Hint {
}
show(): void {
- this.hint.style.display = 'inline';
+ this.hint.style.display = "inline";
}
hide(): void {
- this.hint.style.display = 'none';
+ this.hint.style.display = "none";
}
remove(): void {
@@ -77,7 +77,7 @@ export class LinkHint extends Hint {
}
getLinkTarget(): string | null {
- return this.target.getAttribute('target');
+ return this.target.getAttribute("target");
}
click(): void {
@@ -97,31 +97,31 @@ export class InputHint extends Hint {
activate(): void {
const target = this.target;
switch (target.tagName.toLowerCase()) {
- case 'input':
- switch ((target as HTMLInputElement).type) {
- case 'file':
- case 'checkbox':
- case 'radio':
- case 'submit':
- case 'reset':
- case 'button':
- case 'image':
- case 'color':
- return target.click();
- default:
+ case "input":
+ switch ((target as HTMLInputElement).type) {
+ case "file":
+ case "checkbox":
+ case "radio":
+ case "submit":
+ case "reset":
+ case "button":
+ case "image":
+ case "color":
+ return target.click();
+ default:
+ return target.focus();
+ }
+ case "textarea":
return target.focus();
- }
- case 'textarea':
- return target.focus();
- case 'button':
- case 'summary':
- return target.click();
- default:
- if (doms.isContentEditable(target)) {
- return target.focus();
- } else if (target.hasAttribute('tabindex')) {
+ case "button":
+ case "summary":
return target.click();
- }
+ default:
+ if (doms.isContentEditable(target)) {
+ return target.focus();
+ } else if (target.hasAttribute("tabindex")) {
+ return target.click();
+ }
}
}
}
diff --git a/src/content/presenters/NavigationPresenter.ts b/src/content/presenters/NavigationPresenter.ts
index 951e62a..3edcd12 100644
--- a/src/content/presenters/NavigationPresenter.ts
+++ b/src/content/presenters/NavigationPresenter.ts
@@ -8,7 +8,7 @@ export default interface NavigationPresenter {
openLinkNext(): void;
}
-const REL_PATTERN: {[key: string]: RegExp} = {
+const REL_PATTERN: { [key: string]: RegExp } = {
prev: /^(?:prev(?:ious)?|older)\b|\u2039|\u2190|\xab|\u226a|<</i,
next: /^(?:next|newer)\b|\u203a|\u2192|\xbb|\u226b|>>/i,
};
@@ -18,7 +18,7 @@ const REL_PATTERN: {[key: string]: RegExp} = {
// eslint-disable-next-line func-style
function selectLast<E extends Element>(
selector: string,
- filter?: (e: E) => boolean,
+ filter?: (e: E) => boolean
): E | null {
let nodes = Array.from(
window.document.querySelectorAll(selector) as NodeListOf<E>
@@ -40,15 +40,15 @@ export class NavigationPresenterImpl implements NavigationPresenter {
}
openLinkPrev(): void {
- this.linkRel('prev');
+ this.linkRel("prev");
}
openLinkNext(): void {
- this.linkRel('next');
+ this.linkRel("next");
}
// Code common to linkPrev and linkNext which navigates to the specified page.
- private linkRel(rel: 'prev' | 'next'): void {
+ private linkRel(rel: "prev" | "next"): void {
const link = selectLast<HTMLLinkElement>(`link[rel~=${rel}][href]`);
if (link) {
window.location.href = link.href;
@@ -57,10 +57,11 @@ export class NavigationPresenterImpl implements NavigationPresenter {
const pattern = REL_PATTERN[rel];
- const a = selectLast<HTMLAnchorElement>(`a[rel~=${rel}][href]`) ||
- // `innerText` is much slower than `textContent`, but produces much better
- // (i.e. less unexpected) results
- selectLast('a[href]', lnk => pattern.test(lnk.innerText));
+ const a =
+ selectLast<HTMLAnchorElement>(`a[rel~=${rel}][href]`) ||
+ // `innerText` is much slower than `textContent`, but produces much better
+ // (i.e. less unexpected) results
+ selectLast("a[href]", (lnk) => pattern.test(lnk.innerText));
if (a) {
a.click();
diff --git a/src/content/presenters/ScrollPresenter.ts b/src/content/presenters/ScrollPresenter.ts
index 387ab62..f1a6402 100644
--- a/src/content/presenters/ScrollPresenter.ts
+++ b/src/content/presenters/ScrollPresenter.ts
@@ -1,4 +1,4 @@
-import * as doms from '../../shared/utils/dom';
+import * as doms from "../../shared/utils/dom";
const SCROLL_DELTA_X = 64;
const SCROLL_DELTA_Y = 64;
@@ -9,13 +9,19 @@ let lastTimeoutId: number | null = null;
const isScrollableStyle = (element: Element): boolean => {
const { overflowX, overflowY } = window.getComputedStyle(element);
- return !(overflowX !== 'scroll' && overflowX !== 'auto' &&
- overflowY !== 'scroll' && overflowY !== 'auto');
+ return !(
+ overflowX !== "scroll" &&
+ overflowX !== "auto" &&
+ overflowY !== "scroll" &&
+ overflowY !== "auto"
+ );
};
const isOverflowed = (element: Element): boolean => {
- return element.scrollWidth > element.clientWidth ||
- element.scrollHeight > element.clientHeight;
+ return (
+ element.scrollWidth > element.clientWidth ||
+ element.scrollHeight > element.clientHeight
+ );
};
// Find a visiable and scrollable element by depth-first search. Currently
@@ -73,7 +79,7 @@ class Scroller {
this.element.scrollTo({
left: x,
top: y,
- behavior: 'smooth',
+ behavior: "smooth",
});
this.prepareReset();
}
@@ -94,7 +100,7 @@ class Scroller {
}
}
-export type Point = { x: number, y: number };
+export type Point = { x: number; y: number };
export default interface ScrollPresenter {
getScroll(): Point;