mirror of
https://github.com/ZiuChen/ClipboardManager.git
synced 2025-08-17 22:39:31 +08:00
Merge branch 'v1.4.3'
This commit is contained in:
commit
33306aadac
56
public/listener.js
Normal file
56
public/listener.js
Normal file
@ -0,0 +1,56 @@
|
|||||||
|
const { chmodSync, existsSync } = require('fs')
|
||||||
|
const { EventEmitter } = require('events')
|
||||||
|
const path = require('path')
|
||||||
|
const { execFile } = require('child_process')
|
||||||
|
|
||||||
|
class ClipboardEventListener extends EventEmitter {
|
||||||
|
constructor() {
|
||||||
|
super()
|
||||||
|
this.child = null
|
||||||
|
this.listening = false
|
||||||
|
}
|
||||||
|
startListening(dbPath) {
|
||||||
|
const targetMap = {
|
||||||
|
win32: 'clipboard-event-handler-win32.exe',
|
||||||
|
linux: 'clipboard-event-handler-linux'
|
||||||
|
}
|
||||||
|
const { platform } = process
|
||||||
|
const target = path.resolve(
|
||||||
|
dbPath.split('_utools_clipboard_manager_storage')[0],
|
||||||
|
targetMap[platform]
|
||||||
|
)
|
||||||
|
if (!existsSync(target)) {
|
||||||
|
this.emit('error', '剪贴板监听程序不存在')
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if (platform === 'win32') {
|
||||||
|
this.child = execFile(target)
|
||||||
|
} else if (platform === 'linux') {
|
||||||
|
chmodSync(target, 0o755)
|
||||||
|
this.child = execFile(target)
|
||||||
|
} else {
|
||||||
|
throw 'Not yet supported'
|
||||||
|
}
|
||||||
|
this.child.stdout.on('data', (data) => {
|
||||||
|
if (data.trim() === 'CLIPBOARD_CHANGE') {
|
||||||
|
this.emit('change')
|
||||||
|
}
|
||||||
|
})
|
||||||
|
this.child.stdout.on('close', () => {
|
||||||
|
this.emit('close')
|
||||||
|
this.listening = false
|
||||||
|
})
|
||||||
|
this.child.stdout.on('exit', () => {
|
||||||
|
this.emit('exit')
|
||||||
|
this.listening = false
|
||||||
|
})
|
||||||
|
this.listening = true
|
||||||
|
}
|
||||||
|
stopListening() {
|
||||||
|
const res = this.child.kill()
|
||||||
|
this.listening = false
|
||||||
|
return res
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = new ClipboardEventListener()
|
@ -1,5 +1,5 @@
|
|||||||
{
|
{
|
||||||
"version": "1.4.2",
|
"version": "1.4.3",
|
||||||
"pluginName": "超级剪贴板",
|
"pluginName": "超级剪贴板",
|
||||||
"description": "强大的剪贴板管理工具",
|
"description": "强大的剪贴板管理工具",
|
||||||
"author": "ZiuChen",
|
"author": "ZiuChen",
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
const { existsSync, readFileSync, writeFileSync, mkdirSync } = require('fs')
|
const { existsSync, readFileSync, writeFileSync, mkdirSync } = require('fs')
|
||||||
const crypto = require('crypto')
|
const crypto = require('crypto')
|
||||||
|
const listener = require('./listener')
|
||||||
const { clipboard } = require('electron')
|
const { clipboard } = require('electron')
|
||||||
const time = require('./time')
|
const time = require('./time')
|
||||||
|
|
||||||
@ -11,5 +12,6 @@ window.exports = {
|
|||||||
mkdirSync,
|
mkdirSync,
|
||||||
crypto,
|
crypto,
|
||||||
clipboard,
|
clipboard,
|
||||||
time
|
time,
|
||||||
|
Buffer
|
||||||
}
|
}
|
||||||
|
@ -1,8 +1,8 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="app">
|
<div class="app">
|
||||||
<Main @show-setting="settingShown = true" v-show="!settingShown"></Main>
|
<Main @show-setting="settingShown = true" v-if="!settingShown"></Main>
|
||||||
<transition name="el-fade-in-linear">
|
<transition name="el-fade-in-linear">
|
||||||
<Setting v-show="settingShown" @back="settingShown = false"></Setting>
|
<Setting v-if="settingShown" @back="settingShown = false"></Setting>
|
||||||
</transition>
|
</transition>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
@ -80,9 +80,18 @@ const props = defineProps({
|
|||||||
currentActiveTab: {
|
currentActiveTab: {
|
||||||
type: String,
|
type: String,
|
||||||
required: true
|
required: true
|
||||||
|
},
|
||||||
|
isSearchPanelExpand: {
|
||||||
|
type: Boolean,
|
||||||
|
required: true
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
const emit = defineEmits(['onDataChange', 'onDataRemove', 'onSelectItemAdd', 'onMultiCopyExecute'])
|
const emit = defineEmits([
|
||||||
|
'onDataChange',
|
||||||
|
'onDataRemove',
|
||||||
|
'onMultiCopyExecute',
|
||||||
|
'toggleMultiSelect'
|
||||||
|
])
|
||||||
const isOverSizedContent = (item) => {
|
const isOverSizedContent = (item) => {
|
||||||
const { type, data } = item
|
const { type, data } = item
|
||||||
if (type === 'text') {
|
if (type === 'text') {
|
||||||
@ -111,6 +120,7 @@ const handleItemClick = (ev, item) => {
|
|||||||
if (props.isMultiple === true) {
|
if (props.isMultiple === true) {
|
||||||
const i = selectItemList.value.indexOf(item) // 在已选中列表中的位置
|
const i = selectItemList.value.indexOf(item) // 在已选中列表中的位置
|
||||||
const index = props.showList.indexOf(item) // 在全部列表中的位置
|
const index = props.showList.indexOf(item) // 在全部列表中的位置
|
||||||
|
activeIndex.value = index
|
||||||
if (selectItemList.value.length !== 0 && isShiftDown.value) {
|
if (selectItemList.value.length !== 0 && isShiftDown.value) {
|
||||||
// 列表不为空 且 Shift按下 多选
|
// 列表不为空 且 Shift按下 多选
|
||||||
// 找到selectList的最高位与最低位
|
// 找到selectList的最高位与最低位
|
||||||
@ -159,8 +169,6 @@ const handleItemClick = (ev, item) => {
|
|||||||
selectItemList.value.push(item) // 添加到已选列表中
|
selectItemList.value.push(item) // 添加到已选列表中
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
emit('onSelectItemAdd')
|
|
||||||
} else {
|
} else {
|
||||||
const { button } = ev
|
const { button } = ev
|
||||||
if (button === 0) {
|
if (button === 0) {
|
||||||
@ -178,7 +186,11 @@ const handleItemClick = (ev, item) => {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
const activeIndex = ref(0)
|
const activeIndex = ref(0)
|
||||||
const handleMouseOver = (index) => (activeIndex.value = index)
|
const handleMouseOver = (index) => {
|
||||||
|
if (!props.isMultiple) {
|
||||||
|
activeIndex.value = index
|
||||||
|
}
|
||||||
|
}
|
||||||
// 父组件中改变了引用类型的地址 故要用 getter返回
|
// 父组件中改变了引用类型的地址 故要用 getter返回
|
||||||
watch(
|
watch(
|
||||||
() => props.showList,
|
() => props.showList,
|
||||||
@ -194,25 +206,23 @@ onMounted(() => {
|
|||||||
const isCopy = (ctrlKey || metaKey) && (key === 'C' || key === 'c')
|
const isCopy = (ctrlKey || metaKey) && (key === 'C' || key === 'c')
|
||||||
const isNumber = parseInt(key) <= 9 && parseInt(key) >= 0
|
const isNumber = parseInt(key) <= 9 && parseInt(key) >= 0
|
||||||
const isShift = key === 'Shift'
|
const isShift = key === 'Shift'
|
||||||
|
const isSpace = key === ' '
|
||||||
|
const activeNode = !props.isMultiple
|
||||||
|
? document.querySelector('.clip-item.active' + (isArrowDown ? '+.clip-item' : ''))
|
||||||
|
: document.querySelector('.clip-item.multi-active' + (isArrowDown ? '+.clip-item' : ''))
|
||||||
if (isArrowUp) {
|
if (isArrowUp) {
|
||||||
|
if (activeIndex.value === 1) window.toTop()
|
||||||
if (activeIndex.value > 0) {
|
if (activeIndex.value > 0) {
|
||||||
activeIndex.value--
|
activeIndex.value--
|
||||||
const activeNode = document.querySelector('.clip-item.active')
|
activeNode.previousElementSibling.previousElementSibling.scrollIntoView({
|
||||||
if (activeIndex.value === 1) {
|
block: 'nearest',
|
||||||
window.toTop()
|
inline: 'nearest'
|
||||||
} else {
|
})
|
||||||
activeNode?.previousElementSibling?.previousElementSibling?.scrollIntoView({
|
|
||||||
block: 'nearest',
|
|
||||||
inline: 'nearest'
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
} else if (isArrowDown) {
|
} else if (isArrowDown) {
|
||||||
if (activeIndex.value < props.showList.length - 1) {
|
if (activeIndex.value < props.showList.length - 1) {
|
||||||
activeIndex.value++
|
activeIndex.value++
|
||||||
document
|
activeNode.scrollIntoView({ block: 'nearest', inline: 'nearest' })
|
||||||
.querySelector('.clip-item.active+.clip-item')
|
|
||||||
?.scrollIntoView({ block: 'nearest', inline: 'nearest' })
|
|
||||||
}
|
}
|
||||||
} else if (isCopy) {
|
} else if (isCopy) {
|
||||||
if (!props.fullData.data) {
|
if (!props.fullData.data) {
|
||||||
@ -246,6 +256,25 @@ onMounted(() => {
|
|||||||
if (props.isMultiple) {
|
if (props.isMultiple) {
|
||||||
isShiftDown.value = true
|
isShiftDown.value = true
|
||||||
}
|
}
|
||||||
|
} else if (isSpace) {
|
||||||
|
if (props.isSearchPanelExpand) {
|
||||||
|
// 搜索栏展开状态 不进入多选
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if (!props.isMultiple) {
|
||||||
|
emit('toggleMultiSelect') // 如果不是多选状态 则切换到多选状态
|
||||||
|
}
|
||||||
|
e.preventDefault()
|
||||||
|
const i = selectItemList.value.findIndex((item) => item === props.showList[activeIndex.value])
|
||||||
|
if (i !== -1) {
|
||||||
|
selectItemList.value.splice(i, 1) // 如果已选中 则取消选中
|
||||||
|
} else {
|
||||||
|
selectItemList.value.push(props.showList[activeIndex.value]) // 如果未选中 则选中
|
||||||
|
activeIndex.value++
|
||||||
|
document
|
||||||
|
.querySelector('.clip-item.multi-active+.clip-item')
|
||||||
|
.scrollIntoView({ block: 'nearest', inline: 'nearest' })
|
||||||
|
}
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
document.addEventListener('keyup', (e) => {
|
document.addEventListener('keyup', (e) => {
|
||||||
|
@ -4,7 +4,7 @@
|
|||||||
<template v-for="tab of tabs">
|
<template v-for="tab of tabs">
|
||||||
<div
|
<div
|
||||||
:class="{ 'clip-switch-item': true, active: activeTab === tab.type }"
|
:class="{ 'clip-switch-item': true, active: activeTab === tab.type }"
|
||||||
@click="onNavClick(tab.type)"
|
@click="toggleNav(tab.type)"
|
||||||
>
|
>
|
||||||
<component :is="tab.icon"></component>
|
<component :is="tab.icon"></component>
|
||||||
{{ tab.name }}
|
{{ tab.name }}
|
||||||
@ -27,12 +27,7 @@ const tabs = [
|
|||||||
{ name: '收藏', type: 'collect', icon: Collection }
|
{ name: '收藏', type: 'collect', icon: Collection }
|
||||||
]
|
]
|
||||||
const activeTab = ref('all')
|
const activeTab = ref('all')
|
||||||
const emit = defineEmits(['onNavClick'])
|
|
||||||
const toggleNav = (type) => (activeTab.value = type)
|
const toggleNav = (type) => (activeTab.value = type)
|
||||||
const onNavClick = (type) => {
|
|
||||||
toggleNav(type)
|
|
||||||
emit('onNavClick', type)
|
|
||||||
}
|
|
||||||
defineExpose({
|
defineExpose({
|
||||||
tabs,
|
tabs,
|
||||||
activeTab,
|
activeTab,
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
{
|
{
|
||||||
"title": "重要版本更新提示",
|
"title": "重要版本更新提示",
|
||||||
"content": "1. 如果你是第一次使用此插件, 请务必设置跟随主程序启动选项, 否则可能导致剪贴板记录丢失</br>2. 插件使用过程中遇到任何问题, 请到论坛发布页回帖或加入QQ群反馈",
|
"content": "1. 如果你是第一次使用此插件, 请务必设置跟随主程序启动选项, 否则可能导致剪贴板记录丢失</br>2. 请手动安装`clipboard-event-handler`以获得最佳剪贴板监听性能</br>3. 插件使用过程中遇到任何问题, 请到论坛发布页回帖或加入QQ群反馈",
|
||||||
"version": 2
|
"version": 3
|
||||||
}
|
}
|
||||||
|
@ -49,7 +49,7 @@
|
|||||||
"regex": "^(?:#?[a-f0-9]{6}|(?:(?:25[0-5]|2[0-4]\\d|1?\\d{1,2}), ?){2}(?:25[0-5]|2[0-4]\\d|1?\\d{1,2})|rgba?\\((?:(?:25[0-5]|2[0-4]\\d|1?\\d{1,2}), ?){2}(?:25[0-5]|2[0-4]\\d|1?\\d{1,2})(?:, ?(?:1|0|0\\.\\d{1,2}))?\\)|hs[liv]a?\\((?:360|(?:(?:3[0-5]\\d|[1-2]\\d{2}|\\d{1,2})(?:\\.\\d{1,15})?))(?:deg)?(?:, |,| )(?:100|\\d{1,2}(?:\\.\\d{1,15})?)%?(?:, |,| )(?:100|\\d{1,2}(?:\\.\\d{1,15})?)%?(?:, ?(?:1|0|0\\.\\d{1,2}))?\\))$"
|
"regex": "^(?:#?[a-f0-9]{6}|(?:(?:25[0-5]|2[0-4]\\d|1?\\d{1,2}), ?){2}(?:25[0-5]|2[0-4]\\d|1?\\d{1,2})|rgba?\\((?:(?:25[0-5]|2[0-4]\\d|1?\\d{1,2}), ?){2}(?:25[0-5]|2[0-4]\\d|1?\\d{1,2})(?:, ?(?:1|0|0\\.\\d{1,2}))?\\)|hs[liv]a?\\((?:360|(?:(?:3[0-5]\\d|[1-2]\\d{2}|\\d{1,2})(?:\\.\\d{1,15})?))(?:deg)?(?:, |,| )(?:100|\\d{1,2}(?:\\.\\d{1,15})?)%?(?:, |,| )(?:100|\\d{1,2}(?:\\.\\d{1,15})?)%?(?:, ?(?:1|0|0\\.\\d{1,2}))?\\))$"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"command": "redirect:统计文本次数"
|
"command": "redirect:颜色信息"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"id": "custom.1663490862",
|
"id": "custom.1663490862",
|
||||||
|
@ -1,5 +1,15 @@
|
|||||||
const { utools, existsSync, readFileSync, writeFileSync, mkdirSync, crypto, clipboard, time } =
|
const {
|
||||||
window.exports
|
utools,
|
||||||
|
existsSync,
|
||||||
|
readFileSync,
|
||||||
|
writeFileSync,
|
||||||
|
mkdirSync,
|
||||||
|
crypto,
|
||||||
|
listener,
|
||||||
|
clipboard,
|
||||||
|
time,
|
||||||
|
Buffer
|
||||||
|
} = window.exports
|
||||||
import setting from './readSetting'
|
import setting from './readSetting'
|
||||||
|
|
||||||
export default function initPlugin() {
|
export default function initPlugin() {
|
||||||
@ -205,23 +215,56 @@ export default function initPlugin() {
|
|||||||
db.addItem(item)
|
db.addItem(item)
|
||||||
}
|
}
|
||||||
|
|
||||||
let prev = db.dataBase.data[0] || {}
|
const addCommonListener = () => {
|
||||||
function loop() {
|
let prev = db.dataBase.data[0] || {}
|
||||||
time.sleep(300).then(loop)
|
function loop() {
|
||||||
const item = pbpaste()
|
time.sleep(300).then(loop)
|
||||||
if (!item) return
|
const item = pbpaste()
|
||||||
item.id = crypto.createHash('md5').update(item.data).digest('hex')
|
if (!item) return
|
||||||
if (item && prev.id != item.id) {
|
item.id = crypto.createHash('md5').update(item.data).digest('hex')
|
||||||
// 剪切板元素 与最近一次复制内容不同
|
if (item && prev.id != item.id) {
|
||||||
prev = item
|
// 剪切板元素 与最近一次复制内容不同
|
||||||
handleClipboardChange(item)
|
prev = item
|
||||||
} else {
|
handleClipboardChange(item)
|
||||||
// 剪切板元素 与上次复制内容相同
|
} else {
|
||||||
|
// 剪切板元素 与上次复制内容相同
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
loop()
|
||||||
|
}
|
||||||
|
|
||||||
|
const registerClipEvent = (listener) => {
|
||||||
|
const exitHandler = () => {
|
||||||
|
utools.showNotification('剪贴板监听异常退出 请重启插件以开启监听')
|
||||||
|
utools.outPlugin()
|
||||||
|
}
|
||||||
|
const errorHandler = (error) => {
|
||||||
|
const info = '请到设置页手动安装 clipboard-event-handler 剪贴板监听程序'
|
||||||
|
utools.showNotification('启动剪贴板监听程序启动出错: ' + error + info)
|
||||||
|
addCommonListener()
|
||||||
|
}
|
||||||
|
listener
|
||||||
|
.on('change', handleClipboardChange)
|
||||||
|
.on('close', exitHandler)
|
||||||
|
.on('exit', exitHandler)
|
||||||
|
.on('error', (error) => errorHandler(error))
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!utools.isMacOs()) {
|
||||||
|
// 首次启动插件 即开启监听
|
||||||
|
registerClipEvent(listener)
|
||||||
|
listener.startListening(setting.database.path)
|
||||||
|
} else {
|
||||||
|
// macos 由于无法执行 clipboard-event-handler-mac 所以使用旧方法
|
||||||
|
addCommonListener()
|
||||||
}
|
}
|
||||||
loop()
|
|
||||||
|
|
||||||
utools.onPluginEnter(() => {
|
utools.onPluginEnter(() => {
|
||||||
|
if (!listener.listening && !utools.isMacOs()) {
|
||||||
|
// 进入插件后 如果监听已关闭 则重新开启监听
|
||||||
|
registerClipEvent(listener)
|
||||||
|
listener.startListening(setting.database.path)
|
||||||
|
}
|
||||||
toTop()
|
toTop()
|
||||||
resetNav()
|
resetNav()
|
||||||
})
|
})
|
||||||
|
@ -9,6 +9,7 @@ import 'element-plus/theme-chalk/el-input.css'
|
|||||||
import 'element-plus/theme-chalk/el-select.css'
|
import 'element-plus/theme-chalk/el-select.css'
|
||||||
import 'element-plus/theme-chalk/el-option.css'
|
import 'element-plus/theme-chalk/el-option.css'
|
||||||
import 'element-plus/theme-chalk/el-scrollbar.css'
|
import 'element-plus/theme-chalk/el-scrollbar.css'
|
||||||
|
import 'element-plus/theme-chalk/el-tag.css'
|
||||||
import {
|
import {
|
||||||
ElButton,
|
ElButton,
|
||||||
ElMessageBox,
|
ElMessageBox,
|
||||||
@ -17,7 +18,8 @@ import {
|
|||||||
ElInput,
|
ElInput,
|
||||||
ElSelect,
|
ElSelect,
|
||||||
ElOption,
|
ElOption,
|
||||||
ElScrollbar
|
ElScrollbar,
|
||||||
|
ElTag
|
||||||
} from 'element-plus'
|
} from 'element-plus'
|
||||||
|
|
||||||
const components = [
|
const components = [
|
||||||
@ -28,7 +30,8 @@ const components = [
|
|||||||
ElInput,
|
ElInput,
|
||||||
ElSelect,
|
ElSelect,
|
||||||
ElOption,
|
ElOption,
|
||||||
ElScrollbar
|
ElScrollbar,
|
||||||
|
ElTag
|
||||||
]
|
]
|
||||||
|
|
||||||
document.querySelector('html').className = utools.isDarkColors() ? 'dark' : ''
|
document.querySelector('html').className = utools.isDarkColors() ? 'dark' : ''
|
||||||
|
@ -12,12 +12,16 @@
|
|||||||
width: 85px;
|
width: 85px;
|
||||||
}
|
}
|
||||||
&.operation-select {
|
&.operation-select {
|
||||||
width: 450px;
|
width: 520px;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
.el-textarea {
|
.el-textarea {
|
||||||
width: 70%;
|
width: 70%;
|
||||||
}
|
}
|
||||||
|
.el-tag {
|
||||||
|
margin: 0 10px;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
.path {
|
.path {
|
||||||
width: 65%;
|
width: 65%;
|
||||||
}
|
}
|
||||||
|
@ -7,7 +7,7 @@
|
|||||||
@onDataRemove="handleDataRemove"
|
@onDataRemove="handleDataRemove"
|
||||||
@onOverlayClick="toggleFullData({ type: 'text', data: '' })"
|
@onOverlayClick="toggleFullData({ type: 'text', data: '' })"
|
||||||
></ClipFullData>
|
></ClipFullData>
|
||||||
<ClipSwitch ref="ClipSwitchRef" @onNavClick="handleNavClick">
|
<ClipSwitch ref="ClipSwitchRef">
|
||||||
<template #SidePanel>
|
<template #SidePanel>
|
||||||
<div class="clip-switch-btn-list" v-show="!isSearchPanelExpand">
|
<div class="clip-switch-btn-list" v-show="!isSearchPanelExpand">
|
||||||
<span class="clip-switch-btn clip-select-count" v-show="isMultiple">
|
<span class="clip-switch-btn clip-select-count" v-show="isMultiple">
|
||||||
@ -47,7 +47,9 @@
|
|||||||
:fullData="fullData"
|
:fullData="fullData"
|
||||||
:isMultiple="isMultiple"
|
:isMultiple="isMultiple"
|
||||||
:currentActiveTab="activeTab"
|
:currentActiveTab="activeTab"
|
||||||
|
:isSearchPanelExpand="isSearchPanelExpand"
|
||||||
@onMultiCopyExecute="handleMultiCopyBtnClick"
|
@onMultiCopyExecute="handleMultiCopyBtnClick"
|
||||||
|
@toggleMultiSelect="() => (isMultiple = true)"
|
||||||
@onDataChange="toggleFullData"
|
@onDataChange="toggleFullData"
|
||||||
@onDataRemove="handleDataRemove"
|
@onDataRemove="handleDataRemove"
|
||||||
>
|
>
|
||||||
@ -153,7 +155,7 @@ const textFilterCallBack = (item) => {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const updateShowList = (type) => {
|
const updateShowList = (type, toTop = true) => {
|
||||||
// 更新显示列表
|
// 更新显示列表
|
||||||
showList.value = list.value
|
showList.value = list.value
|
||||||
.filter((item) =>
|
.filter((item) =>
|
||||||
@ -162,7 +164,7 @@ const updateShowList = (type) => {
|
|||||||
.filter((item) => (filterText.value ? item.type !== 'image' : item)) // 有过滤词 排除掉图片 DataURL
|
.filter((item) => (filterText.value ? item.type !== 'image' : item)) // 有过滤词 排除掉图片 DataURL
|
||||||
.filter((item) => textFilterCallBack(item))
|
.filter((item) => textFilterCallBack(item))
|
||||||
.slice(0, GAP) // 重新切分懒加载列表
|
.slice(0, GAP) // 重新切分懒加载列表
|
||||||
window.toTop()
|
toTop && window.toTop()
|
||||||
}
|
}
|
||||||
|
|
||||||
const restoreDataBase = () => {
|
const restoreDataBase = () => {
|
||||||
@ -179,11 +181,6 @@ const restoreDataBase = () => {
|
|||||||
.catch(() => {})
|
.catch(() => {})
|
||||||
}
|
}
|
||||||
|
|
||||||
const handleNavClick = (type) => {
|
|
||||||
updateShowList(type)
|
|
||||||
offset.value = 0 // 重置懒加载偏移量
|
|
||||||
}
|
|
||||||
|
|
||||||
const fullData = ref({ type: 'text', data: '' })
|
const fullData = ref({ type: 'text', data: '' })
|
||||||
const fullDataShow = ref(false)
|
const fullDataShow = ref(false)
|
||||||
const toggleFullData = (item) => {
|
const toggleFullData = (item) => {
|
||||||
@ -197,7 +194,7 @@ const ClipSwitchRef = ref()
|
|||||||
const handleDataRemove = () => {
|
const handleDataRemove = () => {
|
||||||
// 此函数须在挂载后执行
|
// 此函数须在挂载后执行
|
||||||
list.value = window.db.dataBase.data
|
list.value = window.db.dataBase.data
|
||||||
updateShowList(ClipSwitchRef.value.activeTab)
|
updateShowList(ClipSwitchRef.value.activeTab, false)
|
||||||
}
|
}
|
||||||
|
|
||||||
const emit = defineEmits(['showSetting'])
|
const emit = defineEmits(['showSetting'])
|
||||||
@ -226,17 +223,26 @@ onMounted(() => {
|
|||||||
updateShowList(activeTab.value)
|
updateShowList(activeTab.value)
|
||||||
|
|
||||||
// 定期检查更新
|
// 定期检查更新
|
||||||
let prev = {}
|
if (!utools.isMacOs() && window.listener.listening) {
|
||||||
setInterval(() => {
|
// 非macOS系统且监听器开启时
|
||||||
const now = window.db.dataBase.data[0]
|
window.listener.on('change', () => {
|
||||||
if (prev?.id === now?.id) {
|
|
||||||
} else {
|
|
||||||
// 有更新
|
|
||||||
list.value = window.db.dataBase.data
|
list.value = window.db.dataBase.data
|
||||||
updateShowList(activeTab.value)
|
updateShowList(activeTab.value)
|
||||||
prev = now
|
})
|
||||||
}
|
} else {
|
||||||
}, 800)
|
// macOS且监听器启动失败时
|
||||||
|
let prev = {}
|
||||||
|
setInterval(() => {
|
||||||
|
const now = window.db.dataBase.data[0]
|
||||||
|
if (prev?.id === now?.id) {
|
||||||
|
} else {
|
||||||
|
// 有更新
|
||||||
|
list.value = window.db.dataBase.data
|
||||||
|
updateShowList(activeTab.value)
|
||||||
|
prev = now
|
||||||
|
}
|
||||||
|
}, 800)
|
||||||
|
}
|
||||||
|
|
||||||
// 监听搜索框
|
// 监听搜索框
|
||||||
watch(filterText, (val) => updateShowList(activeTab.value))
|
watch(filterText, (val) => updateShowList(activeTab.value))
|
||||||
@ -287,6 +293,7 @@ onMounted(() => {
|
|||||||
const isEnter = key === 'Enter'
|
const isEnter = key === 'Enter'
|
||||||
const isShift = key === 'Shift'
|
const isShift = key === 'Shift'
|
||||||
const isAlt = key === 'Alt'
|
const isAlt = key === 'Alt'
|
||||||
|
const isSpace = key === ' '
|
||||||
if (isTab) {
|
if (isTab) {
|
||||||
const tabTypes = tabs.map((item) => item.type)
|
const tabTypes = tabs.map((item) => item.type)
|
||||||
const index = tabTypes.indexOf(activeTab.value)
|
const index = tabTypes.indexOf(activeTab.value)
|
||||||
@ -308,6 +315,7 @@ onMounted(() => {
|
|||||||
} else if (isMultiple.value) {
|
} else if (isMultiple.value) {
|
||||||
// 退出多选状态
|
// 退出多选状态
|
||||||
isMultiple.value = !isMultiple.value
|
isMultiple.value = !isMultiple.value
|
||||||
|
e.stopPropagation()
|
||||||
} else {
|
} else {
|
||||||
// 无上述情况 执行默认: 隐藏uTools主窗口
|
// 无上述情况 执行默认: 隐藏uTools主窗口
|
||||||
}
|
}
|
||||||
@ -323,6 +331,8 @@ onMounted(() => {
|
|||||||
} else if (ctrlKey || metaKey || isAlt) {
|
} else if (ctrlKey || metaKey || isAlt) {
|
||||||
// Ctrl: utools模拟执行粘贴时触发
|
// Ctrl: utools模拟执行粘贴时触发
|
||||||
// Alt:
|
// Alt:
|
||||||
|
} else if (isSpace) {
|
||||||
|
// 空格向下多选
|
||||||
} else {
|
} else {
|
||||||
window.focus() // 其他键盘事件 直接聚焦搜索框
|
window.focus() // 其他键盘事件 直接聚焦搜索框
|
||||||
}
|
}
|
||||||
|
@ -2,13 +2,23 @@
|
|||||||
<div class="setting">
|
<div class="setting">
|
||||||
<el-card class="setting-card">
|
<el-card class="setting-card">
|
||||||
<template #header>
|
<template #header>
|
||||||
<el-button type="primary" @click="handleLinkClick(0)">🚀 主页</el-button>
|
<el-button type="primary" @click="handleLinkClick(4)">💖 赞赏我</el-button>
|
||||||
<el-button @click="handleLinkClick(1)">⚡ 云同步教程</el-button>
|
<el-button @click="handleLinkClick(0)">🚀 主页</el-button>
|
||||||
<el-button @click="handleLinkClick(1)">💡 创造自己的功能按钮</el-button>
|
<el-button @click="handleLinkClick(1)">⚡ 迁移数据 | 云同步 | 自定义功能</el-button>
|
||||||
<el-button @click="handleLinkClick(2)">⭐ 开源代码</el-button>
|
<el-button @click="handleLinkClick(2)">⭐ 开源代码</el-button>
|
||||||
<el-button @click="handleLinkClick(3)">🎈 论坛发布页</el-button>
|
<el-button @click="handleLinkClick(3)">🎈 论坛发布页</el-button>
|
||||||
</template>
|
</template>
|
||||||
<div class="setting-card-content">
|
<div class="setting-card-content">
|
||||||
|
<div class="setting-card-content-item">
|
||||||
|
<span>剪贴板监听程序状态</span>
|
||||||
|
<el-tag
|
||||||
|
:type="listenStatus ? 'success' : 'warning'"
|
||||||
|
@click="handleLinkClick(1)"
|
||||||
|
title="手动安装剪贴板监听程序"
|
||||||
|
>
|
||||||
|
{{ listenStatus ? '已安装' : '未安装' }}
|
||||||
|
</el-tag>
|
||||||
|
</div>
|
||||||
<div class="setting-card-content-item">
|
<div class="setting-card-content-item">
|
||||||
<span>数据库路径</span>
|
<span>数据库路径</span>
|
||||||
<el-input class="path" v-model="path" :title="path" disabled></el-input>
|
<el-input class="path" v-model="path" :title="path" disabled></el-input>
|
||||||
@ -38,7 +48,6 @@
|
|||||||
multiple
|
multiple
|
||||||
:multiple-limit="5"
|
:multiple-limit="5"
|
||||||
placeholder="请选择"
|
placeholder="请选择"
|
||||||
:teleported="false"
|
|
||||||
>
|
>
|
||||||
<el-option
|
<el-option
|
||||||
v-for="{ id, title, icon } in [
|
v-for="{ id, title, icon } in [
|
||||||
@ -66,7 +75,7 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup>
|
<script setup>
|
||||||
import { ref } from 'vue'
|
import { ref, onMounted } from 'vue'
|
||||||
import { ElMessage, ElMessageBox } from 'element-plus'
|
import { ElMessage, ElMessageBox } from 'element-plus'
|
||||||
import setting from '../global/readSetting'
|
import setting from '../global/readSetting'
|
||||||
import restoreSetting from '../global/restoreSetting'
|
import restoreSetting from '../global/restoreSetting'
|
||||||
@ -83,12 +92,15 @@ const shown = ref(operation.shown)
|
|||||||
const custom = ref(operation.custom)
|
const custom = ref(operation.custom)
|
||||||
const stringCustom = ref(JSON.stringify(operation.custom))
|
const stringCustom = ref(JSON.stringify(operation.custom))
|
||||||
|
|
||||||
|
const listenStatus = ref(false)
|
||||||
|
|
||||||
const handleLinkClick = (index) => {
|
const handleLinkClick = (index) => {
|
||||||
const links = [
|
const links = [
|
||||||
'https://ziuchen.gitee.io/project/ClipboardManager/',
|
'https://ziuchen.gitee.io/project/ClipboardManager/',
|
||||||
'https://ziuchen.gitee.io/project/ClipboardManager/guide/',
|
'https://ziuchen.gitee.io/project/ClipboardManager/guide/',
|
||||||
'https://github.com/ZiuChen/ClipboardManager',
|
'https://github.com/ZiuChen/ClipboardManager',
|
||||||
'https://yuanliao.info/d/5722'
|
'https://yuanliao.info/d/5722',
|
||||||
|
'https://ziuchen.gitee.io/project/ClipboardManager/#%F0%9F%92%9D-%E6%84%9F%E8%B0%A2%E8%B5%9E%E8%B5%8F'
|
||||||
]
|
]
|
||||||
utools.shellOpenExternal(links[index])
|
utools.shellOpenExternal(links[index])
|
||||||
}
|
}
|
||||||
@ -169,6 +181,10 @@ const handleRestoreBtnClick = () => {
|
|||||||
})
|
})
|
||||||
.catch(() => {})
|
.catch(() => {})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
onMounted(() => {
|
||||||
|
listenStatus.value = window.listener.listening
|
||||||
|
})
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="less" scoped>
|
<style lang="less" scoped>
|
||||||
|
Loading…
x
Reference in New Issue
Block a user