diff --git a/README.md b/README.md index 9f451fa..d5b3cca 100644 --- a/README.md +++ b/README.md @@ -15,6 +15,16 @@ ![Instructions.gif](https://s1.ax1x.com/2020/08/19/dQ8R3t.gif) +### v1.6.0 + +- 新增快捷键 + + > ctrl + insert 跳转添加自选基金 + + > ctrl + delete 删除选中的自选基金 + +- 移除删除自选基金界面 + ### v1.5.1 - 今日收益确认无需等待持仓数量为0的基金 diff --git a/package.json b/package.json index dff1c67..9e1af42 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "utools-fund", - "version": "v1.5.1", + "version": "v1.6.0", "description": "自选基金助手", "main": "main.ts", "scripts": { @@ -23,4 +23,4 @@ "typescript": "^3.9.7" }, "dependencies": {} -} \ No newline at end of file +} diff --git a/plugin.config.js b/plugin.config.js index d896022..29723a1 100644 --- a/plugin.config.js +++ b/plugin.config.js @@ -29,12 +29,12 @@ const pluginConfig = { icon: 'assets/img/add.png', cmds: ['添加自选基金', '继续添加自选基金', '基金', 'fund'], }, - { - code: 'utools_fund_del', - explain: '删除自选基金', - icon: 'assets/img/del.png', - cmds: ['删除自选基金', '继续删除自选基金', '基金', 'fund'], - }, + // { + // code: 'utools_fund_del', + // explain: '删除自选基金', + // icon: 'assets/img/del.png', + // cmds: ['删除自选基金', '继续删除自选基金', '基金', 'fund'], + // }, { code: 'utools_fund_my', explain: '我的自选基金', diff --git a/rollup.config.js b/rollup.config.js index b0b5050..8730310 100644 --- a/rollup.config.js +++ b/rollup.config.js @@ -7,7 +7,7 @@ import commonjs from 'rollup-plugin-commonjs'; import pluginConfig from './plugin.config.js'; import copy from 'rollup-plugin-copy'; import replace from 'rollup-plugin-replace'; -import { terser } from "rollup-plugin-terser"; +import { terser } from 'rollup-plugin-terser'; /** * 当前环境 @@ -28,7 +28,7 @@ const rollupOptions = { format: 'cjs', sourcemap: NODE_ENV === 'production' ? false : 'inline', }, - external: ['../assets/js/axios.min.js'], + external: ['../assets/js/axios.min.js', '../assets/js/mousetrap.min.js'], plugins: [ cleaner({ targets: ['dist'], @@ -48,7 +48,7 @@ const rollupOptions = { rename: (name, extension) => 'plugin.json', }, { src: 'README.md', dest: 'dist' }, - { src: 'src/assets/**/*', dest: 'dist' } + { src: 'src/assets/**/*', dest: 'dist' }, ], verbose: true, }), diff --git a/src/assets/js/mousetrap.min.js b/src/assets/js/mousetrap.min.js new file mode 100644 index 0000000..185c42f --- /dev/null +++ b/src/assets/js/mousetrap.min.js @@ -0,0 +1,11 @@ +/* mousetrap v1.6.5 craig.is/killing/mice */ +(function(q,u,c){function v(a,b,g){a.addEventListener?a.addEventListener(b,g,!1):a.attachEvent("on"+b,g)}function z(a){if("keypress"==a.type){var b=String.fromCharCode(a.which);a.shiftKey||(b=b.toLowerCase());return b}return n[a.which]?n[a.which]:r[a.which]?r[a.which]:String.fromCharCode(a.which).toLowerCase()}function F(a){var b=[];a.shiftKey&&b.push("shift");a.altKey&&b.push("alt");a.ctrlKey&&b.push("ctrl");a.metaKey&&b.push("meta");return b}function w(a){return"shift"==a||"ctrl"==a||"alt"==a|| +"meta"==a}function A(a,b){var g,d=[];var e=a;"+"===e?e=["+"]:(e=e.replace(/\+{2}/g,"+plus"),e=e.split("+"));for(g=0;gc||n.hasOwnProperty(c)&&(p[n[c]]=c)}g=p[e]?"keydown":"keypress"}"keypress"==g&&d.length&&(g="keydown");return{key:m,modifiers:d,action:g}}function D(a,b){return null===a||a===u?!1:a===b?!0:D(a.parentNode,b)}function d(a){function b(a){a= +a||{};var b=!1,l;for(l in p)a[l]?b=!0:p[l]=0;b||(x=!1)}function g(a,b,t,f,g,d){var l,E=[],h=t.type;if(!k._callbacks[a])return[];"keyup"==h&&w(a)&&(b=[a]);for(l=0;l":".","?":"/","|":"\\"},B={option:"alt",command:"meta","return":"enter", +escape:"esc",plus:"+",mod:/Mac|iPod|iPhone|iPad/.test(navigator.platform)?"meta":"ctrl"},p;for(c=1;20>c;++c)n[111+c]="f"+c;for(c=0;9>=c;++c)n[c+96]=c.toString();d.prototype.bind=function(a,b,c){a=a instanceof Array?a:[a];this._bindMultiple.call(this,a,b,c);return this};d.prototype.unbind=function(a,b){return this.bind.call(this,a,function(){},b)};d.prototype.trigger=function(a,b){if(this._directMap[a+":"+b])this._directMap[a+":"+b]({},a);return this};d.prototype.reset=function(){this._callbacks={}; +this._directMap={};return this};d.prototype.stopCallback=function(a,b){if(-1<(" "+b.className+" ").indexOf(" mousetrap ")||D(b,this.target))return!1;if("composedPath"in a&&"function"===typeof a.composedPath){var c=a.composedPath()[0];c!==a.target&&(b=c)}return"INPUT"==b.tagName||"SELECT"==b.tagName||"TEXTAREA"==b.tagName||b.isContentEditable};d.prototype.handleKey=function(){return this._handleKey.apply(this,arguments)};d.addKeycodes=function(a){for(var b in a)a.hasOwnProperty(b)&&(n[b]=a[b]);p=null}; +d.init=function(){var a=d(u),b;for(b in a)"_"!==b.charAt(0)&&(d[b]=function(b){return function(){return a[b].apply(a,arguments)}}(b))};d.init();q.Mousetrap=d;"undefined"!==typeof module&&module.exports&&(module.exports=d);"function"===typeof define&&define.amd&&define(function(){return d})}})("undefined"!==typeof window?window:null,"undefined"!==typeof window?document:null); diff --git a/src/features/fundAdd.ts b/src/features/fundAdd.ts index c66c2da..bb778d1 100644 --- a/src/features/fundAdd.ts +++ b/src/features/fundAdd.ts @@ -3,10 +3,26 @@ import { ISearchFundResult } from '@/model/ISearchFundResult'; import { get } from '@/Helper/HttpHelper'; import FundDBHelper from '@/Helper/FundDBHelper'; +const DEFAULT_CB_LIST: CallbackListItem[] = [ + { + title: `我的自选基金`, + description: `回车键返回`, + icon: 'assets/img/logo.png', + }, + // { + // title: `删除自选基金`, + // description: ``, + // icon: 'assets/img/del.png', + // }, +]; + const fundAdd: TplFeature = { mode: 'list', args: { placeholder: '输入基金简称/代码/拼音,回车键确认', + enter: async (action, callbackSetList) => { + callbackSetList(DEFAULT_CB_LIST); + }, search: async (action, searchWord, callbackSetList) => { // 获取一些数据 let cbList: CallbackListItem[] = []; @@ -29,10 +45,17 @@ const fundAdd: TplFeature = { }); } } + callbackSetList(cbList); + } else { + callbackSetList(DEFAULT_CB_LIST); } - callbackSetList(cbList); }, // 用户选择列表中某个条目时被调用 select: (action, itemData, callbackSetList) => { + const defaultOpt = DEFAULT_CB_LIST.find(x => x.title === itemData.title); + if (defaultOpt) { + utools.redirect(itemData.title, ''); + return; + } const existFund = FundDBHelper.get(itemData.title); if (!existFund) { FundDBHelper.set({ diff --git a/src/features/fundMy.ts b/src/features/fundMy.ts index 625dc18..17a03ed 100644 --- a/src/features/fundMy.ts +++ b/src/features/fundMy.ts @@ -4,12 +4,14 @@ import { IFundValuationDetailResult } from '@/model/IFundValuationDetailResult'; import { get } from '@/Helper/HttpHelper'; import { ISearchFundResult } from '@/model/ISearchFundResult'; import { IFundEnt } from '@/model/IFundEnt'; +import Mousetrap from '../assets/js/mousetrap.min.js'; // 缓存基金详情 let CACHE_FUND_DB_LIST: DBItem[]; // 当前搜索关键字 let CURRENT_SEARCH_WORD = ''; let QUERY_TIMER: NodeJS.Timeout; +let CACHE_CALLBACK_SET_LIST: CallbackSetList; const getMyFundDetails = async () => { const dbList = FundDBHelper.getAll(); @@ -142,6 +144,7 @@ const hanlderUTools = { val.onPluginOut = cb => { console.log(`用户退出插件`); clearTimeout(QUERY_TIMER); + unregisterShortCut(); return rawOnPluginOut(cb); }; val.onPluginOut.isMagicRevision = true; @@ -157,18 +160,51 @@ const hanlderUTools = { // }, }; +const registerShortCut = async () => { + // 删除 + Mousetrap.bind('mod+del', () => { + const selectedItem = document.querySelector('.list-item-selected .list-item-title'); + if (selectedItem && selectedItem.innerHTML) { + const fundId = selectedItem.innerHTML.split(' ')[0]; + if (CACHE_FUND_DB_LIST && CACHE_FUND_DB_LIST.length > 0 && CACHE_FUND_DB_LIST.some(x => x.data.id === fundId)) { + FundDBHelper.del(fundId); + if (CACHE_CALLBACK_SET_LIST) { + clearTimeout(QUERY_TIMER); + showFundDetails(CACHE_CALLBACK_SET_LIST); + } else { + console.error(`CACHE_CALLBACK_SET_LIST is null`); + } + } else { + console.error(`del error :`); + console.error(`fundId : ${fundId} , CACHE_FUND_DB_LIST : `, CACHE_FUND_DB_LIST); + } + } + return false; + }); + // 跳转新增 + Mousetrap.bind('mod+ins', () => { + utools.redirect('添加自选基金', ''); + }); +}; +const unregisterShortCut = async () => { + // Mousetrap.unbind(['up', 'down', 'mod+del', 'mod+ins']); +}; + const fundMy: TplFeature = { mode: 'list', args: { - placeholder: '输入持有份额,选择对应基金,回车键保存,s前缀搜索', + placeholder: '输入份额,选择基金,Enter 保存,ctrl + delete 删除 , ctrl + insert 添加 ,s前缀搜索', enter: async (action, callbackSetList) => { + CACHE_CALLBACK_SET_LIST = callbackSetList; if (!utools.isMagicRevision) { utools = new Proxy(utools, hanlderUTools); } clearTimeout(QUERY_TIMER); showFundDetails(callbackSetList); + registerShortCut(); }, search: async (action, searchWord, callbackSetList) => { + CACHE_CALLBACK_SET_LIST = callbackSetList; let dbList = CACHE_FUND_DB_LIST && CACHE_FUND_DB_LIST.length > 0 ? CACHE_FUND_DB_LIST : await getMyFundDetails(); if (searchWord && searchWord.startsWith('s')) { searchWord = searchWord.substring(1); @@ -181,6 +217,7 @@ const fundMy: TplFeature = { callbackSetList(cbList); }, // 用户选择列表中某个条目时被调用 select: (action, itemData, callbackSetList) => { + CACHE_CALLBACK_SET_LIST = callbackSetList; if (!CACHE_FUND_DB_LIST || CACHE_FUND_DB_LIST.length === 0) { utools.redirect('添加自选基金', ''); return; diff --git a/src/main.ts b/src/main.ts index 533ca9b..0d0cd63 100644 --- a/src/main.ts +++ b/src/main.ts @@ -1,6 +1,6 @@ import { TemplatePlugin } from '@/types/utools'; import fundAdd from './features/fundAdd'; -import fundDel from './features/fundDel'; +// import fundDel from './features/fundDel'; import fundMarket from './features/fundMarket'; import fundExport from './features/fundExport'; import fundMy from './features/fundMy'; @@ -8,7 +8,7 @@ import fundImport from './features/fundImport'; const preload: TemplatePlugin = { utools_fund_add: fundAdd, - utools_fund_del: fundDel, + // utools_fund_del: fundDel, utools_fund_my: fundMy, utools_fund_market: fundMarket, utools_fund_config_export: fundExport, diff --git a/src/types/mousetrap.d.ts b/src/types/mousetrap.d.ts new file mode 100644 index 0000000..c7e5754 --- /dev/null +++ b/src/types/mousetrap.d.ts @@ -0,0 +1,34 @@ +declare module '*/mousetrap.min.js' { + namespace Mousetrap { + interface ExtendedKeyboardEvent extends KeyboardEvent { + returnValue: boolean; // IE returnValue + } + + interface MousetrapStatic { + (el?: Element): MousetrapInstance; + new (el?: Element): MousetrapInstance; + addKeycodes(keycodes: { [key: number]: string }): void; + stopCallback: (e: ExtendedKeyboardEvent, element: Element, combo: string) => boolean; + bind(keys: string | string[], callback: (e: ExtendedKeyboardEvent, combo: string) => any, action?: string): MousetrapInstance; + unbind(keys: string | string[], action?: string): MousetrapInstance; + trigger(keys: string, action?: string): MousetrapInstance; + reset(): MousetrapInstance; + + /** https://craig.is/killing/mice#extensions.global */ + bindGlobal(keyArray: string | string[], callback: (e: ExtendedKeyboardEvent, combo: string) => any, action?: string): void; + } + + interface MousetrapInstance { + stopCallback: (e: ExtendedKeyboardEvent, element: Element, combo: string) => boolean; + bind(keys: string | string[], callback: (e: ExtendedKeyboardEvent, combo: string) => any, action?: string): this; + unbind(keys: string | string[], action?: string): this; + trigger(keys: string, action?: string): this; + handleKey(character: string, modifiers: string[], e: ExtendedKeyboardEvent): void; + reset(): this; + } + } + + const Mousetrap: Mousetrap.MousetrapStatic; + + export default Mousetrap; +}