@mindexec/cli 0.2.478 → 0.2.479
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 +323 -323
- package/codex-model-catalog.js +202 -202
- package/codex-runtime.js +1608 -1608
- package/desktop-workspace-state.cjs +120 -120
- package/electron/main.cjs +517 -517
- package/electron/preload.cjs +17 -17
- package/electron/recurring-update-owner-smoke.mjs +55 -55
- package/electron/recurring-update-owner.cjs +97 -97
- package/electron/source-smoke.mjs +108 -108
- package/electron/update-feed-resolver.cjs +79 -79
- package/electron/update-feed.json +10 -10
- package/electron/update-manager-smoke.mjs +146 -146
- package/electron/update-manager.cjs +297 -297
- package/electron/windows-package-smoke.mjs +156 -156
- package/launch-bridge.cjs +236 -236
- package/lzo1x.js +110 -110
- package/mode4-atlas-worker.js +440 -440
- package/mode4-atlas.js +130 -130
- package/package.json +1 -1
- package/port-guard.cjs +285 -285
- package/remote-fast/osx-arm64/MacScreenCaptureKitH264.swift +339 -339
- package/remote-fast/osx-arm64/MacSystemAudioCapture.swift +214 -214
- package/remote-fast/osx-arm64/UnixRawCaptureHelper.mjs +80 -80
- package/remote-fast/osx-arm64/livedesk-raw-capture-resampler.mjs +73 -73
- package/remote-fast/osx-arm64/mindexec-remote-fast.dll +0 -0
- package/remote-fast/osx-x64/MacScreenCaptureKitH264.swift +339 -339
- package/remote-fast/osx-x64/MacSystemAudioCapture.swift +214 -214
- package/remote-fast/osx-x64/UnixRawCaptureHelper.mjs +80 -80
- package/remote-fast/osx-x64/livedesk-raw-capture-resampler.mjs +73 -73
- package/remote-fast/osx-x64/mindexec-remote-fast.dll +0 -0
- package/remote-fast/win-x64/mindexec-remote-fast.dll +0 -0
- package/remote-hub.js +3698 -3698
- package/scripts/auth-session-smoke.mjs +262 -262
- package/scripts/board-render-ownership-smoke.mjs +85 -85
- package/scripts/codex-model-catalog-smoke.mjs +150 -150
- package/scripts/codex-runtime-home-smoke.mjs +58 -58
- package/scripts/codex-sdk-image-live-smoke.mjs +43 -43
- package/scripts/codex-sdk-image-runtime-smoke.mjs +122 -122
- package/scripts/codex-sdk-runtime-smoke.mjs +89 -89
- package/scripts/desktop-update-publisher-smoke.mjs +89 -89
- package/scripts/desktop-update-worker-smoke.mjs +72 -72
- package/scripts/desktop-workspace-state-smoke.mjs +81 -81
- package/scripts/drive-installed-update-smoke.mjs +67 -67
- package/scripts/npm-fresh-install-smoke.mjs +216 -216
- package/scripts/publish-mindexec-desktop-updates.mjs +224 -224
- package/scripts/remote-agent-managed-smoke.mjs +318 -318
- package/scripts/remote-agent-package-smoke.mjs +64 -64
- package/scripts/remote-agent-ws-smoke.mjs +269 -269
- package/scripts/remote-fast-live-rate-smoke.mjs +343 -343
- package/scripts/remote-fast-mdm-browser-smoke.mjs +453 -453
- package/scripts/remote-fleet-render-smoke.mjs +1350 -1350
- package/scripts/remote-frame-ws-smoke.mjs +234 -234
- package/scripts/remote-http-smoke.mjs +592 -592
- package/scripts/remote-hub-identity-smoke.mjs +146 -146
- package/scripts/remote-hub-scale-smoke.mjs +124 -124
- package/scripts/remote-hub-smoke.mjs +699 -699
- package/scripts/remote-input-ws-smoke.mjs +263 -263
- package/scripts/remote-registry-follower-smoke.mjs +815 -815
- package/scripts/setup-tree-sitter-grammars.mjs +59 -59
- package/server.js +7510 -7510
- package/start-bridge.bat +32 -32
- package/start-bridge.sh +81 -81
- package/tree-sitter-grammars/README.md +18 -0
- package/tree-sitter-grammars/tree-sitter-c_sharp.wasm +0 -0
- package/tree-sitter-grammars/tree-sitter-go.wasm +0 -0
- package/tree-sitter-grammars/tree-sitter-java.wasm +0 -0
- package/tree-sitter-grammars/tree-sitter-javascript.wasm +0 -0
- package/tree-sitter-grammars/tree-sitter-python.wasm +0 -0
- package/tree-sitter-grammars/tree-sitter-rust.wasm +0 -0
- package/tree-sitter-grammars/tree-sitter-tsx.wasm +0 -0
- package/tree-sitter-grammars/tree-sitter-typescript.wasm +0 -0
- package/wwwroot/_content/MindExecution.Plugins.Admin/css/admin-dashboard.css +546 -546
- package/wwwroot/_content/MindExecution.Plugins.Directory/background.png +0 -0
- package/wwwroot/_content/MindExecution.Plugins.YouTube/css/youtube-search.css +251 -251
- package/wwwroot/_content/MindExecution.Shared/css/mind-map-overrides.css +3789 -3789
- package/wwwroot/_content/MindExecution.Shared/fonts/NotoSansKR-Bold.ttf +0 -0
- package/wwwroot/_content/MindExecution.Shared/fonts/NotoSansKR-Regular.ttf +0 -0
- package/wwwroot/_content/MindExecution.Shared/js/agent-visualization.js +27 -27
- package/wwwroot/_content/MindExecution.Shared/js/background-themes.js +1449 -1449
- package/wwwroot/_content/MindExecution.Shared/js/code-master.js +8316 -8316
- package/wwwroot/_content/MindExecution.Shared/js/file-system-helper.js +338 -338
- package/wwwroot/_content/MindExecution.Shared/js/marked.min.js +69 -69
- package/wwwroot/_content/MindExecution.Shared/js/mind-map-animated-image-preview.js +270 -270
- package/wwwroot/_content/MindExecution.Shared/js/mind-map-automation-edge-motion.js +170 -170
- package/wwwroot/_content/MindExecution.Shared/js/mind-map-board-render-ownership.js +81 -81
- package/wwwroot/_content/MindExecution.Shared/js/mind-map-core.js +10506 -10506
- package/wwwroot/_content/MindExecution.Shared/js/mind-map-core.js.backup +1059 -0
- package/wwwroot/_content/MindExecution.Shared/js/mind-map-css3d-hotpath.js +902 -902
- package/wwwroot/_content/MindExecution.Shared/js/mind-map-css3d-manager.js +24637 -24637
- package/wwwroot/_content/MindExecution.Shared/js/mind-map-dev-guards.js +325 -325
- package/wwwroot/_content/MindExecution.Shared/js/mind-map-dnd.js +1491 -1491
- package/wwwroot/_content/MindExecution.Shared/js/mind-map-dnd.js.bak +434 -0
- package/wwwroot/_content/MindExecution.Shared/js/mind-map-glow-shader.js +70 -70
- package/wwwroot/_content/MindExecution.Shared/js/mind-map-image-policy.js +218 -218
- package/wwwroot/_content/MindExecution.Shared/js/mind-map-interactions.js +7078 -7078
- package/wwwroot/_content/MindExecution.Shared/js/mind-map-lod-plan-worker.js +160 -160
- package/wwwroot/_content/MindExecution.Shared/js/mind-map-lod-renderer.js +9958 -9958
- package/wwwroot/_content/MindExecution.Shared/js/mind-map-lod-video-placeholder.js +107 -107
- package/wwwroot/_content/MindExecution.Shared/js/mind-map-logic-workers.js +1004 -1004
- package/wwwroot/_content/MindExecution.Shared/js/mind-map-menu-manager.js +1351 -1351
- package/wwwroot/_content/MindExecution.Shared/js/mind-map-multi-select.js +865 -865
- package/wwwroot/_content/MindExecution.Shared/js/mind-map-node-search-worker.js +554 -554
- package/wwwroot/_content/MindExecution.Shared/js/mind-map-nodes.js +4744 -4744
- package/wwwroot/_content/MindExecution.Shared/js/mind-map-normal-boundary-optimizer.js +624 -624
- package/wwwroot/_content/MindExecution.Shared/js/mind-map-object-manager.js +241 -241
- package/wwwroot/_content/MindExecution.Shared/js/mind-map-object-manager.js.backup +372 -0
- package/wwwroot/_content/MindExecution.Shared/js/mind-map-pipeline.js +2290 -2290
- package/wwwroot/_content/MindExecution.Shared/js/mind-map-remote-codecs.js +202 -202
- package/wwwroot/_content/MindExecution.Shared/js/mind-map-render-plan.js +1971 -1971
- package/wwwroot/_content/MindExecution.Shared/js/mind-map-text-lod-system.js +93 -93
- package/wwwroot/_content/MindExecution.Shared/js/mind-map-texture-factory.js +2391 -2391
- package/wwwroot/_content/MindExecution.Shared/js/mind-map-texture-factory.js.backup +1258 -0
- package/wwwroot/_content/MindExecution.Shared/js/mind-map-video-playback-controls.js +95 -95
- package/wwwroot/_content/MindExecution.Shared/js/mind-map-visibility-worker.js +895 -895
- package/wwwroot/_content/MindExecution.Shared/js/mindmap-toolbar.js +636 -636
- package/wwwroot/_content/MindExecution.Shared/js/native-drop-handler.js +45 -45
- package/wwwroot/_content/MindExecution.Shared/js/plan-master.js +117 -117
- package/wwwroot/_content/MindExecution.Shared/js/renderers/CSS3DRenderer.js +114 -114
- package/wwwroot/_content/MindExecution.Shared/js/texture-worker-manager.js +10 -10
- package/wwwroot/_content/MindExecution.Shared/js/three.min.js +6 -6
- package/wwwroot/_content/MindExecution.Shared/js/token-manager.js +7 -7
- package/wwwroot/_content/MindExecution.Shared/js/troika-bundle.js +6 -6
- package/wwwroot/_content/MindExecution.Shared/js/troika-bundle.js.map +2 -2
- package/wwwroot/_content/MindExecution.Shared/lib/font-awesome/css/all.min.css +8 -8
- package/wwwroot/_content/MindExecution.Shared/models/vocab.txt +30522 -30522
- package/wwwroot/_framework/{Google.Protobuf.33g2gb5is0.dll → Google.Protobuf.9h59ukbel7.dll} +0 -0
- package/wwwroot/_framework/{MindExecution.Core.z100xo4mg0.dll → MindExecution.Core.xxsj2s456b.dll} +0 -0
- package/wwwroot/_framework/{MindExecution.Kernel.i9cldrx8yc.dll → MindExecution.Kernel.5jofnc0wrd.dll} +0 -0
- package/wwwroot/_framework/{MindExecution.Plugins.Admin.48lzqddb0a.dll → MindExecution.Plugins.Admin.t7m4jnqjg3.dll} +0 -0
- package/wwwroot/_framework/{MindExecution.Plugins.Business.7m8u1q142p.dll → MindExecution.Plugins.Business.6yjlhhavap.dll} +0 -0
- package/wwwroot/_framework/{MindExecution.Plugins.Concept.cl5wmr53od.dll → MindExecution.Plugins.Concept.iikqq5zxu0.dll} +0 -0
- package/wwwroot/_framework/{MindExecution.Plugins.Directory.slipi39041.dll → MindExecution.Plugins.Directory.c5ribyne4m.dll} +0 -0
- package/wwwroot/_framework/{MindExecution.Plugins.PlanMaster.qfge05l671.dll → MindExecution.Plugins.PlanMaster.365bbuifr9.dll} +0 -0
- package/wwwroot/_framework/{MindExecution.Plugins.YouTube.tn7v29ut77.dll → MindExecution.Plugins.YouTube.ax415cilpk.dll} +0 -0
- package/wwwroot/_framework/MindExecution.Shared.21e2nvf86u.dll +0 -0
- package/wwwroot/_framework/{MindExecution.Web.rwawrxxk38.dll → MindExecution.Web.ppgm8rey59.dll} +0 -0
- package/wwwroot/_framework/{System.Collections.23yxgetbju.dll → System.Collections.zyvbaq6mpd.dll} +0 -0
- package/wwwroot/_framework/blazor.boot.json +25 -25
- package/wwwroot/_headers +40 -40
- package/wwwroot/_redirects +1 -1
- package/wwwroot/index.html +772 -772
- package/wwwroot/js/marketing-tool.js +180 -180
- package/wwwroot/manifest.webmanifest +23 -23
- package/wwwroot/service-worker-assets.js +109 -81
- package/wwwroot/service-worker.js +33 -33
- package/wwwroot/_framework/MindExecution.Shared.rjqlf0umjn.dll +0 -0
|
@@ -1,902 +1,902 @@
|
|
|
1
|
-
(function () {
|
|
2
|
-
'use strict';
|
|
3
|
-
|
|
4
|
-
const BUILD_ID = '20260724-near-css3d-hotpath-v001';
|
|
5
|
-
const projectedCorners = Array.from({ length: 4 }, () => new THREE.Vector3());
|
|
6
|
-
|
|
7
|
-
function createPerfCounters() {
|
|
8
|
-
return {
|
|
9
|
-
buildId: BUILD_ID,
|
|
10
|
-
hitTest: {
|
|
11
|
-
fullBoardFallbackCount: 0,
|
|
12
|
-
candidateSource: '',
|
|
13
|
-
candidateCount: 0,
|
|
14
|
-
elementsFromPointCalls: 0,
|
|
15
|
-
projectedFrameCalculations: 0
|
|
16
|
-
},
|
|
17
|
-
selection: {
|
|
18
|
-
nodesVisited: 0,
|
|
19
|
-
domQueries: 0
|
|
20
|
-
},
|
|
21
|
-
css3d: {
|
|
22
|
-
visibilityPatchEntered: 0,
|
|
23
|
-
visibilityPatchExited: 0,
|
|
24
|
-
visibilityPatchFallbacks: 0,
|
|
25
|
-
sceneObjectsVisited: 0
|
|
26
|
-
}
|
|
27
|
-
};
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
function ensurePerfCounters(module) {
|
|
31
|
-
if (!module) return null;
|
|
32
|
-
if (!module._nearCss3dPerfCounters ||
|
|
33
|
-
module._nearCss3dPerfCounters.buildId !== BUILD_ID) {
|
|
34
|
-
module._nearCss3dPerfCounters = createPerfCounters();
|
|
35
|
-
}
|
|
36
|
-
return module._nearCss3dPerfCounters;
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
function increment(module, section, key, amount = 1) {
|
|
40
|
-
const counters = ensurePerfCounters(module);
|
|
41
|
-
const target = counters?.[section];
|
|
42
|
-
if (!target || !(key in target)) return;
|
|
43
|
-
target[key] = Number(target[key] || 0) + Number(amount || 0);
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
function recordHitCandidates(module, source, count) {
|
|
47
|
-
const hitTest = ensurePerfCounters(module)?.hitTest;
|
|
48
|
-
if (!hitTest) return;
|
|
49
|
-
hitTest.candidateSource = String(source || '');
|
|
50
|
-
hitTest.candidateCount = Math.max(0, Number(count || 0));
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
function getPerfSnapshot(module) {
|
|
54
|
-
const counters = ensurePerfCounters(module);
|
|
55
|
-
if (!counters) return null;
|
|
56
|
-
return {
|
|
57
|
-
buildId: counters.buildId,
|
|
58
|
-
hitTest: { ...counters.hitTest },
|
|
59
|
-
selection: { ...counters.selection },
|
|
60
|
-
css3d: { ...counters.css3d }
|
|
61
|
-
};
|
|
62
|
-
}
|
|
63
|
-
|
|
64
|
-
function resetPerfCounters(module) {
|
|
65
|
-
if (!module) return false;
|
|
66
|
-
module._nearCss3dPerfCounters = createPerfCounters();
|
|
67
|
-
return true;
|
|
68
|
-
}
|
|
69
|
-
|
|
70
|
-
function createPointerHitContext(module, event, viewportMetrics = null) {
|
|
71
|
-
return {
|
|
72
|
-
module,
|
|
73
|
-
event,
|
|
74
|
-
clientX: Number(event?.clientX || 0),
|
|
75
|
-
clientY: Number(event?.clientY || 0),
|
|
76
|
-
viewportMetrics,
|
|
77
|
-
domStack: undefined,
|
|
78
|
-
worldPoint: undefined,
|
|
79
|
-
candidateIds: undefined,
|
|
80
|
-
candidateSource: '',
|
|
81
|
-
cssHit: undefined,
|
|
82
|
-
projectedFrames: new Map()
|
|
83
|
-
};
|
|
84
|
-
}
|
|
85
|
-
|
|
86
|
-
function getDomStack(module, context) {
|
|
87
|
-
if (!context) return [];
|
|
88
|
-
if (context.domStack !== undefined) return context.domStack;
|
|
89
|
-
increment(module, 'hitTest', 'elementsFromPointCalls');
|
|
90
|
-
context.domStack = typeof document !== 'undefined' &&
|
|
91
|
-
typeof document.elementsFromPoint === 'function'
|
|
92
|
-
? document.elementsFromPoint(context.clientX, context.clientY)
|
|
93
|
-
: [];
|
|
94
|
-
return context.domStack;
|
|
95
|
-
}
|
|
96
|
-
|
|
97
|
-
function getContextWorldPoint(context, factory) {
|
|
98
|
-
if (!context) return typeof factory === 'function' ? factory() : null;
|
|
99
|
-
if (context.worldPoint !== undefined) return context.worldPoint;
|
|
100
|
-
const point = typeof factory === 'function' ? factory() : null;
|
|
101
|
-
context.worldPoint = point
|
|
102
|
-
? new THREE.Vector3(Number(point.x || 0), Number(point.y || 0), Number(point.z || 0))
|
|
103
|
-
: null;
|
|
104
|
-
return context.worldPoint;
|
|
105
|
-
}
|
|
106
|
-
|
|
107
|
-
function getContextCandidateIds(module, context, factory, source = '') {
|
|
108
|
-
if (!context) {
|
|
109
|
-
const ids = typeof factory === 'function' ? factory() : [];
|
|
110
|
-
recordHitCandidates(module, source, Array.isArray(ids) ? ids.length : 0);
|
|
111
|
-
return ids;
|
|
112
|
-
}
|
|
113
|
-
if (context.candidateIds !== undefined) return context.candidateIds;
|
|
114
|
-
context.candidateIds = typeof factory === 'function' ? factory() : [];
|
|
115
|
-
context.candidateSource = String(source || '');
|
|
116
|
-
recordHitCandidates(
|
|
117
|
-
module,
|
|
118
|
-
context.candidateSource,
|
|
119
|
-
Array.isArray(context.candidateIds) ? context.candidateIds.length : 0
|
|
120
|
-
);
|
|
121
|
-
return context.candidateIds;
|
|
122
|
-
}
|
|
123
|
-
|
|
124
|
-
function getProjectedClientFrame(module, entry, context, viewportMetrics, cacheKey = null) {
|
|
125
|
-
if (!module?.camera || !entry) return null;
|
|
126
|
-
const metrics = context?.viewportMetrics || viewportMetrics || null;
|
|
127
|
-
if (!metrics || !(metrics.width > 0 && metrics.height > 0)) return null;
|
|
128
|
-
|
|
129
|
-
const frameKey = cacheKey || entry;
|
|
130
|
-
const cachedFrame = context?.projectedFrames?.get?.(frameKey);
|
|
131
|
-
if (cachedFrame) return cachedFrame;
|
|
132
|
-
|
|
133
|
-
const sourceObject = entry.glObject || entry.cssObject;
|
|
134
|
-
const position = sourceObject?.position;
|
|
135
|
-
if (!position) return null;
|
|
136
|
-
const width = Number(
|
|
137
|
-
entry.glObject?.userData?.worldWidth ??
|
|
138
|
-
entry.cssObject?.userData?.worldWidth ??
|
|
139
|
-
entry.model?.width ??
|
|
140
|
-
entry.model?.Width ??
|
|
141
|
-
0
|
|
142
|
-
);
|
|
143
|
-
const height = Number(
|
|
144
|
-
entry.glObject?.userData?.worldHeight ??
|
|
145
|
-
entry.cssObject?.userData?.worldHeight ??
|
|
146
|
-
entry.model?.height ??
|
|
147
|
-
entry.model?.Height ??
|
|
148
|
-
0
|
|
149
|
-
);
|
|
150
|
-
if (!(width > 0 && height > 0)) return null;
|
|
151
|
-
|
|
152
|
-
const z = Number(position.z || 0);
|
|
153
|
-
projectedCorners[0].set(position.x, position.y, z);
|
|
154
|
-
projectedCorners[1].set(position.x + width, position.y, z);
|
|
155
|
-
projectedCorners[2].set(position.x, position.y - height, z);
|
|
156
|
-
projectedCorners[3].set(position.x + width, position.y - height, z);
|
|
157
|
-
|
|
158
|
-
let left = Infinity;
|
|
159
|
-
let right = -Infinity;
|
|
160
|
-
let top = Infinity;
|
|
161
|
-
let bottom = -Infinity;
|
|
162
|
-
for (let i = 0; i < projectedCorners.length; i++) {
|
|
163
|
-
const corner = projectedCorners[i].project(module.camera);
|
|
164
|
-
const x = Number(metrics.left || 0) + ((corner.x + 1) * metrics.width / 2);
|
|
165
|
-
const y = Number(metrics.top || 0) + ((-corner.y + 1) * metrics.height / 2);
|
|
166
|
-
if (x < left) left = x;
|
|
167
|
-
if (x > right) right = x;
|
|
168
|
-
if (y < top) top = y;
|
|
169
|
-
if (y > bottom) bottom = y;
|
|
170
|
-
}
|
|
171
|
-
|
|
172
|
-
const frame = { left, right, top, bottom };
|
|
173
|
-
context?.projectedFrames?.set?.(frameKey, frame);
|
|
174
|
-
increment(module, 'hitTest', 'projectedFrameCalculations');
|
|
175
|
-
return frame;
|
|
176
|
-
}
|
|
177
|
-
|
|
178
|
-
function getDomRefs(entry, module = null, cssObjectOverride = null) {
|
|
179
|
-
const cssObject = cssObjectOverride || entry?.cssObject || null;
|
|
180
|
-
const wrapper = cssObject?.element || null;
|
|
181
|
-
if (!wrapper) return null;
|
|
182
|
-
const version = Number(entry?._css3dDomVersion || cssObject?.userData?._domVersion || 0);
|
|
183
|
-
const firstChild = wrapper.firstElementChild || null;
|
|
184
|
-
const cached = entry?.domRefs || cssObject?.userData?.domRefs || null;
|
|
185
|
-
if (cached?.wrapper === wrapper &&
|
|
186
|
-
cached.firstChild === firstChild &&
|
|
187
|
-
cached.version === version) {
|
|
188
|
-
return cached;
|
|
189
|
-
}
|
|
190
|
-
|
|
191
|
-
const query = (selector) => {
|
|
192
|
-
increment(module, 'selection', 'domQueries');
|
|
193
|
-
return wrapper.querySelector?.(selector) || null;
|
|
194
|
-
};
|
|
195
|
-
const refs = {
|
|
196
|
-
version,
|
|
197
|
-
wrapper,
|
|
198
|
-
firstChild,
|
|
199
|
-
innerRoot: query('.node-container, .map-node, .css3d-dynamic-node'),
|
|
200
|
-
response: query('.node-response, [id^="node-response-"]'),
|
|
201
|
-
textarea: query('textarea, [contenteditable="true"]'),
|
|
202
|
-
scrollable: query('.csv-table-scroll, .node-response, .note-content, .markdown-body, .code-body, .map-node-memo__body-view'),
|
|
203
|
-
memoTitle: query('.map-node-memo__title'),
|
|
204
|
-
memoBody: query('.map-node-memo__body'),
|
|
205
|
-
memoBodyView: query('.map-node-memo__body-view'),
|
|
206
|
-
resizeHandles: Array.from(wrapper.querySelectorAll?.('.resize-handle, [data-resize-handle]') || [])
|
|
207
|
-
};
|
|
208
|
-
if (entry) entry.domRefs = refs;
|
|
209
|
-
cssObject.userData ||= {};
|
|
210
|
-
cssObject.userData.domRefs = refs;
|
|
211
|
-
return refs;
|
|
212
|
-
}
|
|
213
|
-
|
|
214
|
-
function invalidateDomRefs(entry, cssObjectOverride = null) {
|
|
215
|
-
const cssObject = cssObjectOverride || entry?.cssObject || null;
|
|
216
|
-
const nextVersion = Math.max(
|
|
217
|
-
Number(entry?._css3dDomVersion || 0),
|
|
218
|
-
Number(cssObject?.userData?._domVersion || 0)
|
|
219
|
-
) + 1;
|
|
220
|
-
if (entry) {
|
|
221
|
-
entry._css3dDomVersion = nextVersion;
|
|
222
|
-
entry.domRefs = null;
|
|
223
|
-
}
|
|
224
|
-
if (cssObject) {
|
|
225
|
-
cssObject.userData ||= {};
|
|
226
|
-
cssObject.userData._domVersion = nextVersion;
|
|
227
|
-
cssObject.userData.domRefs = null;
|
|
228
|
-
}
|
|
229
|
-
return nextVersion;
|
|
230
|
-
}
|
|
231
|
-
|
|
232
|
-
function invalidateDomRefsByCssObject(module, cssObject, nodeId = '') {
|
|
233
|
-
const normalizedId = String(nodeId || cssObject?.userData?.nodeId || '').trim();
|
|
234
|
-
const entry = normalizedId ? module?.nodeObjectsById?.get?.(normalizedId) : null;
|
|
235
|
-
return invalidateDomRefs(entry, cssObject);
|
|
236
|
-
}
|
|
237
|
-
|
|
238
|
-
function installTextSource(helpers = {}) {
|
|
239
|
-
const styleState = new WeakMap();
|
|
240
|
-
const suspendedClass = 'mind-map-text-overlay-source-suspended';
|
|
241
|
-
const suspendedAttr = 'data-text-overlay-source-suspended';
|
|
242
|
-
|
|
243
|
-
function getModule() {
|
|
244
|
-
return helpers.getModule?.() || null;
|
|
245
|
-
}
|
|
246
|
-
|
|
247
|
-
function getTextOverlaySourceTargets(nodeEntry) {
|
|
248
|
-
if (!nodeEntry?.cssObject?.element || !helpers.supportsTextOverlay?.(nodeEntry.model)) return [];
|
|
249
|
-
const module = getModule();
|
|
250
|
-
const refs = getDomRefs(nodeEntry, module);
|
|
251
|
-
if (helpers.getTextOverlayRenderMode?.(nodeEntry) === 'memo') {
|
|
252
|
-
return [refs?.memoTitle, refs?.memoBodyView].filter(element =>
|
|
253
|
-
!!element && (element.style.display !== 'none' || element.offsetWidth > 0 || element.offsetHeight > 0));
|
|
254
|
-
}
|
|
255
|
-
const root = helpers.getTextOverlayRootElement?.(nodeEntry);
|
|
256
|
-
if (!root?.children?.length) return [];
|
|
257
|
-
return Array.from(root.children).filter(element =>
|
|
258
|
-
!!element &&
|
|
259
|
-
!element.classList?.contains?.('resize-handle') &&
|
|
260
|
-
(element.style.display !== 'none' || element.offsetWidth > 0 || element.offsetHeight > 0));
|
|
261
|
-
}
|
|
262
|
-
|
|
263
|
-
function ensureTextOverlaySourceStyleState(element) {
|
|
264
|
-
if (!element) return null;
|
|
265
|
-
let state = styleState.get(element) || null;
|
|
266
|
-
if (!state) {
|
|
267
|
-
state = {
|
|
268
|
-
opacity: element.style.opacity,
|
|
269
|
-
pointerEvents: element.style.pointerEvents,
|
|
270
|
-
userSelect: element.style.userSelect,
|
|
271
|
-
webkitUserSelect: element.style.webkitUserSelect,
|
|
272
|
-
caretColor: element.style.caretColor,
|
|
273
|
-
contentVisibility: element.style.contentVisibility,
|
|
274
|
-
containIntrinsicSize: element.style.containIntrinsicSize,
|
|
275
|
-
contain: element.style.contain
|
|
276
|
-
};
|
|
277
|
-
styleState.set(element, state);
|
|
278
|
-
}
|
|
279
|
-
return state;
|
|
280
|
-
}
|
|
281
|
-
|
|
282
|
-
function resetTextOverlaySourcePresentation(element) {
|
|
283
|
-
if (!element) return;
|
|
284
|
-
element.classList?.remove?.(suspendedClass);
|
|
285
|
-
element.removeAttribute?.(suspendedAttr);
|
|
286
|
-
element.style.opacity = '';
|
|
287
|
-
element.style.pointerEvents = '';
|
|
288
|
-
element.style.userSelect = '';
|
|
289
|
-
element.style.webkitUserSelect = '';
|
|
290
|
-
element.style.caretColor = '';
|
|
291
|
-
element.style.contentVisibility = '';
|
|
292
|
-
element.style.containIntrinsicSize = '';
|
|
293
|
-
element.style.contain = '';
|
|
294
|
-
}
|
|
295
|
-
|
|
296
|
-
function suspendTextOverlaySourceTarget(element) {
|
|
297
|
-
if (!element) return;
|
|
298
|
-
ensureTextOverlaySourceStyleState(element);
|
|
299
|
-
element.classList?.add?.(suspendedClass);
|
|
300
|
-
element.setAttribute?.(suspendedAttr, 'true');
|
|
301
|
-
element.style.pointerEvents = 'none';
|
|
302
|
-
element.style.userSelect = 'none';
|
|
303
|
-
element.style.webkitUserSelect = 'none';
|
|
304
|
-
element.style.caretColor = 'transparent';
|
|
305
|
-
element.style.opacity = '0';
|
|
306
|
-
element.style.contain = 'layout style paint';
|
|
307
|
-
element.style.contentVisibility = 'visible';
|
|
308
|
-
element.style.containIntrinsicSize = '';
|
|
309
|
-
}
|
|
310
|
-
|
|
311
|
-
function restoreTextOverlaySourceTarget(element) {
|
|
312
|
-
if (!element) return;
|
|
313
|
-
const state = styleState.get(element) || null;
|
|
314
|
-
if (!state) {
|
|
315
|
-
resetTextOverlaySourcePresentation(element);
|
|
316
|
-
return;
|
|
317
|
-
}
|
|
318
|
-
element.classList?.remove?.(suspendedClass);
|
|
319
|
-
element.removeAttribute?.(suspendedAttr);
|
|
320
|
-
Object.assign(element.style, state);
|
|
321
|
-
styleState.delete(element);
|
|
322
|
-
}
|
|
323
|
-
|
|
324
|
-
function stripTextOverlayPresentationOverrides(root) {
|
|
325
|
-
if (!root) return;
|
|
326
|
-
if (root.hasAttribute?.(suspendedAttr) || root.classList?.contains?.(suspendedClass)) {
|
|
327
|
-
resetTextOverlaySourcePresentation(root);
|
|
328
|
-
}
|
|
329
|
-
root.querySelectorAll?.(`[${suspendedAttr}], .${suspendedClass}`)
|
|
330
|
-
?.forEach?.(resetTextOverlaySourcePresentation);
|
|
331
|
-
}
|
|
332
|
-
|
|
333
|
-
function getNativeTextSelectionSourceNodeId(module) {
|
|
334
|
-
return String(module?._nativeTextSelectionSourceNodeId || '').trim();
|
|
335
|
-
}
|
|
336
|
-
|
|
337
|
-
function hasNativeTextSelectionSource(module, nodeId = null) {
|
|
338
|
-
const activeId = getNativeTextSelectionSourceNodeId(module);
|
|
339
|
-
if (!activeId) return false;
|
|
340
|
-
return nodeId === null || activeId === String(nodeId || '').trim();
|
|
341
|
-
}
|
|
342
|
-
|
|
343
|
-
function setNativeTextSelectionOwnerClass(module, nodeId = null) {
|
|
344
|
-
if (!module) return false;
|
|
345
|
-
const nextId = String(nodeId || '').trim();
|
|
346
|
-
const previousId = String(module._nativeTextSelectionOwnerNodeId || '').trim();
|
|
347
|
-
if (previousId === nextId) return true;
|
|
348
|
-
|
|
349
|
-
const getWrapper = (id) => {
|
|
350
|
-
const entry = id ? module.nodeObjectsById?.get?.(id) : null;
|
|
351
|
-
return getDomRefs(entry, module)?.wrapper || null;
|
|
352
|
-
};
|
|
353
|
-
const previousWrapper = getWrapper(previousId);
|
|
354
|
-
const nextWrapper = getWrapper(nextId);
|
|
355
|
-
if (previousWrapper) {
|
|
356
|
-
previousWrapper.classList?.remove?.('is-text-selection-owner');
|
|
357
|
-
increment(module, 'selection', 'nodesVisited');
|
|
358
|
-
}
|
|
359
|
-
if (nextWrapper) {
|
|
360
|
-
nextWrapper.classList?.add?.('is-text-selection-owner');
|
|
361
|
-
increment(module, 'selection', 'nodesVisited');
|
|
362
|
-
}
|
|
363
|
-
module._nativeTextSelectionOwnerNodeId = nextId || null;
|
|
364
|
-
return true;
|
|
365
|
-
}
|
|
366
|
-
|
|
367
|
-
function activateNativeTextSelectionSource(module, nodeId) {
|
|
368
|
-
const id = String(nodeId || '').trim();
|
|
369
|
-
if (!module || !id) return false;
|
|
370
|
-
module._nativeTextSelectionSourceNodeId = id;
|
|
371
|
-
setNativeTextSelectionOwnerClass(module, id);
|
|
372
|
-
helpers.ensureTextOverlaySourceVisible?.(module, id);
|
|
373
|
-
return true;
|
|
374
|
-
}
|
|
375
|
-
|
|
376
|
-
function clearNativeTextSelectionSource(module, nodeId = null) {
|
|
377
|
-
const activeId = getNativeTextSelectionSourceNodeId(module);
|
|
378
|
-
const requestedId = nodeId === null ? activeId : String(nodeId || '').trim();
|
|
379
|
-
if (!module || !activeId || !requestedId || activeId !== requestedId) return false;
|
|
380
|
-
module._nativeTextSelectionSourceNodeId = null;
|
|
381
|
-
setNativeTextSelectionOwnerClass(module, null);
|
|
382
|
-
return true;
|
|
383
|
-
}
|
|
384
|
-
|
|
385
|
-
function isTextOverlaySelectionNode(module, nodeEntry) {
|
|
386
|
-
const contentType = String(nodeEntry?.model?.contentType ?? nodeEntry?.model?.ContentType ?? '').toLowerCase();
|
|
387
|
-
if (contentType !== 'text' && contentType !== 'markdown') return false;
|
|
388
|
-
const nodeId = String(helpers.getNodeId?.(nodeEntry?.model) || '').trim();
|
|
389
|
-
return hasNativeTextSelectionSource(module, nodeId);
|
|
390
|
-
}
|
|
391
|
-
|
|
392
|
-
function setTextOverlaySourceActive(nodeEntry, isActive) {
|
|
393
|
-
if (helpers.isCss3dMediaNode?.(nodeEntry?.model)) {
|
|
394
|
-
helpers.restoreCss3dMediaOverlayState?.(nodeEntry.model, nodeEntry.cssObject);
|
|
395
|
-
nodeEntry._textOverlayActive = false;
|
|
396
|
-
nodeEntry._css3dSourceSuspended = false;
|
|
397
|
-
return;
|
|
398
|
-
}
|
|
399
|
-
const host = helpers.getTextOverlayHostElement?.(nodeEntry);
|
|
400
|
-
if (!host?.classList) return;
|
|
401
|
-
host.classList.toggle('mind-map-text-overlay-active', !!isActive);
|
|
402
|
-
getTextOverlaySourceTargets(nodeEntry).forEach(target => {
|
|
403
|
-
if (isActive) suspendTextOverlaySourceTarget(target);
|
|
404
|
-
else restoreTextOverlaySourceTarget(target);
|
|
405
|
-
});
|
|
406
|
-
nodeEntry._textOverlayActive = nodeEntry._css3dSourceSuspended = !!isActive;
|
|
407
|
-
}
|
|
408
|
-
|
|
409
|
-
return {
|
|
410
|
-
getTextOverlaySourceTargets,
|
|
411
|
-
ensureTextOverlaySourceStyleState,
|
|
412
|
-
resetTextOverlaySourcePresentation,
|
|
413
|
-
suspendTextOverlaySourceTarget,
|
|
414
|
-
restoreTextOverlaySourceTarget,
|
|
415
|
-
stripTextOverlayPresentationOverrides,
|
|
416
|
-
getNativeTextSelectionSourceNodeId,
|
|
417
|
-
hasNativeTextSelectionSource,
|
|
418
|
-
setNativeTextSelectionOwnerClass,
|
|
419
|
-
activateNativeTextSelectionSource,
|
|
420
|
-
clearNativeTextSelectionSource,
|
|
421
|
-
isTextOverlaySelectionNode,
|
|
422
|
-
setTextOverlaySourceActive
|
|
423
|
-
};
|
|
424
|
-
}
|
|
425
|
-
|
|
426
|
-
function installOverlayGeometry(helpers = {}) {
|
|
427
|
-
function getTextOverlayPlacementInfo(module, element) {
|
|
428
|
-
if (!module?.container || !element) return null;
|
|
429
|
-
const rect = element.getBoundingClientRect();
|
|
430
|
-
const containerRect = module.container.getBoundingClientRect();
|
|
431
|
-
const width = Math.max(0, rect.width || 0);
|
|
432
|
-
const height = Math.max(0, rect.height || 0);
|
|
433
|
-
if (width < 1 || height < 1) return null;
|
|
434
|
-
const left = rect.left - containerRect.left;
|
|
435
|
-
const top = rect.top - containerRect.top;
|
|
436
|
-
return {
|
|
437
|
-
left,
|
|
438
|
-
top,
|
|
439
|
-
width,
|
|
440
|
-
height,
|
|
441
|
-
baseWidth: Math.max(1, Number(element.offsetWidth || width || 1)),
|
|
442
|
-
baseHeight: Math.max(1, Number(element.offsetHeight || height || 1)),
|
|
443
|
-
right: left + width,
|
|
444
|
-
bottom: top + height
|
|
445
|
-
};
|
|
446
|
-
}
|
|
447
|
-
|
|
448
|
-
function doesTextOverlayRectOverlap(a, b, padding = 0) {
|
|
449
|
-
if (!a || !b) return false;
|
|
450
|
-
const inset = Number.isFinite(Number(padding)) ? Number(padding) : 0;
|
|
451
|
-
return !(
|
|
452
|
-
(a.left + a.width + inset) < b.left ||
|
|
453
|
-
(b.left + b.width + inset) < a.left ||
|
|
454
|
-
(a.top + a.height + inset) < b.top ||
|
|
455
|
-
(b.top + b.height + inset) < a.top
|
|
456
|
-
);
|
|
457
|
-
}
|
|
458
|
-
|
|
459
|
-
function isTextOverlayPlacementVisible(module, placement, options = {}) {
|
|
460
|
-
if (!module?.container || !placement) return false;
|
|
461
|
-
const { ignoreMinSize = false } = options;
|
|
462
|
-
if (!ignoreMinSize &&
|
|
463
|
-
(placement.width < Number(helpers.minWidth || 0) ||
|
|
464
|
-
placement.height < Number(helpers.minHeight || 0))) {
|
|
465
|
-
return false;
|
|
466
|
-
}
|
|
467
|
-
const maxWidth = Number(module.container.clientWidth || 0);
|
|
468
|
-
const maxHeight = Number(module.container.clientHeight || 0);
|
|
469
|
-
if (!(maxWidth > 0) || !(maxHeight > 0)) return false;
|
|
470
|
-
return !(
|
|
471
|
-
placement.right < 0 ||
|
|
472
|
-
placement.left > maxWidth ||
|
|
473
|
-
placement.bottom < 0 ||
|
|
474
|
-
placement.top > maxHeight
|
|
475
|
-
);
|
|
476
|
-
}
|
|
477
|
-
|
|
478
|
-
function getTextOverlayPriority(module, nodeEntry) {
|
|
479
|
-
const nodeModel = nodeEntry?.model;
|
|
480
|
-
const nodeId = String(helpers.getNodeId?.(nodeModel) || '').trim();
|
|
481
|
-
if (!nodeModel || !nodeId) return Number.NEGATIVE_INFINITY;
|
|
482
|
-
let priority = 0;
|
|
483
|
-
if (String(module?.selectedNodeIdJs || '').trim() === nodeId) priority += 100000;
|
|
484
|
-
else if (module?.multiSelectedNodeIds?.has?.(nodeId)) priority += 50000;
|
|
485
|
-
const width = Math.max(1, Number(nodeModel.width || nodeModel.Width || 0));
|
|
486
|
-
const height = Math.max(1, Number(nodeModel.height || nodeModel.Height || 0));
|
|
487
|
-
priority += Math.min(6000, (width * height) / 18);
|
|
488
|
-
if (module?.camera) {
|
|
489
|
-
const centerX = Number(nodeModel.positionX ?? nodeModel.PositionX ?? nodeModel.x ?? nodeModel.X ?? 0) + (width * 0.5);
|
|
490
|
-
const centerY = Number(nodeModel.positionY ?? nodeModel.PositionY ?? nodeModel.y ?? nodeModel.Y ?? 0) - (height * 0.5);
|
|
491
|
-
priority += Math.max(
|
|
492
|
-
0,
|
|
493
|
-
24000 -
|
|
494
|
-
Math.abs(centerX - Number(module.camera.position?.x || 0)) -
|
|
495
|
-
Math.abs(centerY - Number(module.camera.position?.y || 0))
|
|
496
|
-
);
|
|
497
|
-
}
|
|
498
|
-
const zIndex = Number(nodeEntry?.cssObject?.element?.style?.zIndex || 0);
|
|
499
|
-
if (Number.isFinite(zIndex)) priority += zIndex * 10;
|
|
500
|
-
return priority;
|
|
501
|
-
}
|
|
502
|
-
|
|
503
|
-
function isAlwaysTextOverlayNode(nodeEntry) {
|
|
504
|
-
const contentType = String(
|
|
505
|
-
nodeEntry?.model?.contentType ??
|
|
506
|
-
nodeEntry?.model?.ContentType ??
|
|
507
|
-
''
|
|
508
|
-
).toLowerCase();
|
|
509
|
-
return contentType === 'markdown' || contentType === 'text';
|
|
510
|
-
}
|
|
511
|
-
|
|
512
|
-
function getTextOverlayContentSignature(nodeEntry) {
|
|
513
|
-
const model = nodeEntry?.model || {};
|
|
514
|
-
const contentType = String(model.contentType ?? model.ContentType ?? '').toLowerCase();
|
|
515
|
-
const prompt = String(model.prompt ?? model.Prompt ?? '');
|
|
516
|
-
const response = String(model.response ?? model.Response ?? '');
|
|
517
|
-
const isLoading = (model.isLoading ?? model.IsLoading ?? false) ? '1' : '0';
|
|
518
|
-
const width = Math.max(0, Number(model.width ?? model.Width ?? 0));
|
|
519
|
-
const height = Math.max(0, Number(model.height ?? model.Height ?? 0));
|
|
520
|
-
return `${contentType}||${prompt}||${response}||${isLoading}||${width}||${height}`;
|
|
521
|
-
}
|
|
522
|
-
|
|
523
|
-
function getTextOverlayLayoutSignature(sourceElement, mode = 'full', hostPlacement = null) {
|
|
524
|
-
if (!sourceElement) return '';
|
|
525
|
-
if (mode === 'memo') {
|
|
526
|
-
const titleInput = sourceElement.querySelector('.map-node-memo__title');
|
|
527
|
-
const bodyView = sourceElement.querySelector('.map-node-memo__body-view');
|
|
528
|
-
const hostWidth = Math.round(Number(hostPlacement?.baseWidth || sourceElement.offsetWidth || 0));
|
|
529
|
-
const hostHeight = Math.round(Number(hostPlacement?.baseHeight || sourceElement.offsetHeight || 0));
|
|
530
|
-
const titleSignature = titleInput
|
|
531
|
-
? `${titleInput.offsetLeft}:${titleInput.offsetTop}:${titleInput.offsetWidth}:${titleInput.offsetHeight}:${titleInput.style.display}`
|
|
532
|
-
: 'title:none';
|
|
533
|
-
const bodySignature = bodyView
|
|
534
|
-
? `${bodyView.offsetLeft}:${bodyView.offsetTop}:${bodyView.offsetWidth}:${bodyView.offsetHeight}:${bodyView.style.display}`
|
|
535
|
-
: 'body:none';
|
|
536
|
-
return `${mode}||${hostWidth}x${hostHeight}||${titleSignature}||${bodySignature}`;
|
|
537
|
-
}
|
|
538
|
-
const rootWidth = Math.round(Number(sourceElement.offsetWidth || 0));
|
|
539
|
-
const rootHeight = Math.round(Number(sourceElement.offsetHeight || 0));
|
|
540
|
-
const childSignature = Array.from(sourceElement.children || [])
|
|
541
|
-
.map(child => `${child.tagName}:${child.offsetWidth}:${child.offsetHeight}:${child.style.display}`)
|
|
542
|
-
.join('|');
|
|
543
|
-
return `${mode}||${rootWidth}x${rootHeight}||${childSignature}`;
|
|
544
|
-
}
|
|
545
|
-
|
|
546
|
-
return {
|
|
547
|
-
getTextOverlayPlacementInfo,
|
|
548
|
-
doesTextOverlayRectOverlap,
|
|
549
|
-
isTextOverlayPlacementVisible,
|
|
550
|
-
getTextOverlayPriority,
|
|
551
|
-
isAlwaysTextOverlayNode,
|
|
552
|
-
getTextOverlayContentSignature,
|
|
553
|
-
getTextOverlayLayoutSignature
|
|
554
|
-
};
|
|
555
|
-
}
|
|
556
|
-
|
|
557
|
-
function getNodeBounds(entry) {
|
|
558
|
-
const shared = window.MindMapNodeBounds?.getNodeWorldBounds?.(entry);
|
|
559
|
-
if (shared) return shared;
|
|
560
|
-
const model = entry?.model || null;
|
|
561
|
-
const object = entry?.glObject || entry?.cssObject || null;
|
|
562
|
-
if (!model && !object) return null;
|
|
563
|
-
const width = Math.max(1, Number(
|
|
564
|
-
entry?.glObject?.userData?.worldWidth ??
|
|
565
|
-
entry?.cssObject?.userData?.worldWidth ??
|
|
566
|
-
model?.width ??
|
|
567
|
-
model?.Width ??
|
|
568
|
-
400
|
|
569
|
-
));
|
|
570
|
-
const height = Math.max(1, Number(
|
|
571
|
-
entry?.glObject?.userData?.worldHeight ??
|
|
572
|
-
entry?.cssObject?.userData?.worldHeight ??
|
|
573
|
-
model?.height ??
|
|
574
|
-
model?.Height ??
|
|
575
|
-
200
|
|
576
|
-
));
|
|
577
|
-
const x = Number(object?.position?.x ?? model?.positionX ?? model?.x ?? 0);
|
|
578
|
-
const y = Number(object?.position?.y ?? model?.positionY ?? model?.y ?? 0);
|
|
579
|
-
return { minX: x, maxX: x + width, minY: y - height, maxY: y };
|
|
580
|
-
}
|
|
581
|
-
|
|
582
|
-
function getSpatialGridKeysForBounds(module, entry) {
|
|
583
|
-
const bounds = getNodeBounds(entry);
|
|
584
|
-
if (!bounds) return new Set();
|
|
585
|
-
const cellSize = Math.max(1, Number(module?.GRID_CELL_SIZE || 500));
|
|
586
|
-
const keys = new Set();
|
|
587
|
-
const startX = Math.floor(bounds.minX / cellSize);
|
|
588
|
-
const endX = Math.floor(bounds.maxX / cellSize);
|
|
589
|
-
const startY = Math.floor(bounds.minY / cellSize);
|
|
590
|
-
const endY = Math.floor(bounds.maxY / cellSize);
|
|
591
|
-
for (let x = startX; x <= endX; x++) {
|
|
592
|
-
for (let y = startY; y <= endY; y++) keys.add(`${x}:${y}`);
|
|
593
|
-
}
|
|
594
|
-
return keys;
|
|
595
|
-
}
|
|
596
|
-
|
|
597
|
-
function setEntrySpatialKeys(entry, keys) {
|
|
598
|
-
if (!entry) return;
|
|
599
|
-
entry._spatialGridKeys = keys;
|
|
600
|
-
if (entry.glObject) {
|
|
601
|
-
entry.glObject.userData ||= {};
|
|
602
|
-
entry.glObject.userData.spatialGridKeys = keys;
|
|
603
|
-
}
|
|
604
|
-
if (entry.cssObject) {
|
|
605
|
-
entry.cssObject.userData ||= {};
|
|
606
|
-
entry.cssObject.userData.spatialGridKeys = keys;
|
|
607
|
-
}
|
|
608
|
-
}
|
|
609
|
-
|
|
610
|
-
function collectSpatialRectCandidateIds(module, rect) {
|
|
611
|
-
if (!module?.spatialGrid || module._spatialIndexRepairState || !rect) return null;
|
|
612
|
-
const cellSize = Math.max(1, Number(module.GRID_CELL_SIZE || 500));
|
|
613
|
-
const ids = [];
|
|
614
|
-
const seen = new Set();
|
|
615
|
-
const startX = Math.floor(Number(rect.left || 0) / cellSize);
|
|
616
|
-
const endX = Math.floor(Number(rect.right || 0) / cellSize);
|
|
617
|
-
const startY = Math.floor(Number(rect.bottom || 0) / cellSize);
|
|
618
|
-
const endY = Math.floor(Number(rect.top || 0) / cellSize);
|
|
619
|
-
for (let x = startX; x <= endX; x++) {
|
|
620
|
-
for (let y = startY; y <= endY; y++) {
|
|
621
|
-
module.spatialGrid.get(`${x}:${y}`)?.forEach?.(nodeId => {
|
|
622
|
-
const id = String(nodeId || '').trim();
|
|
623
|
-
if (id && !seen.has(id)) {
|
|
624
|
-
seen.add(id);
|
|
625
|
-
ids.push(id);
|
|
626
|
-
}
|
|
627
|
-
});
|
|
628
|
-
}
|
|
629
|
-
}
|
|
630
|
-
return ids;
|
|
631
|
-
}
|
|
632
|
-
|
|
633
|
-
function getBoundedFallbackIds(module) {
|
|
634
|
-
const ids = new Set();
|
|
635
|
-
const add = (value) => {
|
|
636
|
-
const id = String(value || '').trim();
|
|
637
|
-
if (id && module?.nodeObjectsById?.has?.(id)) ids.add(id);
|
|
638
|
-
};
|
|
639
|
-
module?._visibleIds?.forEach?.(add);
|
|
640
|
-
module?._prevVisibleIds?.forEach?.(add);
|
|
641
|
-
add(module?.selectedNodeIdJs);
|
|
642
|
-
module?.multiSelectedNodeIds?.forEach?.(add);
|
|
643
|
-
add(module?.draggedNodeId);
|
|
644
|
-
add(module?._nativeTextSelectionSourceNodeId);
|
|
645
|
-
add(module?._editingOverlayState?.nodeId);
|
|
646
|
-
add(module?._textOverlayV2State?.editing?.nodeId);
|
|
647
|
-
module?.lodRenderer?._nearCssVisibleIds?.forEach?.(add);
|
|
648
|
-
module?.lodRenderer?._lodImageCssFallbackNodeIds?.forEach?.(add);
|
|
649
|
-
module?.lodRenderer?._lodTemplateCssNodeIds?.forEach?.(add);
|
|
650
|
-
return Array.from(ids);
|
|
651
|
-
}
|
|
652
|
-
|
|
653
|
-
function scheduleSpatialIndexRepair(module, reason = 'index-unavailable') {
|
|
654
|
-
if (!module?.nodeObjectsById || module._spatialIndexRepairState) return false;
|
|
655
|
-
const ownerMap = module.nodeObjectsById;
|
|
656
|
-
const state = {
|
|
657
|
-
ownerMap,
|
|
658
|
-
iterator: ownerMap.entries(),
|
|
659
|
-
reason: String(reason || 'index-unavailable'),
|
|
660
|
-
processed: 0
|
|
661
|
-
};
|
|
662
|
-
module._spatialIndexRepairState = state;
|
|
663
|
-
module.spatialGrid = new Map();
|
|
664
|
-
window.MindCanvasTrace?.emit?.('hitTest.spatialRepairScheduled', {
|
|
665
|
-
reason: state.reason,
|
|
666
|
-
nodeCount: ownerMap.size
|
|
667
|
-
});
|
|
668
|
-
|
|
669
|
-
const schedule = (callback) => {
|
|
670
|
-
if (typeof requestIdleCallback === 'function') requestIdleCallback(callback, { timeout: 120 });
|
|
671
|
-
else setTimeout(() => callback(null), 0);
|
|
672
|
-
};
|
|
673
|
-
const run = (deadline) => {
|
|
674
|
-
if (module._spatialIndexRepairState !== state || module.nodeObjectsById !== ownerMap) return;
|
|
675
|
-
let processedThisSlice = 0;
|
|
676
|
-
while (processedThisSlice < 128 &&
|
|
677
|
-
(!deadline?.timeRemaining || deadline.timeRemaining() > 1)) {
|
|
678
|
-
const next = state.iterator.next();
|
|
679
|
-
if (next.done) {
|
|
680
|
-
module._spatialIndexRepairState = null;
|
|
681
|
-
module.logicWorkerBridge?.rebuildNodeTables?.(module, {
|
|
682
|
-
reason: 'hit-test-spatial-repair'
|
|
683
|
-
});
|
|
684
|
-
window.MindCanvasTrace?.emit?.('hitTest.spatialRepairCompleted', {
|
|
685
|
-
reason: state.reason,
|
|
686
|
-
processed: state.processed
|
|
687
|
-
});
|
|
688
|
-
return;
|
|
689
|
-
}
|
|
690
|
-
const [nodeId, entry] = next.value;
|
|
691
|
-
const keys = getSpatialGridKeysForBounds(module, entry);
|
|
692
|
-
keys.forEach(key => {
|
|
693
|
-
if (!module.spatialGrid.has(key)) module.spatialGrid.set(key, new Set());
|
|
694
|
-
module.spatialGrid.get(key).add(nodeId);
|
|
695
|
-
});
|
|
696
|
-
setEntrySpatialKeys(entry, keys);
|
|
697
|
-
processedThisSlice++;
|
|
698
|
-
state.processed++;
|
|
699
|
-
}
|
|
700
|
-
schedule(run);
|
|
701
|
-
};
|
|
702
|
-
schedule(run);
|
|
703
|
-
return true;
|
|
704
|
-
}
|
|
705
|
-
|
|
706
|
-
function noteUnavailableIndex(module, reason = 'index-unavailable') {
|
|
707
|
-
window.MindCanvasTrace?.emit?.('hitTest.fullBoardFallback', {
|
|
708
|
-
blocked: true,
|
|
709
|
-
reason
|
|
710
|
-
});
|
|
711
|
-
scheduleSpatialIndexRepair(module, reason);
|
|
712
|
-
}
|
|
713
|
-
|
|
714
|
-
function ensureCssRendererHooks(module) {
|
|
715
|
-
const renderer = module?.cssRenderer || null;
|
|
716
|
-
if (!renderer) return false;
|
|
717
|
-
if (renderer._nearCss3dHooksInstalled === BUILD_ID) return true;
|
|
718
|
-
|
|
719
|
-
const counters = {
|
|
720
|
-
sceneObjectsVisited: 0,
|
|
721
|
-
visibilityPatchEntered: 0,
|
|
722
|
-
visibilityPatchExited: 0
|
|
723
|
-
};
|
|
724
|
-
const existingGetDebugCounters =
|
|
725
|
-
typeof renderer.getDebugCounters === 'function'
|
|
726
|
-
? renderer.getDebugCounters.bind(renderer)
|
|
727
|
-
: null;
|
|
728
|
-
const existingResetDebugCounters =
|
|
729
|
-
typeof renderer.resetDebugCounters === 'function'
|
|
730
|
-
? renderer.resetDebugCounters.bind(renderer)
|
|
731
|
-
: null;
|
|
732
|
-
const originalRender =
|
|
733
|
-
typeof renderer.render === 'function'
|
|
734
|
-
? renderer.render.bind(renderer)
|
|
735
|
-
: null;
|
|
736
|
-
|
|
737
|
-
if (!existingGetDebugCounters && originalRender) {
|
|
738
|
-
renderer.render = (scene, camera) => {
|
|
739
|
-
let visited = 0;
|
|
740
|
-
if (module.renderDebugFlags?.enableFramePerfProbe === true) {
|
|
741
|
-
scene?.traverse?.(() => {
|
|
742
|
-
visited++;
|
|
743
|
-
});
|
|
744
|
-
}
|
|
745
|
-
const result = originalRender(scene, camera);
|
|
746
|
-
counters.sceneObjectsVisited += visited;
|
|
747
|
-
return result;
|
|
748
|
-
};
|
|
749
|
-
}
|
|
750
|
-
|
|
751
|
-
if (typeof renderer.applyVisibilityDiff !== 'function') {
|
|
752
|
-
renderer.applyVisibilityDiff = (enteredObjects, exitedObjects) => {
|
|
753
|
-
const entered = Array.isArray(enteredObjects) ? enteredObjects : [];
|
|
754
|
-
const exited = Array.isArray(exitedObjects) ? exitedObjects : [];
|
|
755
|
-
const cameraElement = renderer.getCameraElement?.() || null;
|
|
756
|
-
let visited = 0;
|
|
757
|
-
const patchObject = (object) => {
|
|
758
|
-
if (!object?.isCSS3DObject || !object.element) return;
|
|
759
|
-
object.updateMatrixWorld?.(true);
|
|
760
|
-
const layoutPrepared =
|
|
761
|
-
object.userData?._residentTransitionPrepared === true ||
|
|
762
|
-
object.userData?._fullResFringePrepared === true;
|
|
763
|
-
object.element.style.removeProperty?.('display');
|
|
764
|
-
if (object.visible !== true && layoutPrepared !== true) {
|
|
765
|
-
object.element.style.display = 'none';
|
|
766
|
-
}
|
|
767
|
-
if (cameraElement && object.element.parentNode !== cameraElement) {
|
|
768
|
-
cameraElement.appendChild(object.element);
|
|
769
|
-
}
|
|
770
|
-
visited++;
|
|
771
|
-
};
|
|
772
|
-
try {
|
|
773
|
-
exited.forEach(patchObject);
|
|
774
|
-
entered.forEach(patchObject);
|
|
775
|
-
} catch (error) {
|
|
776
|
-
return {
|
|
777
|
-
complete: false,
|
|
778
|
-
reason: 'visibility-diff-exception',
|
|
779
|
-
visited,
|
|
780
|
-
error
|
|
781
|
-
};
|
|
782
|
-
}
|
|
783
|
-
counters.visibilityPatchEntered += entered.length;
|
|
784
|
-
counters.visibilityPatchExited += exited.length;
|
|
785
|
-
return {
|
|
786
|
-
complete: true,
|
|
787
|
-
entered: entered.length,
|
|
788
|
-
exited: exited.length,
|
|
789
|
-
visited
|
|
790
|
-
};
|
|
791
|
-
};
|
|
792
|
-
}
|
|
793
|
-
|
|
794
|
-
if (!existingGetDebugCounters) {
|
|
795
|
-
renderer.getDebugCounters = () => ({ ...counters });
|
|
796
|
-
}
|
|
797
|
-
if (!existingResetDebugCounters) {
|
|
798
|
-
renderer.resetDebugCounters = () => {
|
|
799
|
-
counters.sceneObjectsVisited = 0;
|
|
800
|
-
counters.visibilityPatchEntered = 0;
|
|
801
|
-
counters.visibilityPatchExited = 0;
|
|
802
|
-
};
|
|
803
|
-
}
|
|
804
|
-
renderer._nearCss3dHooksInstalled = BUILD_ID;
|
|
805
|
-
return true;
|
|
806
|
-
}
|
|
807
|
-
|
|
808
|
-
function applyVisibilityDiff(module, enteredIds, exitedIds) {
|
|
809
|
-
const fallback = (reason) => {
|
|
810
|
-
increment(module, 'css3d', 'visibilityPatchFallbacks');
|
|
811
|
-
return { complete: false, reason };
|
|
812
|
-
};
|
|
813
|
-
const renderer = module?.cssRenderer;
|
|
814
|
-
ensureCssRendererHooks(module);
|
|
815
|
-
if (!renderer || typeof renderer.applyVisibilityDiff !== 'function') return fallback('renderer-api-unavailable');
|
|
816
|
-
if (module._cssParentRepairNeeded === true) return fallback('parent-repair-pending');
|
|
817
|
-
if ((module._cssTransformDirtyIds?.size || 0) > 0) return fallback('transform-dirty');
|
|
818
|
-
|
|
819
|
-
const cssScene = module.cssScene || module.scene || null;
|
|
820
|
-
const enteredObjects = [];
|
|
821
|
-
const exitedObjects = [];
|
|
822
|
-
|
|
823
|
-
for (const value of enteredIds || []) {
|
|
824
|
-
const nodeId = String(value || '').trim();
|
|
825
|
-
const entry = nodeId ? module.nodeObjectsById?.get?.(nodeId) : null;
|
|
826
|
-
if (!entry) continue;
|
|
827
|
-
if (entry.currentType !== 'CSS') {
|
|
828
|
-
if (entry.cssObject?.visible === true) return fallback('entered-owner-mismatch');
|
|
829
|
-
continue;
|
|
830
|
-
}
|
|
831
|
-
if (!entry.cssObject?.element || entry.cssObject.visible !== true || entry.isCssDirty === true) {
|
|
832
|
-
return fallback('entered-owner-not-ready');
|
|
833
|
-
}
|
|
834
|
-
if (cssScene && entry.cssObject.parent !== cssScene) return fallback('entered-parent-mismatch');
|
|
835
|
-
enteredObjects.push(entry.cssObject);
|
|
836
|
-
}
|
|
837
|
-
|
|
838
|
-
for (const value of exitedIds || []) {
|
|
839
|
-
const nodeId = String(value || '').trim();
|
|
840
|
-
const entry = nodeId ? module.nodeObjectsById?.get?.(nodeId) : null;
|
|
841
|
-
const cssObject = entry?.cssObject || null;
|
|
842
|
-
if (!cssObject) continue;
|
|
843
|
-
if (entry.isCssDirty === true) return fallback('exited-content-dirty');
|
|
844
|
-
if (cssObject.parent === cssScene) {
|
|
845
|
-
exitedObjects.push(cssObject);
|
|
846
|
-
} else if (cssObject.visible === true || entry.currentType === 'CSS') {
|
|
847
|
-
return fallback('exited-owner-mismatch');
|
|
848
|
-
}
|
|
849
|
-
}
|
|
850
|
-
|
|
851
|
-
const result = renderer.applyVisibilityDiff(enteredObjects, exitedObjects);
|
|
852
|
-
if (result?.complete !== true) return fallback(result?.reason || 'renderer-patch-failed');
|
|
853
|
-
|
|
854
|
-
increment(module, 'css3d', 'visibilityPatchEntered', Number(result.entered || 0));
|
|
855
|
-
increment(module, 'css3d', 'visibilityPatchExited', Number(result.exited || 0));
|
|
856
|
-
increment(module, 'css3d', 'sceneObjectsVisited', Number(result.visited || 0));
|
|
857
|
-
return {
|
|
858
|
-
complete: true,
|
|
859
|
-
entered: Number(result.entered || 0),
|
|
860
|
-
exited: Number(result.exited || 0),
|
|
861
|
-
visited: Number(result.visited || 0)
|
|
862
|
-
};
|
|
863
|
-
}
|
|
864
|
-
|
|
865
|
-
function replaceGeometryIfSizeChanged(object, key, createGeometry) {
|
|
866
|
-
if (!object || typeof createGeometry !== 'function') return false;
|
|
867
|
-
object.userData ||= {};
|
|
868
|
-
if (object.geometry && object.userData.geometrySizeKey === key) return false;
|
|
869
|
-
const previous = object.geometry || null;
|
|
870
|
-
object.geometry = createGeometry();
|
|
871
|
-
object.userData.geometrySizeKey = key;
|
|
872
|
-
previous?.dispose?.();
|
|
873
|
-
return true;
|
|
874
|
-
}
|
|
875
|
-
|
|
876
|
-
window.MindMapCss3dHotPath = {
|
|
877
|
-
BUILD_ID,
|
|
878
|
-
applyVisibilityDiff,
|
|
879
|
-
collectSpatialRectCandidateIds,
|
|
880
|
-
createPointerHitContext,
|
|
881
|
-
ensureCssRendererHooks,
|
|
882
|
-
ensurePerfCounters,
|
|
883
|
-
getBoundedFallbackIds,
|
|
884
|
-
getContextCandidateIds,
|
|
885
|
-
getContextWorldPoint,
|
|
886
|
-
getDomRefs,
|
|
887
|
-
getDomStack,
|
|
888
|
-
getPerfSnapshot,
|
|
889
|
-
getProjectedClientFrame,
|
|
890
|
-
getSpatialGridKeysForBounds,
|
|
891
|
-
increment,
|
|
892
|
-
installOverlayGeometry,
|
|
893
|
-
installTextSource,
|
|
894
|
-
invalidateDomRefs,
|
|
895
|
-
invalidateDomRefsByCssObject,
|
|
896
|
-
noteUnavailableIndex,
|
|
897
|
-
recordHitCandidates,
|
|
898
|
-
replaceGeometryIfSizeChanged,
|
|
899
|
-
resetPerfCounters,
|
|
900
|
-
scheduleSpatialIndexRepair
|
|
901
|
-
};
|
|
902
|
-
})();
|
|
1
|
+
(function () {
|
|
2
|
+
'use strict';
|
|
3
|
+
|
|
4
|
+
const BUILD_ID = '20260724-near-css3d-hotpath-v001';
|
|
5
|
+
const projectedCorners = Array.from({ length: 4 }, () => new THREE.Vector3());
|
|
6
|
+
|
|
7
|
+
function createPerfCounters() {
|
|
8
|
+
return {
|
|
9
|
+
buildId: BUILD_ID,
|
|
10
|
+
hitTest: {
|
|
11
|
+
fullBoardFallbackCount: 0,
|
|
12
|
+
candidateSource: '',
|
|
13
|
+
candidateCount: 0,
|
|
14
|
+
elementsFromPointCalls: 0,
|
|
15
|
+
projectedFrameCalculations: 0
|
|
16
|
+
},
|
|
17
|
+
selection: {
|
|
18
|
+
nodesVisited: 0,
|
|
19
|
+
domQueries: 0
|
|
20
|
+
},
|
|
21
|
+
css3d: {
|
|
22
|
+
visibilityPatchEntered: 0,
|
|
23
|
+
visibilityPatchExited: 0,
|
|
24
|
+
visibilityPatchFallbacks: 0,
|
|
25
|
+
sceneObjectsVisited: 0
|
|
26
|
+
}
|
|
27
|
+
};
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
function ensurePerfCounters(module) {
|
|
31
|
+
if (!module) return null;
|
|
32
|
+
if (!module._nearCss3dPerfCounters ||
|
|
33
|
+
module._nearCss3dPerfCounters.buildId !== BUILD_ID) {
|
|
34
|
+
module._nearCss3dPerfCounters = createPerfCounters();
|
|
35
|
+
}
|
|
36
|
+
return module._nearCss3dPerfCounters;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
function increment(module, section, key, amount = 1) {
|
|
40
|
+
const counters = ensurePerfCounters(module);
|
|
41
|
+
const target = counters?.[section];
|
|
42
|
+
if (!target || !(key in target)) return;
|
|
43
|
+
target[key] = Number(target[key] || 0) + Number(amount || 0);
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
function recordHitCandidates(module, source, count) {
|
|
47
|
+
const hitTest = ensurePerfCounters(module)?.hitTest;
|
|
48
|
+
if (!hitTest) return;
|
|
49
|
+
hitTest.candidateSource = String(source || '');
|
|
50
|
+
hitTest.candidateCount = Math.max(0, Number(count || 0));
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
function getPerfSnapshot(module) {
|
|
54
|
+
const counters = ensurePerfCounters(module);
|
|
55
|
+
if (!counters) return null;
|
|
56
|
+
return {
|
|
57
|
+
buildId: counters.buildId,
|
|
58
|
+
hitTest: { ...counters.hitTest },
|
|
59
|
+
selection: { ...counters.selection },
|
|
60
|
+
css3d: { ...counters.css3d }
|
|
61
|
+
};
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
function resetPerfCounters(module) {
|
|
65
|
+
if (!module) return false;
|
|
66
|
+
module._nearCss3dPerfCounters = createPerfCounters();
|
|
67
|
+
return true;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
function createPointerHitContext(module, event, viewportMetrics = null) {
|
|
71
|
+
return {
|
|
72
|
+
module,
|
|
73
|
+
event,
|
|
74
|
+
clientX: Number(event?.clientX || 0),
|
|
75
|
+
clientY: Number(event?.clientY || 0),
|
|
76
|
+
viewportMetrics,
|
|
77
|
+
domStack: undefined,
|
|
78
|
+
worldPoint: undefined,
|
|
79
|
+
candidateIds: undefined,
|
|
80
|
+
candidateSource: '',
|
|
81
|
+
cssHit: undefined,
|
|
82
|
+
projectedFrames: new Map()
|
|
83
|
+
};
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
function getDomStack(module, context) {
|
|
87
|
+
if (!context) return [];
|
|
88
|
+
if (context.domStack !== undefined) return context.domStack;
|
|
89
|
+
increment(module, 'hitTest', 'elementsFromPointCalls');
|
|
90
|
+
context.domStack = typeof document !== 'undefined' &&
|
|
91
|
+
typeof document.elementsFromPoint === 'function'
|
|
92
|
+
? document.elementsFromPoint(context.clientX, context.clientY)
|
|
93
|
+
: [];
|
|
94
|
+
return context.domStack;
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
function getContextWorldPoint(context, factory) {
|
|
98
|
+
if (!context) return typeof factory === 'function' ? factory() : null;
|
|
99
|
+
if (context.worldPoint !== undefined) return context.worldPoint;
|
|
100
|
+
const point = typeof factory === 'function' ? factory() : null;
|
|
101
|
+
context.worldPoint = point
|
|
102
|
+
? new THREE.Vector3(Number(point.x || 0), Number(point.y || 0), Number(point.z || 0))
|
|
103
|
+
: null;
|
|
104
|
+
return context.worldPoint;
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
function getContextCandidateIds(module, context, factory, source = '') {
|
|
108
|
+
if (!context) {
|
|
109
|
+
const ids = typeof factory === 'function' ? factory() : [];
|
|
110
|
+
recordHitCandidates(module, source, Array.isArray(ids) ? ids.length : 0);
|
|
111
|
+
return ids;
|
|
112
|
+
}
|
|
113
|
+
if (context.candidateIds !== undefined) return context.candidateIds;
|
|
114
|
+
context.candidateIds = typeof factory === 'function' ? factory() : [];
|
|
115
|
+
context.candidateSource = String(source || '');
|
|
116
|
+
recordHitCandidates(
|
|
117
|
+
module,
|
|
118
|
+
context.candidateSource,
|
|
119
|
+
Array.isArray(context.candidateIds) ? context.candidateIds.length : 0
|
|
120
|
+
);
|
|
121
|
+
return context.candidateIds;
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
function getProjectedClientFrame(module, entry, context, viewportMetrics, cacheKey = null) {
|
|
125
|
+
if (!module?.camera || !entry) return null;
|
|
126
|
+
const metrics = context?.viewportMetrics || viewportMetrics || null;
|
|
127
|
+
if (!metrics || !(metrics.width > 0 && metrics.height > 0)) return null;
|
|
128
|
+
|
|
129
|
+
const frameKey = cacheKey || entry;
|
|
130
|
+
const cachedFrame = context?.projectedFrames?.get?.(frameKey);
|
|
131
|
+
if (cachedFrame) return cachedFrame;
|
|
132
|
+
|
|
133
|
+
const sourceObject = entry.glObject || entry.cssObject;
|
|
134
|
+
const position = sourceObject?.position;
|
|
135
|
+
if (!position) return null;
|
|
136
|
+
const width = Number(
|
|
137
|
+
entry.glObject?.userData?.worldWidth ??
|
|
138
|
+
entry.cssObject?.userData?.worldWidth ??
|
|
139
|
+
entry.model?.width ??
|
|
140
|
+
entry.model?.Width ??
|
|
141
|
+
0
|
|
142
|
+
);
|
|
143
|
+
const height = Number(
|
|
144
|
+
entry.glObject?.userData?.worldHeight ??
|
|
145
|
+
entry.cssObject?.userData?.worldHeight ??
|
|
146
|
+
entry.model?.height ??
|
|
147
|
+
entry.model?.Height ??
|
|
148
|
+
0
|
|
149
|
+
);
|
|
150
|
+
if (!(width > 0 && height > 0)) return null;
|
|
151
|
+
|
|
152
|
+
const z = Number(position.z || 0);
|
|
153
|
+
projectedCorners[0].set(position.x, position.y, z);
|
|
154
|
+
projectedCorners[1].set(position.x + width, position.y, z);
|
|
155
|
+
projectedCorners[2].set(position.x, position.y - height, z);
|
|
156
|
+
projectedCorners[3].set(position.x + width, position.y - height, z);
|
|
157
|
+
|
|
158
|
+
let left = Infinity;
|
|
159
|
+
let right = -Infinity;
|
|
160
|
+
let top = Infinity;
|
|
161
|
+
let bottom = -Infinity;
|
|
162
|
+
for (let i = 0; i < projectedCorners.length; i++) {
|
|
163
|
+
const corner = projectedCorners[i].project(module.camera);
|
|
164
|
+
const x = Number(metrics.left || 0) + ((corner.x + 1) * metrics.width / 2);
|
|
165
|
+
const y = Number(metrics.top || 0) + ((-corner.y + 1) * metrics.height / 2);
|
|
166
|
+
if (x < left) left = x;
|
|
167
|
+
if (x > right) right = x;
|
|
168
|
+
if (y < top) top = y;
|
|
169
|
+
if (y > bottom) bottom = y;
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
const frame = { left, right, top, bottom };
|
|
173
|
+
context?.projectedFrames?.set?.(frameKey, frame);
|
|
174
|
+
increment(module, 'hitTest', 'projectedFrameCalculations');
|
|
175
|
+
return frame;
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
function getDomRefs(entry, module = null, cssObjectOverride = null) {
|
|
179
|
+
const cssObject = cssObjectOverride || entry?.cssObject || null;
|
|
180
|
+
const wrapper = cssObject?.element || null;
|
|
181
|
+
if (!wrapper) return null;
|
|
182
|
+
const version = Number(entry?._css3dDomVersion || cssObject?.userData?._domVersion || 0);
|
|
183
|
+
const firstChild = wrapper.firstElementChild || null;
|
|
184
|
+
const cached = entry?.domRefs || cssObject?.userData?.domRefs || null;
|
|
185
|
+
if (cached?.wrapper === wrapper &&
|
|
186
|
+
cached.firstChild === firstChild &&
|
|
187
|
+
cached.version === version) {
|
|
188
|
+
return cached;
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
const query = (selector) => {
|
|
192
|
+
increment(module, 'selection', 'domQueries');
|
|
193
|
+
return wrapper.querySelector?.(selector) || null;
|
|
194
|
+
};
|
|
195
|
+
const refs = {
|
|
196
|
+
version,
|
|
197
|
+
wrapper,
|
|
198
|
+
firstChild,
|
|
199
|
+
innerRoot: query('.node-container, .map-node, .css3d-dynamic-node'),
|
|
200
|
+
response: query('.node-response, [id^="node-response-"]'),
|
|
201
|
+
textarea: query('textarea, [contenteditable="true"]'),
|
|
202
|
+
scrollable: query('.csv-table-scroll, .node-response, .note-content, .markdown-body, .code-body, .map-node-memo__body-view'),
|
|
203
|
+
memoTitle: query('.map-node-memo__title'),
|
|
204
|
+
memoBody: query('.map-node-memo__body'),
|
|
205
|
+
memoBodyView: query('.map-node-memo__body-view'),
|
|
206
|
+
resizeHandles: Array.from(wrapper.querySelectorAll?.('.resize-handle, [data-resize-handle]') || [])
|
|
207
|
+
};
|
|
208
|
+
if (entry) entry.domRefs = refs;
|
|
209
|
+
cssObject.userData ||= {};
|
|
210
|
+
cssObject.userData.domRefs = refs;
|
|
211
|
+
return refs;
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
function invalidateDomRefs(entry, cssObjectOverride = null) {
|
|
215
|
+
const cssObject = cssObjectOverride || entry?.cssObject || null;
|
|
216
|
+
const nextVersion = Math.max(
|
|
217
|
+
Number(entry?._css3dDomVersion || 0),
|
|
218
|
+
Number(cssObject?.userData?._domVersion || 0)
|
|
219
|
+
) + 1;
|
|
220
|
+
if (entry) {
|
|
221
|
+
entry._css3dDomVersion = nextVersion;
|
|
222
|
+
entry.domRefs = null;
|
|
223
|
+
}
|
|
224
|
+
if (cssObject) {
|
|
225
|
+
cssObject.userData ||= {};
|
|
226
|
+
cssObject.userData._domVersion = nextVersion;
|
|
227
|
+
cssObject.userData.domRefs = null;
|
|
228
|
+
}
|
|
229
|
+
return nextVersion;
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
function invalidateDomRefsByCssObject(module, cssObject, nodeId = '') {
|
|
233
|
+
const normalizedId = String(nodeId || cssObject?.userData?.nodeId || '').trim();
|
|
234
|
+
const entry = normalizedId ? module?.nodeObjectsById?.get?.(normalizedId) : null;
|
|
235
|
+
return invalidateDomRefs(entry, cssObject);
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
function installTextSource(helpers = {}) {
|
|
239
|
+
const styleState = new WeakMap();
|
|
240
|
+
const suspendedClass = 'mind-map-text-overlay-source-suspended';
|
|
241
|
+
const suspendedAttr = 'data-text-overlay-source-suspended';
|
|
242
|
+
|
|
243
|
+
function getModule() {
|
|
244
|
+
return helpers.getModule?.() || null;
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
function getTextOverlaySourceTargets(nodeEntry) {
|
|
248
|
+
if (!nodeEntry?.cssObject?.element || !helpers.supportsTextOverlay?.(nodeEntry.model)) return [];
|
|
249
|
+
const module = getModule();
|
|
250
|
+
const refs = getDomRefs(nodeEntry, module);
|
|
251
|
+
if (helpers.getTextOverlayRenderMode?.(nodeEntry) === 'memo') {
|
|
252
|
+
return [refs?.memoTitle, refs?.memoBodyView].filter(element =>
|
|
253
|
+
!!element && (element.style.display !== 'none' || element.offsetWidth > 0 || element.offsetHeight > 0));
|
|
254
|
+
}
|
|
255
|
+
const root = helpers.getTextOverlayRootElement?.(nodeEntry);
|
|
256
|
+
if (!root?.children?.length) return [];
|
|
257
|
+
return Array.from(root.children).filter(element =>
|
|
258
|
+
!!element &&
|
|
259
|
+
!element.classList?.contains?.('resize-handle') &&
|
|
260
|
+
(element.style.display !== 'none' || element.offsetWidth > 0 || element.offsetHeight > 0));
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
function ensureTextOverlaySourceStyleState(element) {
|
|
264
|
+
if (!element) return null;
|
|
265
|
+
let state = styleState.get(element) || null;
|
|
266
|
+
if (!state) {
|
|
267
|
+
state = {
|
|
268
|
+
opacity: element.style.opacity,
|
|
269
|
+
pointerEvents: element.style.pointerEvents,
|
|
270
|
+
userSelect: element.style.userSelect,
|
|
271
|
+
webkitUserSelect: element.style.webkitUserSelect,
|
|
272
|
+
caretColor: element.style.caretColor,
|
|
273
|
+
contentVisibility: element.style.contentVisibility,
|
|
274
|
+
containIntrinsicSize: element.style.containIntrinsicSize,
|
|
275
|
+
contain: element.style.contain
|
|
276
|
+
};
|
|
277
|
+
styleState.set(element, state);
|
|
278
|
+
}
|
|
279
|
+
return state;
|
|
280
|
+
}
|
|
281
|
+
|
|
282
|
+
function resetTextOverlaySourcePresentation(element) {
|
|
283
|
+
if (!element) return;
|
|
284
|
+
element.classList?.remove?.(suspendedClass);
|
|
285
|
+
element.removeAttribute?.(suspendedAttr);
|
|
286
|
+
element.style.opacity = '';
|
|
287
|
+
element.style.pointerEvents = '';
|
|
288
|
+
element.style.userSelect = '';
|
|
289
|
+
element.style.webkitUserSelect = '';
|
|
290
|
+
element.style.caretColor = '';
|
|
291
|
+
element.style.contentVisibility = '';
|
|
292
|
+
element.style.containIntrinsicSize = '';
|
|
293
|
+
element.style.contain = '';
|
|
294
|
+
}
|
|
295
|
+
|
|
296
|
+
function suspendTextOverlaySourceTarget(element) {
|
|
297
|
+
if (!element) return;
|
|
298
|
+
ensureTextOverlaySourceStyleState(element);
|
|
299
|
+
element.classList?.add?.(suspendedClass);
|
|
300
|
+
element.setAttribute?.(suspendedAttr, 'true');
|
|
301
|
+
element.style.pointerEvents = 'none';
|
|
302
|
+
element.style.userSelect = 'none';
|
|
303
|
+
element.style.webkitUserSelect = 'none';
|
|
304
|
+
element.style.caretColor = 'transparent';
|
|
305
|
+
element.style.opacity = '0';
|
|
306
|
+
element.style.contain = 'layout style paint';
|
|
307
|
+
element.style.contentVisibility = 'visible';
|
|
308
|
+
element.style.containIntrinsicSize = '';
|
|
309
|
+
}
|
|
310
|
+
|
|
311
|
+
function restoreTextOverlaySourceTarget(element) {
|
|
312
|
+
if (!element) return;
|
|
313
|
+
const state = styleState.get(element) || null;
|
|
314
|
+
if (!state) {
|
|
315
|
+
resetTextOverlaySourcePresentation(element);
|
|
316
|
+
return;
|
|
317
|
+
}
|
|
318
|
+
element.classList?.remove?.(suspendedClass);
|
|
319
|
+
element.removeAttribute?.(suspendedAttr);
|
|
320
|
+
Object.assign(element.style, state);
|
|
321
|
+
styleState.delete(element);
|
|
322
|
+
}
|
|
323
|
+
|
|
324
|
+
function stripTextOverlayPresentationOverrides(root) {
|
|
325
|
+
if (!root) return;
|
|
326
|
+
if (root.hasAttribute?.(suspendedAttr) || root.classList?.contains?.(suspendedClass)) {
|
|
327
|
+
resetTextOverlaySourcePresentation(root);
|
|
328
|
+
}
|
|
329
|
+
root.querySelectorAll?.(`[${suspendedAttr}], .${suspendedClass}`)
|
|
330
|
+
?.forEach?.(resetTextOverlaySourcePresentation);
|
|
331
|
+
}
|
|
332
|
+
|
|
333
|
+
function getNativeTextSelectionSourceNodeId(module) {
|
|
334
|
+
return String(module?._nativeTextSelectionSourceNodeId || '').trim();
|
|
335
|
+
}
|
|
336
|
+
|
|
337
|
+
function hasNativeTextSelectionSource(module, nodeId = null) {
|
|
338
|
+
const activeId = getNativeTextSelectionSourceNodeId(module);
|
|
339
|
+
if (!activeId) return false;
|
|
340
|
+
return nodeId === null || activeId === String(nodeId || '').trim();
|
|
341
|
+
}
|
|
342
|
+
|
|
343
|
+
function setNativeTextSelectionOwnerClass(module, nodeId = null) {
|
|
344
|
+
if (!module) return false;
|
|
345
|
+
const nextId = String(nodeId || '').trim();
|
|
346
|
+
const previousId = String(module._nativeTextSelectionOwnerNodeId || '').trim();
|
|
347
|
+
if (previousId === nextId) return true;
|
|
348
|
+
|
|
349
|
+
const getWrapper = (id) => {
|
|
350
|
+
const entry = id ? module.nodeObjectsById?.get?.(id) : null;
|
|
351
|
+
return getDomRefs(entry, module)?.wrapper || null;
|
|
352
|
+
};
|
|
353
|
+
const previousWrapper = getWrapper(previousId);
|
|
354
|
+
const nextWrapper = getWrapper(nextId);
|
|
355
|
+
if (previousWrapper) {
|
|
356
|
+
previousWrapper.classList?.remove?.('is-text-selection-owner');
|
|
357
|
+
increment(module, 'selection', 'nodesVisited');
|
|
358
|
+
}
|
|
359
|
+
if (nextWrapper) {
|
|
360
|
+
nextWrapper.classList?.add?.('is-text-selection-owner');
|
|
361
|
+
increment(module, 'selection', 'nodesVisited');
|
|
362
|
+
}
|
|
363
|
+
module._nativeTextSelectionOwnerNodeId = nextId || null;
|
|
364
|
+
return true;
|
|
365
|
+
}
|
|
366
|
+
|
|
367
|
+
function activateNativeTextSelectionSource(module, nodeId) {
|
|
368
|
+
const id = String(nodeId || '').trim();
|
|
369
|
+
if (!module || !id) return false;
|
|
370
|
+
module._nativeTextSelectionSourceNodeId = id;
|
|
371
|
+
setNativeTextSelectionOwnerClass(module, id);
|
|
372
|
+
helpers.ensureTextOverlaySourceVisible?.(module, id);
|
|
373
|
+
return true;
|
|
374
|
+
}
|
|
375
|
+
|
|
376
|
+
function clearNativeTextSelectionSource(module, nodeId = null) {
|
|
377
|
+
const activeId = getNativeTextSelectionSourceNodeId(module);
|
|
378
|
+
const requestedId = nodeId === null ? activeId : String(nodeId || '').trim();
|
|
379
|
+
if (!module || !activeId || !requestedId || activeId !== requestedId) return false;
|
|
380
|
+
module._nativeTextSelectionSourceNodeId = null;
|
|
381
|
+
setNativeTextSelectionOwnerClass(module, null);
|
|
382
|
+
return true;
|
|
383
|
+
}
|
|
384
|
+
|
|
385
|
+
function isTextOverlaySelectionNode(module, nodeEntry) {
|
|
386
|
+
const contentType = String(nodeEntry?.model?.contentType ?? nodeEntry?.model?.ContentType ?? '').toLowerCase();
|
|
387
|
+
if (contentType !== 'text' && contentType !== 'markdown') return false;
|
|
388
|
+
const nodeId = String(helpers.getNodeId?.(nodeEntry?.model) || '').trim();
|
|
389
|
+
return hasNativeTextSelectionSource(module, nodeId);
|
|
390
|
+
}
|
|
391
|
+
|
|
392
|
+
function setTextOverlaySourceActive(nodeEntry, isActive) {
|
|
393
|
+
if (helpers.isCss3dMediaNode?.(nodeEntry?.model)) {
|
|
394
|
+
helpers.restoreCss3dMediaOverlayState?.(nodeEntry.model, nodeEntry.cssObject);
|
|
395
|
+
nodeEntry._textOverlayActive = false;
|
|
396
|
+
nodeEntry._css3dSourceSuspended = false;
|
|
397
|
+
return;
|
|
398
|
+
}
|
|
399
|
+
const host = helpers.getTextOverlayHostElement?.(nodeEntry);
|
|
400
|
+
if (!host?.classList) return;
|
|
401
|
+
host.classList.toggle('mind-map-text-overlay-active', !!isActive);
|
|
402
|
+
getTextOverlaySourceTargets(nodeEntry).forEach(target => {
|
|
403
|
+
if (isActive) suspendTextOverlaySourceTarget(target);
|
|
404
|
+
else restoreTextOverlaySourceTarget(target);
|
|
405
|
+
});
|
|
406
|
+
nodeEntry._textOverlayActive = nodeEntry._css3dSourceSuspended = !!isActive;
|
|
407
|
+
}
|
|
408
|
+
|
|
409
|
+
return {
|
|
410
|
+
getTextOverlaySourceTargets,
|
|
411
|
+
ensureTextOverlaySourceStyleState,
|
|
412
|
+
resetTextOverlaySourcePresentation,
|
|
413
|
+
suspendTextOverlaySourceTarget,
|
|
414
|
+
restoreTextOverlaySourceTarget,
|
|
415
|
+
stripTextOverlayPresentationOverrides,
|
|
416
|
+
getNativeTextSelectionSourceNodeId,
|
|
417
|
+
hasNativeTextSelectionSource,
|
|
418
|
+
setNativeTextSelectionOwnerClass,
|
|
419
|
+
activateNativeTextSelectionSource,
|
|
420
|
+
clearNativeTextSelectionSource,
|
|
421
|
+
isTextOverlaySelectionNode,
|
|
422
|
+
setTextOverlaySourceActive
|
|
423
|
+
};
|
|
424
|
+
}
|
|
425
|
+
|
|
426
|
+
function installOverlayGeometry(helpers = {}) {
|
|
427
|
+
function getTextOverlayPlacementInfo(module, element) {
|
|
428
|
+
if (!module?.container || !element) return null;
|
|
429
|
+
const rect = element.getBoundingClientRect();
|
|
430
|
+
const containerRect = module.container.getBoundingClientRect();
|
|
431
|
+
const width = Math.max(0, rect.width || 0);
|
|
432
|
+
const height = Math.max(0, rect.height || 0);
|
|
433
|
+
if (width < 1 || height < 1) return null;
|
|
434
|
+
const left = rect.left - containerRect.left;
|
|
435
|
+
const top = rect.top - containerRect.top;
|
|
436
|
+
return {
|
|
437
|
+
left,
|
|
438
|
+
top,
|
|
439
|
+
width,
|
|
440
|
+
height,
|
|
441
|
+
baseWidth: Math.max(1, Number(element.offsetWidth || width || 1)),
|
|
442
|
+
baseHeight: Math.max(1, Number(element.offsetHeight || height || 1)),
|
|
443
|
+
right: left + width,
|
|
444
|
+
bottom: top + height
|
|
445
|
+
};
|
|
446
|
+
}
|
|
447
|
+
|
|
448
|
+
function doesTextOverlayRectOverlap(a, b, padding = 0) {
|
|
449
|
+
if (!a || !b) return false;
|
|
450
|
+
const inset = Number.isFinite(Number(padding)) ? Number(padding) : 0;
|
|
451
|
+
return !(
|
|
452
|
+
(a.left + a.width + inset) < b.left ||
|
|
453
|
+
(b.left + b.width + inset) < a.left ||
|
|
454
|
+
(a.top + a.height + inset) < b.top ||
|
|
455
|
+
(b.top + b.height + inset) < a.top
|
|
456
|
+
);
|
|
457
|
+
}
|
|
458
|
+
|
|
459
|
+
function isTextOverlayPlacementVisible(module, placement, options = {}) {
|
|
460
|
+
if (!module?.container || !placement) return false;
|
|
461
|
+
const { ignoreMinSize = false } = options;
|
|
462
|
+
if (!ignoreMinSize &&
|
|
463
|
+
(placement.width < Number(helpers.minWidth || 0) ||
|
|
464
|
+
placement.height < Number(helpers.minHeight || 0))) {
|
|
465
|
+
return false;
|
|
466
|
+
}
|
|
467
|
+
const maxWidth = Number(module.container.clientWidth || 0);
|
|
468
|
+
const maxHeight = Number(module.container.clientHeight || 0);
|
|
469
|
+
if (!(maxWidth > 0) || !(maxHeight > 0)) return false;
|
|
470
|
+
return !(
|
|
471
|
+
placement.right < 0 ||
|
|
472
|
+
placement.left > maxWidth ||
|
|
473
|
+
placement.bottom < 0 ||
|
|
474
|
+
placement.top > maxHeight
|
|
475
|
+
);
|
|
476
|
+
}
|
|
477
|
+
|
|
478
|
+
function getTextOverlayPriority(module, nodeEntry) {
|
|
479
|
+
const nodeModel = nodeEntry?.model;
|
|
480
|
+
const nodeId = String(helpers.getNodeId?.(nodeModel) || '').trim();
|
|
481
|
+
if (!nodeModel || !nodeId) return Number.NEGATIVE_INFINITY;
|
|
482
|
+
let priority = 0;
|
|
483
|
+
if (String(module?.selectedNodeIdJs || '').trim() === nodeId) priority += 100000;
|
|
484
|
+
else if (module?.multiSelectedNodeIds?.has?.(nodeId)) priority += 50000;
|
|
485
|
+
const width = Math.max(1, Number(nodeModel.width || nodeModel.Width || 0));
|
|
486
|
+
const height = Math.max(1, Number(nodeModel.height || nodeModel.Height || 0));
|
|
487
|
+
priority += Math.min(6000, (width * height) / 18);
|
|
488
|
+
if (module?.camera) {
|
|
489
|
+
const centerX = Number(nodeModel.positionX ?? nodeModel.PositionX ?? nodeModel.x ?? nodeModel.X ?? 0) + (width * 0.5);
|
|
490
|
+
const centerY = Number(nodeModel.positionY ?? nodeModel.PositionY ?? nodeModel.y ?? nodeModel.Y ?? 0) - (height * 0.5);
|
|
491
|
+
priority += Math.max(
|
|
492
|
+
0,
|
|
493
|
+
24000 -
|
|
494
|
+
Math.abs(centerX - Number(module.camera.position?.x || 0)) -
|
|
495
|
+
Math.abs(centerY - Number(module.camera.position?.y || 0))
|
|
496
|
+
);
|
|
497
|
+
}
|
|
498
|
+
const zIndex = Number(nodeEntry?.cssObject?.element?.style?.zIndex || 0);
|
|
499
|
+
if (Number.isFinite(zIndex)) priority += zIndex * 10;
|
|
500
|
+
return priority;
|
|
501
|
+
}
|
|
502
|
+
|
|
503
|
+
function isAlwaysTextOverlayNode(nodeEntry) {
|
|
504
|
+
const contentType = String(
|
|
505
|
+
nodeEntry?.model?.contentType ??
|
|
506
|
+
nodeEntry?.model?.ContentType ??
|
|
507
|
+
''
|
|
508
|
+
).toLowerCase();
|
|
509
|
+
return contentType === 'markdown' || contentType === 'text';
|
|
510
|
+
}
|
|
511
|
+
|
|
512
|
+
function getTextOverlayContentSignature(nodeEntry) {
|
|
513
|
+
const model = nodeEntry?.model || {};
|
|
514
|
+
const contentType = String(model.contentType ?? model.ContentType ?? '').toLowerCase();
|
|
515
|
+
const prompt = String(model.prompt ?? model.Prompt ?? '');
|
|
516
|
+
const response = String(model.response ?? model.Response ?? '');
|
|
517
|
+
const isLoading = (model.isLoading ?? model.IsLoading ?? false) ? '1' : '0';
|
|
518
|
+
const width = Math.max(0, Number(model.width ?? model.Width ?? 0));
|
|
519
|
+
const height = Math.max(0, Number(model.height ?? model.Height ?? 0));
|
|
520
|
+
return `${contentType}||${prompt}||${response}||${isLoading}||${width}||${height}`;
|
|
521
|
+
}
|
|
522
|
+
|
|
523
|
+
function getTextOverlayLayoutSignature(sourceElement, mode = 'full', hostPlacement = null) {
|
|
524
|
+
if (!sourceElement) return '';
|
|
525
|
+
if (mode === 'memo') {
|
|
526
|
+
const titleInput = sourceElement.querySelector('.map-node-memo__title');
|
|
527
|
+
const bodyView = sourceElement.querySelector('.map-node-memo__body-view');
|
|
528
|
+
const hostWidth = Math.round(Number(hostPlacement?.baseWidth || sourceElement.offsetWidth || 0));
|
|
529
|
+
const hostHeight = Math.round(Number(hostPlacement?.baseHeight || sourceElement.offsetHeight || 0));
|
|
530
|
+
const titleSignature = titleInput
|
|
531
|
+
? `${titleInput.offsetLeft}:${titleInput.offsetTop}:${titleInput.offsetWidth}:${titleInput.offsetHeight}:${titleInput.style.display}`
|
|
532
|
+
: 'title:none';
|
|
533
|
+
const bodySignature = bodyView
|
|
534
|
+
? `${bodyView.offsetLeft}:${bodyView.offsetTop}:${bodyView.offsetWidth}:${bodyView.offsetHeight}:${bodyView.style.display}`
|
|
535
|
+
: 'body:none';
|
|
536
|
+
return `${mode}||${hostWidth}x${hostHeight}||${titleSignature}||${bodySignature}`;
|
|
537
|
+
}
|
|
538
|
+
const rootWidth = Math.round(Number(sourceElement.offsetWidth || 0));
|
|
539
|
+
const rootHeight = Math.round(Number(sourceElement.offsetHeight || 0));
|
|
540
|
+
const childSignature = Array.from(sourceElement.children || [])
|
|
541
|
+
.map(child => `${child.tagName}:${child.offsetWidth}:${child.offsetHeight}:${child.style.display}`)
|
|
542
|
+
.join('|');
|
|
543
|
+
return `${mode}||${rootWidth}x${rootHeight}||${childSignature}`;
|
|
544
|
+
}
|
|
545
|
+
|
|
546
|
+
return {
|
|
547
|
+
getTextOverlayPlacementInfo,
|
|
548
|
+
doesTextOverlayRectOverlap,
|
|
549
|
+
isTextOverlayPlacementVisible,
|
|
550
|
+
getTextOverlayPriority,
|
|
551
|
+
isAlwaysTextOverlayNode,
|
|
552
|
+
getTextOverlayContentSignature,
|
|
553
|
+
getTextOverlayLayoutSignature
|
|
554
|
+
};
|
|
555
|
+
}
|
|
556
|
+
|
|
557
|
+
function getNodeBounds(entry) {
|
|
558
|
+
const shared = window.MindMapNodeBounds?.getNodeWorldBounds?.(entry);
|
|
559
|
+
if (shared) return shared;
|
|
560
|
+
const model = entry?.model || null;
|
|
561
|
+
const object = entry?.glObject || entry?.cssObject || null;
|
|
562
|
+
if (!model && !object) return null;
|
|
563
|
+
const width = Math.max(1, Number(
|
|
564
|
+
entry?.glObject?.userData?.worldWidth ??
|
|
565
|
+
entry?.cssObject?.userData?.worldWidth ??
|
|
566
|
+
model?.width ??
|
|
567
|
+
model?.Width ??
|
|
568
|
+
400
|
|
569
|
+
));
|
|
570
|
+
const height = Math.max(1, Number(
|
|
571
|
+
entry?.glObject?.userData?.worldHeight ??
|
|
572
|
+
entry?.cssObject?.userData?.worldHeight ??
|
|
573
|
+
model?.height ??
|
|
574
|
+
model?.Height ??
|
|
575
|
+
200
|
|
576
|
+
));
|
|
577
|
+
const x = Number(object?.position?.x ?? model?.positionX ?? model?.x ?? 0);
|
|
578
|
+
const y = Number(object?.position?.y ?? model?.positionY ?? model?.y ?? 0);
|
|
579
|
+
return { minX: x, maxX: x + width, minY: y - height, maxY: y };
|
|
580
|
+
}
|
|
581
|
+
|
|
582
|
+
function getSpatialGridKeysForBounds(module, entry) {
|
|
583
|
+
const bounds = getNodeBounds(entry);
|
|
584
|
+
if (!bounds) return new Set();
|
|
585
|
+
const cellSize = Math.max(1, Number(module?.GRID_CELL_SIZE || 500));
|
|
586
|
+
const keys = new Set();
|
|
587
|
+
const startX = Math.floor(bounds.minX / cellSize);
|
|
588
|
+
const endX = Math.floor(bounds.maxX / cellSize);
|
|
589
|
+
const startY = Math.floor(bounds.minY / cellSize);
|
|
590
|
+
const endY = Math.floor(bounds.maxY / cellSize);
|
|
591
|
+
for (let x = startX; x <= endX; x++) {
|
|
592
|
+
for (let y = startY; y <= endY; y++) keys.add(`${x}:${y}`);
|
|
593
|
+
}
|
|
594
|
+
return keys;
|
|
595
|
+
}
|
|
596
|
+
|
|
597
|
+
function setEntrySpatialKeys(entry, keys) {
|
|
598
|
+
if (!entry) return;
|
|
599
|
+
entry._spatialGridKeys = keys;
|
|
600
|
+
if (entry.glObject) {
|
|
601
|
+
entry.glObject.userData ||= {};
|
|
602
|
+
entry.glObject.userData.spatialGridKeys = keys;
|
|
603
|
+
}
|
|
604
|
+
if (entry.cssObject) {
|
|
605
|
+
entry.cssObject.userData ||= {};
|
|
606
|
+
entry.cssObject.userData.spatialGridKeys = keys;
|
|
607
|
+
}
|
|
608
|
+
}
|
|
609
|
+
|
|
610
|
+
function collectSpatialRectCandidateIds(module, rect) {
|
|
611
|
+
if (!module?.spatialGrid || module._spatialIndexRepairState || !rect) return null;
|
|
612
|
+
const cellSize = Math.max(1, Number(module.GRID_CELL_SIZE || 500));
|
|
613
|
+
const ids = [];
|
|
614
|
+
const seen = new Set();
|
|
615
|
+
const startX = Math.floor(Number(rect.left || 0) / cellSize);
|
|
616
|
+
const endX = Math.floor(Number(rect.right || 0) / cellSize);
|
|
617
|
+
const startY = Math.floor(Number(rect.bottom || 0) / cellSize);
|
|
618
|
+
const endY = Math.floor(Number(rect.top || 0) / cellSize);
|
|
619
|
+
for (let x = startX; x <= endX; x++) {
|
|
620
|
+
for (let y = startY; y <= endY; y++) {
|
|
621
|
+
module.spatialGrid.get(`${x}:${y}`)?.forEach?.(nodeId => {
|
|
622
|
+
const id = String(nodeId || '').trim();
|
|
623
|
+
if (id && !seen.has(id)) {
|
|
624
|
+
seen.add(id);
|
|
625
|
+
ids.push(id);
|
|
626
|
+
}
|
|
627
|
+
});
|
|
628
|
+
}
|
|
629
|
+
}
|
|
630
|
+
return ids;
|
|
631
|
+
}
|
|
632
|
+
|
|
633
|
+
function getBoundedFallbackIds(module) {
|
|
634
|
+
const ids = new Set();
|
|
635
|
+
const add = (value) => {
|
|
636
|
+
const id = String(value || '').trim();
|
|
637
|
+
if (id && module?.nodeObjectsById?.has?.(id)) ids.add(id);
|
|
638
|
+
};
|
|
639
|
+
module?._visibleIds?.forEach?.(add);
|
|
640
|
+
module?._prevVisibleIds?.forEach?.(add);
|
|
641
|
+
add(module?.selectedNodeIdJs);
|
|
642
|
+
module?.multiSelectedNodeIds?.forEach?.(add);
|
|
643
|
+
add(module?.draggedNodeId);
|
|
644
|
+
add(module?._nativeTextSelectionSourceNodeId);
|
|
645
|
+
add(module?._editingOverlayState?.nodeId);
|
|
646
|
+
add(module?._textOverlayV2State?.editing?.nodeId);
|
|
647
|
+
module?.lodRenderer?._nearCssVisibleIds?.forEach?.(add);
|
|
648
|
+
module?.lodRenderer?._lodImageCssFallbackNodeIds?.forEach?.(add);
|
|
649
|
+
module?.lodRenderer?._lodTemplateCssNodeIds?.forEach?.(add);
|
|
650
|
+
return Array.from(ids);
|
|
651
|
+
}
|
|
652
|
+
|
|
653
|
+
function scheduleSpatialIndexRepair(module, reason = 'index-unavailable') {
|
|
654
|
+
if (!module?.nodeObjectsById || module._spatialIndexRepairState) return false;
|
|
655
|
+
const ownerMap = module.nodeObjectsById;
|
|
656
|
+
const state = {
|
|
657
|
+
ownerMap,
|
|
658
|
+
iterator: ownerMap.entries(),
|
|
659
|
+
reason: String(reason || 'index-unavailable'),
|
|
660
|
+
processed: 0
|
|
661
|
+
};
|
|
662
|
+
module._spatialIndexRepairState = state;
|
|
663
|
+
module.spatialGrid = new Map();
|
|
664
|
+
window.MindCanvasTrace?.emit?.('hitTest.spatialRepairScheduled', {
|
|
665
|
+
reason: state.reason,
|
|
666
|
+
nodeCount: ownerMap.size
|
|
667
|
+
});
|
|
668
|
+
|
|
669
|
+
const schedule = (callback) => {
|
|
670
|
+
if (typeof requestIdleCallback === 'function') requestIdleCallback(callback, { timeout: 120 });
|
|
671
|
+
else setTimeout(() => callback(null), 0);
|
|
672
|
+
};
|
|
673
|
+
const run = (deadline) => {
|
|
674
|
+
if (module._spatialIndexRepairState !== state || module.nodeObjectsById !== ownerMap) return;
|
|
675
|
+
let processedThisSlice = 0;
|
|
676
|
+
while (processedThisSlice < 128 &&
|
|
677
|
+
(!deadline?.timeRemaining || deadline.timeRemaining() > 1)) {
|
|
678
|
+
const next = state.iterator.next();
|
|
679
|
+
if (next.done) {
|
|
680
|
+
module._spatialIndexRepairState = null;
|
|
681
|
+
module.logicWorkerBridge?.rebuildNodeTables?.(module, {
|
|
682
|
+
reason: 'hit-test-spatial-repair'
|
|
683
|
+
});
|
|
684
|
+
window.MindCanvasTrace?.emit?.('hitTest.spatialRepairCompleted', {
|
|
685
|
+
reason: state.reason,
|
|
686
|
+
processed: state.processed
|
|
687
|
+
});
|
|
688
|
+
return;
|
|
689
|
+
}
|
|
690
|
+
const [nodeId, entry] = next.value;
|
|
691
|
+
const keys = getSpatialGridKeysForBounds(module, entry);
|
|
692
|
+
keys.forEach(key => {
|
|
693
|
+
if (!module.spatialGrid.has(key)) module.spatialGrid.set(key, new Set());
|
|
694
|
+
module.spatialGrid.get(key).add(nodeId);
|
|
695
|
+
});
|
|
696
|
+
setEntrySpatialKeys(entry, keys);
|
|
697
|
+
processedThisSlice++;
|
|
698
|
+
state.processed++;
|
|
699
|
+
}
|
|
700
|
+
schedule(run);
|
|
701
|
+
};
|
|
702
|
+
schedule(run);
|
|
703
|
+
return true;
|
|
704
|
+
}
|
|
705
|
+
|
|
706
|
+
function noteUnavailableIndex(module, reason = 'index-unavailable') {
|
|
707
|
+
window.MindCanvasTrace?.emit?.('hitTest.fullBoardFallback', {
|
|
708
|
+
blocked: true,
|
|
709
|
+
reason
|
|
710
|
+
});
|
|
711
|
+
scheduleSpatialIndexRepair(module, reason);
|
|
712
|
+
}
|
|
713
|
+
|
|
714
|
+
function ensureCssRendererHooks(module) {
|
|
715
|
+
const renderer = module?.cssRenderer || null;
|
|
716
|
+
if (!renderer) return false;
|
|
717
|
+
if (renderer._nearCss3dHooksInstalled === BUILD_ID) return true;
|
|
718
|
+
|
|
719
|
+
const counters = {
|
|
720
|
+
sceneObjectsVisited: 0,
|
|
721
|
+
visibilityPatchEntered: 0,
|
|
722
|
+
visibilityPatchExited: 0
|
|
723
|
+
};
|
|
724
|
+
const existingGetDebugCounters =
|
|
725
|
+
typeof renderer.getDebugCounters === 'function'
|
|
726
|
+
? renderer.getDebugCounters.bind(renderer)
|
|
727
|
+
: null;
|
|
728
|
+
const existingResetDebugCounters =
|
|
729
|
+
typeof renderer.resetDebugCounters === 'function'
|
|
730
|
+
? renderer.resetDebugCounters.bind(renderer)
|
|
731
|
+
: null;
|
|
732
|
+
const originalRender =
|
|
733
|
+
typeof renderer.render === 'function'
|
|
734
|
+
? renderer.render.bind(renderer)
|
|
735
|
+
: null;
|
|
736
|
+
|
|
737
|
+
if (!existingGetDebugCounters && originalRender) {
|
|
738
|
+
renderer.render = (scene, camera) => {
|
|
739
|
+
let visited = 0;
|
|
740
|
+
if (module.renderDebugFlags?.enableFramePerfProbe === true) {
|
|
741
|
+
scene?.traverse?.(() => {
|
|
742
|
+
visited++;
|
|
743
|
+
});
|
|
744
|
+
}
|
|
745
|
+
const result = originalRender(scene, camera);
|
|
746
|
+
counters.sceneObjectsVisited += visited;
|
|
747
|
+
return result;
|
|
748
|
+
};
|
|
749
|
+
}
|
|
750
|
+
|
|
751
|
+
if (typeof renderer.applyVisibilityDiff !== 'function') {
|
|
752
|
+
renderer.applyVisibilityDiff = (enteredObjects, exitedObjects) => {
|
|
753
|
+
const entered = Array.isArray(enteredObjects) ? enteredObjects : [];
|
|
754
|
+
const exited = Array.isArray(exitedObjects) ? exitedObjects : [];
|
|
755
|
+
const cameraElement = renderer.getCameraElement?.() || null;
|
|
756
|
+
let visited = 0;
|
|
757
|
+
const patchObject = (object) => {
|
|
758
|
+
if (!object?.isCSS3DObject || !object.element) return;
|
|
759
|
+
object.updateMatrixWorld?.(true);
|
|
760
|
+
const layoutPrepared =
|
|
761
|
+
object.userData?._residentTransitionPrepared === true ||
|
|
762
|
+
object.userData?._fullResFringePrepared === true;
|
|
763
|
+
object.element.style.removeProperty?.('display');
|
|
764
|
+
if (object.visible !== true && layoutPrepared !== true) {
|
|
765
|
+
object.element.style.display = 'none';
|
|
766
|
+
}
|
|
767
|
+
if (cameraElement && object.element.parentNode !== cameraElement) {
|
|
768
|
+
cameraElement.appendChild(object.element);
|
|
769
|
+
}
|
|
770
|
+
visited++;
|
|
771
|
+
};
|
|
772
|
+
try {
|
|
773
|
+
exited.forEach(patchObject);
|
|
774
|
+
entered.forEach(patchObject);
|
|
775
|
+
} catch (error) {
|
|
776
|
+
return {
|
|
777
|
+
complete: false,
|
|
778
|
+
reason: 'visibility-diff-exception',
|
|
779
|
+
visited,
|
|
780
|
+
error
|
|
781
|
+
};
|
|
782
|
+
}
|
|
783
|
+
counters.visibilityPatchEntered += entered.length;
|
|
784
|
+
counters.visibilityPatchExited += exited.length;
|
|
785
|
+
return {
|
|
786
|
+
complete: true,
|
|
787
|
+
entered: entered.length,
|
|
788
|
+
exited: exited.length,
|
|
789
|
+
visited
|
|
790
|
+
};
|
|
791
|
+
};
|
|
792
|
+
}
|
|
793
|
+
|
|
794
|
+
if (!existingGetDebugCounters) {
|
|
795
|
+
renderer.getDebugCounters = () => ({ ...counters });
|
|
796
|
+
}
|
|
797
|
+
if (!existingResetDebugCounters) {
|
|
798
|
+
renderer.resetDebugCounters = () => {
|
|
799
|
+
counters.sceneObjectsVisited = 0;
|
|
800
|
+
counters.visibilityPatchEntered = 0;
|
|
801
|
+
counters.visibilityPatchExited = 0;
|
|
802
|
+
};
|
|
803
|
+
}
|
|
804
|
+
renderer._nearCss3dHooksInstalled = BUILD_ID;
|
|
805
|
+
return true;
|
|
806
|
+
}
|
|
807
|
+
|
|
808
|
+
function applyVisibilityDiff(module, enteredIds, exitedIds) {
|
|
809
|
+
const fallback = (reason) => {
|
|
810
|
+
increment(module, 'css3d', 'visibilityPatchFallbacks');
|
|
811
|
+
return { complete: false, reason };
|
|
812
|
+
};
|
|
813
|
+
const renderer = module?.cssRenderer;
|
|
814
|
+
ensureCssRendererHooks(module);
|
|
815
|
+
if (!renderer || typeof renderer.applyVisibilityDiff !== 'function') return fallback('renderer-api-unavailable');
|
|
816
|
+
if (module._cssParentRepairNeeded === true) return fallback('parent-repair-pending');
|
|
817
|
+
if ((module._cssTransformDirtyIds?.size || 0) > 0) return fallback('transform-dirty');
|
|
818
|
+
|
|
819
|
+
const cssScene = module.cssScene || module.scene || null;
|
|
820
|
+
const enteredObjects = [];
|
|
821
|
+
const exitedObjects = [];
|
|
822
|
+
|
|
823
|
+
for (const value of enteredIds || []) {
|
|
824
|
+
const nodeId = String(value || '').trim();
|
|
825
|
+
const entry = nodeId ? module.nodeObjectsById?.get?.(nodeId) : null;
|
|
826
|
+
if (!entry) continue;
|
|
827
|
+
if (entry.currentType !== 'CSS') {
|
|
828
|
+
if (entry.cssObject?.visible === true) return fallback('entered-owner-mismatch');
|
|
829
|
+
continue;
|
|
830
|
+
}
|
|
831
|
+
if (!entry.cssObject?.element || entry.cssObject.visible !== true || entry.isCssDirty === true) {
|
|
832
|
+
return fallback('entered-owner-not-ready');
|
|
833
|
+
}
|
|
834
|
+
if (cssScene && entry.cssObject.parent !== cssScene) return fallback('entered-parent-mismatch');
|
|
835
|
+
enteredObjects.push(entry.cssObject);
|
|
836
|
+
}
|
|
837
|
+
|
|
838
|
+
for (const value of exitedIds || []) {
|
|
839
|
+
const nodeId = String(value || '').trim();
|
|
840
|
+
const entry = nodeId ? module.nodeObjectsById?.get?.(nodeId) : null;
|
|
841
|
+
const cssObject = entry?.cssObject || null;
|
|
842
|
+
if (!cssObject) continue;
|
|
843
|
+
if (entry.isCssDirty === true) return fallback('exited-content-dirty');
|
|
844
|
+
if (cssObject.parent === cssScene) {
|
|
845
|
+
exitedObjects.push(cssObject);
|
|
846
|
+
} else if (cssObject.visible === true || entry.currentType === 'CSS') {
|
|
847
|
+
return fallback('exited-owner-mismatch');
|
|
848
|
+
}
|
|
849
|
+
}
|
|
850
|
+
|
|
851
|
+
const result = renderer.applyVisibilityDiff(enteredObjects, exitedObjects);
|
|
852
|
+
if (result?.complete !== true) return fallback(result?.reason || 'renderer-patch-failed');
|
|
853
|
+
|
|
854
|
+
increment(module, 'css3d', 'visibilityPatchEntered', Number(result.entered || 0));
|
|
855
|
+
increment(module, 'css3d', 'visibilityPatchExited', Number(result.exited || 0));
|
|
856
|
+
increment(module, 'css3d', 'sceneObjectsVisited', Number(result.visited || 0));
|
|
857
|
+
return {
|
|
858
|
+
complete: true,
|
|
859
|
+
entered: Number(result.entered || 0),
|
|
860
|
+
exited: Number(result.exited || 0),
|
|
861
|
+
visited: Number(result.visited || 0)
|
|
862
|
+
};
|
|
863
|
+
}
|
|
864
|
+
|
|
865
|
+
function replaceGeometryIfSizeChanged(object, key, createGeometry) {
|
|
866
|
+
if (!object || typeof createGeometry !== 'function') return false;
|
|
867
|
+
object.userData ||= {};
|
|
868
|
+
if (object.geometry && object.userData.geometrySizeKey === key) return false;
|
|
869
|
+
const previous = object.geometry || null;
|
|
870
|
+
object.geometry = createGeometry();
|
|
871
|
+
object.userData.geometrySizeKey = key;
|
|
872
|
+
previous?.dispose?.();
|
|
873
|
+
return true;
|
|
874
|
+
}
|
|
875
|
+
|
|
876
|
+
window.MindMapCss3dHotPath = {
|
|
877
|
+
BUILD_ID,
|
|
878
|
+
applyVisibilityDiff,
|
|
879
|
+
collectSpatialRectCandidateIds,
|
|
880
|
+
createPointerHitContext,
|
|
881
|
+
ensureCssRendererHooks,
|
|
882
|
+
ensurePerfCounters,
|
|
883
|
+
getBoundedFallbackIds,
|
|
884
|
+
getContextCandidateIds,
|
|
885
|
+
getContextWorldPoint,
|
|
886
|
+
getDomRefs,
|
|
887
|
+
getDomStack,
|
|
888
|
+
getPerfSnapshot,
|
|
889
|
+
getProjectedClientFrame,
|
|
890
|
+
getSpatialGridKeysForBounds,
|
|
891
|
+
increment,
|
|
892
|
+
installOverlayGeometry,
|
|
893
|
+
installTextSource,
|
|
894
|
+
invalidateDomRefs,
|
|
895
|
+
invalidateDomRefsByCssObject,
|
|
896
|
+
noteUnavailableIndex,
|
|
897
|
+
recordHitCandidates,
|
|
898
|
+
replaceGeometryIfSizeChanged,
|
|
899
|
+
resetPerfCounters,
|
|
900
|
+
scheduleSpatialIndexRepair
|
|
901
|
+
};
|
|
902
|
+
})();
|