dsh-whale-widget 0.3.4 → 0.3.5

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.
@@ -10107,6 +10107,30 @@ root.appendChild(menuBtn)
10107
10107
  document.body.appendChild(root)
10108
10108
  document.body.appendChild(menuBox)
10109
10109
 
10110
+ // ===== PR #105 后半:DOM 守护(SPA 切路由 / 别的插件替换 body 子树时把节点摘掉)=====
10111
+ // 背景:DSH 是 SPA,切到会话列表 / 设置 / 插件市场再回来、或其它客户端插件整体替换
10112
+ // document.body 的子树时,挂件节点会被顺带移除,而它不会自己回来(脚本只初始化一次)。
10113
+ // 做法:暴露 window.__dshWhaleRoot 供外部定位/调试,并用一个 MutationObserver 盯着;
10114
+ // 一旦发现节点已不在文档里就**把同一个节点补挂回 body**(不重建、不重新初始化,
10115
+ // 位置/设置/状态全部保留)。
10116
+ try { window.__dshWhaleRoot = root } catch (err) {}
10117
+ function dshwReattachRoot() {
10118
+ try {
10119
+ if (!root || root.isConnected) return
10120
+ document.body.appendChild(root)
10121
+ // 菜单是独立挂在 body 上的浮层:它也被摘掉且当前正打开时一并补回,否则菜单会"消失"
10122
+ if (menuBox && menuOpen && !menuBox.isConnected) document.body.appendChild(menuBox)
10123
+ } catch (err) {}
10124
+ }
10125
+ try {
10126
+ if (typeof MutationObserver === 'function') {
10127
+ var dshwRootGuard = new MutationObserver(function () {
10128
+ if (root && !root.isConnected) dshwReattachRoot()
10129
+ })
10130
+ dshwRootGuard.observe(document.documentElement, { childList: true, subtree: true })
10131
+ }
10132
+ } catch (err) {}
10133
+
10110
10134
  // 泡泡内容整体与视觉中心对齐:
10111
10135
  // 读取 SVG 主体(bshape)的包围盒,取其中点作为文字内容区的视觉中心,
10112
10136
  // 写入 --dshw-vx/--dshw-vy(相对 .dshwv-pop 尺寸的百分比)。
@@ -14387,7 +14411,7 @@ function onDocPointerUp(e) {
14387
14411
  try { if (isWhaleHit(e)) { e.preventDefault(); e.stopPropagation() } } catch (err) {}
14388
14412
  endDrag(e, true)
14389
14413
  }
14390
- function onDocPointerCancel(e) { endDrag(e, false) }
14414
+ function onDocPointerCancel(e) { endDrag(e, false, true) }
14391
14415
  function onDocClickStopper(e) {
14392
14416
  // 只在鲸鱼命中区域拦截 click(保持透明区 pass-through)。
14393
14417
  // 持久注册(不随 endDrag 移除)——click 在 pointerup 之后派发,
@@ -14548,7 +14572,7 @@ document.addEventListener('pointermove', onDocPointerMoveCursor, true)
14548
14572
  // 配置读回来之后还会再应用一次,这里是配置请求失败时的兜底。
14549
14573
  try { applyMenuBtnHideUI() } catch (err) {}
14550
14574
 
14551
- function endDrag(e, clickAllowed) {
14575
+ function endDrag(e, clickAllowed, cancelled) {
14552
14576
  if (!drag || !drag.active) return
14553
14577
  drag.active = false
14554
14578
  document.removeEventListener('pointermove', onDocPointerMove, true)
@@ -14556,6 +14580,20 @@ function endDrag(e, clickAllowed) {
14556
14580
  document.removeEventListener('pointercancel', onDocPointerCancel, true)
14557
14581
  pressUp()
14558
14582
  root.classList.remove('dshwv-dragging')
14583
+ // issue #79 缺陷2:pointercancel(Android 把手势判成页面滚动、或系统抢走手势时派发)的
14584
+ // clientX/clientY 常常是 0,而 endDrag 又是「按坐标收尾 + saveConfig() 落盘」——
14585
+ // 于是位移被算成"一口气拖到了 (0,0)",归边判定吃进左上角,损坏锚点被写进 localStorage。
14586
+ // 0.3.2 的「非法距离自愈」只治负数 / 超出视口,救不回这个**合法的 (0,0)**,所以必须在这里拦住。
14587
+ // 处理:取消的手势一律回到按下前的位置、并且**不落盘**(取消不该提交位置)。
14588
+ var noCoord = (!e || typeof e.clientX !== 'number' || typeof e.clientY !== 'number' ||
14589
+ !isFinite(e.clientX) || !isFinite(e.clientY))
14590
+ var zeroBoth = (e && e.clientX === 0 && e.clientY === 0 && drag.moved)
14591
+ if (cancelled || noCoord || zeroBoth) {
14592
+ try { state.left = drag.origLeft; state.top = drag.origTop } catch (err) {}
14593
+ setWidgetCursor('')
14594
+ settle()
14595
+ return
14596
+ }
14559
14597
  setWidgetCursor(isWhaleHit(e) ? 'grab' : '')
14560
14598
  if (clickAllowed && !drag.moved) {
14561
14599
  // 长按刚唤出菜单:这次抬手不再当作点击(避免顺带弹出余额泡)
package/lib/index.js CHANGED
@@ -929,7 +929,7 @@ export default {
929
929
  const days = new Set([today, ...Object.keys(led.history || {}), ...accountingDays(led)])
930
930
  for (const e of events) if (/^\d{4}-\d{2}-\d{2}$/.test(e.day)) days.add(e.day)
931
931
  return {
932
- ok: true, version: '0.3.4', today: todayData, days7,
932
+ ok: true, version: '0.3.5', today: todayData, days7,
933
933
  total7: total7ByCurrency[todayData.currency] || 0, total7Currency: todayData.currency, total7ByCurrency,
934
934
  all: {
935
935
  days: Array.from(days).filter(d => /^\d{4}-\d{2}-\d{2}$/.test(d)).sort().reverse().map(forDay),
@@ -2005,7 +2005,7 @@ export default {
2005
2005
  const led = readUsageLedger()
2006
2006
  const summary = daySummary(led, todayKey())
2007
2007
  return {
2008
- ...visible, version: '0.3.4', isPeak: isPeakTime(Math.floor(Date.now() / 1000)),
2008
+ ...visible, version: '0.3.5', isPeak: isPeakTime(Math.floor(Date.now() / 1000)),
2009
2009
  todayUsage: summary.amount, todayUsageCurrency: summary.currency,
2010
2010
  usageSource: summary.source, usageLabel: summary.label, usageMode: 'ledger',
2011
2011
  accounting: balanceSummary(led, todayKey()),
@@ -2087,6 +2087,7 @@ export default {
2087
2087
  menuBtnHide: mbh,
2088
2088
  updatedAt: new Date().toISOString(),
2089
2089
  })
2090
+ let lastSizeErr = null
2090
2091
  for (const p of SIZE_FILE_CANDIDATES) {
2091
2092
  try {
2092
2093
  fs.writeFileSync(p, body, 'utf8')
@@ -2105,9 +2106,11 @@ export default {
2105
2106
  scrollGapPx: sgp,
2106
2107
  menuBtnHide: mbh,
2107
2108
  }
2108
- } catch (err) {}
2109
+ } catch (err) { lastSizeErr = err }
2109
2110
  }
2110
- return { ok: false, error: '无法持久化挂件尺寸' }
2111
+ // #88 / #97 报告者建议:把底层原因(EPERM / EACCES / 路径问题…)带出去。
2112
+ // 原先无论哪个候选路径失败,返回的都是同一句固定文案,即使前端检查了响应也定位不到原因。
2113
+ return { ok: false, error: '无法持久化挂件尺寸' + (lastSizeErr && lastSizeErr.message ? ':' + lastSizeErr.message : '') }
2111
2114
  }
2112
2115
 
2113
2116
  function readBody(req) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "dsh-whale-widget",
3
- "version": "0.3.4",
3
+ "version": "0.3.5",
4
4
  "description": "DSH Web 界面右下角的 DeepSeek 余额小鲸鱼挂件:余额/今日已用/峰谷定价、自定义泡泡点击序列(文本/余额/今日/峰谷/图片/随机语句与并列加权选择)、逐行样式与字体、悬浮快捷编辑、音效与每轮消耗、自定义角色/动图/音效、吸附与翻转自定义",
5
5
  "keywords": [
6
6
  "dsh",