使用组件而非插件的形式重写 quickcommandUI

This commit is contained in:
fofolee 2022-04-25 01:43:57 +08:00
parent b0d06875b3
commit 6d8034d950
18 changed files with 426 additions and 493 deletions

View File

@ -212,22 +212,22 @@ if (process.platform !== 'linux') quickcommand.runInTerminal = function(cmdline,
}
let getCommandToLaunchTerminal = (cmdline, dir) => {
let cd = ''
if (utools.isWindows()) {
let appPath = path.join(utools.getPath('home'), '/AppData/Local/Microsoft/WindowsApps/')
// 直接 existsSync wt.exe 无效
if (fs.existsSync(appPath) && fs.readdirSync(appPath).includes('wt.exe')) {
cmdline = cmdline.replace(/"/g, `\\"`)
if (dir) cd = `-d "${dir.replace(/\\/g, '/')}"`
command = `${appPath}wt.exe ${cd} cmd /k "${cmdline}"`
let cd = ''
if (utools.isWindows()) {
let appPath = path.join(utools.getPath('home'), '/AppData/Local/Microsoft/WindowsApps/')
// 直接 existsSync wt.exe 无效
if (fs.existsSync(appPath) && fs.readdirSync(appPath).includes('wt.exe')) {
cmdline = cmdline.replace(/"/g, `\\"`)
if (dir) cd = `-d "${dir.replace(/\\/g, '/')}"`
command = `${appPath}wt.exe ${cd} cmd /k "${cmdline}"`
} else {
cmdline = cmdline.replace(/"/g, `^"`)
if (dir) cd = `cd /d "${dir.replace(/\\/g, '/')}" &&`
command = `${cd} start "" cmd /k "${cmdline}"`
}
} else {
cmdline = cmdline.replace(/"/g, `^"`)
if (dir) cd = `cd /d "${dir.replace(/\\/g, '/')}" &&`
command = `${cd} start "" cmd /k "${cmdline}"`
}
} else {
cmdline = cmdline.replace(/"/g, `\\"`)
if (dir) cd = `cd ${dir.replace(/ /g, `\\\\ `)} &&`
cmdline = cmdline.replace(/"/g, `\\"`)
if (dir) cd = `cd ${dir.replace(/ /g, `\\\\ `)} &&`
if (fs.existsSync('/Applications/iTerm.app')) {
command = `osascript -e 'tell application "iTerm"
create window with default profile
@ -476,12 +476,11 @@ let getSandboxFuns = () => {
var sandbox = {
fetch: fetch.bind(window),
utools: getuToolsLite(),
quickcommand: _.cloneDeep(quickcommand),
electron,
axios,
Audio,
_,
// 兼容老版本
// 兼容老版本
fs,
path,
os,
@ -503,17 +502,17 @@ let liteErr = e => {
utools.isDev() && (window.godMode = code => eval(code))
// vm 模块将无法在渲染进程中使用,改用 ses 来执行代码
window.evalCodeInSandbox = (code, userVars = {}) => {
let sandboxWithUV = Object.assign(userVars, getSandboxFuns())
window.evalCodeInSandbox = (code, addVars = {}) => {
let sandboxWithAD = Object.assign(addVars, getSandboxFuns())
try {
return new Compartment(sandboxWithUV).evaluate(code);
return new Compartment(sandboxWithAD).evaluate(code);
} catch (error) {
throw liteErr(error)
}
}
let isWatchingError = false
window.runCodeInSandbox = (code, callback, userVars = {}) => {
window.runCodeInSandbox = (code, callback, addVars = {}) => {
let sandbox = getSandboxFuns()
sandbox.console = {
log: (...stdout) => {
@ -524,9 +523,9 @@ window.runCodeInSandbox = (code, callback, userVars = {}) => {
callback(null, parseStdout(stderr))
}
}
let sandboxWithUV = Object.assign(userVars, sandbox)
let sandboxWithAD = Object.assign(addVars, sandbox)
try {
new Compartment(sandboxWithUV).evaluate(code)
new Compartment(sandboxWithAD).evaluate(code)
} catch (e) {
console.log('Error: ', e)
callback(null, liteErr(e))
@ -629,7 +628,7 @@ window.quickcommandHttpServer = () => {
// 错误返回 500
if (stderr) return httpResponse(res, 500, stderr)
return httpResponse(res, 200, stdout)
}, userVars)
}, Object.assign(userVars, _.cloneDeep(quickcommand)))
}
httpServer = http.createServer()
httpServer.on('request', (req, res) => {

View File

@ -117,7 +117,7 @@ module.exports = configure(function(ctx) {
// directives: [],
// Quasar plugins
plugins: ['Dialog', 'Notify']
plugins: ['Notify']
},
// animations: 'all', // --- includes all animations
@ -258,4 +258,4 @@ module.exports = configure(function(ctx) {
}
}
});
});

View File

@ -2,6 +2,7 @@
<router-view v-slot="{ Component }">
<component ref="view" :is="Component" />
</router-view>
<QuickCommand />
</template>
<script>
@ -11,8 +12,10 @@ import UTOOLS from "./js/utools.js";
import programmings from "./js/options/programs.js";
import defaultProfile from "./js/options/defaultProfile.js";
import Cron from "croner";
import QuickCommand from "components/quickcommandUI/QuickCommand";
export default defineComponent({
components: { QuickCommand },
name: "App",
data() {
return {
@ -21,6 +24,7 @@ export default defineComponent({
profile: defaultProfile,
utools: UTOOLS,
cronJobs: {},
enterData: {},
};
},
computed: {},
@ -82,8 +86,7 @@ export default defineComponent({
// 使
this.usageStatistics(enter.code, this.parseDate(new Date()));
this.$q.dark.set(utools.isDarkColors());
quickcommand.enterData = enter;
quickcommand.payload = enter.payload;
this.enterData = enter;
this.$router.push(enter.code);
},
outPlugin() {
@ -91,7 +94,7 @@ export default defineComponent({
_.cloneDeep(this.profile),
this.utools.DBPRE.CFG + "preferences"
);
this.$refs.view.$refs?.commandEditor?.saveCodeHistory()
this.$refs.view.$refs?.commandEditor?.saveCodeHistory();
this.$router.push("/");
},
runCronTask(featureCode, cronExp) {
@ -102,7 +105,9 @@ export default defineComponent({
runCommandSilently(featureCode) {
let command = this.utools.getDB(this.utools.DBPRE.QC + featureCode);
if (command.program === "quickcommand") {
window.runCodeInSandbox(command.cmd, () => {});
window.runCodeInSandbox(command.cmd, () => {}, {
quickcommand: _.cloneDeep(quickcommand),
});
} else {
let option =
command.program === "custom"

View File

@ -113,14 +113,21 @@ export default {
utools.outPlugin();
}, 500);
if (currentCommand.program === "quickcommand") {
window.runCodeInSandbox(currentCommand.cmd, (stdout, stderr) => {
if (stderr) {
return quitBeforeShowResult
? alert(stderr)
: this.showRunResult(stderr, false, action);
}
!outPlugin && this.showRunResult(stdout, true, action);
});
let qc = _.cloneDeep(quickcommand);
qc.enterData = this.$root.enterData;
qc.type = this.$root.enterData.type;
window.runCodeInSandbox(
currentCommand.cmd,
(stdout, stderr) => {
if (stderr) {
return quitBeforeShowResult
? alert(stderr)
: this.showRunResult(stderr, false, action);
}
!outPlugin && this.showRunResult(stdout, true, action);
},
{ quickcommand: qc }
);
} else if (currentCommand.program === "html") {
this.showRunResult(currentCommand.cmd, true, action);
} else {
@ -150,7 +157,9 @@ export default {
let spVars = _.filter(specialVars, (sp) => sp.repl);
_.forIn(spVars, (val, key) => {
if (cmd.includes(val.label.slice(0, -2))) {
cmd = cmd.replace(val.match, (x) => val.repl(x));
cmd = cmd.replace(val.match, (x) =>
val.repl(x, this.$root.enterData)
);
}
});
return cmd;
@ -208,7 +217,7 @@ export default {
if (!this.needTempPayload) return;
let type =
currentCommand.cmdType || currentCommand.features?.cmds[0].type;
quickcommand.enterData = {
this.$root.enterData = {
type: type || "text",
payload: await commandTypes[type]?.tempPayload?.(),
};
@ -255,14 +264,11 @@ export default {
this.clear();
},
clear() {
if (!!this.quickcommandListener) {
document.removeEventListener("keydown", this.quickcommandListener);
}
if (!!this.childProcess) {
quickcommand.kill(this.childProcess.pid);
}
quickcommand.closeWaitBtn?.();
quickcommand.closeWaitBtn = () => {};
quickcommand.removeListener();
quickcommand.closeWaitButton();
},
frameLoad(initHeight) {
this.outputAutoHeight(this.fromUtools);
@ -272,11 +278,5 @@ export default {
unmounted() {
this.stopRun();
},
mounted() {
quickcommand.listenKeydown = (callback) => {
this.quickcommandListener = callback;
document.addEventListener("keydown", callback);
};
},
};
</script>

View File

@ -2,7 +2,7 @@
export default {
mounted() {
utools.setExpendHeight(0);
quickcommand.enterData.payload.forEach((file) => {
this.$root.payload.forEach((file) => {
let uid = this.getUid();
let fileInfo = window.getFileInfo({
type: "file",

View File

@ -24,7 +24,7 @@ export default {
);
url = choise.text + "://" + url;
}
let title = quickcommand.enterData.payload.title
let title = this.$root.payload.title
.replace(/和另外 \d+ 个页面.*/, "")
.replace(/[-|—] .*?[Edge|Firefox|Chrome].*/, "")
.trim();

View File

@ -1,21 +1,20 @@
<template>
<q-dialog ref="dialog" @hide="onDialogHide">
<q-card class="q-dialog-plugin">
<q-card-section>
<div class="text-h5" align="center" v-text="title"></div>
</q-card-section>
<q-card-section class="q-gutter-lg">
<div v-for="(label, index) in labels" :key="index">
<q-btn
class="full-width"
color="primary"
:label="label"
@click="onOKClick(label, index)"
/>
</div>
</q-card-section>
</q-card>
</q-dialog>
<q-card class="q-dialog-plugin">
<q-card-section>
<div class="text-h5" align="center" v-text="options.title"></div>
</q-card-section>
<q-card-section class="q-gutter-lg">
<div v-for="(label, index) in options.labels" :key="index">
<q-btn
class="full-width"
color="primary"
:label="label"
v-close-popup
@click="clickOK(label, index)"
/>
</div>
</q-card-section>
</q-card>
</template>
<script>
@ -26,29 +25,11 @@ export default {
};
},
props: {
labels: Array,
title: String,
options: Object,
},
emits: ["ok", "hide"],
methods: {
show() {
this.$refs.dialog.show();
},
hide() {
this.$refs.dialog.hide();
},
onDialogHide() {
this.$emit("hide");
},
onOKClick(label, index) {
this.$emit("ok", { id: index, text: label });
this.hide();
},
onCancelClick() {
this.hide();
clickOK(label, index) {
this.$emit("clickOK", { id: index, text: label });
},
},
};

View File

@ -0,0 +1,34 @@
<template>
<q-card class="q-dialog-plugin">
<q-card-section>
<div class="text-h5" align="left" v-text="options.title"></div>
</q-card-section>
<q-card-section>
{{ options.message }}
</q-card-section>
<q-card-section class="flex justify-end q-gutter-sm">
<q-btn flat label="取消" color="grey" v-close-popup />
<q-btn
flat
autofocus
label="确定"
color="primary"
v-close-popup
@click="clickOK()"
/>
</q-card-section>
</q-card>
</template>
<script>
export default {
methods: {
clickOK() {
this.$emit("clickOK");
},
},
props: {
options: Object,
},
};
</script>

View File

@ -1,63 +1,41 @@
<template>
<q-dialog ref="dialog" @hide="onDialogHide">
<q-card class="q-dialog-plugin">
<q-card-section>
<div class="text-h5" align="center" v-text="title"></div>
</q-card-section>
<q-card-section class="q-gutter-sm">
<div v-for="(label, index) in labels" :key="index">
<q-input
outlined
v-model="results[index]"
:label="label"
:hint="hints[index]"
hide-hint
autofocus
@keyup.enter="onOKClick"
/>
</div>
</q-card-section>
<q-card-actions align="right">
<q-btn color="blue-9" label="确定" @click="onOKClick" />
<q-btn color="negative" label="取消" @click="onCancelClick" />
</q-card-actions>
</q-card>
</q-dialog>
<q-card class="q-dialog-plugin">
<q-card-section>
<div class="text-h5" align="center" v-text="options.title"></div>
</q-card-section>
<q-card-section class="q-gutter-sm">
<div v-for="(label, index) in options.labels" :key="index">
<q-input
outlined
v-model="results[index]"
:label="label"
:hint="options.hints[index]"
hide-hint
autofocus
@keyup.enter="clickOK"
/>
</div>
</q-card-section>
<q-card-actions align="right">
<q-btn color="blue-9" label="确定" @click="clickOK" v-close-popup />
<q-btn color="negative" label="取消" v-close-popup />
</q-card-actions>
</q-card>
</template>
<script>
export default {
data() {
return {
results: this.values,
results: this.options.values,
};
},
props: {
labels: Array,
title: String,
hints: Array,
values: Array
options: Object,
},
emits: ["ok", "hide"],
methods: {
show() {
this.$refs.dialog.show();
},
hide() {
this.$refs.dialog.hide();
},
onDialogHide() {
this.$emit("hide");
},
onOKClick() {
this.$emit("ok", this.results);
this.hide();
},
onCancelClick() {
this.hide();
clickOK() {
this.$emit("clickOK", this.results);
},
},
};

View File

@ -0,0 +1,156 @@
<template>
<q-dialog
v-model="showDialog"
:maximized="maximized"
:transition-show="maximized ? 'fade' : 'scale'"
:transition-hide="maximized ? 'fade' : 'scale'"
>
<component
ref="ui"
:is="currentUI"
:options="options"
@clickOK="clickOK"
@hide="showDialog = false"
/>
</q-dialog>
<!-- waitButton 单独一个 -->
<q-dialog seamless position="right" style="z-index: 9999" v-model="showWb">
<q-card>
<q-btn color="primary" :label="wbLabel" @click="wbEvent" v-close-popup />
</q-card>
</q-dialog>
</template>
<script>
import { Notify } from "quasar";
import { markRaw } from "vue";
import InputBox from "components/quickcommandUI/InputBox";
import ButtonBox from "components/quickcommandUI/ButtonBox";
import ConfirmBox from "components/quickcommandUI/ConfirmBox";
import TextArea from "components/quickcommandUI/TextArea";
import SelectList from "components/quickcommandUI/SelectList";
export default {
components: {
InputBox: markRaw(InputBox),
ButtonBox: markRaw(ButtonBox),
ConfirmBox: markRaw(ConfirmBox),
TextArea: markRaw(TextArea),
SelectList: markRaw(SelectList),
},
data() {
return {
currentUI: null,
options: {},
showDialog: false,
maximized: false,
showWb: false,
wbLabel: "",
listeners: [],
};
},
mounted() {
const quickcommandUI = {
showInputBox: (options = ["请输入"], title = "") =>
new Promise((reslove, reject) => {
let props = {
labels: [],
values: [],
hints: [],
title: title,
};
if (!_.isObject(options))
return reject(new TypeError(`应为 Object, 而非 ${typeof options}`));
if (_.isArray(options)) props.labels = options;
else Object.assign(props, options);
this.showUI(InputBox, props, false, reslove);
}),
showButtonBox: (labels = ["确定"], title = "") =>
new Promise((reslove, reject) => {
if (!_.isArray(labels))
return reject(new TypeError(`应为 Array, 而非 ${typeof labels}`));
this.showUI(ButtonBox, { labels, title }, false, reslove);
}),
showConfirmBox: (message = "", title = "提示") =>
new Promise((reslove, reject) => {
this.showUI(ConfirmBox, { message, title }, false, reslove);
}),
showMessageBox: (message, icon = "success", time = 3000) => {
if (icon === "success") icon = "positive";
if (icon === "error") icon = "negative";
Notify.create({
type: icon,
message: message,
timeout: time,
position: "top",
});
},
showTextArea: (placeholder = "", value = "") =>
new Promise((reslove, reject) => {
this.showUI(TextArea, { placeholder, value }, true, reslove);
}),
showSelectList: (initItems, options = {}) =>
new Promise((reslove, reject) => {
if (!_.isArray(initItems))
return reject(
new TypeError(`应为 Array, 而非 ${typeof initItems}`)
);
let defaultOptions = {
placeholder: "输入进行筛选,支持拼音",
optionType: "plaintext",
enableSearch: true,
showCancelButton: false,
closeOnSelect: true,
};
options = Object.assign(defaultOptions, options);
this.showUI(SelectList, { initItems, options }, true, reslove);
}),
showWaitButton: (callback, label = "确定") => {
this.wbLabel = label;
this.showWb = true;
this.wbEvent = callback;
},
closeWaitButton: () => {
this.showWb = false;
},
updateSelectList: (opt, id) => {
if (this.currentUI !== SelectList) throw "请先创建 selectList";
if (typeof id === "undefined") this.$refs.ui.items.push(opt);
else this.$refs.ui.items[id] = opt;
},
listenKeydown: (callback) => {
this.listeners.push(callback);
document.addEventListener("keydown", callback);
},
removeListener: () => {
this.listeners.forEach((listener) => {
document.removeEventListener("keydown", listener);
});
},
};
Object.assign(window.quickcommand, quickcommandUI);
Object.freeze(quickcommand);
},
methods: {
clickOK() {},
wbEvent() {},
showUI(uiComponent, options, maximized, reslove) {
this.showDialog = true;
this.options = options;
this.maximized = maximized;
this.currentUI = uiComponent;
this.clickOK = reslove;
},
},
};
</script>

View File

@ -1,66 +1,54 @@
<template>
<q-dialog
@keydown="keyEvent"
maximized
ref="dialog"
transition-show="fade"
transition-hide="fade"
@hide="onDialogHide"
>
<q-card>
<q-virtual-scroll
ref="scrollBar"
:style="{ maxHeight: listMaxHeight + 'px', height: '100vh' }"
:virtual-scroll-slice-size="lazyItemSize"
:virtual-scroll-item-size="itemHeight"
@virtual-scroll="scrollEvent"
:items="matchedItems"
>
<template v-slot="{ item, index }">
<q-item
:key="index"
clickable
v-ripple
@mousemove="currentIndex = index"
@click="onOKClick"
manual-focus
:focused="index === currentIndex"
:active="index === currentIndex"
:style="{
height: itemHeight + 'px',
}"
>
<q-item-section v-if="isText">
<q-item-label lines="1">{{ item }}</q-item-label>
</q-item-section>
<q-item-section
v-else-if="isJson"
class="content-start q-gutter-md"
>
<q-avatar size="40px" v-if="item.icon">
<q-img :src="item.icon" />
</q-avatar>
<q-item-label lines="1">{{ item.title }}</q-item-label>
<q-item-label lines="1" caption>{{
item.description
}}</q-item-label>
</q-item-section>
<q-item-section v-else-if="isHtml">
<div v-html="item"></div>
</q-item-section>
</q-item>
</template>
</q-virtual-scroll>
<q-btn
v-if="options.showCancelButton"
class="absolute-bottom-right q-ma-xs"
round
color="primary"
icon="close"
@click="onCancelClick"
/>
</q-card>
</q-dialog>
<q-card @keydown="keyEvent">
<q-virtual-scroll
ref="scrollBar"
:style="{ maxHeight: listMaxHeight + 'px', height: '100vh' }"
:virtual-scroll-slice-size="lazyItemSize"
:virtual-scroll-item-size="itemHeight"
@virtual-scroll="scrollEvent"
:items="matchedItems"
>
<template v-slot="{ item, index }">
<q-item
:key="index"
clickable
v-ripple
@mousemove="currentIndex = index"
@click="clickOK"
manual-focus
:focused="index === currentIndex"
:active="index === currentIndex"
:style="{
height: itemHeight + 'px',
}"
>
<q-item-section v-if="isText">
<q-item-label lines="1">{{ item }}</q-item-label>
</q-item-section>
<q-item-section v-else-if="isJson" class="content-start q-gutter-md">
<q-avatar size="40px" v-if="item.icon">
<q-img :src="item.icon" />
</q-avatar>
<q-item-label lines="1">{{ item.title }}</q-item-label>
<q-item-label lines="1" caption>{{
item.description
}}</q-item-label>
</q-item-section>
<q-item-section v-else-if="isHtml">
<div v-html="item"></div>
</q-item-section>
</q-item>
</template>
</q-virtual-scroll>
<q-btn
v-if="options.showCancelButton"
class="absolute-bottom-right q-ma-xs"
round
color="primary"
icon="close"
@click="hide"
/>
</q-card>
</template>
<script>
@ -69,7 +57,7 @@ import pinyinMatch from "pinyin-match";
export default {
data() {
return {
items: this.initItems,
items: this.options.initItems,
listMaxHeight: 500,
currentIndex: 0,
itemHeight: 50,
@ -78,11 +66,7 @@ export default {
};
},
mounted() {
quickcommand.updateSelectList = (opt, id) => {
if (typeof id === "undefined") this.items.push(opt);
else this.items[id] = opt;
};
this.options.enableSearch && this.setSubInput();
this.options.options.enableSearch && this.setSubInput();
this.setUtoolsHeight(this.itemHeight * this.matchedItemsSize);
},
unmounted() {
@ -102,48 +86,33 @@ export default {
return this.matchedItems.length;
},
isJson() {
return this.options.optionType === "json";
return this.options.options.optionType === "json";
},
isHtml() {
return this.options.optionType === "html";
return this.options.options.optionType === "html";
},
isText() {
return this.options.optionType === "plaintext";
return this.options.options.optionType === "plaintext";
},
},
props: {
options: Object,
initItems: Array,
},
emits: ["ok", "hide"],
methods: {
show() {
this.$refs.dialog.show();
},
hide() {
this.$refs.dialog.hide();
},
onDialogHide() {
this.clear();
this.$emit("hide");
},
onOKClick() {
let selected =
this.options.optionType === "json"
? this.matchedItems[this.currentIndex]
: {
id: this.currentIndex,
text: this.matchedItems[this.currentIndex],
};
this.$emit("ok", selected);
this.options.closeOnSelect && this.hide();
},
onCancelClick() {
this.hide();
clickOK() {
let selected = this.isJson
? this.matchedItems[this.currentIndex]
: {
id: this.currentIndex,
text: this.matchedItems[this.currentIndex],
};
this.$emit("clickOK", selected);
this.options.options.closeOnSelect && this.hide();
},
keyEvent(e) {
@ -159,7 +128,7 @@ export default {
);
break;
case 13:
this.onOKClick();
this.clickOK();
return;
}
this.$refs.scrollBar.scrollTo(this.currentIndex);
@ -181,7 +150,7 @@ export default {
setSubInput() {
utools.setSubInput(({ text }) => {
this.searchWords = text;
}, this.options.placeholder);
}, this.options.options.placeholder);
},
setUtoolsHeight(height) {
@ -191,8 +160,13 @@ export default {
clear() {
utools.removeSubInput();
this.setUtoolsHeight(this.listMaxHeight);
quickcommand.updateSelectList = () => {};
},
},
};
</script>
<style scoped>
.q-card--dark {
background: var(--q-dark-page);
}
</style>

View File

@ -1,65 +1,43 @@
<template>
<q-dialog maximized ref="dialog" @hide="onDialogHide">
<q-card class="q-dialog-plugin">
<textarea
v-model="result"
:placeholder="placeholder"
autofocus
class="fixed"
:style="{
top: 0,
bottom: 0,
left: 0,
right: 0,
background: '#00000000',
color: $q.dark.isActive ? 'white' : 'black',
fontSize: '16px',
outline: 'none',
border: '3px solid #3577cb',
borderRadius: '5px',
}"
/>
<div
class="fixed-bottom-right q-pa-md q-gutter-sm"
>
<q-btn round color="blue-grey" icon="arrow_back" @click="onCancelClick" />
<q-btn round color="primary" icon="done" @click="onOKClick" />
</div>
</q-card>
</q-dialog>
<q-card class="q-dialog-plugin">
<textarea
v-model="result"
:placeholder="options.placeholder"
autofocus
class="fixed"
:style="{
top: 0,
bottom: 0,
left: 0,
right: 0,
background: '#00000000',
color: $q.dark.isActive ? 'white' : 'black',
fontSize: '16px',
outline: 'none',
border: '3px solid #3577cb',
borderRadius: '5px',
}"
/>
<div class="fixed-bottom-right q-pa-md q-gutter-sm">
<q-btn round color="blue-grey" icon="arrow_back" v-close-popup />
<q-btn round color="primary" icon="done" @click="clickOK" />
</div>
</q-card>
</template>
<script>
export default {
data() {
return {
result: this.value,
result: this.options.value,
};
},
props: {
placeholder: String,
value: String,
options: Object,
},
emits: ["ok", "hide"],
methods: {
show() {
this.$refs.dialog.show();
},
hide() {
this.$refs.dialog.hide();
},
onDialogHide() {
this.$emit("hide");
},
onOKClick() {
this.$emit("ok", this.result);
this.hide();
},
onCancelClick() {
this.hide();
clickOK() {
this.$emit("clickOK", this.result);
},
},
};

View File

@ -1,47 +0,0 @@
<template>
<q-dialog
ref="dialog"
seamless
position="right"
@hide="onDialogHide"
style="z-index: 9999"
>
<q-card>
<q-btn color="primary" :label="label" @click="onOKClick" v-close-popup />
</q-card>
</q-dialog>
</template>
<script>
export default {
props: {
label: String,
},
mounted() {
quickcommand.closeWaitBtn = () => {
this.$refs?.dialog?.hide();
};
},
emits: ["ok", "hide"],
methods: {
show() {
this.$refs.dialog.show();
},
hide() {
this.$refs.dialog.hide();
},
onDialogHide() {
this.$emit("hide");
},
onOKClick() {
this.$emit("ok");
},
onCancelClick() {
this.hide();
},
},
};
</script>

View File

@ -8,10 +8,10 @@ let escapeItem = item => {
return item.replace('$', '$$$')
}
let handlingJsonVar = (jsonVar, name) => {
let handlingJsonVar = (jsonVar, name, payload) => {
try {
return escapeItem(window.evalCodeInSandbox(jsonVar.slice(2, -2), {
[name]: quickcommand.enterData.payload
[name]: payload
}))
} catch (e) {
return utools.showNotification(e)
@ -73,7 +73,7 @@ const specialVars = {
label: "{{input}}",
desc: "主输入框的文本",
match: /{{input}}/mg,
repl: () => quickcommand.enterData.payload
repl: (text, enterData) => enterData.payload
},
pwd: {
name: "pwd",
@ -88,21 +88,21 @@ const specialVars = {
desc: "当前窗口信息JSON格式可以指定键值如{{WindowInfo.id}}",
type: "json",
match: /{{WindowInfo(.*?)}}/mg,
repl: jsonVar => handlingJsonVar(jsonVar, "WindowInfo")
repl: (jsonVar, enterData) => handlingJsonVar(jsonVar, "WindowInfo", enterData.payload)
},
MatchImage: {
name: "MatchImage",
label: "{{MatchImage}}",
desc: "匹配到图片的 DataUrl",
match: /{{MatchImage}}/mg,
repl: () => quickcommand.enterData.payload
repl: (text, enterData) => enterData.payload
},
SelectFile: {
name: "SelectFile",
label: "{{SelectFile}}",
desc: "文件管理器选中的文件不支持Linux",
match: /{{SelectFile}}/mg,
repl: () => window.getSelectFile(quickcommand.enterData.payload.id)
repl: (text, enterData) => window.getSelectFile(enterData.payload.id)
},
MatchedFiles: {
name: "MatchedFiles",
@ -110,14 +110,14 @@ const specialVars = {
desc: "匹配的文件JSON格式可以指定键值如{{MatchedFiles[0].path}}",
type: "json",
match: /{{MatchedFiles(.*?)}}/mg,
repl: jsonVar => handlingJsonVar(jsonVar, "MatchedFiles")
repl: (jsonVar, enterData) => handlingJsonVar(jsonVar, "MatchedFiles", enterData.payload)
},
type: {
name: "type",
label: "{{type}}",
desc: "onPluginEnter的type匹配的类型",
match: /{{type}}/mg,
repl: () => quickcommand.enterData.type
repl: (text, enterData) => enterData.type
},
payload: {
name: "payload",
@ -125,7 +125,7 @@ const specialVars = {
desc: "onPluginEnter的payload,当为JSON时可以指定键值如{{payload.id}}",
type: "json",
match: /{{payload(.*?)}}/mg,
repl: jsonVar => handlingJsonVar(jsonVar, "payload")
repl: (jsonVar, enterData) => handlingJsonVar(jsonVar, "payload", enterData.payload)
},
js: {
name: "js",

View File

@ -1,131 +0,0 @@
/**
* 通过quickcommand的api快速生成可交互的UI界面
* UI界面基于quasar
*/
import {
Dialog,
Notify
} from 'quasar'
import inputBox from "../components/quickcommandUI/InputBox"
import buttonBox from "../components/quickcommandUI/ButtonBox"
import TextArea from "../components/quickcommandUI/TextArea"
import SelectList from "../components/quickcommandUI/SelectList"
import WaitButton from "../components/quickcommandUI/waitButton"
const quickcommand = {
showInputBox: (options = ["请输入"], title = "") => new Promise((reslove, reject) => {
let props = {
labels: [],
values: [],
hints: [],
title: title
}
if (!_.isObject(options)) return reject(new TypeError(`应为 Object, 而非 ${typeof options}`))
if (_.isArray(options)) props.labels = options
else Object.assign(props, options)
Dialog.create({
component: inputBox,
componentProps: props
}).onOk(results => {
reslove(Array.from(results))
}).onCancel(() => {
console.log('取消')
})
}),
showButtonBox: (labels = ["确定"], title = "") => new Promise((reslove, reject) => {
if (!_.isArray(labels)) return reject(new TypeError(`应为 Array, 而非 ${typeof labels}`))
let props = {
labels: labels,
title: title
}
Dialog.create({
component: buttonBox,
componentProps: props
}).onOk(results => {
reslove(results)
}).onCancel(() => {
console.log('取消')
})
}),
showConfirmBox: (message = "", title = "提示") => new Promise((reslove, reject) => {
Dialog.create({
title: title,
message: message,
cancel: true,
persistent: true
}).onOk(() => {
reslove(true)
}).onCancel(() => {
reslove(false)
})
}),
showMessageBox: (message, icon = 'success', time = 3000) => {
if (icon === 'success') icon = 'positive'
if (icon === 'error') icon = 'negative'
Notify.create({
type: icon,
message: message,
timeout: time,
position: 'top',
})
},
showTextArea: (placeholder = "", value = "") => new Promise((reslove, reject) => {
let props = {
placeholder: placeholder,
value: value
}
Dialog.create({
component: TextArea,
componentProps: props
}).onOk(results => {
reslove(results)
}).onCancel(() => {
console.log('取消')
})
}),
showSelectList: (selects, options = {}) => new Promise((reslove, reject) => {
if (!_.isArray(selects)) return reject(new TypeError(`应为 Array, 而非 ${typeof selects}`))
let defaultOptions = {
placeholder: "输入进行筛选,支持拼音",
optionType: "plaintext",
enableSearch: true,
showCancelButton: false,
closeOnSelect: true
}
Object.assign(defaultOptions, options)
let props = {
initItems: selects,
options: defaultOptions
}
Dialog.create({
component: SelectList,
componentProps: props
}).onOk(results => {
reslove(results)
}).onCancel(() => {
console.log('取消')
})
}),
showWaitButton: (callback, label = "确定") => {
Dialog.create({
component: WaitButton,
componentProps: {
label
}
}).onOk(() => {
callback()
}).onCancel(() => {
console.log('取消')
})
}
}
export default quickcommand

View File

@ -315,8 +315,8 @@ export default {
initPage() {
// newcommand
if (this.newCommandDirect) {
if (quickcommand.enterData.type === "text") this.addNewCommand();
else this.editCommand(JSON.parse(quickcommand.enterData.payload));
if (this.$root.enterData.type === "text") this.addNewCommand();
else this.editCommand(JSON.parse(this.$root.enterData.payload));
this.$router.push("/configuration");
}
// features

View File

@ -174,8 +174,10 @@ interface quickcommandApi {
/**
*
*
* 退
*/
closeWaitBtn(): void;
closeWaitButton(): void;
/**
*
@ -192,6 +194,13 @@ interface quickcommandApi {
*/
listenKeydown(callback: (event) => void): void;
/**
*
*
* 退
*/
removeListener(): void;
/**
*
* @param ms

View File

@ -1,9 +1,6 @@
import { route } from 'quasar/wrappers'
import { createRouter, createMemoryHistory, createWebHistory, createWebHashHistory } from 'vue-router'
import routes from './routes'
import quickcommandUI from '../js/quickcommand'
Object.assign(window.quickcommand, quickcommandUI)
/*
* If not building with SSR mode, you can
@ -14,20 +11,20 @@ Object.assign(window.quickcommand, quickcommandUI)
* with the Router instance.
*/
export default route(function (/* { store, ssrContext } */) {
const createHistory = process.env.SERVER
? createMemoryHistory
: (process.env.VUE_ROUTER_MODE === 'history' ? createWebHistory : createWebHashHistory)
export default route(function( /* { store, ssrContext } */ ) {
const createHistory = process.env.SERVER ?
createMemoryHistory :
(process.env.VUE_ROUTER_MODE === 'history' ? createWebHistory : createWebHashHistory)
const Router = createRouter({
scrollBehavior: () => ({ left: 0, top: 0 }),
routes,
const Router = createRouter({
scrollBehavior: () => ({ left: 0, top: 0 }),
routes,
// Leave this as is and make changes in quasar.conf.js instead!
// quasar.conf.js -> build -> vueRouterMode
// quasar.conf.js -> build -> publicPath
history: createHistory(process.env.MODE === 'ssr' ? void 0 : process.env.VUE_ROUTER_BASE)
})
// Leave this as is and make changes in quasar.conf.js instead!
// quasar.conf.js -> build -> vueRouterMode
// quasar.conf.js -> build -> publicPath
history: createHistory(process.env.MODE === 'ssr' ? void 0 : process.env.VUE_ROUTER_BASE)
})
return Router
return Router
})