From ae833be107d8478eac7811410ed34e5a85ee1003 Mon Sep 17 00:00:00 2001 From: rhysd Date: Thu, 20 Apr 2017 11:47:44 +0900 Subject: [PATCH] implement key shortcut plugin --- main/config.ts | 4 +- renderer/index.ts | 78 +----------------------------- renderer/key_handler.ts | 103 ++++++++++++++++++++++++++++++++++++++++ 3 files changed, 108 insertions(+), 77 deletions(-) create mode 100644 renderer/key_handler.ts diff --git a/main/config.ts b/main/config.ts index bc514c5..3bf6361 100644 --- a/main/config.ts +++ b/main/config.ts @@ -1,7 +1,7 @@ import {app, systemPreferences, dialog, shell} from 'electron'; import * as fs from 'fs'; import log from './log'; -import {CONFIG_FILE, IS_DARWIN, IS_WINDOWS} from './common'; +import {CONFIG_FILE, IS_DARWIN, IS_WINDOWS, DATA_DIR} from './common'; export interface Account { host: string; @@ -18,6 +18,7 @@ export interface Config { zoom_factor: number; accounts: Account[]; chromium_sandbox: boolean; + __DATA_DIR?: string; keymaps: {[key: string]: string}; } @@ -100,6 +101,7 @@ export default function loadConfig(): Promise { if (!config.accounts || config.accounts[0].host === '' || config.accounts[0].name === '') { recommendConfigAndDie(CONFIG_FILE); } else { + config.__DATA_DIR = DATA_DIR; resolve(config); } } catch (e) { diff --git a/renderer/index.ts b/renderer/index.ts index c58f33a..d227b1b 100644 --- a/renderer/index.ts +++ b/renderer/index.ts @@ -1,82 +1,8 @@ -import * as Mousetrap from 'mousetrap'; import {Config, Account} from '../main/config'; import * as Ipc from './ipc'; -import log from './log'; - -function scrollable() { - const scrollable = document.querySelector('.scrollable'); - if (!scrollable) { - log.error('Scrollable element was not found!'); - return {scrollTop: 0}; - } - return scrollable; -} - -function navigateTo(host: string, path: string) { - const url = `https://${host}${path}`; - if (window.location.href === url) { - log.info('Current URL is already', url); - return; - } - - const link = document.querySelector(`a[href="${path}"]`); - if (link) { - log.info('Click link by shortcut', path); - (link as HTMLAnchorElement).click(); - } else { - log.info('Force navigation by shortcut', path); - window.location.href = url; - } -} - -const ShortcutActions = { - 'scroll-top': () => { - scrollable().scrollTop = 0; - }, - 'scroll-bottom': () => { - scrollable().scrollTop = document.body.scrollHeight; - }, - 'scroll-down': () => { - scrollable().scrollTop += window.innerHeight / 3; - }, - 'scroll-up': () => { - scrollable().scrollTop -= window.innerHeight / 3; - }, - 'next-account': () => { - Ipc.send('mstdn:next-account'); - }, - 'prev-account': () => { - Ipc.send('mstdn:prev-account'); - }, -} as {[action: string]: () => void}; - -function setupKeybinds(keybinds: {[key: string]: string}, host: string) { - for (const key in keybinds) { - const action = keybinds[key]; - if (action.startsWith('/')) { - Mousetrap.bind(key, e => { - e.preventDefault(); - navigateTo(host, action); - }); - } else { - const func = ShortcutActions[action]; - if (!func) { - log.error('Unknown shortcut action:', action); - continue; - } - Mousetrap.bind(key, e => { - log.info('Shortcut:', action); - e.preventDefault(); - func(); - }); - } - } -} - -let config: Config | null = null; +import setupKeymaps from './key_handler'; Ipc.on('mstdn:config', (c: Config, a: Account) => { - config = c; - setupKeybinds(config.keymaps, a.host); + setupKeymaps(c, a); document.title = `${document.title} @${a.name}@${a.host}`; }); diff --git a/renderer/key_handler.ts b/renderer/key_handler.ts new file mode 100644 index 0000000..62a0f7c --- /dev/null +++ b/renderer/key_handler.ts @@ -0,0 +1,103 @@ +import * as path from 'path'; +import * as Mousetrap from 'mousetrap'; +import * as Ipc from './ipc'; +import log from './log'; +import {Config, Account} from '../main/config'; + +function scrollable() { + const scrollable = document.querySelector('.scrollable'); + if (!scrollable) { + log.error('Scrollable element was not found!'); + return {scrollTop: 0}; + } + return scrollable; +} + +function navigateTo(host: string, path: string) { + const url = `https://${host}${path}`; + if (window.location.href === url) { + log.info('Current URL is already', url); + return; + } + + const link = document.querySelector(`a[href="${path}"]`); + if (link) { + log.info('Click link by shortcut', path); + (link as HTMLAnchorElement).click(); + } else { + log.info('Force navigation by shortcut', path); + window.location.href = url; + } +} + +const ShortcutActions = { + 'scroll-top': () => { + scrollable().scrollTop = 0; + }, + 'scroll-bottom': () => { + scrollable().scrollTop = document.body.scrollHeight; + }, + 'scroll-down': () => { + scrollable().scrollTop += window.innerHeight / 3; + }, + 'scroll-up': () => { + scrollable().scrollTop -= window.innerHeight / 3; + }, + 'next-account': () => { + Ipc.send('mstdn:next-account'); + }, + 'prev-account': () => { + Ipc.send('mstdn:prev-account'); + }, +} as {[action: string]: () => void}; + +export default function setupKeymaps( + config: Config, + account: Account, +) { + const dataDir = config.__DATA_DIR || '/'; + for (const key in config.keymaps) { + const action = config.keymaps[key]; + if (action.endsWith('.js')) { + if (config.chromium_sandbox) { + log.info('Loading external script is limited because Chromium sandbox is enabled. Disable shortcut:', action); + continue; + } + const script = path.join(dataDir, action); + + let plugin: (c: Config, a: Account) => void; + try { + plugin = require(script); + } catch (e) { + log.error('Error while loading plugin ' + script, e); + continue; + } + Mousetrap.bind(key, e => { + e.preventDefault(); + log.info('Shortcut:', action); + try { + plugin(config, account); + } catch (e) { + log.error('Failed to run shortcut script ' + script, e); + } + }); + } else if (action.startsWith('/')) { + Mousetrap.bind(key, e => { + e.preventDefault(); + navigateTo(account.host, action); + }); + } else { + const func = ShortcutActions[action]; + if (!func) { + log.error('Unknown shortcut action:', action); + continue; + } + Mousetrap.bind(key, e => { + log.info('Shortcut:', action); + e.preventDefault(); + func(); + }); + } + } +} +