fish-dock-plugin-filemgr 1.0.5 → 1.0.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +1 -1
- package/plugin.json +5 -5
- package/plugins/filemgr/filemgr.css +8 -0
- package/plugins/filemgr/page.js +17 -5
- package/plugins/filemgr/sdk.mjs +5 -2
package/package.json
CHANGED
package/plugin.json
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
"schema": 1,
|
|
3
3
|
"id": "jassdingk.filemgr",
|
|
4
4
|
"name": "文件管理",
|
|
5
|
-
"version": "1.0.
|
|
5
|
+
"version": "1.0.6",
|
|
6
6
|
"hostApi": 1,
|
|
7
7
|
"platforms": [
|
|
8
8
|
"windows-x86_64"
|
|
@@ -27,19 +27,19 @@
|
|
|
27
27
|
],
|
|
28
28
|
"files": {
|
|
29
29
|
"bridge.js": "f38f93994e3cb2b71f2ff1810b3f68fb42f4261550f8ab01b0bfa3eecd5f94ee",
|
|
30
|
-
"package.json": "
|
|
30
|
+
"package.json": "d2b066289c54ebfb40da8591f8dbaf261c8cbd0dcb80ea03f5206c7f0aa50e35",
|
|
31
31
|
"plugins/filemgr/backend.mjs": "b448aa688ff11f2abc4c5281b4714646ed6c384473d873cfe431a8e64b066d26",
|
|
32
32
|
"plugins/filemgr/clip.ps1": "b0a32fca35cf2d25133338f46e20a0db20d78c5bb6b5c2aab899998bfbd6c6ab",
|
|
33
33
|
"plugins/filemgr/dock.css": "e795214dd39de3b473ac0b1a7b79f6922a88c761fca4d3ea4da8fd9b60188bcf",
|
|
34
|
-
"plugins/filemgr/filemgr.css": "
|
|
34
|
+
"plugins/filemgr/filemgr.css": "79b878b29499284935d71dfa877716232f85ed40d864437382a059fa8ced0479",
|
|
35
35
|
"plugins/filemgr/FolderPicker.ps1": "4b7f86c543e06fd8f93fa5d8002997d944c8189cb0ae031bedf864ea89196427",
|
|
36
36
|
"plugins/filemgr/page.css": "0801a05b5148cd091a68957beac21cc982a7818ef4707cd06fd11b20adbc7765",
|
|
37
37
|
"plugins/filemgr/page.html": "3cfda31be29cd23b1e0f7f6004b6c03522c3526b78f9df4711e320962a660831",
|
|
38
|
-
"plugins/filemgr/page.js": "
|
|
38
|
+
"plugins/filemgr/page.js": "74a7ccae18f7857be9656f14db07c2bddbf4591fff57a7eb16722ee4128e739d",
|
|
39
39
|
"plugins/filemgr/pick-files.ps1": "88bff92d9a2e5b69e9411bb372441ff0b86899b7f5b31f5ed8d154c4f6fc2f37",
|
|
40
40
|
"plugins/filemgr/pick-folder.ps1": "ff031c14df32149c1c80c7ab6a21710c1a68e823e96e3068c458a60902ae3b6f",
|
|
41
41
|
"plugins/filemgr/preview.mjs": "a5596e77180fe7928443244a0148b6d3ea8381a1f886ee01f9a08be038c7ee80",
|
|
42
|
-
"plugins/filemgr/sdk.mjs": "
|
|
42
|
+
"plugins/filemgr/sdk.mjs": "91061dae337157c88e2303d1899f9149ccecd656df4675c76dd5721bc405bf07",
|
|
43
43
|
"plugins/filemgr/stash.css": "fce2aaa13a86dbd7675b685c533f0bb916c7e610fc612a3ade660c67069f5662",
|
|
44
44
|
"plugins/filemgr/stash.mjs": "c33cea6b845a3847950d26a10b9aba1ef68d39b1f9fc423b23055dead7638866",
|
|
45
45
|
"README.md": "e9fb4ca9831b778a1d530b67518fcaf2b42cf02494b9d68deaad16bf2b947687"
|
|
@@ -71,6 +71,14 @@ body[data-resizing=true]{user-select:none;cursor:col-resize}
|
|
|
71
71
|
.stash-group>.stash-tag.active>.stash-tag-count{opacity:.8}
|
|
72
72
|
.stash-group>.stash-tag.active>.stash-tag-del{color:#1a1035;opacity:.75}
|
|
73
73
|
.stash-group>.stash-tag.active>.stash-tag-del:hover{color:#7a1010}
|
|
74
|
+
/* 拖动文件悬停到某个分组标签上:高亮该分组名,提示松手即落入此分组 */
|
|
75
|
+
.stash-group>.stash-tag.drop-hover{
|
|
76
|
+
color:#1a1035;background:var(--dock-accent);border-color:var(--dock-accent);
|
|
77
|
+
box-shadow:0 0 0 2px color-mix(in srgb,var(--dock-accent) 40%,transparent);
|
|
78
|
+
}
|
|
79
|
+
.stash-group>.stash-tag.drop-hover>.stash-tag-dot{background:#1a1035}
|
|
80
|
+
.stash-group>.stash-tag.drop-hover>.stash-tag-count{opacity:.85}
|
|
81
|
+
.stash-group>.stash-tag.drop-hover>.stash-tag-del{color:#1a1035;opacity:.75}
|
|
74
82
|
/* 右侧文件列表:已在暂存/分组里的文件 */
|
|
75
83
|
.filelist .row.stashed .nm{color:var(--dock-accent)}
|
|
76
84
|
.stash-badge{flex:none;font-size:10px;line-height:1;padding:2px 6px;border-radius:999px;
|
package/plugins/filemgr/page.js
CHANGED
|
@@ -1472,6 +1472,7 @@
|
|
|
1472
1472
|
|
|
1473
1473
|
const summary = el('summary', {
|
|
1474
1474
|
class: 'stash-tag' + (active ? ' active' : ''),
|
|
1475
|
+
dataset: { group: bucket.key }, // 供拖拽命中:拖到此标签上即高亮该组名并落入该分组
|
|
1475
1476
|
title: `${bucket.label} · ${bucket.items.length} 项(点箭头/整条折叠;点右侧漏斗图标只在看本组与全部间切换)`,
|
|
1476
1477
|
})
|
|
1477
1478
|
// 单击整条标签 = 折叠/展开(summary 默认行为,不拦截)。
|
|
@@ -1765,11 +1766,12 @@
|
|
|
1765
1766
|
// 批量加入(框选后拖进暂存区走这一条)。
|
|
1766
1767
|
// 后端 stash.add 本来就吃 paths 数组,所以只是把多行一次性递过去;
|
|
1767
1768
|
// 逐个报告"加了几项/几项重复",比只弹一个含糊的 toast 更好懂。
|
|
1768
|
-
async function addManyToStash(paths) {
|
|
1769
|
+
async function addManyToStash(paths, group) {
|
|
1769
1770
|
const list = (paths || []).filter(Boolean)
|
|
1770
1771
|
if (!list.length) return
|
|
1771
|
-
|
|
1772
|
-
const
|
|
1772
|
+
// 显式传入的分组(拖到某个分组标签上)优先;未指定时回退到当前视图分组。
|
|
1773
|
+
const targetGroup = group === undefined ? (state.view === 'all' ? '' : state.view) : group
|
|
1774
|
+
const row = await callSoft('stash.add', { paths: list, group: targetGroup })
|
|
1773
1775
|
if (row && row.ok) {
|
|
1774
1776
|
const added = Array.isArray(row.items) ? row.items.length : 0
|
|
1775
1777
|
const dup = list.length - added
|
|
@@ -1800,6 +1802,7 @@
|
|
|
1800
1802
|
let moved = false
|
|
1801
1803
|
let suppressClick = false
|
|
1802
1804
|
let ghost = null
|
|
1805
|
+
let dropGroup = undefined // 拖拽时命中的分组标签 key(undefined=未命中,回退当前视图)
|
|
1803
1806
|
|
|
1804
1807
|
const rows = () => Array.from(list.querySelectorAll('.row[data-path]'))
|
|
1805
1808
|
|
|
@@ -1836,6 +1839,8 @@
|
|
|
1836
1839
|
if (ghost) { ghost.remove(); ghost = null }
|
|
1837
1840
|
for (const node of list.querySelectorAll('.row.drag-src')) node.classList.remove('drag-src')
|
|
1838
1841
|
if (stashCol) stashCol.classList.remove('drop-target')
|
|
1842
|
+
dropGroup = undefined
|
|
1843
|
+
for (const node of document.querySelectorAll('.stash-tag.drop-hover')) node.classList.remove('drop-hover')
|
|
1839
1844
|
}
|
|
1840
1845
|
|
|
1841
1846
|
list.addEventListener('pointerdown', event => {
|
|
@@ -1920,8 +1925,14 @@
|
|
|
1920
1925
|
} else if (mode === 'drag' && ghost) {
|
|
1921
1926
|
ghost.style.left = `${event.clientX + 14}px`
|
|
1922
1927
|
ghost.style.top = `${event.clientY + 14}px`
|
|
1923
|
-
const
|
|
1928
|
+
const under = document.elementFromPoint(event.clientX, event.clientY)
|
|
1929
|
+
const over = stashCol && under?.closest('#stash-col')
|
|
1924
1930
|
if (stashCol) stashCol.classList.toggle('drop-target', !!over)
|
|
1931
|
+
// 命中哪个分组标签,就高亮哪个分组名并把它作为落点;未命中分组标签则回退当前视图分组。
|
|
1932
|
+
const hitTag = under && under.closest('.stash-tag[data-group]')
|
|
1933
|
+
dropGroup = hitTag ? hitTag.dataset.group : undefined
|
|
1934
|
+
for (const node of document.querySelectorAll('.stash-tag.drop-hover')) node.classList.remove('drop-hover')
|
|
1935
|
+
if (hitTag) hitTag.classList.add('drop-hover')
|
|
1925
1936
|
}
|
|
1926
1937
|
event.preventDefault()
|
|
1927
1938
|
})
|
|
@@ -1930,6 +1941,7 @@
|
|
|
1930
1941
|
if (mode === 'idle') return
|
|
1931
1942
|
const was = mode
|
|
1932
1943
|
const paths = dragPaths.slice()
|
|
1944
|
+
const group = dropGroup // 松手前记录命中的分组(reset 会清空)
|
|
1933
1945
|
const dropped = was === 'drag' && !!(
|
|
1934
1946
|
stashCol && document.elementFromPoint(event.clientX, event.clientY)?.closest('#stash-col')
|
|
1935
1947
|
)
|
|
@@ -1940,7 +1952,7 @@
|
|
|
1940
1952
|
setTimeout(() => { suppressClick = false }, 0)
|
|
1941
1953
|
}
|
|
1942
1954
|
reset()
|
|
1943
|
-
if (dropped && paths.length) await addManyToStash(paths)
|
|
1955
|
+
if (dropped && paths.length) await addManyToStash(paths, group)
|
|
1944
1956
|
}
|
|
1945
1957
|
|
|
1946
1958
|
list.addEventListener('pointerup', event => { finish(event) })
|
package/plugins/filemgr/sdk.mjs
CHANGED
|
@@ -3,7 +3,7 @@ const CATEGORIES = new Set(['credentials','roster','keys','config','exports','ba
|
|
|
3
3
|
const DEFAULT_LIMIT = 1024 * 1024;
|
|
4
4
|
export function createPlugin({ id, input = process.stdin, output = process.stdout,
|
|
5
5
|
activate = async () => {}, deactivate = async () => {}, onEvent = async () => {}, commands = {},
|
|
6
|
-
onError = () => {}, maxLine = DEFAULT_LIMIT, requestTimeout =
|
|
6
|
+
onError = () => {}, maxLine = DEFAULT_LIMIT, requestTimeout = 12000 } = {}) {
|
|
7
7
|
if (!/^[a-z0-9]+(?:-[a-z0-9]+)*\.[a-z0-9]+(?:-[a-z0-9]+)*$/.test(id ?? '')) throw new Error('插件 ID 格式无效');
|
|
8
8
|
if (!Number.isSafeInteger(maxLine) || maxLine < 128 || maxLine > DEFAULT_LIMIT) throw new Error('协议帧大小无效');
|
|
9
9
|
if (!Number.isSafeInteger(requestTimeout) || requestTimeout < 1 || requestTimeout > 30000) throw new Error('宿主调用时限无效');
|
|
@@ -94,7 +94,10 @@ export function createPlugin({ id, input = process.stdin, output = process.stdou
|
|
|
94
94
|
if (!row || typeof row !== 'object' || Array.isArray(row)) throw new Error('插件协议应为 JSON 对象');
|
|
95
95
|
if (!Object.hasOwn(row,'method')) {
|
|
96
96
|
const waiter = pending.get(row.id);
|
|
97
|
-
|
|
97
|
+
// 迟到/重复的宿主响应(原请求已因超时被清理):静默丢弃,绝不让整个插件会话崩溃。
|
|
98
|
+
// 原实现此处 throw 会经 receive() → close()+onError() 杀死插件;任何一次超过
|
|
99
|
+
// requestTimeout 的存储调用,其迟到响应都会触发。调用方早已通过超时 reject 感知失败。
|
|
100
|
+
if (!waiter) return;
|
|
98
101
|
pending.delete(row.id); clearTimeout(waiter.timer);
|
|
99
102
|
if (Object.hasOwn(row,'result') === Object.hasOwn(row,'error')) return waiter.reject(new Error('宿主响应结构无效'));
|
|
100
103
|
if (row.error) waiter.reject(new Error('宿主存储操作失败')); else waiter.resolve(row.result);
|