diff --git a/src/shared/blacklists.ts b/src/shared/blacklists.ts index 61720c3..61ee4de 100644 --- a/src/shared/blacklists.ts +++ b/src/shared/blacklists.ts @@ -1,6 +1,6 @@ -import * as re from 'shared/utils/re'; +import * as re from './utils/re'; -const includes = (blacklist, url) => { +const includes = (blacklist: string[], url: string): boolean => { let u = new URL(url); return blacklist.some((item) => { if (!item.includes('/')) { diff --git a/src/shared/messages.ts b/src/shared/messages.ts index ddf3368..2bc12d8 100644 --- a/src/shared/messages.ts +++ b/src/shared/messages.ts @@ -1,5 +1,8 @@ -const onWebMessage = (listener) => { - window.addEventListener('message', (event) => { +type WebMessageSender = Window | MessagePort | ServiceWorker | null; +type WebMessageListener = (msg: any, sender: WebMessageSender | null) => void; + +const onWebMessage = (listener: WebMessageListener) => { + window.addEventListener('message', (event: MessageEvent) => { let sender = event.source; let message = null; try { @@ -12,11 +15,15 @@ const onWebMessage = (listener) => { }); }; -const onBackgroundMessage = (listener) => { +const onBackgroundMessage = ( + listener: (msg: any, sender: browser.runtime.MessageSender, +) => void) => { browser.runtime.onMessage.addListener(listener); }; -const onMessage = (listener) => { +const onMessage = ( + listener: (msg: any, sender: WebMessageSender | browser.runtime.MessageSender, +) => void) => { onWebMessage(listener); onBackgroundMessage(listener); }; diff --git a/src/shared/operations.ts b/src/shared/operations.ts index 8674f4d..d59723e 100644 --- a/src/shared/operations.ts +++ b/src/shared/operations.ts @@ -1,4 +1,4 @@ -export default { +const operations: { [key: string]: string } = { // Hide console, or cancel some user actions CANCEL: 'cancel', @@ -76,3 +76,5 @@ export default { MARK_SET_PREFIX: 'mark.set.prefix', MARK_JUMP_PREFIX: 'mark.jump.prefix', }; + +export default operations; diff --git a/src/shared/settings/properties.ts b/src/shared/settings/properties.ts index f8e61a0..7d037df 100644 --- a/src/shared/settings/properties.ts +++ b/src/shared/settings/properties.ts @@ -2,20 +2,20 @@ // mystr: 'string', // mynum: 'number', // mybool: 'boolean', -const types = { +const types: { [key: string]: string } = { hintchars: 'string', smoothscroll: 'boolean', complete: 'string', }; // describe default values of a property -const defaults = { +const defaults: { [key: string]: string | number | boolean } = { hintchars: 'abcdefghijklmnopqrstuvwxyz', smoothscroll: false, complete: 'sbh', }; -const docs = { +const docs: { [key: string]: string } = { hintchars: 'hint characters on follow mode', smoothscroll: 'smooth scroll', complete: 'which are completed at the open page', diff --git a/src/shared/settings/storage.ts b/src/shared/settings/storage.ts index 5dce3b0..90a3a66 100644 --- a/src/shared/settings/storage.ts +++ b/src/shared/settings/storage.ts @@ -1,12 +1,12 @@ import DefaultSettings from './default'; import * as settingsValues from './values'; -const loadRaw = async() => { +const loadRaw = async(): Promise => { let { settings } = await browser.storage.local.get('settings'); if (!settings) { return DefaultSettings; } - return { ...DefaultSettings, ...settings }; + return { ...DefaultSettings, ...settings as object }; }; const loadValue = async() => { @@ -23,7 +23,7 @@ const loadValue = async() => { return { ...settingsValues.valueFromJson(DefaultSettings.json), ...value }; }; -const save = (settings) => { +const save = (settings: any): Promise => { return browser.storage.local.set({ settings, }); diff --git a/src/shared/settings/validator.ts b/src/shared/settings/validator.ts index a800a52..0483931 100644 --- a/src/shared/settings/validator.ts +++ b/src/shared/settings/validator.ts @@ -1,4 +1,4 @@ -import operations from 'shared/operations'; +import operations from '../operations'; import * as properties from './properties'; const VALID_TOP_KEYS = ['keymaps', 'search', 'blacklist', 'properties']; @@ -6,7 +6,7 @@ const VALID_OPERATION_VALUES = Object.keys(operations).map((key) => { return operations[key]; }); -const validateInvalidTopKeys = (settings) => { +const validateInvalidTopKeys = (settings: any): void => { let invalidKey = Object.keys(settings).find((key) => { return !VALID_TOP_KEYS.includes(key); }); @@ -15,7 +15,7 @@ const validateInvalidTopKeys = (settings) => { } }; -const validateKeymaps = (keymaps) => { +const validateKeymaps = (keymaps: any): void => { for (let key of Object.keys(keymaps)) { let value = keymaps[key]; if (!VALID_OPERATION_VALUES.includes(value.type)) { @@ -24,7 +24,7 @@ const validateKeymaps = (keymaps) => { } }; -const validateSearch = (search) => { +const validateSearch = (search: any): void => { let engines = search.engines; for (let key of Object.keys(engines)) { if ((/\s/).test(key)) { @@ -49,7 +49,7 @@ const validateSearch = (search) => { } }; -const validateProperties = (props) => { +const validateProperties = (props: any): void => { for (let name of Object.keys(props)) { if (!properties.types[name]) { throw new Error(`Unknown property name: "${name}"`); @@ -60,7 +60,7 @@ const validateProperties = (props) => { } }; -const validate = (settings) => { +const validate = (settings: any): void => { validateInvalidTopKeys(settings); if (settings.keymaps) { validateKeymaps(settings.keymaps); diff --git a/src/shared/settings/values.ts b/src/shared/settings/values.ts index 9828af6..cb6a668 100644 --- a/src/shared/settings/values.ts +++ b/src/shared/settings/values.ts @@ -1,6 +1,6 @@ import * as properties from './properties'; -const operationFromFormName = (name) => { +const operationFromFormName = (name: string): any => { let [type, argStr] = name.split('?'); let args = {}; if (argStr) { @@ -9,7 +9,7 @@ const operationFromFormName = (name) => { return { type, ...args }; }; -const operationToFormName = (op) => { +const operationToFormName = (op: any): string => { let type = op.type; let args = { ...op }; delete args.type; @@ -20,12 +20,12 @@ const operationToFormName = (op) => { return op.type + '?' + JSON.stringify(args); }; -const valueFromJson = (json) => { +const valueFromJson = (json: string): object => { return JSON.parse(json); }; -const valueFromForm = (form) => { - let keymaps = undefined; +const valueFromForm = (form: any): object => { + let keymaps: any = undefined; if (form.keymaps) { keymaps = {}; for (let name of Object.keys(form.keymaps)) { @@ -34,7 +34,7 @@ const valueFromForm = (form) => { } } - let search = undefined; + let search: any = undefined; if (form.search) { search = { default: form.search.default }; @@ -54,12 +54,12 @@ const valueFromForm = (form) => { }; }; -const jsonFromValue = (value) => { +const jsonFromValue = (value: any): string => { return JSON.stringify(value, undefined, 2); }; -const formFromValue = (value, allowedOps) => { - let keymaps = undefined; +const formFromValue = (value: any, allowedOps: any[]): any => { + let keymaps: any = undefined; if (value.keymaps) { let allowedSet = new Set(allowedOps); @@ -73,7 +73,7 @@ const formFromValue = (value, allowedOps) => { } } - let search = undefined; + let search: any = undefined; if (value.search) { search = { default: value.search.default }; if (value.search.engines) { @@ -93,11 +93,11 @@ const formFromValue = (value, allowedOps) => { }; }; -const jsonFromForm = (form) => { +const jsonFromForm = (form: any): string => { return jsonFromValue(valueFromForm(form)); }; -const formFromJson = (json, allowedOps) => { +const formFromJson = (json: string, allowedOps: any[]): any => { let value = valueFromJson(json); return formFromValue(value, allowedOps); }; diff --git a/src/shared/urls.ts b/src/shared/urls.ts index 94b1220..18349c8 100644 --- a/src/shared/urls.ts +++ b/src/shared/urls.ts @@ -1,11 +1,11 @@ -const trimStart = (str) => { +const trimStart = (str: string): string => { // NOTE String.trimStart is available on Firefox 61 return str.replace(/^\s+/, ''); }; const SUPPORTED_PROTOCOLS = ['http:', 'https:', 'ftp:', 'mailto:', 'about:']; -const searchUrl = (keywords, searchSettings) => { +const searchUrl = (keywords: string, searchSettings: any): string => { try { let u = new URL(keywords); if (SUPPORTED_PROTOCOLS.includes(u.protocol.toLowerCase())) { @@ -28,7 +28,7 @@ const searchUrl = (keywords, searchSettings) => { return template.replace('{}', encodeURIComponent(query)); }; -const normalizeUrl = (url) => { +const normalizeUrl = (url: string): string => { try { let u = new URL(url); if (SUPPORTED_PROTOCOLS.includes(u.protocol.toLowerCase())) { diff --git a/src/shared/utils/dom.ts b/src/shared/utils/dom.ts index 974d534..c1f2190 100644 --- a/src/shared/utils/dom.ts +++ b/src/shared/utils/dom.ts @@ -1,16 +1,24 @@ -const isContentEditable = (element) => { - return element.hasAttribute('contenteditable') && ( - element.getAttribute('contenteditable').toLowerCase() === 'true' || - element.getAttribute('contenteditable').toLowerCase() === '' - ); +const isContentEditable = (element: Element): boolean => { + let value = element.getAttribute('contenteditable'); + if (value === null) { + return false; + } + return value.toLowerCase() === 'true' || value.toLowerCase() === ''; }; -const rectangleCoordsRect = (coords) => { +interface Rect { + left: number; + top: number; + right: number; + bottom: number; +} + +const rectangleCoordsRect = (coords: string): Rect => { let [left, top, right, bottom] = coords.split(',').map(n => Number(n)); return { left, top, right, bottom }; }; -const circleCoordsRect = (coords) => { +const circleCoordsRect = (coords: string): Rect => { let [x, y, r] = coords.split(',').map(n => Number(n)); return { left: x - r, @@ -20,7 +28,7 @@ const circleCoordsRect = (coords) => { }; }; -const polygonCoordsRect = (coords) => { +const polygonCoordsRect = (coords: string): Rect => { let params = coords.split(','); let minx = Number(params[0]), maxx = Number(params[0]), @@ -46,18 +54,24 @@ const polygonCoordsRect = (coords) => { return { left: minx, top: miny, right: maxx, bottom: maxy }; }; -const viewportRect = (e) => { +const viewportRect = (e: Element): Rect => { if (e.tagName !== 'AREA') { return e.getBoundingClientRect(); } - let mapElement = e.parentNode; - let imgElement = document.querySelector(`img[usemap="#${mapElement.name}"]`); + let mapElement = e.parentNode as HTMLMapElement; + let imgElement = document.querySelector( + `img[usemap="#${mapElement.name}"]` + ) as HTMLImageElement; let { left: mapLeft, top: mapTop } = imgElement.getBoundingClientRect(); let coords = e.getAttribute('coords'); + if (!coords) { + return e.getBoundingClientRect(); + } + let rect = { left: 0, top: 0, right: 0, bottom: 0 }; switch (e.getAttribute('shape')) { case 'rect': @@ -81,7 +95,7 @@ const viewportRect = (e) => { }; }; -const isVisible = (element) => { +const isVisible = (element: Element): boolean => { let rect = element.getBoundingClientRect(); let style = window.getComputedStyle(element); @@ -94,7 +108,8 @@ const isVisible = (element) => { if (window.innerWidth < rect.left && window.innerHeight < rect.top) { return false; } - if (element.nodeName === 'INPUT' && element.type.toLowerCase() === 'hidden') { + if (element instanceof HTMLInputElement && + element.type.toLowerCase() === 'hidden') { return false; } diff --git a/src/shared/utils/keys.ts b/src/shared/utils/keys.ts index f024069..d9abef7 100644 --- a/src/shared/utils/keys.ts +++ b/src/shared/utils/keys.ts @@ -1,4 +1,12 @@ -const modifiedKeyName = (name) => { +interface Key { + key: string; + shiftKey: boolean | undefined; + ctrlKey: boolean | undefined; + altKey: boolean | undefined; + metaKey: boolean | undefined; +} + +const modifiedKeyName = (name: string): string => { if (name === ' ') { return 'Space'; } @@ -10,7 +18,7 @@ const modifiedKeyName = (name) => { return name; }; -const fromKeyboardEvent = (e) => { +const fromKeyboardEvent = (e: KeyboardEvent): Key => { let key = modifiedKeyName(e.key); let shift = e.shiftKey; if (key.length === 1 && key.toUpperCase() === key.toLowerCase()) { @@ -28,7 +36,7 @@ const fromKeyboardEvent = (e) => { }; }; -const fromMapKey = (key) => { +const fromMapKey = (key: string): Key => { if (key.startsWith('<') && key.endsWith('>')) { let inner = key.slice(1, -1); let shift = inner.includes('S-'); @@ -55,8 +63,10 @@ const fromMapKey = (key) => { }; }; -const fromMapKeys = (keys) => { - const fromMapKeysRecursive = (remainings, mappedKeys) => { +const fromMapKeys = (keys: string): Key[] => { + const fromMapKeysRecursive = ( + remainings: string, mappedKeys: Key[], + ): Key[] => { if (remainings.length === 0) { return mappedKeys; } @@ -78,7 +88,7 @@ const fromMapKeys = (keys) => { return fromMapKeysRecursive(keys, []); }; -const equals = (e1, e2) => { +const equals = (e1: Key, e2: Key): boolean => { return e1.key === e2.key && e1.ctrlKey === e2.ctrlKey && e1.metaKey === e2.metaKey && diff --git a/src/shared/utils/re.ts b/src/shared/utils/re.ts index 7db9091..34f4fa6 100644 --- a/src/shared/utils/re.ts +++ b/src/shared/utils/re.ts @@ -1,4 +1,4 @@ -const fromWildcard = (pattern) => { +const fromWildcard = (pattern: string): RegExp => { let regexStr = '^' + pattern.replace(/\*/g, '.*') + '$'; return new RegExp(regexStr); };