From 1b55377c3c7718674aede4b08f661de57670565e Mon Sep 17 00:00:00 2001 From: fofolee Date: Mon, 11 Apr 2022 12:15:31 +0800 Subject: [PATCH] selectList 80% --- public/preload.js | 11 +- src/components/quickcommandUI/SelectList.vue | 152 ++++-- src/js/quickcommand.js | 17 +- .../monaco/types/quickcommand.api.d.ts | 469 +++++++++--------- 4 files changed, 364 insertions(+), 285 deletions(-) diff --git a/public/preload.js b/public/preload.js index ef6722f..1212f8c 100644 --- a/public/preload.js +++ b/public/preload.js @@ -94,15 +94,6 @@ window.quickcommand = { }) }, - // 显示选项列表 - showSelectList: function(selects, opt = {}) { - return new Promise((reslove, reject) => {}) - }, - // 更新选项列表 - updateSelectList: function(opt, id) { - - }, - // 关闭进程 kill: function(pid, signal = 'SIGTERM') { process.kill(pid, signal) @@ -683,4 +674,4 @@ runCodeFile = (cmd, option, terminal, callback) => { // let stderr = err_chunks.join(""); // callback(stdout, stderr) // }) -} \ No newline at end of file +} diff --git a/src/components/quickcommandUI/SelectList.vue b/src/components/quickcommandUI/SelectList.vue index d7d357e..417754f 100644 --- a/src/components/quickcommandUI/SelectList.vue +++ b/src/components/quickcommandUI/SelectList.vue @@ -4,43 +4,54 @@ maximized ref="dialog" transition-show="fade" + transition-hide="fade" @hide="onDialogHide" > - - - - - - - + + + + + + @@ -48,17 +59,44 @@ export default { data() { return { - result: this.items[0], + listMaxHeight: 500, currentIndex: 0, itemHeight: 50, + lazyItemSize: 50, + searchWords: "", }; }, mounted() { window.SelectList = this; + this.setSubInput(); + this.setUtoolsHeight(this.itemHeight * this.itemSize); }, computed: { - maxIndex() { - return this.items.length - 1; + itemSize() { + return this.items.length; + }, + matchedItems() { + if (!this.searchWords) return this.items; + let matchedItems = this.items.filter((x) => { + if (typeof x === "string") { + return x.toLowerCase().includes(this.searchWords.toLowerCase()); + } + return ( + x.title.toLowerCase().includes(this.searchWords.toLowerCase()) || + x.description.toLowerCase().includes(this.searchWords.toLowerCase()) + ); + }); + this.setUtoolsHeight(this.itemHeight * matchedItems.length); + return matchedItems; + }, + isJson() { + return this.options.optionType === "json"; + }, + isHtml() { + return this.options.optionType === "html"; + }, + isText() { + return this.options.optionType === "plaintext"; }, }, props: { @@ -70,6 +108,7 @@ export default { show() { this.$refs.dialog.show(); }, + hide() { this.$refs.dialog.hide(); }, @@ -79,11 +118,20 @@ export default { }, onOKClick() { - this.$emit("ok", this.result); + utools.removeSubInput(); + let selected = + this.options.optionType === "json" + ? this.matchedItems[this.currentIndex] + : { + id: this.currentIndex, + text: this.matchedItems[this.currentIndex], + }; + this.$emit("ok", selected); this.hide(); }, onCancelClick() { + utools.removeSubInput(); this.hide(); }, @@ -94,13 +142,33 @@ export default { this.currentIndex = Math.max(0, this.currentIndex - 1); break; case 40: - this.currentIndex = Math.min(this.maxIndex, this.currentIndex + 1); + this.currentIndex = Math.min( + this.itemSize - 1, + this.currentIndex + 1 + ); break; + case 13: + this.onOKClick(); + return; } - // this.$refs.qitems[this.currentIndex].$el.scrollIntoViewIfNeeded(false); + this.$refs.scrollBar.scrollTo(this.currentIndex); }, + scrollEvent(e) { - console.log(e); + this.currentIndex = + e.direction === "increase" + ? Math.max(e.index, this.currentIndex) + : Math.min(e.index + 9, this.currentIndex); + }, + + setSubInput() { + utools.setSubInput(({ text }) => { + this.searchWords = text; + }, this.options.placeholder); + }, + + setUtoolsHeight(height) { + utools.setExpendHeight(Math.min(height, this.listMaxHeight)); }, }, }; diff --git a/src/js/quickcommand.js b/src/js/quickcommand.js index 4385966..fb370e3 100644 --- a/src/js/quickcommand.js +++ b/src/js/quickcommand.js @@ -89,11 +89,9 @@ const quickcommand = { }) }), - - showSelectList: (selects, options = { - placeholder: "请选择", - optionType: "plaintext" - }) => new Promise((reslove, reject) => { + showSelectList: (selects, options = {}) => new Promise((reslove, reject) => { + if (!options.placeholder) options.placeholder = "输入进行筛选" + if (!options.optionType) options.optionType = "plaintext" let props = { items: selects, options: options @@ -106,7 +104,12 @@ const quickcommand = { }).onCancel(() => { console.log('取消') }) - }) + }), + + // 更新选项列表 + updateSelectList: (opt, id) => { + + }, } -export default quickcommand \ No newline at end of file +export default quickcommand diff --git a/src/plugins/monaco/types/quickcommand.api.d.ts b/src/plugins/monaco/types/quickcommand.api.d.ts index 09ffeb0..cf8f9bf 100644 --- a/src/plugins/monaco/types/quickcommand.api.d.ts +++ b/src/plugins/monaco/types/quickcommand.api.d.ts @@ -12,270 +12,287 @@ interface quickcommandApi { * @param buttons 每一个按钮的名称 * @param title 窗口标题,默认为空 */ - showButtonBox(buttons: array, title?: string): Promise<{ id: number, text: string }>; + showButtonBox( + buttons: array, + title?: string + ): Promise<{ id: number; text: string }>; /** - * 显示一个输入框组对话框,并返回用户输入的所有值 - * - * ```js - * quickcommand.showInputBox(["输入框1", "输入框2", "输入框3"]).then(values => { - * console.log(`输入的内容分别为${values}`) - * }) - * - * quickcommand.showInputBox({labels:["输入框标签"],values:["默认值"],hints:["输入框提示"]}).then(values => { - * console.log(`输入的内容分别为${values}`) - * }) - * ``` - * - * - * - * @param options 数组时,为每一个输入框的标签名;对象时,为每一个输入框的属性 - * @param title 窗口标题,默认为空 - */ - showInputBox(options: array | { labels: array, values: array, hints: array }, title?: string): Promise; + * 显示一个输入框组对话框,并返回用户输入的所有值 + * + * ```js + * quickcommand.showInputBox(["输入框1", "输入框2", "输入框3"]).then(values => { + * console.log(`输入的内容分别为${values}`) + * }) + * + * quickcommand.showInputBox({labels:["输入框标签"],values:["默认值"],hints:["输入框提示"]}).then(values => { + * console.log(`输入的内容分别为${values}`) + * }) + * ``` + * + * + * + * @param options 数组时,为每一个输入框的标签名;对象时,为每一个输入框的属性 + * @param title 窗口标题,默认为空 + */ + showInputBox( + options: array | { labels: array; values: array; hints: array }, + title?: string + ): Promise; /** - * 显示一个支持搜索的且可以动态更新的选项列表,并返回用户点击选项的索引及名称 - * - * ```js - * // plaintext - * var opt = [] - * for (var i = 0; i < 15; i++) { - * // 每一个选项为文本格式 - * opt.push(`选项` + i) - * } - * quickcommand.showSelectList(opt).then(choise => { - * console.log(`选择的选项为${choise.text}`) - * }) - * ​ - * // json - * var opt = [] - * for (var i = 0; i < 15; i++) { - * // 每一个选项为 json 格式 - * opt.push({title: `选项${i}`, description: `选项${i}的描述`, abcd: `选项${i}的自定义属性`}) - * } - * quickcommand.showSelectList(opt, {optionType: 'json'}).then(choise => { - * console.log(`选择的选项为${choise.title}`) - * }) - * ​ - * // html - * var opt = [] - * for (var i = 0; i < 15; i++) { - * // 每一个选项为 html 格式 - * opt.push(`
选项${i}
`) - * } - * quickcommand.showSelectList(opt, {optionType: 'html'}).then(choise => { - * console.log(`选择的选项为${quickcommand.htmlParse(choise.text).body.innerText}`) - * }) - * ``` - * - * @param selects 每一个列表选项 - * @param options 列表的选项。placeholder: 搜索框占位符,optionType: 选项的格式,默认为plaintext - */ - showSelectList(selects: array, options?: { placeholder: string, optionType: 'plaintext' | 'html' | 'json' }): Promise<{ id: number, text: string }>; + * 显示一个支持搜索的且可以动态更新的选项列表,选项类型为文本或html时,返回选择的索引和文本,为对象时,返回选择的对象 + * + * ```js + * // plaintext + * var opt = [] + * for (var i = 0; i < 15; i++) { + * // 每一个选项为文本格式 + * opt.push(`选项` + i) + * } + * quickcommand.showSelectList(opt).then(choise => { + * console.log(`选择的选项为${choise.text}`) + * }) + * ​ + * // json + * var opt = [] + * for (var i = 0; i < 15; i++) { + * // 每一个选项为 json 格式 + * opt.push({title: `选项${i}`, description: `选项${i}的描述`, icon: `选项${i}的图标`,abcd: `选项${i}的自定义属性`}) + * } + * quickcommand.showSelectList(opt, {optionType: 'json'}).then(choise => { + * console.log(`选择的选项为${choise.title}`) + * }) + * ​ + * // html + * var opt = [] + * for (var i = 0; i < 15; i++) { + * // 每一个选项为 html 格式 + * opt.push(`
选项${i}
`) + * } + * quickcommand.showSelectList(opt, {optionType: 'html'}).then(choise => { + * console.log(`选择的选项为${quickcommand.htmlParse(choise.text).body.innerText}`) + * }) + * ``` + * + * @param selects 每一个列表选项 + * @param options 列表的选项。placeholder: 搜索框占位符,optionType: 选项的格式,默认为plaintext + */ + showSelectList( + selects: array, + options?: { placeholder: string; optionType: "plaintext" | "html" | "json" } + ): Promise<{ id: number; text: string | object }>; /** - * 动态更新当前的选项列表的选项 - * - * ```js - * // 初始状态只有 1、2、3 三个选项 - * quickcommand.showSelectList(['1','2','3']).then(x=>{ - * console.log(x) - * }) - * ​ - * // 1s 后追加一个选项 - * quickcommand.setTimeout(()=>{ - * quickcommand.updateSelectList('4') - * }, 1000) - * ​ - * // 2s 后更新第二个选项的值 - * quickcommand.setTimeout(()=>{ - * quickcommand.updateSelectList('updated', 1) - * }, 2000) - * ``` - * - * @param opt 要更新的选项 - * @param id 要更新的选项的序号,不赋值时则追加到最后一个选项后面 - */ + * 动态更新当前的选项列表的选项 + * + * ```js + * // 初始状态只有 1、2、3 三个选项 + * quickcommand.showSelectList(['1','2','3']).then(x=>{ + * console.log(x) + * }) + * ​ + * // 1s 后追加一个选项 + * quickcommand.setTimeout(()=>{ + * quickcommand.updateSelectList('4') + * }, 1000) + * ​ + * // 2s 后更新第二个选项的值 + * quickcommand.setTimeout(()=>{ + * quickcommand.updateSelectList('updated', 1) + * }, 2000) + * ``` + * + * @param opt 要更新的选项 + * @param id 要更新的选项的序号,不赋值时则追加到最后一个选项后面 + */ updateSelectList(opt: string, id?: number): void; /** - * 显示一个文本框,并返回用户输入的值 - * - * ```js - * quickcommand.showTextAera("请输入文本").then(text=>{ - * console.log(`输入的文本为${text}`) - * }) - * ``` - * - * @param placeholder 文本框占位符 - * @param value 默认的文本值 - */ + * 显示一个文本框,并返回用户输入的值 + * + * ```js + * quickcommand.showTextAera("请输入文本").then(text=>{ + * console.log(`输入的文本为${text}`) + * }) + * ``` + * + * @param placeholder 文本框占位符 + * @param value 默认的文本值 + */ showTextArea(placeholder?: string, value?: string): Promise; /** - * 显示一个自动消失的提示框 - * - * ```js - * quickcommand.showMessageBox("这是一段3s后自动消失的成功提示") - * ``` - * @param message 显示的消息内容 - * @param icon 图标,默认为 success - * @param time 多少毫秒后消失,默认为 3000 - */ - showMessageBox(message: string, icon?: 'success' | 'error' | 'warning' | 'info' , time?: number): void; + * 显示一个自动消失的提示框 + * + * ```js + * quickcommand.showMessageBox("这是一段3s后自动消失的成功提示") + * ``` + * @param message 显示的消息内容 + * @param icon 图标,默认为 success + * @param time 多少毫秒后消失,默认为 3000 + */ + showMessageBox( + message: string, + icon?: "success" | "error" | "warning" | "info", + time?: number + ): void; /** - * 显示一个确认框,返回是否点击了确认 - * - * ```js - * quickcommand.showConfirmBox().then(confirmed => { - * confirmed && console.log('点击了确定') - * }) - * ``` - * @param message 提示的内容 - * @param title 提示的标题 - */ + * 显示一个确认框,返回是否点击了确认 + * + * ```js + * quickcommand.showConfirmBox().then(confirmed => { + * confirmed && console.log('点击了确定') + * }) + * ``` + * @param message 提示的内容 + * @param title 提示的标题 + */ showConfirmBox(message?: string, title?: string): Promise; /** - * 同步等待,会阻塞进程 - * @param ms 等待的毫秒数 - */ + * 同步等待,会阻塞进程 + * @param ms 等待的毫秒数 + */ sleep(ms: number): void; /** - * 异步等待 - * - * ```js - * quickcommand.setTimeout(()=>{ - * console.log('2000毫秒后执行') - * }, 2000) - * ``` - * - * @param ms 等待的毫秒数 - */ - setTimeout(callback: () => void, ms) + * 异步等待 + * + * ```js + * quickcommand.setTimeout(()=>{ + * console.log('2000毫秒后执行') + * }, 2000) + * ``` + * + * @param ms 等待的毫秒数 + */ + setTimeout(callback: () => void, ms); /** - * 将给定的html字符串解析为 DOM 对象,用于快速编写爬虫脚本 - * - * ```js - * var html = `uTools` - * var href = quickcommand.htmlParse(html).querySelector('a').href - * console.log(`解析出来的a标签地址为${href}`) - * ``` - * - * @param html 需要解析的 html 文本 - */ - htmlParse(html: string): object - + * 将给定的html字符串解析为 DOM 对象,用于快速编写爬虫脚本 + * + * ```js + * var html = `uTools` + * var href = quickcommand.htmlParse(html).querySelector('a').href + * console.log(`解析出来的a标签地址为${href}`) + * ``` + * + * @param html 需要解析的 html 文本 + */ + htmlParse(html: string): object; /** - * 下载文件,并返回文件的 Buffer,可选直接下载到指定路径,或者弹出对话框选择下载路径 - * - * ```js - * // 下载文件到D:/ - * quickcommand.downloadFile('https://res.u-tools.cn/currentversion/uTools-1.1.3.exe', 'D:/') - * ​ - * // 下载文件,并弹出对话框询问保存路径 - * quickcommand.downloadFile('https://res.u-tools.cn/currentversion/uTools-1.1.3.exe') - * ``` - * - * @param url 地址 - * @param file 当赋值为文件路径时,则表示下载文件的绝对路径; - * 不赋值时,则会弹出对话框要求选择下载到的路径; - * 赋值为 Object时,表示弹出对话框的 options,格式和 utools.showSaveDialog 中的 options一致 - */ - downloadFile(url, file?: string | object): Promise + * 下载文件,并返回文件的 Buffer,可选直接下载到指定路径,或者弹出对话框选择下载路径 + * + * ```js + * // 下载文件到D:/ + * quickcommand.downloadFile('https://res.u-tools.cn/currentversion/uTools-1.1.3.exe', 'D:/') + * ​ + * // 下载文件,并弹出对话框询问保存路径 + * quickcommand.downloadFile('https://res.u-tools.cn/currentversion/uTools-1.1.3.exe') + * ``` + * + * @param url 地址 + * @param file 当赋值为文件路径时,则表示下载文件的绝对路径; + * 不赋值时,则会弹出对话框要求选择下载到的路径; + * 赋值为 Object时,表示弹出对话框的 options,格式和 utools.showSaveDialog 中的 options一致 + */ + downloadFile(url, file?: string | object): Promise; /** - * 上传文件,可以直接上传指定文件,或者弹出对话框选择要上传的文件,可以自定义表单数据 - * - * ```js - * // 上传图片到图床 - * quickcommand.uploadFile("https://imgkr.com/api/v2/files/upload", "C:\\test.jpg").then(res=>{ - * console.log('上传成功,图片地址为:' + res.data.data) - * }) - * ​ - * // 包含额外表单数据 - * quickcommand.uploadFile("https://catbox.moe/user/api.php", "C:\\test.jpg", 'fileToUpload', { - * "reqtype": "fileupload" - * }).then(res=>{ - * console.log('上传成功,图片地址为:' + res.data) - * }) - * ``` - * - * @param url 地址 - * @param file 当赋值为文件路径时,则表示要上传的文件的绝对路径; - * 不赋值时,则会弹出对话框要求选择要上传的文件的路径; - * 赋值为 Object时,表示弹出对话框的 options,格式和 utools.showOpenDialog 中的 options一致 - * - * @param name 文件名,默认为 file - * @param formData 其他需要提交的表单数据 - */ - uploadFile(url: string, file?: string | object, name?: string, formData?: object): Promise + * 上传文件,可以直接上传指定文件,或者弹出对话框选择要上传的文件,可以自定义表单数据 + * + * ```js + * // 上传图片到图床 + * quickcommand.uploadFile("https://imgkr.com/api/v2/files/upload", "C:\\test.jpg").then(res=>{ + * console.log('上传成功,图片地址为:' + res.data.data) + * }) + * ​ + * // 包含额外表单数据 + * quickcommand.uploadFile("https://catbox.moe/user/api.php", "C:\\test.jpg", 'fileToUpload', { + * "reqtype": "fileupload" + * }).then(res=>{ + * console.log('上传成功,图片地址为:' + res.data) + * }) + * ``` + * + * @param url 地址 + * @param file 当赋值为文件路径时,则表示要上传的文件的绝对路径; + * 不赋值时,则会弹出对话框要求选择要上传的文件的路径; + * 赋值为 Object时,表示弹出对话框的 options,格式和 utools.showOpenDialog 中的 options一致 + * + * @param name 文件名,默认为 file + * @param formData 其他需要提交的表单数据 + */ + uploadFile( + url: string, + file?: string | object, + name?: string, + formData?: object + ): Promise; /** - * 加载一个远程脚本文件,并返回脚本 export 的对象 - * - * ```js - * let remote = 'https://cdn.jsdelivr.net/npm/sweetalert2@9' - * quickcommand.loadRemoteScript(remote).then(swal => { - * swal.fire('已加载 sweetalert2 并成功弹窗') - * }) - * ``` - * - * @param url 脚本地址 - */ - loadRemoteScript(url: string): Promise + * 加载一个远程脚本文件,并返回脚本 export 的对象 + * + * ```js + * let remote = 'https://cdn.jsdelivr.net/npm/sweetalert2@9' + * quickcommand.loadRemoteScript(remote).then(swal => { + * swal.fire('已加载 sweetalert2 并成功弹窗') + * }) + * ``` + * + * @param url 脚本地址 + */ + loadRemoteScript(url: string): Promise; /** - * 将 signal 发送给 pid 标识的进程 , 默认为关闭进程,同process.kill - * @param pid 进程 ID - * @param signal 进程信号,默认为SIGTERM - */ - kill(pid: number, signal?: number | string): void + * 将 signal 发送给 pid 标识的进程 , 默认为关闭进程,同process.kill + * @param pid 进程 ID + * @param signal 进程信号,默认为SIGTERM + */ + kill(pid: number, signal?: number | string): void; /** - * windows 下运行 VBS 脚本并返回运行结果 - * - * ```js - * quickcommand.runVbs(`CreateObject("SAPI.SpVoice").Speak"Hello"`) - * ``` - * - * @param script VBS 代码 - */ - runVbs(script: string): Promise + * windows 下运行 VBS 脚本并返回运行结果 + * + * ```js + * quickcommand.runVbs(`CreateObject("SAPI.SpVoice").Speak"Hello"`) + * ``` + * + * @param script VBS 代码 + */ + runVbs(script: string): Promise; /** - * 对应 utools.onPluginEnter 的 code type 和 payload - * - * code: 唯一标识 - * - * type: 匹配模式,可以为 text | img | files | regex | over | window - * - * payload: 当匹配模式为关键字时,返回进入插件的关键字;为正则时,返回匹配的文本;为窗口时,返回匹配的窗口信息;为文件时,返回匹配的文件信息 - * - * ```js - * if (quickcommand.enterData.type == 'regex'){ - * var text = quickcommand.enterData.payload - * console.log(`主输入框匹配的文本为${text}`) - * } - * ``` - * - */ - enterData: { code: string, type: string, payload: any } + * 对应 utools.onPluginEnter 的 code type 和 payload + * + * code: 唯一标识 + * + * type: 匹配模式,可以为 text | img | files | regex | over | window + * + * payload: 当匹配模式为关键字时,返回进入插件的关键字;为正则时,返回匹配的文本;为窗口时,返回匹配的窗口信息;为文件时,返回匹配的文件信息 + * + * ```js + * if (quickcommand.enterData.type == 'regex'){ + * var text = quickcommand.enterData.payload + * console.log(`主输入框匹配的文本为${text}`) + * } + * ``` + * + */ + enterData: { code: string; type: string; payload: any }; /** - * 模拟复制操作 - */ - simulateCopy() + * 模拟复制操作 + */ + simulateCopy(); /** - * 模拟粘贴操作 - */ - simulatePaste() + * 模拟粘贴操作 + */ + simulatePaste(); } declare var quickcommand: quickcommandApi;