diff --git a/docs/img1.png b/docs/img1.png index 3f0d0ea..8064fb7 100644 Binary files a/docs/img1.png and b/docs/img1.png differ diff --git a/public/plugin.json b/public/plugin.json index 4a54d82..6b573bb 100644 --- a/public/plugin.json +++ b/public/plugin.json @@ -1,5 +1,5 @@ { - "version": "1.1.6", + "version": "1.2.2", "pluginName": "超级剪贴板", "description": "强大的剪贴板管理工具", "author": "ZiuChen", diff --git a/public/preload.js b/public/preload.js index 11b1f11..49d5d96 100644 --- a/public/preload.js +++ b/public/preload.js @@ -7,6 +7,7 @@ const fs = require('fs') const crypto = require('crypto') const { clipboard } = require('electron') +const time = require('./time') const homePath = utools.getPath('home') const userDataPath = utools.getPath('userData') @@ -36,10 +37,12 @@ class DB { // 读取磁盘记录到内存 const dataBase = JSON.parse(data) this.dataBase = dataBase - // 将超过14天的数据删除 + // 将超过14天的数据删除 排除掉收藏 const now = new Date().getTime() const deleteTime = now - '\u0031\u0034' * '\u0032\u0034' * 60 * 60 * 1000 // unicode - this.dataBase.data = this.dataBase.data.filter((item) => item.updateTime > deleteTime) + this.dataBase.data = this.dataBase.data?.filter( + (item) => item.updateTime > deleteTime || item.collect + ) this.updateDataBaseLocal() } catch (err) { utools.showNotification('读取剪切板出错' + err) @@ -71,14 +74,16 @@ class DB { addItem(cItem) { this.dataBase.data.unshift(cItem) this.updateDataBase() - // unicode - if (this.dataBase.data.length > '\u0035\u0030\u0030') { - // 达到条数限制 - this.dataBase.data.pop() - // 仍然大于: 超出了不止一条 - if (this.dataBase.data.length > '\u0035\u0030\u0030') { - this.dataBase.data = this.dataBase.data.splice(0, 499) + const exceedCount = this.dataBase.data.length - '\u0035\u0030\u0030' + if (exceedCount > 0) { + // 达到条数限制 在收藏条数限制内遍历非收藏历史并删除 + // 所有被移除的 item都存入tempList + const tmpList = [] + for (let i = 0; i < exceedCount; i++) { + const item = this.dataBase.data.pop() + tmpList.push(item) } + tmpList.forEach((item) => !item.collect || this.dataBase.data.push(item)) // 收藏内容 重新入栈 } this.updateDataBaseLocal() } @@ -118,49 +123,49 @@ class DB { } } -const pbpaste = async () => { - return new Promise((res) => { - // file - const files = utools.getCopyedFiles() // null | Array - if (files) { - res({ - type: 'file', - data: JSON.stringify(files) - }) +const pbpaste = () => { + // file + const files = utools.getCopyedFiles() // null | Array + if (files) { + return { + type: 'file', + data: JSON.stringify(files) } - // text - const text = clipboard.readText() - if (text.trim()) res({ type: 'text', data: text }) - // image - const image = clipboard.readImage() // 大图卡顿来源 - const data = image.toDataURL() - globalImageOversize = data.length > 4e5 - if (!image.isEmpty()) { - res({ - type: 'image', - data: data - }) + } + // text + const text = clipboard.readText() + if (text.trim()) return { type: 'text', data: text } + // image + const image = clipboard.readImage() // 大图卡顿来源 + const data = image.toDataURL() + globalImageOversize = data.length > 4e5 + if (!image.isEmpty()) { + return { + type: 'image', + data: data } - }) + } } const watchClipboard = async (db, fn) => { let prev = db.dataBase.data[0] || {} - setInterval(() => { - pbpaste().then((item) => { - item.id = crypto.createHash('md5').update(item.data).digest('hex') - if (item && prev.id != item.id) { - // 剪切板元素 与最近一次复制内容不同 - prev = item - fn(item) - } else { - // 剪切板元素 与上次复制内容相同 - } - }) - }, 250) + function loop() { + time.sleep(250).then(loop) + const item = pbpaste() + if (!item) return + item.id = crypto.createHash('md5').update(item.data).digest('hex') + if (item && prev.id != item.id) { + // 剪切板元素 与最近一次复制内容不同 + prev = item + fn(item) + } else { + // 剪切板元素 与上次复制内容相同 + } + } + loop() } -const copy = (item) => { +const copy = (item, isHideMainWindow = true) => { switch (item.type) { case 'text': utools.copyText(item.data) @@ -173,7 +178,7 @@ const copy = (item) => { utools.copyFile(paths) break } - utools.hideMainWindow() + isHideMainWindow && utools.hideMainWindow() } const paste = () => { @@ -186,7 +191,13 @@ db.init() const remove = (item) => db.removeItemViaId(item.id) -const focus = () => document.querySelector('.clip-search input')?.focus() +const select = () => document.querySelector('.clip-search input').select() +const focus = () => { + document.querySelector('.clip-search-input').style.display !== 'none' + ? document.querySelector('.clip-search-input')?.focus() + : (document.querySelector('.clip-search-btn')?.click(), + document.querySelector('.clip-search-input')?.focus()) +} const toTop = () => (document.scrollingElement.scrollTop = 0) const resetNav = () => document.querySelectorAll('.clip-switch-item')[0]?.click() @@ -208,8 +219,8 @@ utools.onPluginEnter(() => { utools.copyText('ImageOverSized') globalImageOversize = false } - document.querySelector('.clip-search input').select() // 进入插件将搜索框内容全选 focus() + select() // 进入插件将搜索框内容全选 toTop() resetNav() }) @@ -219,6 +230,7 @@ window.copy = copy window.paste = paste window.remove = remove window.openFile = utools.shellOpenPath +window.openFileFolder = utools.shellShowItemInFolder window.getIcon = utools.getFileIcon window.focus = focus window.toTop = toTop diff --git a/public/time.js b/public/time.js new file mode 100644 index 0000000..05079ef --- /dev/null +++ b/public/time.js @@ -0,0 +1,68 @@ +// author: inu1255 + +const path = require('path') + +function newPromise(fn) { + let a, b + var tmp = { + resolve(x) { + if (this.pending) { + a(x) + this.resolved = true + this.pending = false + } + }, + reject(e) { + if (this.pending) { + b(e) + this.rejectd = true + this.pending = false + } + }, + pending: true, + resolved: false, + rejected: false + } + /** @type {Promise} */ + var pms = new Promise(function (resolve, reject) { + a = resolve + b = reject + if (fn) fn(tmp.resolve, tmp.reject) + }) + return Object.assign(pms, tmp) +} + +let cbIdx = 1 +const cbMap = new Map() +function getWorker() { + if (getWorker.worker) return getWorker.worker + const worker = new Worker(path.join(__dirname, 'time.worker.js')) + getWorker.worker = worker + worker.onmessage = (e) => { + if (e.data && cbMap.has(e.data.cb)) { + cbMap.get(e.data.cb).apply(null, e.data.args) + } + } + return worker +} + +function call(method, args) { + const cb = cbIdx++ + let pms = newPromise() + cbMap.set(cb, function (err, data) { + if (err) pms.reject(err) + else pms.resolve(data) + }) + getWorker().postMessage({ + method, + args, + cb + }) + return pms +} + +function sleep(ms) { + return call('sleep', [ms]) +} + +exports.sleep = sleep diff --git a/public/time.worker.js b/public/time.worker.js new file mode 100644 index 0000000..d62d14e --- /dev/null +++ b/public/time.worker.js @@ -0,0 +1,21 @@ +// author: inu1255 + +const apis = { + sleep(ms) { + return new Promise((resolve) => setTimeout(resolve, ms)) + } +} + +onmessage = (event) => { + const data = event.data + if (!data) return + const { cb, method, args } = data + if (!apis[method]) { + postMessage({ cb, err: 'no such method' }) + return + } + apis[method].apply(null, args).then( + (res) => postMessage({ cb, data: res }), + (err) => postMessage({ cb, err }) + ) +} diff --git a/src/cpns/ClipFloatBtn.vue b/src/cpns/ClipFloatBtn.vue new file mode 100644 index 0000000..0499d5c --- /dev/null +++ b/src/cpns/ClipFloatBtn.vue @@ -0,0 +1,18 @@ + + + diff --git a/src/cpns/ClipFullData.vue b/src/cpns/ClipFullData.vue index 7c109e6..5453575 100644 --- a/src/cpns/ClipFullData.vue +++ b/src/cpns/ClipFullData.vue @@ -1,12 +1,23 @@