console.log( "=== simpread keyboard ===" ) import Mousetrap from 'mousetrap'; import {browser} from 'browser'; import * as msg from 'message'; import * as conf from 'config'; let $root, current_mode = ""; // include: keyboard const trigger = "s r", key = [ ".", "," ], global_keys = key.map( item => `${trigger} ${item}` ); /*********************** * Entry: Render ***********************/ function render( $target ) { $root = $target; } /*********************** * Golbal ***********************/ Mousetrap.bind( trigger, () => { if ( $( "html" ).find( ".simpread-read-root" ).length == 0 ) return; if ( current_mode == "" ) { current_mode = "keyboard"; new Notify().Render( "已进入快捷键操作模式,退出请使用 sr,帮助请按," ); } else { current_mode = ""; new Notify().Render( "已退出快捷键操作模式!" ); } }); Mousetrap.bind( key, ( event, combo ) => { current_mode == "keyboard" && task( combo ); }); function task( key ) { switch ( key ) { case ".": openLink(); break; case ",": keyboradmap(); break; } } function listenESC( callback ) { const cb = $.Callbacks(); cb.add( callback ); Mousetrap.bind( "esc", ( event, combo ) => { if ( helpExist() ) { removeHelp(); } else if ( openLinkExist() ) { removeOpenLink(); } else if ( current_mode == "keyboard" ) { Mousetrap.trigger( trigger ); } else { cb.fire( combo ); } }); } function listen( callback ) { const cb = $.Callbacks(); cb.add( callback ); let keys = new Map(); Object.values( conf.keyboard ).forEach( item => { Object.values( item ).forEach( obj => { const kbd = `${obj.kbd[0]} ${obj.kbd[1]}`, loop = ( item, idx ) => { const type = obj.type.replace( "_", "" ); keys.delete( kbd ); keys.set( `${kbd} ${idx+1}`, obj.type + conf.shortcuts[type].name[idx] ); }; keys.set( kbd, obj.type ); switch ( obj.type ) { case "fontfamily_": Array(5).fill(1).forEach( loop ); break; case "fontsize_": case "layout_": Array(3).fill(1).forEach( loop ); break; case "theme_next": keys.delete( kbd ); keys.set( `${kbd} right`, obj.type ); break; case "theme_prev": keys.delete( kbd ); keys.set( `${kbd} left`, obj.type ); break; } }); }); console.log( "current shortcuts is", keys ) Mousetrap.bind( [ ...keys.keys() ] , ( event, combo ) => { current_mode == "keyboard" && cb.fire( keys.get( combo ) ) }); } function bind( combo, callback ) { Mousetrap.bind( combo, callback ); } /*********************** * Task: Open link ***********************/ let links = []; const charts = [ "A","B","C","D","E","F","G","H","I","J","K","L","M","N","O","P","Q","R","S","T","U","V","W","X","Y","Z" ], getName = idx => { switch ( true ) { case idx < 26: return charts[idx]; case idx >= 26 && idx <= 99: return charts[idx[0]] + charts[idx[1]]; case idx > 99: return charts[idx[0]] + charts[idx[1]] + charts[idx[2]]; } }; function openLink() { if ( openLinkExist() ) { removeOpenLink(); return; } $root.find( "a" ).map( ( idx, item ) => { const key = getName( idx + "" ); $(item).addClass( "sr-kbd-a" ).append( `${key}` ); links.push( key.toLowerCase() ); }); links.length > 0 && $( "html" ).on( "keypress", openLinkEventHander ); } function openLinkEventHander( event ) { const combo = event.key.toUpperCase(), result = links.join("").match( new RegExp( combo, "ig" ) ); if ( combo == "." ) return; if ( result ) { if ( result.length == 1 ) { const $target = $root.find( `sr-kbd[id=${combo}]` ); if ( $target && $target.is( "sr-kbd" ) ) { const url = $target.parent()[0].href; url && url.startsWith( "http" ) && browser.runtime.sendMessage( msg.Add( msg.MESSAGE_ACTION.new_tab, { url } )); url && url.startsWith( "http" ) && removeOpenLink(); } } else { new Notify().Render( "已缩小查询范围。" ); links = []; let idx = 0; $root.find( `sr-kbd` ).map( ( _, item ) => { if ( item.id.includes( combo ) ) { const key = getName( idx + "" ); item.outerHTML = `${key}` links.push( key.toLowerCase() ); idx++; } else { $(item).remove(); } }); } } else { new Notify().Render( "当前已进入链接模式,如需其它操作,请使用 ESC 退出此模式。" ); } } function removeOpenLink() { $( "sr-kbd" ).remove(); $root.find( "a" ).removeClass( "sr-kbd-a" ); $( "html" ).off( "keypress", openLinkEventHander ); links = []; } function openLinkExist() { return $root && $root.find( $( "sr-kbd" ) ).length > 0 ? true : false; } /*********************** * Keyboard map ***********************/ function keyboradmap() { let html = ""; Object.keys( conf.keyboard ).forEach( item => { let maptml = ""; Object.keys( conf.keyboard[item] ).forEach( ( map, idx ) => { const obj = conf.keyboard[item][map]; maptml += `${obj.kbd}${obj.desc}` }); html += `${item}${maptml}`; }); const tmpl = ` 快捷键一览 全局 esc退出当前模式 前一页 后一页 阅读模式 sr快捷键开启/关闭条件 ,打开/关闭快捷键一览 .打开当前页面的任意链接 ${ html } `; helpExist() ? removeHelp() : $root.parent().append( `${tmpl}` ); } function removeHelp() { $root.parent().find( "kbd-bg" ).remove(); } function helpExist() { return $( "kbd-bg" ).length > 0 ? true : false; } /*********************** * Export ***********************/ export { render as Render, listenESC as ListenESC, listen as Listen, bind as Bind, }