dsh-edit-turn 0.3.2 → 0.3.3
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/README.md +6 -0
- package/lib/client.js +33 -14
- package/lib/index.js +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -250,6 +250,12 @@ ln -s /path/to/dsh-install/node_modules ./node_modules
|
|
|
250
250
|
|
|
251
251
|
### 更新日志
|
|
252
252
|
|
|
253
|
+
**0.3.3** —— 编辑器锚定到刚按下的铅笔,位置不再跑到屏幕另一端。
|
|
254
|
+
|
|
255
|
+
- 回复的编辑按钮在 turn-tail 操作条里,而编辑器的锚点行可能是比屏幕还高的回答行;0.3.2 会把它钳到视口顶部,按钮可达但离点击处很远。现在把锚点记为按下的按钮本身:优先贴在按钮下方,放不下就贴在按钮上方,再按视口钳制。
|
|
256
|
+
- 长草稿仍由编辑器自身滚动、footer sticky,保存/取消始终可见。
|
|
257
|
+
- **测试**:`npm test` **213/213**、`npm run verify:contract` **96** 项、`npm run verify:client` **184** 项。
|
|
258
|
+
|
|
253
259
|
**0.3.2** —— 修复编辑器在长回答或页面底部时位置错误、按钮点不到的问题。
|
|
254
260
|
|
|
255
261
|
- **视口钳制**:编辑框优先放在行下方;放不下就翻到行上方;行比屏幕高、底部在视口外时钉在视口底部,不再跟着行跑到屏幕外。
|
package/lib/client.js
CHANGED
|
@@ -42,7 +42,7 @@ window.__ModuleLoader__.load({
|
|
|
42
42
|
const RERUN_PREFIX = '/dsh-rerun-turn'
|
|
43
43
|
|
|
44
44
|
/** Keep in sync with package.json and lib/index.js. */
|
|
45
|
-
const PLUGIN_VERSION = '0.3.
|
|
45
|
+
const PLUGIN_VERSION = '0.3.3'
|
|
46
46
|
|
|
47
47
|
// --- copy -----------------------------------------------------------------
|
|
48
48
|
|
|
@@ -364,6 +364,7 @@ window.__ModuleLoader__.load({
|
|
|
364
364
|
this.editorElement = null
|
|
365
365
|
this.editorBox = null
|
|
366
366
|
this.editorRow = null
|
|
367
|
+
this.editorAnchor = null
|
|
367
368
|
this.editorFocus = false
|
|
368
369
|
this.editorDraft = ''
|
|
369
370
|
// The block list being edited: what the carrier will be rebuilt from.
|
|
@@ -563,6 +564,9 @@ window.__ModuleLoader__.load({
|
|
|
563
564
|
}
|
|
564
565
|
: target
|
|
565
566
|
this.editor = normalized
|
|
567
|
+
this.editorAnchor = target.anchor !== undefined && target.anchor !== null && target.anchor.isConnected === true
|
|
568
|
+
? target.anchor
|
|
569
|
+
: null
|
|
566
570
|
this.editorBlocks = replyBlocks
|
|
567
571
|
this.editorBlockIndex = chosen === undefined ? null : chosen.index
|
|
568
572
|
this.editorBlockKind = chosen === undefined ? null : chosen.kind
|
|
@@ -644,6 +648,7 @@ window.__ModuleLoader__.load({
|
|
|
644
648
|
this.editorElement = null
|
|
645
649
|
this.editorBox = null
|
|
646
650
|
this.editorRow = null
|
|
651
|
+
this.editorAnchor = null
|
|
647
652
|
this.editorFocus = false
|
|
648
653
|
this.editor = null
|
|
649
654
|
this.editorDraft = ''
|
|
@@ -1197,9 +1202,9 @@ window.__ModuleLoader__.load({
|
|
|
1197
1202
|
* at all and reads exactly like a dead pencil.
|
|
1198
1203
|
*/
|
|
1199
1204
|
function wireAction(button) {
|
|
1200
|
-
pressable(button, () => {
|
|
1205
|
+
pressable(button, (event) => {
|
|
1201
1206
|
const activate = button[ACTIVATE]
|
|
1202
|
-
if (typeof activate === 'function') activate()
|
|
1207
|
+
if (typeof activate === 'function') activate(event)
|
|
1203
1208
|
})
|
|
1204
1209
|
}
|
|
1205
1210
|
|
|
@@ -1815,7 +1820,14 @@ window.__ModuleLoader__.load({
|
|
|
1815
1820
|
} else if (button.dataset !== undefined && button.dataset.dshetFallback !== undefined) {
|
|
1816
1821
|
delete button.dataset.dshetFallback
|
|
1817
1822
|
}
|
|
1818
|
-
button[ACTIVATE] = () => controller.open(
|
|
1823
|
+
button[ACTIVATE] = (event) => controller.open({
|
|
1824
|
+
...entry.target,
|
|
1825
|
+
// The editor belongs beside the pencil the user just pressed, not at the
|
|
1826
|
+
// top of a row that may be taller than the screen.
|
|
1827
|
+
anchor: event !== undefined && event !== null && event.currentTarget !== undefined
|
|
1828
|
+
? event.currentTarget
|
|
1829
|
+
: button,
|
|
1830
|
+
})
|
|
1819
1831
|
liveHosts.add(host)
|
|
1820
1832
|
if (button.getAttribute('aria-label') !== label) {
|
|
1821
1833
|
button.setAttribute('aria-label', label)
|
|
@@ -1961,10 +1973,16 @@ window.__ModuleLoader__.load({
|
|
|
1961
1973
|
// past the bottom edge where nothing could reach it. Flip above the row when
|
|
1962
1974
|
// there is room, otherwise pin the box to the bottom of the viewport and let
|
|
1963
1975
|
// its own scrollbar carry the content; the footer stays sticky either way.
|
|
1964
|
-
function placeEditor(row, box) {
|
|
1976
|
+
function placeEditor(row, box, anchor = null) {
|
|
1965
1977
|
const layer = ensureEditorLayer()
|
|
1966
1978
|
if (box.parentElement !== layer) layer.appendChild(box)
|
|
1967
1979
|
const rect = row.getBoundingClientRect()
|
|
1980
|
+
let anchorRect = null
|
|
1981
|
+
if (anchor !== null && anchor !== undefined && anchor.isConnected === true && typeof anchor.getBoundingClientRect === 'function') {
|
|
1982
|
+
const candidate = anchor.getBoundingClientRect()
|
|
1983
|
+
if (candidate.width > 0 && candidate.height > 0) anchorRect = candidate
|
|
1984
|
+
}
|
|
1985
|
+
const vertical = anchorRect === null ? rect : anchorRect
|
|
1968
1986
|
const viewport = viewportSize()
|
|
1969
1987
|
const margin = 8
|
|
1970
1988
|
const width = viewport.width > 0
|
|
@@ -1973,11 +1991,11 @@ window.__ModuleLoader__.load({
|
|
|
1973
1991
|
box.style.width = `${Math.round(width)}px`
|
|
1974
1992
|
const measured = box.getBoundingClientRect()
|
|
1975
1993
|
const height = (measured && measured.height) || box.offsetHeight || 0
|
|
1976
|
-
let top =
|
|
1994
|
+
let top = vertical.bottom + 6
|
|
1977
1995
|
if (viewport.height > 0 && height > 0) {
|
|
1978
1996
|
const maxTop = Math.max(margin, viewport.height - height - margin)
|
|
1979
1997
|
if (top + height > viewport.height - margin) {
|
|
1980
|
-
const above =
|
|
1998
|
+
const above = vertical.top - height - 6
|
|
1981
1999
|
top = above >= margin ? above : maxTop
|
|
1982
2000
|
}
|
|
1983
2001
|
// A row taller than the screen has its bottom above the viewport after
|
|
@@ -2019,7 +2037,7 @@ window.__ModuleLoader__.load({
|
|
|
2019
2037
|
pressed = true
|
|
2020
2038
|
event.preventDefault()
|
|
2021
2039
|
event.stopPropagation()
|
|
2022
|
-
action()
|
|
2040
|
+
action(event)
|
|
2023
2041
|
}
|
|
2024
2042
|
button.onclick = (event) => {
|
|
2025
2043
|
event.preventDefault()
|
|
@@ -2028,7 +2046,7 @@ window.__ModuleLoader__.load({
|
|
|
2028
2046
|
pressed = false
|
|
2029
2047
|
return
|
|
2030
2048
|
}
|
|
2031
|
-
action()
|
|
2049
|
+
action(event)
|
|
2032
2050
|
}
|
|
2033
2051
|
}
|
|
2034
2052
|
|
|
@@ -2270,7 +2288,7 @@ window.__ModuleLoader__.load({
|
|
|
2270
2288
|
? controller.editorBox
|
|
2271
2289
|
: null
|
|
2272
2290
|
if (existing && existing.dataset.dshetFor === marker) {
|
|
2273
|
-
placeEditor(row, existing)
|
|
2291
|
+
placeEditor(row, existing, controller.editorAnchor)
|
|
2274
2292
|
return
|
|
2275
2293
|
}
|
|
2276
2294
|
|
|
@@ -2337,13 +2355,13 @@ window.__ModuleLoader__.load({
|
|
|
2337
2355
|
fitEditorHeight(area)
|
|
2338
2356
|
const row = controller.editorRow
|
|
2339
2357
|
const box = controller.editorBox
|
|
2340
|
-
if (row !== null && box !== null && box.isConnected === true) placeEditor(row, box)
|
|
2358
|
+
if (row !== null && box !== null && box.isConnected === true) placeEditor(row, box, controller.editorAnchor)
|
|
2341
2359
|
})
|
|
2342
2360
|
area.addEventListener('compositionend', () => {
|
|
2343
2361
|
fitEditorHeight(area)
|
|
2344
2362
|
const row = controller.editorRow
|
|
2345
2363
|
const box = controller.editorBox
|
|
2346
|
-
if (row !== null && box !== null && box.isConnected === true) placeEditor(row, box)
|
|
2364
|
+
if (row !== null && box !== null && box.isConnected === true) placeEditor(row, box, controller.editorAnchor)
|
|
2347
2365
|
})
|
|
2348
2366
|
area.addEventListener('focus', () => {
|
|
2349
2367
|
controller.editorFocus = true
|
|
@@ -2458,7 +2476,7 @@ window.__ModuleLoader__.load({
|
|
|
2458
2476
|
controller.editorRow = row
|
|
2459
2477
|
controller.editorElement = area
|
|
2460
2478
|
fitEditorHeight(area)
|
|
2461
|
-
placeEditor(row, box)
|
|
2479
|
+
placeEditor(row, box, controller.editorAnchor)
|
|
2462
2480
|
if (!view.confirming && !view.pending && (fresh || wasFocused)) {
|
|
2463
2481
|
try {
|
|
2464
2482
|
area.focus()
|
|
@@ -2932,6 +2950,7 @@ window.__ModuleLoader__.load({
|
|
|
2932
2950
|
event.preventDefault()
|
|
2933
2951
|
event.stopPropagation()
|
|
2934
2952
|
controller.open({
|
|
2953
|
+
anchor: event.currentTarget,
|
|
2935
2954
|
seq: entry.seq,
|
|
2936
2955
|
mode: 'reply',
|
|
2937
2956
|
turn: entry.turn,
|
|
@@ -2985,7 +3004,7 @@ window.__ModuleLoader__.load({
|
|
|
2985
3004
|
const keepPlaced = () => {
|
|
2986
3005
|
const row = controller.editorRow
|
|
2987
3006
|
const box = controller.editorBox
|
|
2988
|
-
if (row !== null && box !== null && box.isConnected === true) placeEditor(row, box)
|
|
3007
|
+
if (row !== null && box !== null && box.isConnected === true) placeEditor(row, box, controller.editorAnchor)
|
|
2989
3008
|
}
|
|
2990
3009
|
document.addEventListener('pointerdown', onPointerDown, true)
|
|
2991
3010
|
// Scroll events do not bubble; capture reaches the inner scroller too.
|
package/lib/index.js
CHANGED
|
@@ -80,7 +80,7 @@ export const PLUGIN_ID = 'dsh-edit-turn'
|
|
|
80
80
|
export const name = PLUGIN_ID
|
|
81
81
|
|
|
82
82
|
/** Keep in sync with package.json and lib/client.js. */
|
|
83
|
-
export const PLUGIN_VERSION = '0.3.
|
|
83
|
+
export const PLUGIN_VERSION = '0.3.3'
|
|
84
84
|
|
|
85
85
|
// A ring of the last few requests, answering "did the browser half even ask, and
|
|
86
86
|
// what did it get?" without needing its console. Read-only diagnostics: the
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "dsh-edit-turn",
|
|
3
|
-
"version": "0.3.
|
|
3
|
+
"version": "0.3.3",
|
|
4
4
|
"description": "Edit any message in DeepSeek Harness in place: a prompt is replaced where it stands; a model reply block (answer text or reasoning) is patched through a plugin record and a message projection, so the turn stays where it is, later turns are untouched and the log grows by one small record. Falls back to the replay splice on hosts without the projection API. The append-only session log is never rewritten.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "lib/index.js",
|