1
0
mirror of https://github.com/rhysd/Mstdn.git synced 2025-01-21 20:52:11 +01:00

implement key shortcut plugin

This commit is contained in:
rhysd 2017-04-20 11:47:44 +09:00
parent 8bb5b78ef9
commit ae833be107
3 changed files with 108 additions and 77 deletions

View File

@ -1,7 +1,7 @@
import {app, systemPreferences, dialog, shell} from 'electron'; import {app, systemPreferences, dialog, shell} from 'electron';
import * as fs from 'fs'; import * as fs from 'fs';
import log from './log'; 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 { export interface Account {
host: string; host: string;
@ -18,6 +18,7 @@ export interface Config {
zoom_factor: number; zoom_factor: number;
accounts: Account[]; accounts: Account[];
chromium_sandbox: boolean; chromium_sandbox: boolean;
__DATA_DIR?: string;
keymaps: {[key: string]: string}; keymaps: {[key: string]: string};
} }
@ -100,6 +101,7 @@ export default function loadConfig(): Promise<Config> {
if (!config.accounts || config.accounts[0].host === '' || config.accounts[0].name === '') { if (!config.accounts || config.accounts[0].host === '' || config.accounts[0].name === '') {
recommendConfigAndDie(CONFIG_FILE); recommendConfigAndDie(CONFIG_FILE);
} else { } else {
config.__DATA_DIR = DATA_DIR;
resolve(config); resolve(config);
} }
} catch (e) { } catch (e) {

View File

@ -1,82 +1,8 @@
import * as Mousetrap from 'mousetrap';
import {Config, Account} from '../main/config'; import {Config, Account} from '../main/config';
import * as Ipc from './ipc'; import * as Ipc from './ipc';
import log from './log'; import setupKeymaps from './key_handler';
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;
Ipc.on('mstdn:config', (c: Config, a: Account) => { Ipc.on('mstdn:config', (c: Config, a: Account) => {
config = c; setupKeymaps(c, a);
setupKeybinds(config.keymaps, a.host);
document.title = `${document.title} @${a.name}@${a.host}`; document.title = `${document.title} @${a.name}@${a.host}`;
}); });

103
renderer/key_handler.ts Normal file
View File

@ -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();
});
}
}
}