@mindexec/cli 0.2.0
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 +275 -0
- package/codex-runtime.js +960 -0
- package/launch-bridge.cjs +162 -0
- package/package.json +61 -0
- package/port-guard.cjs +232 -0
- package/scripts/setup-tree-sitter-grammars.mjs +59 -0
- package/server.js +8422 -0
- package/start-bridge.bat +32 -0
- package/start-bridge.sh +81 -0
- 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/MindExecution.Web.styles.css +3 -0
- package/wwwroot/_content/MindExecution.Plugins.Admin/css/admin-dashboard.css +546 -0
- package/wwwroot/_content/MindExecution.Plugins.Directory/MindExecution.Plugins.Directory.u7utcng611.bundle.scp.css +7 -0
- package/wwwroot/_content/MindExecution.Plugins.Directory/background.png +0 -0
- package/wwwroot/_content/MindExecution.Plugins.Directory/directory-manager.js +202 -0
- package/wwwroot/_content/MindExecution.Plugins.Directory/exampleJsInterop.js +6 -0
- package/wwwroot/_content/MindExecution.Plugins.YouTube/css/youtube-search.css +251 -0
- package/wwwroot/_content/MindExecution.Shared/MindExecution.Shared.wsano1j4wp.bundle.scp.css +4 -0
- package/wwwroot/_content/MindExecution.Shared/css/admin-dashboard.css +559 -0
- package/wwwroot/_content/MindExecution.Shared/css/app.css +1 -0
- package/wwwroot/_content/MindExecution.Shared/css/mind-map-overrides.css +2936 -0
- 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 +359 -0
- package/wwwroot/_content/MindExecution.Shared/js/background-themes.js +1721 -0
- package/wwwroot/_content/MindExecution.Shared/js/code-master.js +8316 -0
- package/wwwroot/_content/MindExecution.Shared/js/file-system-helper.js +639 -0
- package/wwwroot/_content/MindExecution.Shared/js/helpers/InfiniteGridHelper.js +109 -0
- package/wwwroot/_content/MindExecution.Shared/js/marked.min.js +69 -0
- package/wwwroot/_content/MindExecution.Shared/js/mind-map-core.js +7982 -0
- package/wwwroot/_content/MindExecution.Shared/js/mind-map-core.js.backup +1059 -0
- package/wwwroot/_content/MindExecution.Shared/js/mind-map-css3d-manager.js +15803 -0
- package/wwwroot/_content/MindExecution.Shared/js/mind-map-dev-guards.js +325 -0
- package/wwwroot/_content/MindExecution.Shared/js/mind-map-dnd.js +1430 -0
- package/wwwroot/_content/MindExecution.Shared/js/mind-map-dnd.js.bak +434 -0
- package/wwwroot/_content/MindExecution.Shared/js/mind-map-glow-shader.js +260 -0
- package/wwwroot/_content/MindExecution.Shared/js/mind-map-interactions.js +7640 -0
- package/wwwroot/_content/MindExecution.Shared/js/mind-map-lod-plan-worker.js +160 -0
- package/wwwroot/_content/MindExecution.Shared/js/mind-map-lod-renderer.js +9923 -0
- package/wwwroot/_content/MindExecution.Shared/js/mind-map-logic-workers.js +977 -0
- package/wwwroot/_content/MindExecution.Shared/js/mind-map-menu-manager.js +1431 -0
- package/wwwroot/_content/MindExecution.Shared/js/mind-map-multi-select.js +1716 -0
- package/wwwroot/_content/MindExecution.Shared/js/mind-map-node-search-worker.js +553 -0
- package/wwwroot/_content/MindExecution.Shared/js/mind-map-nodes.js +4541 -0
- package/wwwroot/_content/MindExecution.Shared/js/mind-map-object-manager.js +489 -0
- package/wwwroot/_content/MindExecution.Shared/js/mind-map-object-manager.js.backup +372 -0
- package/wwwroot/_content/MindExecution.Shared/js/mind-map-pipeline.js +2075 -0
- package/wwwroot/_content/MindExecution.Shared/js/mind-map-text-lod-system.js +646 -0
- package/wwwroot/_content/MindExecution.Shared/js/mind-map-text-overlay-v2.js +4323 -0
- package/wwwroot/_content/MindExecution.Shared/js/mind-map-texture-factory.js +2260 -0
- package/wwwroot/_content/MindExecution.Shared/js/mind-map-texture-factory.js.backup +1258 -0
- package/wwwroot/_content/MindExecution.Shared/js/mind-map-visibility-worker.js +890 -0
- package/wwwroot/_content/MindExecution.Shared/js/mindmap-toolbar.js +594 -0
- package/wwwroot/_content/MindExecution.Shared/js/native-drop-handler.js +170 -0
- package/wwwroot/_content/MindExecution.Shared/js/plan-master.js +788 -0
- package/wwwroot/_content/MindExecution.Shared/js/renderers/CSS3DRenderer.js +50 -0
- package/wwwroot/_content/MindExecution.Shared/js/texture-worker-manager.js +188 -0
- package/wwwroot/_content/MindExecution.Shared/js/texture-worker.js +208 -0
- package/wwwroot/_content/MindExecution.Shared/js/three.min.js +6 -0
- package/wwwroot/_content/MindExecution.Shared/js/titlebar-handler.js +191 -0
- package/wwwroot/_content/MindExecution.Shared/js/token-manager.js +37 -0
- package/wwwroot/_content/MindExecution.Shared/js/token-worker.js +28 -0
- package/wwwroot/_content/MindExecution.Shared/js/troika-bundle.js +5626 -0
- package/wwwroot/_content/MindExecution.Shared/js/troika-bundle.js.map +7 -0
- package/wwwroot/_content/MindExecution.Shared/lib/font-awesome/css/all.min.css +9 -0
- package/wwwroot/_content/MindExecution.Shared/lib/font-awesome/webfonts/fa-brands-400.ttf +0 -0
- package/wwwroot/_content/MindExecution.Shared/lib/font-awesome/webfonts/fa-brands-400.woff2 +0 -0
- package/wwwroot/_content/MindExecution.Shared/lib/font-awesome/webfonts/fa-regular-400.ttf +0 -0
- package/wwwroot/_content/MindExecution.Shared/lib/font-awesome/webfonts/fa-regular-400.woff2 +0 -0
- package/wwwroot/_content/MindExecution.Shared/lib/font-awesome/webfonts/fa-solid-900.ttf +0 -0
- package/wwwroot/_content/MindExecution.Shared/lib/font-awesome/webfonts/fa-solid-900.woff2 +0 -0
- package/wwwroot/_content/MindExecution.Shared/models/all-MiniLM-L6-v2-quantized.onnx +0 -0
- package/wwwroot/_content/MindExecution.Shared/models/vocab.txt +30522 -0
- package/wwwroot/_framework/Google.Protobuf.9h59ukbel7.dll +0 -0
- package/wwwroot/_framework/Markdig.d1j7v41cl1.dll +0 -0
- package/wwwroot/_framework/MessagePack.Annotations.l6qv48kgpt.dll +0 -0
- package/wwwroot/_framework/MessagePack.eqoptzx9d5.dll +0 -0
- package/wwwroot/_framework/Microsoft.AspNetCore.Authorization.k7dsih5y5g.dll +0 -0
- package/wwwroot/_framework/Microsoft.AspNetCore.Components.6nyje9sa0g.dll +0 -0
- package/wwwroot/_framework/Microsoft.AspNetCore.Components.Authorization.iycd6unprw.dll +0 -0
- package/wwwroot/_framework/Microsoft.AspNetCore.Components.Web.487u3twia4.dll +0 -0
- package/wwwroot/_framework/Microsoft.AspNetCore.Components.WebAssembly.d0gcnmlxxz.dll +0 -0
- package/wwwroot/_framework/Microsoft.AspNetCore.Metadata.h4yevl9adi.dll +0 -0
- package/wwwroot/_framework/Microsoft.CSharp.qrvp77qmhs.dll +0 -0
- package/wwwroot/_framework/Microsoft.Data.Sqlite.jdlxgv2jtg.dll +0 -0
- package/wwwroot/_framework/Microsoft.EntityFrameworkCore.4gjazp7kjf.dll +0 -0
- package/wwwroot/_framework/Microsoft.EntityFrameworkCore.Abstractions.gocudnvz7b.dll +0 -0
- package/wwwroot/_framework/Microsoft.EntityFrameworkCore.Relational.lt4rsvinuo.dll +0 -0
- package/wwwroot/_framework/Microsoft.EntityFrameworkCore.Sqlite.69luj0fa9r.dll +0 -0
- package/wwwroot/_framework/Microsoft.Extensions.Caching.Abstractions.364t4jh3zz.dll +0 -0
- package/wwwroot/_framework/Microsoft.Extensions.Caching.Memory.izlxhpzosu.dll +0 -0
- package/wwwroot/_framework/Microsoft.Extensions.Configuration.8zq7hh41o7.dll +0 -0
- package/wwwroot/_framework/Microsoft.Extensions.Configuration.Abstractions.8if74zs6ea.dll +0 -0
- package/wwwroot/_framework/Microsoft.Extensions.Configuration.Json.duvlngw8i0.dll +0 -0
- package/wwwroot/_framework/Microsoft.Extensions.DependencyInjection.Abstractions.t2hh9kvx0o.dll +0 -0
- package/wwwroot/_framework/Microsoft.Extensions.DependencyInjection.n4tg99oy8l.dll +0 -0
- package/wwwroot/_framework/Microsoft.Extensions.DependencyModel.h0d06ixk3e.dll +0 -0
- package/wwwroot/_framework/Microsoft.Extensions.Logging.Abstractions.rl32bkx2sd.dll +0 -0
- package/wwwroot/_framework/Microsoft.Extensions.Logging.dlht1xei0t.dll +0 -0
- package/wwwroot/_framework/Microsoft.Extensions.Options.qeunebioml.dll +0 -0
- package/wwwroot/_framework/Microsoft.Extensions.Primitives.18cr6vnuuz.dll +0 -0
- package/wwwroot/_framework/Microsoft.IO.RecyclableMemoryStream.r915vovvw4.dll +0 -0
- package/wwwroot/_framework/Microsoft.IdentityModel.Abstractions.1ejljk3erv.dll +0 -0
- package/wwwroot/_framework/Microsoft.IdentityModel.JsonWebTokens.1596zr8gne.dll +0 -0
- package/wwwroot/_framework/Microsoft.IdentityModel.Logging.229uyvpgio.dll +0 -0
- package/wwwroot/_framework/Microsoft.IdentityModel.Tokens.9sibtajc9f.dll +0 -0
- package/wwwroot/_framework/Microsoft.JSInterop.17lq4j1j7g.dll +0 -0
- package/wwwroot/_framework/Microsoft.JSInterop.WebAssembly.ryia5gxiad.dll +0 -0
- package/wwwroot/_framework/Microsoft.ML.OnnxRuntime.w9deo1m5ss.dll +0 -0
- package/wwwroot/_framework/Microsoft.ML.Tokenizers.cm2vuv2z61.dll +0 -0
- package/wwwroot/_framework/Microsoft.NET.StringTools.3qbrf4v2ki.dll +0 -0
- package/wwwroot/_framework/MimeMapping.og9ys58ylm.dll +0 -0
- package/wwwroot/_framework/MindExecution.Core.1q1trifbuu.dll +0 -0
- package/wwwroot/_framework/MindExecution.Kernel.gwwc40sc45.dll +0 -0
- package/wwwroot/_framework/MindExecution.Plugins.Admin.0jgrn1sckv.dll +0 -0
- package/wwwroot/_framework/MindExecution.Plugins.Business.13mme2qcag.dll +0 -0
- package/wwwroot/_framework/MindExecution.Plugins.Concept.dfp2mdt45q.dll +0 -0
- package/wwwroot/_framework/MindExecution.Plugins.Directory.3w4t6n3se0.dll +0 -0
- package/wwwroot/_framework/MindExecution.Plugins.PlanMaster.s0qpntz420.dll +0 -0
- package/wwwroot/_framework/MindExecution.Plugins.YouTube.iu11fq8d16.dll +0 -0
- package/wwwroot/_framework/MindExecution.Shared.7j27dcqnrc.dll +0 -0
- package/wwwroot/_framework/MindExecution.Web.pq1ty8ov2v.dll +0 -0
- package/wwwroot/_framework/Newtonsoft.Json.a56zs13vug.dll +0 -0
- package/wwwroot/_framework/SQLitePCLRaw.batteries_v2.rrd1nzawpp.dll +0 -0
- package/wwwroot/_framework/SQLitePCLRaw.core.1dxloztpfz.dll +0 -0
- package/wwwroot/_framework/SQLitePCLRaw.provider.e_sqlite3.oekyzl53i1.dll +0 -0
- package/wwwroot/_framework/Supabase.Core.s1pkj4aj0l.dll +0 -0
- package/wwwroot/_framework/Supabase.Functions.qz4nu782sg.dll +0 -0
- package/wwwroot/_framework/Supabase.Gotrue.twah27pkik.dll +0 -0
- package/wwwroot/_framework/Supabase.Postgrest.gmuuv369ih.dll +0 -0
- package/wwwroot/_framework/Supabase.Realtime.ox3kchdy3w.dll +0 -0
- package/wwwroot/_framework/Supabase.Storage.fnjnepaowr.dll +0 -0
- package/wwwroot/_framework/Supabase.azmaw5pgcz.dll +0 -0
- package/wwwroot/_framework/System.Collections.Concurrent.y1zmvuyipi.dll +0 -0
- package/wwwroot/_framework/System.Collections.Immutable.ug3j698qms.dll +0 -0
- package/wwwroot/_framework/System.Collections.NonGeneric.h66hj3863h.dll +0 -0
- package/wwwroot/_framework/System.Collections.Specialized.umr3y27ntj.dll +0 -0
- package/wwwroot/_framework/System.Collections.x53e19vfsj.dll +0 -0
- package/wwwroot/_framework/System.ComponentModel.Annotations.tz6gnt4ebt.dll +0 -0
- package/wwwroot/_framework/System.ComponentModel.Primitives.j7tiphu4rg.dll +0 -0
- package/wwwroot/_framework/System.ComponentModel.TypeConverter.ujlztox1gx.dll +0 -0
- package/wwwroot/_framework/System.ComponentModel.x9xz0ojfb6.dll +0 -0
- package/wwwroot/_framework/System.Console.ijzpqmj7ne.dll +0 -0
- package/wwwroot/_framework/System.Data.Common.1r0sqffq1p.dll +0 -0
- package/wwwroot/_framework/System.Diagnostics.DiagnosticSource.9upoqwq09o.dll +0 -0
- package/wwwroot/_framework/System.Diagnostics.Process.m99azzntjm.dll +0 -0
- package/wwwroot/_framework/System.Diagnostics.TraceSource.pl7wv26myr.dll +0 -0
- package/wwwroot/_framework/System.Diagnostics.Tracing.crlhfx6tut.dll +0 -0
- package/wwwroot/_framework/System.Drawing.Primitives.22e4y9ikq9.dll +0 -0
- package/wwwroot/_framework/System.Drawing.mi7d8hwowb.dll +0 -0
- package/wwwroot/_framework/System.Formats.Asn1.jx23sjiqnn.dll +0 -0
- package/wwwroot/_framework/System.IO.Compression.6fyoii3uej.dll +0 -0
- package/wwwroot/_framework/System.IO.Pipelines.vg77t4cd4d.dll +0 -0
- package/wwwroot/_framework/System.IdentityModel.Tokens.Jwt.t67es60z5b.dll +0 -0
- package/wwwroot/_framework/System.Linq.1bkoxlqgmq.dll +0 -0
- package/wwwroot/_framework/System.Linq.Expressions.24xqiypwdt.dll +0 -0
- package/wwwroot/_framework/System.Linq.Queryable.hvd01d6rsa.dll +0 -0
- package/wwwroot/_framework/System.Memory.8dx3lwgym4.dll +0 -0
- package/wwwroot/_framework/System.Net.Http.Json.3mhdm9l1rf.dll +0 -0
- package/wwwroot/_framework/System.Net.Http.eitrz660my.dll +0 -0
- package/wwwroot/_framework/System.Net.NetworkInformation.3pkuofcv9r.dll +0 -0
- package/wwwroot/_framework/System.Net.Ping.8clj5pklrp.dll +0 -0
- package/wwwroot/_framework/System.Net.Primitives.qrp4wcjz1p.dll +0 -0
- package/wwwroot/_framework/System.Net.WebSockets.Client.2u6pv01g69.dll +0 -0
- package/wwwroot/_framework/System.Net.WebSockets.qp6u31zvm5.dll +0 -0
- package/wwwroot/_framework/System.Numerics.Tensors.0c7z4mt3on.dll +0 -0
- package/wwwroot/_framework/System.Numerics.Vectors.kc7ufp2j4l.dll +0 -0
- package/wwwroot/_framework/System.ObjectModel.qv82fot1ib.dll +0 -0
- package/wwwroot/_framework/System.Private.CoreLib.rkafq04oma.dll +0 -0
- package/wwwroot/_framework/System.Private.Uri.t9542hmr6j.dll +0 -0
- package/wwwroot/_framework/System.Private.Xml.Linq.n8n3ptrbwu.dll +0 -0
- package/wwwroot/_framework/System.Private.Xml.rxd3tytisn.dll +0 -0
- package/wwwroot/_framework/System.Reactive.t3fuon548l.dll +0 -0
- package/wwwroot/_framework/System.Reflection.Emit.9tjhp6y0j3.dll +0 -0
- package/wwwroot/_framework/System.Reflection.Emit.ILGeneration.stxyk8zoo1.dll +0 -0
- package/wwwroot/_framework/System.Reflection.Emit.Lightweight.6xrd5v8vg0.dll +0 -0
- package/wwwroot/_framework/System.Reflection.Primitives.wgn8fpwwvv.dll +0 -0
- package/wwwroot/_framework/System.Runtime.InteropServices.JavaScript.sliym526xh.dll +0 -0
- package/wwwroot/_framework/System.Runtime.InteropServices.RuntimeInformation.oji7zut14z.dll +0 -0
- package/wwwroot/_framework/System.Runtime.InteropServices.te07xr2we9.dll +0 -0
- package/wwwroot/_framework/System.Runtime.Intrinsics.507y4h8nzq.dll +0 -0
- package/wwwroot/_framework/System.Runtime.Loader.v7gk4bse0k.dll +0 -0
- package/wwwroot/_framework/System.Runtime.Numerics.eqy5xjv3nd.dll +0 -0
- package/wwwroot/_framework/System.Runtime.Serialization.Formatters.zpkrub8lab.dll +0 -0
- package/wwwroot/_framework/System.Runtime.Serialization.Primitives.vhkpnbxjip.dll +0 -0
- package/wwwroot/_framework/System.Runtime.jn319d5nyg.dll +0 -0
- package/wwwroot/_framework/System.Security.Claims.0ztig1q9vo.dll +0 -0
- package/wwwroot/_framework/System.Security.Cryptography.vttizqc9ho.dll +0 -0
- package/wwwroot/_framework/System.Text.Encoding.Extensions.utdd47ny8f.dll +0 -0
- package/wwwroot/_framework/System.Text.Encodings.Web.wah8r1zoe0.dll +0 -0
- package/wwwroot/_framework/System.Text.Json.kxlfxj0wrs.dll +0 -0
- package/wwwroot/_framework/System.Text.RegularExpressions.dbqn58klox.dll +0 -0
- package/wwwroot/_framework/System.Threading.42ao9vi047.dll +0 -0
- package/wwwroot/_framework/System.Threading.Channels.hfa7j0uv2w.dll +0 -0
- package/wwwroot/_framework/System.Threading.Thread.caul0pdqul.dll +0 -0
- package/wwwroot/_framework/System.Transactions.Local.fimi2hamzo.dll +0 -0
- package/wwwroot/_framework/System.Web.HttpUtility.gq8yz50p2e.dll +0 -0
- package/wwwroot/_framework/System.Xml.Linq.kitin4zjoj.dll +0 -0
- package/wwwroot/_framework/System.Xml.ReaderWriter.kzvw3qgxb0.dll +0 -0
- package/wwwroot/_framework/System.Xml.XDocument.c539ki6cuq.dll +0 -0
- package/wwwroot/_framework/System.m05i39uvk9.dll +0 -0
- package/wwwroot/_framework/Websocket.Client.vapounvmnl.dll +0 -0
- package/wwwroot/_framework/blazor.boot.json +305 -0
- package/wwwroot/_framework/blazor.webassembly.js +1 -0
- package/wwwroot/_framework/dotnet.js +4 -0
- package/wwwroot/_framework/dotnet.native.vz0adxojrz.wasm +0 -0
- package/wwwroot/_framework/dotnet.native.xsn1d6x2kd.js +16 -0
- package/wwwroot/_framework/dotnet.runtime.dstopyvqzi.js +4 -0
- package/wwwroot/_framework/icudt_CJK.tjcz0u77k5.dat +0 -0
- package/wwwroot/_framework/icudt_EFIGS.tptq2av103.dat +0 -0
- package/wwwroot/_framework/icudt_no_CJK.lfu7j35m59.dat +0 -0
- package/wwwroot/_framework/netstandard.0xet7jg7ky.dll +0 -0
- package/wwwroot/_headers +40 -0
- package/wwwroot/_redirects +1 -0
- package/wwwroot/appsettings.json +71 -0
- package/wwwroot/icon-192.png +0 -0
- package/wwwroot/icon-512.png +0 -0
- package/wwwroot/index.html +710 -0
- package/wwwroot/js/marketing-tool.js +180 -0
- package/wwwroot/manifest.webmanifest +22 -0
- package/wwwroot/robots.txt +4 -0
- package/wwwroot/service-worker-assets.js +857 -0
- package/wwwroot/service-worker.js +33 -0
- package/wwwroot/sitemap.xml +27 -0
|
@@ -0,0 +1,4323 @@
|
|
|
1
|
+
(function () {
|
|
2
|
+
'use strict';
|
|
3
|
+
|
|
4
|
+
const DEBUG = false;
|
|
5
|
+
const DEFAULT_OVERLAY_SCROLLABLE_SELECTOR = '.node-response, .note-content, .markdown-body, .prose, .note-textarea, .code-body, .code-content, .pdf-content, .text-content, .file-content, .map-node-memo__body, .map-node-memo__body-view, .map-node-memo__agent-plan-body, .map-node-memo__agent-console-body, pre, code';
|
|
6
|
+
const PASSIVE_OVERLAY_NEAR_EXIT_GRACE_MS = 220;
|
|
7
|
+
const PASSIVE_OVERLAY_CANDIDATE_GRACE_MS = 160;
|
|
8
|
+
const PASSIVE_OVERLAY_VIEWPORT_PAD_PX = 32;
|
|
9
|
+
const PASSIVE_OVERLAY_CARD_LIMIT_DEFAULT = 28;
|
|
10
|
+
const PASSIVE_OVERLAY_CARD_LIMIT_DENSE = 20;
|
|
11
|
+
const PASSIVE_OVERLAY_CARD_LIMIT_VERY_SLOW = 12;
|
|
12
|
+
const PASSIVE_OVERLAY_FRAGMENT_WIDTH_BIAS_PX = 0;
|
|
13
|
+
const PASSIVE_OVERLAY_OVERLAP_MIN_PX = 2;
|
|
14
|
+
const PASSIVE_OVERLAY_OVERLAP_MIN_AREA_PX = 16;
|
|
15
|
+
const PASSIVE_OVERLAY_STACK_Z_SCALE = 10000;
|
|
16
|
+
const log = DEBUG ? console.log.bind(console, '[MindMapTextOverlayV2]') : () => { };
|
|
17
|
+
let _projCornerTopLeft = null;
|
|
18
|
+
let _projCornerTopRight = null;
|
|
19
|
+
let _projCornerBottomLeft = null;
|
|
20
|
+
let _projCornerBottomRight = null;
|
|
21
|
+
|
|
22
|
+
function ensureProjectionTemps() {
|
|
23
|
+
const THREERef = globalThis.THREE;
|
|
24
|
+
if (!THREERef) {
|
|
25
|
+
return null;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
if (!_projCornerTopLeft) {
|
|
29
|
+
_projCornerTopLeft = new THREERef.Vector3();
|
|
30
|
+
_projCornerTopRight = new THREERef.Vector3();
|
|
31
|
+
_projCornerBottomLeft = new THREERef.Vector3();
|
|
32
|
+
_projCornerBottomRight = new THREERef.Vector3();
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
return THREERef;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
function normalizeId(nodeId) {
|
|
39
|
+
return String(nodeId ?? '').trim();
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
function getModel(target) {
|
|
43
|
+
return target?.model || target || null;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
function getNodeId(target) {
|
|
47
|
+
const model = getModel(target);
|
|
48
|
+
return normalizeId(model?.id ?? model?.Id);
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
function getContentType(target) {
|
|
52
|
+
const model = getModel(target);
|
|
53
|
+
return String(model?.contentType ?? model?.ContentType ?? '').trim().toLowerCase();
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
function isMediaOverlayExcluded(entry) {
|
|
57
|
+
const type = getContentType(entry);
|
|
58
|
+
return type === 'image' || type === 'video' || type === 'embed';
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
function getPrompt(target) {
|
|
62
|
+
const model = getModel(target);
|
|
63
|
+
return String(model?.prompt ?? model?.Prompt ?? '');
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
function getResponse(target) {
|
|
67
|
+
const model = getModel(target);
|
|
68
|
+
return String(model?.response ?? model?.Response ?? model?.content ?? model?.Content ?? '');
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
function getMetadata(target) {
|
|
72
|
+
const model = getModel(target);
|
|
73
|
+
return model?.metadata || model?.Metadata || {};
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
function getNodeSemanticType(target) {
|
|
77
|
+
const metadata = getMetadata(target);
|
|
78
|
+
const model = getModel(target);
|
|
79
|
+
return String(metadata?.SemanticType || metadata?.semanticType || model?.SemanticType || model?.semanticType || '').trim();
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
function isAgentStyledMemoEntry(entry) {
|
|
83
|
+
const semanticType = getNodeSemanticType(entry);
|
|
84
|
+
return semanticType === 'MindCanvasAgent'
|
|
85
|
+
|| semanticType === 'AgentCommand'
|
|
86
|
+
|| semanticType === 'BusinessAutomationNode';
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
function isDomOverlayDebugEnabled(module) {
|
|
90
|
+
return module?.renderDebugFlags?.enableDomOverlay !== false;
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
function isEnabled(module) {
|
|
94
|
+
return module?.useTextOverlayV2 === true && isDomOverlayDebugEnabled(module);
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
function nowMs() {
|
|
98
|
+
if (typeof performance !== 'undefined' && typeof performance.now === 'function') {
|
|
99
|
+
return performance.now();
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
return Date.now();
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
function getCss3dManager() {
|
|
106
|
+
return window.MindMapCss3DManager || null;
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
function supportsTextOverlayEntry(entry) {
|
|
110
|
+
const manager = getCss3dManager();
|
|
111
|
+
const model = getModel(entry);
|
|
112
|
+
if (manager?.supportsTextOverlay) {
|
|
113
|
+
return manager.supportsTextOverlay(model);
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
const type = getContentType(entry);
|
|
117
|
+
return type === 'text' || type === 'markdown' || type === 'note' || type === 'memo' || type === 'code';
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
function supportsSelection(entry) {
|
|
121
|
+
const manager = getCss3dManager();
|
|
122
|
+
const model = getModel(entry);
|
|
123
|
+
if (manager?.supportsSelectionTextOverlay) {
|
|
124
|
+
return manager.supportsSelectionTextOverlay(model);
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
const type = getContentType(entry);
|
|
128
|
+
return type === 'text' || type === 'markdown';
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
function supportsPassiveDisplay(entry) {
|
|
132
|
+
const manager = getCss3dManager();
|
|
133
|
+
if (manager?.getReadonlyTextOverlayMode) {
|
|
134
|
+
return String(getReadonlySelectionMode(entry) || '').trim().toLowerCase() !== 'none';
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
return supportsTextOverlayEntry(entry);
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
function blocksPassiveOverlayStack(entry) {
|
|
141
|
+
const type = getContentType(entry);
|
|
142
|
+
const isVisualStackBlocker = type === 'image'
|
|
143
|
+
|| type === 'video'
|
|
144
|
+
|| type === 'embed'
|
|
145
|
+
|| type === 'memo'
|
|
146
|
+
|| isAgentStyledMemoEntry(entry);
|
|
147
|
+
if (!isVisualStackBlocker) {
|
|
148
|
+
return false;
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
const hasVisibleGl = !!entry?.glObject && entry.glObject.visible !== false;
|
|
152
|
+
const hasVisibleCss = !!entry?.cssObject && entry.cssObject.visible !== false;
|
|
153
|
+
return hasVisibleGl || hasVisibleCss;
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
function shouldKeepPassiveCardWhenSelected(entry) {
|
|
157
|
+
return supportsPassiveDisplay(entry);
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
function supportsEditing(entry) {
|
|
161
|
+
const manager = getCss3dManager();
|
|
162
|
+
const model = getModel(entry);
|
|
163
|
+
if (manager?.supportsEditingOverlay) {
|
|
164
|
+
return manager.supportsEditingOverlay(model);
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
const type = getContentType(entry);
|
|
168
|
+
return type === 'memo' || type === 'note';
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
function usesDomTextOverlay(module) {
|
|
172
|
+
return module?.useDomTextOverlay === true;
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
function getCurrentLodBand(module) {
|
|
176
|
+
const explicitBand = String(module?.lodRenderer?._currentLodBand || '').trim().toUpperCase();
|
|
177
|
+
if (explicitBand) {
|
|
178
|
+
return explicitBand;
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
const cameraZ = Number(module?.camera?.position?.z || 0);
|
|
182
|
+
const thresholds = globalThis.LODRenderer?.LOD_THRESHOLDS || {
|
|
183
|
+
NEAR: 4500,
|
|
184
|
+
NORMAL: 12000,
|
|
185
|
+
MID: 12000,
|
|
186
|
+
FAR: 30000
|
|
187
|
+
};
|
|
188
|
+
|
|
189
|
+
if (cameraZ >= Number(thresholds.FAR || 25000)) {
|
|
190
|
+
return 'FAR';
|
|
191
|
+
}
|
|
192
|
+
if (cameraZ >= Number(thresholds.MID || thresholds.NORMAL || 12000)) {
|
|
193
|
+
return 'MID';
|
|
194
|
+
}
|
|
195
|
+
if (cameraZ >= Number(thresholds.NORMAL || thresholds.NEAR || 4500)) {
|
|
196
|
+
return 'NORMAL';
|
|
197
|
+
}
|
|
198
|
+
return 'NEAR';
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
function getScrollableSelector() {
|
|
202
|
+
return getCss3dManager()?.getTextInteractionScrollableSelectors?.()
|
|
203
|
+
|| DEFAULT_OVERLAY_SCROLLABLE_SELECTOR;
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
function getScrollSyncSelectors() {
|
|
207
|
+
return getCss3dManager()?.getTextOverlayScrollSyncSelectors?.() || [
|
|
208
|
+
'.node-response',
|
|
209
|
+
'.note-content',
|
|
210
|
+
'.markdown-body',
|
|
211
|
+
'.prose',
|
|
212
|
+
'.code-body',
|
|
213
|
+
'.note-textarea',
|
|
214
|
+
'.map-node-memo__body',
|
|
215
|
+
'.map-node-memo__body-view',
|
|
216
|
+
'.map-node-memo__agent-plan-body',
|
|
217
|
+
'.map-node-memo__agent-console-body'
|
|
218
|
+
];
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
function getPrimaryContentSelector() {
|
|
222
|
+
return getCss3dManager()?.getTextOverlayPrimaryContentSelectors?.()
|
|
223
|
+
|| '[id^="node-response-"], .node-response, .note-content, .markdown-body, .code-body, .map-node-memo__body-view, .map-node-memo__agent-plan-body, .map-node-memo__agent-console-body';
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
function shouldRenderPassiveDomOverlays(module) {
|
|
227
|
+
if (!isEnabled(module) || !usesDomTextOverlay(module)) {
|
|
228
|
+
return false;
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
const state = ensureState(module);
|
|
232
|
+
if (hasBlockingPassiveOverlayInteraction(module, state)) {
|
|
233
|
+
if (state) {
|
|
234
|
+
state.passiveNearStickyUntil = 0;
|
|
235
|
+
}
|
|
236
|
+
return false;
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
const currentBand = getCurrentLodBand(module);
|
|
240
|
+
if (currentBand === 'NEAR') {
|
|
241
|
+
if (state) {
|
|
242
|
+
state.passiveNearStickyUntil = nowMs() + PASSIVE_OVERLAY_NEAR_EXIT_GRACE_MS;
|
|
243
|
+
}
|
|
244
|
+
return true;
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
if (state) {
|
|
248
|
+
state.passiveNearStickyUntil = 0;
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
return false;
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
function shouldUseVisiblePassiveOverlayCandidates(module) {
|
|
255
|
+
return module?.renderDebugFlags?.enablePassiveOverlayForVisibleNodes !== false;
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
function hasBlockingPassiveOverlayInteraction(module, state = ensureState(module)) {
|
|
259
|
+
const hasBlockingTextInteraction =
|
|
260
|
+
!!normalizeId(state?.selectionNodeId) ||
|
|
261
|
+
!!normalizeId(state?.editing?.nodeId) ||
|
|
262
|
+
module?.isEditingNote === true ||
|
|
263
|
+
getCss3dManager()?.hasNativeTextSelectionSource?.(module) === true ||
|
|
264
|
+
getCss3dManager()?.hasSelectableTextOverlay?.(module) === true;
|
|
265
|
+
|
|
266
|
+
return hasBlockingTextInteraction;
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
function buildInteractionKey(module, state) {
|
|
270
|
+
const selectedNodeId = normalizeId(module?.selectedNodeIdJs);
|
|
271
|
+
const multiSelectedCount = Number(module?.multiSelectedNodeIds?.size || 0);
|
|
272
|
+
const nativeSelectionNodeId = normalizeId(module?._nativeTextSelectionSourceNodeId);
|
|
273
|
+
const selectableOverlayNodeId = normalizeId(module?._selectableTextOverlayNodeId);
|
|
274
|
+
const activeSelectionNodeId = normalizeId(state?.selectionNodeId);
|
|
275
|
+
const editingNodeId = normalizeId(state?.editing?.nodeId);
|
|
276
|
+
const isEditingNote = module?.isEditingNote === true ? '1' : '0';
|
|
277
|
+
return [
|
|
278
|
+
selectedNodeId,
|
|
279
|
+
String(multiSelectedCount),
|
|
280
|
+
nativeSelectionNodeId,
|
|
281
|
+
selectableOverlayNodeId,
|
|
282
|
+
activeSelectionNodeId,
|
|
283
|
+
editingNodeId,
|
|
284
|
+
isEditingNote
|
|
285
|
+
].join('|');
|
|
286
|
+
}
|
|
287
|
+
|
|
288
|
+
function getPassiveViewportWorldBounds(module) {
|
|
289
|
+
const container = module?.container || null;
|
|
290
|
+
const camera = module?.camera || null;
|
|
291
|
+
if (!container || !camera?.isPerspectiveCamera) {
|
|
292
|
+
return null;
|
|
293
|
+
}
|
|
294
|
+
|
|
295
|
+
const viewportWidthPx = Math.max(1, Number(container.clientWidth || container.offsetWidth || 0));
|
|
296
|
+
const viewportHeightPx = Math.max(1, Number(container.clientHeight || container.offsetHeight || 0));
|
|
297
|
+
const cameraZ = Number(camera.position?.z || 0);
|
|
298
|
+
const fov = Number(camera.fov || 0);
|
|
299
|
+
if (!(viewportWidthPx > 0) || !(viewportHeightPx > 0) || !(cameraZ > 0) || !(fov > 0)) {
|
|
300
|
+
return null;
|
|
301
|
+
}
|
|
302
|
+
|
|
303
|
+
const vfov = (fov * Math.PI) / 180;
|
|
304
|
+
const worldHeight = 2 * Math.tan(vfov / 2) * cameraZ;
|
|
305
|
+
if (!(worldHeight > 0)) {
|
|
306
|
+
return null;
|
|
307
|
+
}
|
|
308
|
+
|
|
309
|
+
const worldWidth = worldHeight * Number(camera.aspect || (viewportWidthPx / viewportHeightPx) || 1);
|
|
310
|
+
const pixelsPerWorld = viewportHeightPx / worldHeight;
|
|
311
|
+
const padWorld = PASSIVE_OVERLAY_VIEWPORT_PAD_PX / Math.max(0.0001, pixelsPerWorld);
|
|
312
|
+
const halfWidth = worldWidth * 0.5;
|
|
313
|
+
const halfHeight = worldHeight * 0.5;
|
|
314
|
+
const centerX = Number(camera.position?.x || 0);
|
|
315
|
+
const centerY = Number(camera.position?.y || 0);
|
|
316
|
+
|
|
317
|
+
return {
|
|
318
|
+
left: centerX - halfWidth - padWorld,
|
|
319
|
+
right: centerX + halfWidth + padWorld,
|
|
320
|
+
top: centerY + halfHeight + padWorld,
|
|
321
|
+
bottom: centerY - halfHeight - padWorld,
|
|
322
|
+
centerX,
|
|
323
|
+
centerY
|
|
324
|
+
};
|
|
325
|
+
}
|
|
326
|
+
|
|
327
|
+
function getPassiveCandidateWorldBounds(entry) {
|
|
328
|
+
const model = getModel(entry);
|
|
329
|
+
const obj = entry?.glObject || entry?.cssObject || null;
|
|
330
|
+
if (!model || !obj?.position) {
|
|
331
|
+
return null;
|
|
332
|
+
}
|
|
333
|
+
|
|
334
|
+
const width = Math.max(
|
|
335
|
+
1,
|
|
336
|
+
Number(model?.width || model?.Width || 0),
|
|
337
|
+
Number(entry?.cssObject?.element?.offsetWidth || 0)
|
|
338
|
+
);
|
|
339
|
+
const height = Math.max(
|
|
340
|
+
1,
|
|
341
|
+
Number(model?.height || model?.Height || 0),
|
|
342
|
+
Number(entry?.cssObject?.element?.offsetHeight || 0)
|
|
343
|
+
);
|
|
344
|
+
const left = Number(obj.position.x || 0);
|
|
345
|
+
const top = Number(obj.position.y || 0);
|
|
346
|
+
|
|
347
|
+
return {
|
|
348
|
+
left,
|
|
349
|
+
right: left + width,
|
|
350
|
+
top,
|
|
351
|
+
bottom: top - height,
|
|
352
|
+
centerX: left + (width * 0.5),
|
|
353
|
+
centerY: top - (height * 0.5)
|
|
354
|
+
};
|
|
355
|
+
}
|
|
356
|
+
|
|
357
|
+
function intersectsPassiveViewport(bounds, viewportBounds) {
|
|
358
|
+
if (!bounds || !viewportBounds) {
|
|
359
|
+
return true;
|
|
360
|
+
}
|
|
361
|
+
|
|
362
|
+
return !(
|
|
363
|
+
bounds.right < viewportBounds.left ||
|
|
364
|
+
bounds.left > viewportBounds.right ||
|
|
365
|
+
bounds.top < viewportBounds.bottom ||
|
|
366
|
+
bounds.bottom > viewportBounds.top
|
|
367
|
+
);
|
|
368
|
+
}
|
|
369
|
+
|
|
370
|
+
function getPassiveViewportVisibleArea(bounds, viewportBounds) {
|
|
371
|
+
if (!bounds || !viewportBounds) {
|
|
372
|
+
return 0;
|
|
373
|
+
}
|
|
374
|
+
|
|
375
|
+
const overlapWidth = Math.max(
|
|
376
|
+
0,
|
|
377
|
+
Math.min(bounds.right, viewportBounds.right) - Math.max(bounds.left, viewportBounds.left)
|
|
378
|
+
);
|
|
379
|
+
const overlapHeight = Math.max(
|
|
380
|
+
0,
|
|
381
|
+
Math.min(bounds.top, viewportBounds.top) - Math.max(bounds.bottom, viewportBounds.bottom)
|
|
382
|
+
);
|
|
383
|
+
return overlapWidth * overlapHeight;
|
|
384
|
+
}
|
|
385
|
+
|
|
386
|
+
function parseCssStackZIndex(element) {
|
|
387
|
+
const readNumeric = value => {
|
|
388
|
+
const raw = String(value ?? '').trim();
|
|
389
|
+
if (!raw || raw.toLowerCase() === 'auto') {
|
|
390
|
+
return null;
|
|
391
|
+
}
|
|
392
|
+
|
|
393
|
+
const number = Number(raw);
|
|
394
|
+
return Number.isFinite(number) ? number : null;
|
|
395
|
+
};
|
|
396
|
+
|
|
397
|
+
const inlineZ = readNumeric(element?.style?.zIndex);
|
|
398
|
+
if (inlineZ !== null) {
|
|
399
|
+
return inlineZ;
|
|
400
|
+
}
|
|
401
|
+
|
|
402
|
+
try {
|
|
403
|
+
return readNumeric(window.getComputedStyle?.(element)?.zIndex);
|
|
404
|
+
} catch {
|
|
405
|
+
return null;
|
|
406
|
+
}
|
|
407
|
+
}
|
|
408
|
+
|
|
409
|
+
function getCss3dDomStackIndex(entry, fallbackIndex = 0) {
|
|
410
|
+
const element = entry?.cssObject?.element || null;
|
|
411
|
+
const parentElement = element?.parentElement || null;
|
|
412
|
+
if (parentElement?.children?.length) {
|
|
413
|
+
const index = Array.prototype.indexOf.call(parentElement.children, element);
|
|
414
|
+
if (index >= 0) {
|
|
415
|
+
return index;
|
|
416
|
+
}
|
|
417
|
+
}
|
|
418
|
+
|
|
419
|
+
const cssParent = entry?.cssObject?.parent || null;
|
|
420
|
+
const cssChildren = cssParent?.children || null;
|
|
421
|
+
if (Array.isArray(cssChildren)) {
|
|
422
|
+
const index = cssChildren.indexOf(entry.cssObject);
|
|
423
|
+
if (index >= 0) {
|
|
424
|
+
return index;
|
|
425
|
+
}
|
|
426
|
+
}
|
|
427
|
+
|
|
428
|
+
return Number(fallbackIndex || 0);
|
|
429
|
+
}
|
|
430
|
+
|
|
431
|
+
function getWebglRenderStackIndex(entry, fallbackIndex = 0) {
|
|
432
|
+
let maxOrder = Number(entry?.glObject?.userData?.baseRenderOrder);
|
|
433
|
+
if (!Number.isFinite(maxOrder)) {
|
|
434
|
+
maxOrder = Number(entry?.bodyMesh?.renderOrder);
|
|
435
|
+
}
|
|
436
|
+
|
|
437
|
+
entry?.glObject?.traverse?.(child => {
|
|
438
|
+
if (!child || !(child.isMesh || child.isLine)) {
|
|
439
|
+
return;
|
|
440
|
+
}
|
|
441
|
+
|
|
442
|
+
const order = Number(child.renderOrder);
|
|
443
|
+
if (Number.isFinite(order) && (!Number.isFinite(maxOrder) || order > maxOrder)) {
|
|
444
|
+
maxOrder = order;
|
|
445
|
+
}
|
|
446
|
+
});
|
|
447
|
+
|
|
448
|
+
return Number.isFinite(maxOrder) ? maxOrder : Number(fallbackIndex || 0);
|
|
449
|
+
}
|
|
450
|
+
|
|
451
|
+
function getPassiveOverlayStackRank(entry, sourceIndex = 0) {
|
|
452
|
+
const element = entry?.cssObject?.element || null;
|
|
453
|
+
const cssZIndex = parseCssStackZIndex(element);
|
|
454
|
+
const zBand = Number.isFinite(cssZIndex)
|
|
455
|
+
? cssZIndex
|
|
456
|
+
: (!element ? getWebglRenderStackIndex(entry, 0) : 0);
|
|
457
|
+
const domIndex = element
|
|
458
|
+
? getCss3dDomStackIndex(entry, sourceIndex)
|
|
459
|
+
: Number(sourceIndex || 0);
|
|
460
|
+
|
|
461
|
+
// Match CSS3D stacking: explicit CSS z-index first, DOM sibling order second.
|
|
462
|
+
return (zBand * PASSIVE_OVERLAY_STACK_Z_SCALE) + domIndex;
|
|
463
|
+
}
|
|
464
|
+
|
|
465
|
+
function getPassiveOverlayScreenRect(module, entry) {
|
|
466
|
+
const rect = getPlacementRect(module, entry);
|
|
467
|
+
if (!rect) {
|
|
468
|
+
return null;
|
|
469
|
+
}
|
|
470
|
+
|
|
471
|
+
const left = Number(rect.left || 0);
|
|
472
|
+
const top = Number(rect.top || 0);
|
|
473
|
+
const width = Math.max(1, Number(rect.width || rect.baseWidth || 1));
|
|
474
|
+
const height = Math.max(1, Number(rect.height || rect.baseHeight || 1));
|
|
475
|
+
if (!Number.isFinite(left) || !Number.isFinite(top) || !Number.isFinite(width) || !Number.isFinite(height)) {
|
|
476
|
+
return null;
|
|
477
|
+
}
|
|
478
|
+
|
|
479
|
+
return {
|
|
480
|
+
left,
|
|
481
|
+
top,
|
|
482
|
+
right: left + width,
|
|
483
|
+
bottom: top + height,
|
|
484
|
+
width,
|
|
485
|
+
height
|
|
486
|
+
};
|
|
487
|
+
}
|
|
488
|
+
|
|
489
|
+
function doPassiveOverlayRectsOverlap(a, b) {
|
|
490
|
+
if (!a || !b) {
|
|
491
|
+
return false;
|
|
492
|
+
}
|
|
493
|
+
|
|
494
|
+
const overlapWidth = Math.min(a.right, b.right) - Math.max(a.left, b.left);
|
|
495
|
+
const overlapHeight = Math.min(a.bottom, b.bottom) - Math.max(a.top, b.top);
|
|
496
|
+
if (overlapWidth <= PASSIVE_OVERLAY_OVERLAP_MIN_PX || overlapHeight <= PASSIVE_OVERLAY_OVERLAP_MIN_PX) {
|
|
497
|
+
return false;
|
|
498
|
+
}
|
|
499
|
+
|
|
500
|
+
return (overlapWidth * overlapHeight) >= PASSIVE_OVERLAY_OVERLAP_MIN_AREA_PX;
|
|
501
|
+
}
|
|
502
|
+
|
|
503
|
+
function collectBlockerConnectedPassiveOverlayIds(enriched) {
|
|
504
|
+
const suppressedIds = new Set();
|
|
505
|
+
if (!Array.isArray(enriched) || enriched.length <= 1) {
|
|
506
|
+
return suppressedIds;
|
|
507
|
+
}
|
|
508
|
+
|
|
509
|
+
const seeds = enriched.filter(item =>
|
|
510
|
+
item?.renderPassiveOverlay === false &&
|
|
511
|
+
item.rect &&
|
|
512
|
+
Number.isFinite(item.stackRank));
|
|
513
|
+
if (seeds.length === 0) {
|
|
514
|
+
return suppressedIds;
|
|
515
|
+
}
|
|
516
|
+
|
|
517
|
+
const visited = new Set();
|
|
518
|
+
const queue = seeds.map(seed => ({
|
|
519
|
+
item: seed,
|
|
520
|
+
blockerRank: Number(seed.stackRank)
|
|
521
|
+
}));
|
|
522
|
+
|
|
523
|
+
while (queue.length > 0) {
|
|
524
|
+
const current = queue.shift();
|
|
525
|
+
const currentItem = current?.item || null;
|
|
526
|
+
const blockerRank = Number(current?.blockerRank);
|
|
527
|
+
if (!currentItem?.rect || !Number.isFinite(blockerRank)) {
|
|
528
|
+
continue;
|
|
529
|
+
}
|
|
530
|
+
|
|
531
|
+
enriched.forEach(candidate => {
|
|
532
|
+
if (!candidate?.rect || candidate === currentItem) {
|
|
533
|
+
return;
|
|
534
|
+
}
|
|
535
|
+
|
|
536
|
+
const candidateRank = Number(candidate.stackRank);
|
|
537
|
+
if (Number.isFinite(candidateRank) && candidateRank > blockerRank) {
|
|
538
|
+
return;
|
|
539
|
+
}
|
|
540
|
+
|
|
541
|
+
if (!doPassiveOverlayRectsOverlap(currentItem.rect, candidate.rect)) {
|
|
542
|
+
return;
|
|
543
|
+
}
|
|
544
|
+
|
|
545
|
+
const visitKey = `${candidate.nodeId || candidate.priorityIndex}|${blockerRank}`;
|
|
546
|
+
if (visited.has(visitKey)) {
|
|
547
|
+
return;
|
|
548
|
+
}
|
|
549
|
+
|
|
550
|
+
visited.add(visitKey);
|
|
551
|
+
if (candidate.renderPassiveOverlay !== false) {
|
|
552
|
+
suppressedIds.add(candidate.nodeId);
|
|
553
|
+
}
|
|
554
|
+
|
|
555
|
+
queue.push({
|
|
556
|
+
item: candidate,
|
|
557
|
+
blockerRank
|
|
558
|
+
});
|
|
559
|
+
});
|
|
560
|
+
}
|
|
561
|
+
|
|
562
|
+
return suppressedIds;
|
|
563
|
+
}
|
|
564
|
+
|
|
565
|
+
function comparePassiveOverlayStack(a, b) {
|
|
566
|
+
const stackDelta = Number(b?.stackRank || 0) - Number(a?.stackRank || 0);
|
|
567
|
+
if (stackDelta !== 0) {
|
|
568
|
+
return stackDelta;
|
|
569
|
+
}
|
|
570
|
+
|
|
571
|
+
const sourceDelta = Number(b?.sourceIndex || 0) - Number(a?.sourceIndex || 0);
|
|
572
|
+
if (sourceDelta !== 0) {
|
|
573
|
+
return sourceDelta;
|
|
574
|
+
}
|
|
575
|
+
|
|
576
|
+
return Number(a?.priorityIndex || 0) - Number(b?.priorityIndex || 0);
|
|
577
|
+
}
|
|
578
|
+
|
|
579
|
+
function collectConnectedPassiveOverlayWinnerIds(enriched, suppressedIds) {
|
|
580
|
+
const winnerIds = new Set();
|
|
581
|
+
const candidates = Array.isArray(enriched)
|
|
582
|
+
? enriched.filter(item =>
|
|
583
|
+
item?.renderPassiveOverlay !== false &&
|
|
584
|
+
item.nodeId &&
|
|
585
|
+
item.rect &&
|
|
586
|
+
!(suppressedIds instanceof Set && suppressedIds.has(item.nodeId)))
|
|
587
|
+
: [];
|
|
588
|
+
if (candidates.length === 0) {
|
|
589
|
+
return winnerIds;
|
|
590
|
+
}
|
|
591
|
+
|
|
592
|
+
const visited = new Set();
|
|
593
|
+
candidates.forEach(seed => {
|
|
594
|
+
if (!seed?.nodeId || visited.has(seed.nodeId)) {
|
|
595
|
+
return;
|
|
596
|
+
}
|
|
597
|
+
|
|
598
|
+
const component = [];
|
|
599
|
+
const queue = [seed];
|
|
600
|
+
visited.add(seed.nodeId);
|
|
601
|
+
|
|
602
|
+
while (queue.length > 0) {
|
|
603
|
+
const current = queue.shift();
|
|
604
|
+
component.push(current);
|
|
605
|
+
|
|
606
|
+
candidates.forEach(candidate => {
|
|
607
|
+
if (!candidate?.nodeId || visited.has(candidate.nodeId)) {
|
|
608
|
+
return;
|
|
609
|
+
}
|
|
610
|
+
|
|
611
|
+
if (!doPassiveOverlayRectsOverlap(current.rect, candidate.rect)) {
|
|
612
|
+
return;
|
|
613
|
+
}
|
|
614
|
+
|
|
615
|
+
visited.add(candidate.nodeId);
|
|
616
|
+
queue.push(candidate);
|
|
617
|
+
});
|
|
618
|
+
}
|
|
619
|
+
|
|
620
|
+
component.sort(comparePassiveOverlayStack);
|
|
621
|
+
if (component[0]?.nodeId) {
|
|
622
|
+
winnerIds.add(component[0].nodeId);
|
|
623
|
+
}
|
|
624
|
+
});
|
|
625
|
+
|
|
626
|
+
return winnerIds;
|
|
627
|
+
}
|
|
628
|
+
|
|
629
|
+
function filterPassiveOverlayTopmostCandidates(module, prioritized, blockers = []) {
|
|
630
|
+
const overlayCandidates = Array.isArray(prioritized) ? prioritized : [];
|
|
631
|
+
const visualBlockers = Array.isArray(blockers) ? blockers : [];
|
|
632
|
+
const stackItems = overlayCandidates.concat(visualBlockers);
|
|
633
|
+
if (stackItems.length <= 1) {
|
|
634
|
+
return {
|
|
635
|
+
candidates: overlayCandidates,
|
|
636
|
+
suppressedCount: 0,
|
|
637
|
+
suppressedIds: new Set()
|
|
638
|
+
};
|
|
639
|
+
}
|
|
640
|
+
|
|
641
|
+
const enriched = stackItems.map((candidate, priorityIndex) => {
|
|
642
|
+
const entry = candidate?.entry || module?.nodeObjectsById?.get?.(candidate?.nodeId) || null;
|
|
643
|
+
return {
|
|
644
|
+
...candidate,
|
|
645
|
+
entry,
|
|
646
|
+
priorityIndex,
|
|
647
|
+
renderPassiveOverlay: candidate?.renderPassiveOverlay !== false,
|
|
648
|
+
stackRank: getPassiveOverlayStackRank(entry, candidate?.sourceIndex ?? priorityIndex),
|
|
649
|
+
rect: entry ? getPassiveOverlayScreenRect(module, entry) : null
|
|
650
|
+
};
|
|
651
|
+
});
|
|
652
|
+
|
|
653
|
+
const blockerConnectedSuppressedIds = collectBlockerConnectedPassiveOverlayIds(enriched);
|
|
654
|
+
const connectedWinnerIds = collectConnectedPassiveOverlayWinnerIds(enriched, blockerConnectedSuppressedIds);
|
|
655
|
+
const byStack = enriched.slice().sort(comparePassiveOverlayStack);
|
|
656
|
+
|
|
657
|
+
const acceptedTopmost = [];
|
|
658
|
+
let suppressedCount = 0;
|
|
659
|
+
const suppressedIds = new Set();
|
|
660
|
+
const suppressCandidate = candidate => {
|
|
661
|
+
if (!candidate?.nodeId || suppressedIds.has(candidate.nodeId)) {
|
|
662
|
+
return;
|
|
663
|
+
}
|
|
664
|
+
|
|
665
|
+
suppressedCount += 1;
|
|
666
|
+
suppressedIds.add(candidate.nodeId);
|
|
667
|
+
};
|
|
668
|
+
|
|
669
|
+
byStack.forEach(candidate => {
|
|
670
|
+
if (candidate.renderPassiveOverlay === false) {
|
|
671
|
+
if (candidate.rect) {
|
|
672
|
+
acceptedTopmost.push(candidate);
|
|
673
|
+
}
|
|
674
|
+
return;
|
|
675
|
+
}
|
|
676
|
+
|
|
677
|
+
if (blockerConnectedSuppressedIds.has(candidate.nodeId)) {
|
|
678
|
+
suppressCandidate(candidate);
|
|
679
|
+
return;
|
|
680
|
+
}
|
|
681
|
+
|
|
682
|
+
if (!connectedWinnerIds.has(candidate.nodeId)) {
|
|
683
|
+
suppressCandidate(candidate);
|
|
684
|
+
return;
|
|
685
|
+
}
|
|
686
|
+
|
|
687
|
+
const overlapsTopCandidate = candidate.rect && acceptedTopmost.some(existing =>
|
|
688
|
+
existing.rect && doPassiveOverlayRectsOverlap(candidate.rect, existing.rect));
|
|
689
|
+
if (overlapsTopCandidate) {
|
|
690
|
+
suppressCandidate(candidate);
|
|
691
|
+
return;
|
|
692
|
+
}
|
|
693
|
+
|
|
694
|
+
acceptedTopmost.push(candidate);
|
|
695
|
+
});
|
|
696
|
+
|
|
697
|
+
const acceptedIds = new Set(acceptedTopmost
|
|
698
|
+
.filter(candidate => candidate.renderPassiveOverlay !== false)
|
|
699
|
+
.map(candidate => candidate.nodeId));
|
|
700
|
+
return {
|
|
701
|
+
candidates: enriched
|
|
702
|
+
.filter(candidate => candidate.renderPassiveOverlay !== false && acceptedIds.has(candidate.nodeId))
|
|
703
|
+
.sort((a, b) => a.priorityIndex - b.priorityIndex),
|
|
704
|
+
suppressedCount,
|
|
705
|
+
suppressedIds
|
|
706
|
+
};
|
|
707
|
+
}
|
|
708
|
+
|
|
709
|
+
function getPassiveOverlayCardLimit(module, candidateCount) {
|
|
710
|
+
if (!(candidateCount > 0)) {
|
|
711
|
+
return 0;
|
|
712
|
+
}
|
|
713
|
+
|
|
714
|
+
const avgFrameTime = Number(module?._avgFrameTime || 0);
|
|
715
|
+
const cameraZ = Number(module?.camera?.position?.z || 0);
|
|
716
|
+
let limit = PASSIVE_OVERLAY_CARD_LIMIT_DEFAULT;
|
|
717
|
+
|
|
718
|
+
if (candidateCount >= 32) {
|
|
719
|
+
limit = Math.min(limit, PASSIVE_OVERLAY_CARD_LIMIT_DENSE);
|
|
720
|
+
}
|
|
721
|
+
|
|
722
|
+
if (avgFrameTime > 28) {
|
|
723
|
+
limit = Math.min(limit, PASSIVE_OVERLAY_CARD_LIMIT_VERY_SLOW);
|
|
724
|
+
} else if (avgFrameTime > 22) {
|
|
725
|
+
limit = Math.min(limit, 16);
|
|
726
|
+
} else if (avgFrameTime > 18) {
|
|
727
|
+
limit = Math.min(limit, 18);
|
|
728
|
+
}
|
|
729
|
+
|
|
730
|
+
if (cameraZ > 3600) {
|
|
731
|
+
limit = Math.min(limit, 16);
|
|
732
|
+
} else if (cameraZ > 3000) {
|
|
733
|
+
limit = Math.min(limit, 18);
|
|
734
|
+
} else if (cameraZ > 2200) {
|
|
735
|
+
limit = Math.min(limit, 22);
|
|
736
|
+
}
|
|
737
|
+
|
|
738
|
+
return Math.min(candidateCount, Math.max(6, limit));
|
|
739
|
+
}
|
|
740
|
+
|
|
741
|
+
function collectVisiblePassiveCandidateIds(module, state, visibleIds) {
|
|
742
|
+
const prioritized = [];
|
|
743
|
+
const blockers = [];
|
|
744
|
+
const viewportBounds = getPassiveViewportWorldBounds(module);
|
|
745
|
+
let supportedVisibleCount = 0;
|
|
746
|
+
let sourceIndex = 0;
|
|
747
|
+
let blockerCount = 0;
|
|
748
|
+
|
|
749
|
+
visibleIds.forEach(nodeId => {
|
|
750
|
+
const normalizedId = normalizeId(nodeId);
|
|
751
|
+
if (!normalizedId) {
|
|
752
|
+
return;
|
|
753
|
+
}
|
|
754
|
+
|
|
755
|
+
const entry = module?.nodeObjectsById?.get?.(normalizedId) || null;
|
|
756
|
+
if (!entry) {
|
|
757
|
+
return;
|
|
758
|
+
}
|
|
759
|
+
|
|
760
|
+
const bounds = getPassiveCandidateWorldBounds(entry);
|
|
761
|
+
if (viewportBounds && bounds && !intersectsPassiveViewport(bounds, viewportBounds)) {
|
|
762
|
+
return;
|
|
763
|
+
}
|
|
764
|
+
|
|
765
|
+
const nextSourceIndex = sourceIndex++;
|
|
766
|
+
if (!supportsPassiveDisplay(entry)) {
|
|
767
|
+
if (blocksPassiveOverlayStack(entry)) {
|
|
768
|
+
blockers.push({
|
|
769
|
+
nodeId: normalizedId,
|
|
770
|
+
entry,
|
|
771
|
+
sourceIndex: nextSourceIndex,
|
|
772
|
+
renderPassiveOverlay: false
|
|
773
|
+
});
|
|
774
|
+
blockerCount += 1;
|
|
775
|
+
}
|
|
776
|
+
return;
|
|
777
|
+
}
|
|
778
|
+
|
|
779
|
+
supportedVisibleCount += 1;
|
|
780
|
+
const card = state?.cards?.get?.(selectionCardKey(normalizedId)) || null;
|
|
781
|
+
const visibleArea = getPassiveViewportVisibleArea(bounds, viewportBounds);
|
|
782
|
+
const dx = bounds ? (bounds.centerX - Number(viewportBounds?.centerX || 0)) : 0;
|
|
783
|
+
const dy = bounds ? (bounds.centerY - Number(viewportBounds?.centerY || 0)) : 0;
|
|
784
|
+
prioritized.push({
|
|
785
|
+
nodeId: normalizedId,
|
|
786
|
+
entry,
|
|
787
|
+
sourceIndex: nextSourceIndex,
|
|
788
|
+
sticky: card && card.style.display !== 'none' ? 0 : 1,
|
|
789
|
+
canRenderFromCss: canOverlayCssEntry(entry) ? 0 : 1,
|
|
790
|
+
visibleArea,
|
|
791
|
+
distSq: (dx * dx) + (dy * dy)
|
|
792
|
+
});
|
|
793
|
+
});
|
|
794
|
+
|
|
795
|
+
prioritized.sort((a, b) => {
|
|
796
|
+
if (a.sticky !== b.sticky) {
|
|
797
|
+
return a.sticky - b.sticky;
|
|
798
|
+
}
|
|
799
|
+
if (a.canRenderFromCss !== b.canRenderFromCss) {
|
|
800
|
+
return a.canRenderFromCss - b.canRenderFromCss;
|
|
801
|
+
}
|
|
802
|
+
if (a.visibleArea !== b.visibleArea) {
|
|
803
|
+
return b.visibleArea - a.visibleArea;
|
|
804
|
+
}
|
|
805
|
+
return a.distSq - b.distSq;
|
|
806
|
+
});
|
|
807
|
+
|
|
808
|
+
const overlapFiltered = filterPassiveOverlayTopmostCandidates(module, prioritized, blockers);
|
|
809
|
+
const filteredCandidates = overlapFiltered.candidates;
|
|
810
|
+
const limit = getPassiveOverlayCardLimit(module, filteredCandidates.length);
|
|
811
|
+
const candidateIds = new Set();
|
|
812
|
+
for (let i = 0; i < filteredCandidates.length && candidateIds.size < limit; i++) {
|
|
813
|
+
candidateIds.add(filteredCandidates[i].nodeId);
|
|
814
|
+
}
|
|
815
|
+
|
|
816
|
+
module._overlayDebugPassiveVisibleCandidateCount = candidateIds.size;
|
|
817
|
+
module._overlayDebugPassiveVisibleSupportedCount = supportedVisibleCount;
|
|
818
|
+
module._overlayDebugPassiveViewportCandidateCount = prioritized.length;
|
|
819
|
+
module._overlayDebugPassiveCardLimit = limit;
|
|
820
|
+
module._overlayDebugPassiveOverlapSuppressedCount = Number(overlapFiltered.suppressedCount || 0);
|
|
821
|
+
module._overlayDebugPassiveOccluderCount = blockerCount;
|
|
822
|
+
module._overlaySuppressedPassiveNodeIds = overlapFiltered.suppressedIds instanceof Set
|
|
823
|
+
? overlapFiltered.suppressedIds
|
|
824
|
+
: new Set();
|
|
825
|
+
return candidateIds;
|
|
826
|
+
}
|
|
827
|
+
|
|
828
|
+
function shouldPreferOverlayCssZoom(module, entry = null) {
|
|
829
|
+
if (module?.renderDebugFlags?.enableOverlayCssZoom === false) {
|
|
830
|
+
return false;
|
|
831
|
+
}
|
|
832
|
+
|
|
833
|
+
if (entry && supportsTextOverlayEntry(entry)) {
|
|
834
|
+
return false;
|
|
835
|
+
}
|
|
836
|
+
|
|
837
|
+
return true;
|
|
838
|
+
}
|
|
839
|
+
|
|
840
|
+
function ensureState(module) {
|
|
841
|
+
if (!module) {
|
|
842
|
+
return null;
|
|
843
|
+
}
|
|
844
|
+
|
|
845
|
+
if (!module._textOverlayV2State) {
|
|
846
|
+
module._textOverlayV2State = {
|
|
847
|
+
layer: null,
|
|
848
|
+
cards: new Map(),
|
|
849
|
+
dirtyNodes: new Set(),
|
|
850
|
+
dirtyLayout: true,
|
|
851
|
+
dirtySelection: true,
|
|
852
|
+
dirtyEditing: true,
|
|
853
|
+
selectionNodeId: '',
|
|
854
|
+
editing: null,
|
|
855
|
+
motionHintActive: false,
|
|
856
|
+
lastPassiveRenderEnabled: null,
|
|
857
|
+
lastViewKey: '',
|
|
858
|
+
lastVisibilityVersion: -1,
|
|
859
|
+
lastInteractionKey: '',
|
|
860
|
+
layoutSnapshot: null,
|
|
861
|
+
passiveNearStickyUntil: 0,
|
|
862
|
+
passiveCandidateIds: new Set(),
|
|
863
|
+
passiveCandidateVisibleUntil: 0
|
|
864
|
+
};
|
|
865
|
+
}
|
|
866
|
+
|
|
867
|
+
return module._textOverlayV2State;
|
|
868
|
+
}
|
|
869
|
+
|
|
870
|
+
function ensureLayer(module) {
|
|
871
|
+
const state = ensureState(module);
|
|
872
|
+
if (!state || !module?.container) {
|
|
873
|
+
return null;
|
|
874
|
+
}
|
|
875
|
+
|
|
876
|
+
if (!state.layer || !state.layer.isConnected) {
|
|
877
|
+
const layer = document.createElement('div');
|
|
878
|
+
layer.className = 'mind-map-text-overlay-v2-layer';
|
|
879
|
+
state.layer = layer;
|
|
880
|
+
}
|
|
881
|
+
|
|
882
|
+
if (state.layer.parentElement !== module.container) {
|
|
883
|
+
module.container.appendChild(state.layer);
|
|
884
|
+
}
|
|
885
|
+
|
|
886
|
+
state.layer.classList.toggle('is-motion-hint', state.motionHintActive === true);
|
|
887
|
+
state.layer.style.willChange = state.motionHintActive === true ? 'transform' : 'auto';
|
|
888
|
+
state.layer.style.backfaceVisibility = state.motionHintActive === true ? 'hidden' : '';
|
|
889
|
+
state.layer.style.webkitBackfaceVisibility = state.motionHintActive === true ? 'hidden' : '';
|
|
890
|
+
|
|
891
|
+
return state.layer;
|
|
892
|
+
}
|
|
893
|
+
|
|
894
|
+
function getHostElement(entry) {
|
|
895
|
+
const wrapper = entry?.cssObject?.element || null;
|
|
896
|
+
if (!wrapper) {
|
|
897
|
+
return null;
|
|
898
|
+
}
|
|
899
|
+
|
|
900
|
+
return wrapper.firstElementChild || wrapper;
|
|
901
|
+
}
|
|
902
|
+
|
|
903
|
+
function getReadonlyCloneSourceElement(entry) {
|
|
904
|
+
return entry?.cssObject?.element || getHostElement(entry) || null;
|
|
905
|
+
}
|
|
906
|
+
|
|
907
|
+
function getReadonlySelectionSourceRoot(entry) {
|
|
908
|
+
return getHostElement(entry) || getReadonlyCloneSourceElement(entry) || null;
|
|
909
|
+
}
|
|
910
|
+
|
|
911
|
+
function getReadonlySelectionMode(entry) {
|
|
912
|
+
return getCss3dManager()?.getReadonlyTextOverlayMode?.(entry) || 'none';
|
|
913
|
+
}
|
|
914
|
+
|
|
915
|
+
function getReadonlySourceEpoch(module) {
|
|
916
|
+
return Number(module?._readonlyOverlaySourceEpoch || 0);
|
|
917
|
+
}
|
|
918
|
+
|
|
919
|
+
function bumpReadonlySourceEpoch(module) {
|
|
920
|
+
if (!module) {
|
|
921
|
+
return 0;
|
|
922
|
+
}
|
|
923
|
+
|
|
924
|
+
const nextEpoch = getReadonlySourceEpoch(module) + 1;
|
|
925
|
+
module._readonlyOverlaySourceEpoch = nextEpoch;
|
|
926
|
+
return nextEpoch;
|
|
927
|
+
}
|
|
928
|
+
|
|
929
|
+
function getDomPlacementRect(module, entry) {
|
|
930
|
+
const container = module?.container;
|
|
931
|
+
const model = getModel(entry);
|
|
932
|
+
const host = getHostElement(entry);
|
|
933
|
+
if (!container || !host || !host.isConnected) {
|
|
934
|
+
return null;
|
|
935
|
+
}
|
|
936
|
+
|
|
937
|
+
const hostRect = host.getBoundingClientRect();
|
|
938
|
+
const containerRect = container.getBoundingClientRect();
|
|
939
|
+
if (hostRect.width <= 0 || hostRect.height <= 0) {
|
|
940
|
+
return null;
|
|
941
|
+
}
|
|
942
|
+
|
|
943
|
+
const logicalWidth = Math.max(
|
|
944
|
+
Number(host.offsetWidth || 0),
|
|
945
|
+
Number(host.clientWidth || 0),
|
|
946
|
+
Number(model?.width || model?.Width || 0)
|
|
947
|
+
);
|
|
948
|
+
const logicalHeight = Math.max(
|
|
949
|
+
Number(host.offsetHeight || 0),
|
|
950
|
+
Number(host.clientHeight || 0),
|
|
951
|
+
Number(model?.height || model?.Height || 0)
|
|
952
|
+
);
|
|
953
|
+
|
|
954
|
+
return {
|
|
955
|
+
left: hostRect.left - containerRect.left,
|
|
956
|
+
top: hostRect.top - containerRect.top,
|
|
957
|
+
width: hostRect.width,
|
|
958
|
+
height: hostRect.height,
|
|
959
|
+
baseWidth: Math.max(1, logicalWidth > 0 ? logicalWidth : Math.round(hostRect.width)),
|
|
960
|
+
baseHeight: Math.max(1, logicalHeight > 0 ? logicalHeight : Math.round(hostRect.height))
|
|
961
|
+
};
|
|
962
|
+
}
|
|
963
|
+
|
|
964
|
+
function getPlacementRect(module, entry) {
|
|
965
|
+
const container = module?.container;
|
|
966
|
+
const camera = module?.camera || null;
|
|
967
|
+
const model = getModel(entry);
|
|
968
|
+
const obj = entry?.glObject || entry?.cssObject || null;
|
|
969
|
+
if (!container) {
|
|
970
|
+
return null;
|
|
971
|
+
}
|
|
972
|
+
|
|
973
|
+
const domRect = getDomPlacementRect(module, entry);
|
|
974
|
+
if (domRect) {
|
|
975
|
+
return domRect;
|
|
976
|
+
}
|
|
977
|
+
|
|
978
|
+
const THREERef = camera && obj ? ensureProjectionTemps() : null;
|
|
979
|
+
if (THREERef && obj?.matrixWorld && typeof _projCornerTopLeft?.project === 'function') {
|
|
980
|
+
const viewportWidth = Math.max(1, Number(container.clientWidth || container.offsetWidth || 0));
|
|
981
|
+
const viewportHeight = Math.max(1, Number(container.clientHeight || container.offsetHeight || 0));
|
|
982
|
+
const baseWidth = Math.max(1, Number(model?.width || model?.Width || 1));
|
|
983
|
+
const baseHeight = Math.max(1, Number(model?.height || model?.Height || 1));
|
|
984
|
+
|
|
985
|
+
obj.updateWorldMatrix?.(true, false);
|
|
986
|
+
|
|
987
|
+
const corners = [
|
|
988
|
+
_projCornerTopLeft.set(0, 0, 0).applyMatrix4(obj.matrixWorld),
|
|
989
|
+
_projCornerTopRight.set(baseWidth, 0, 0).applyMatrix4(obj.matrixWorld),
|
|
990
|
+
_projCornerBottomLeft.set(0, -baseHeight, 0).applyMatrix4(obj.matrixWorld),
|
|
991
|
+
_projCornerBottomRight.set(baseWidth, -baseHeight, 0).applyMatrix4(obj.matrixWorld)
|
|
992
|
+
];
|
|
993
|
+
|
|
994
|
+
let minX = Number.POSITIVE_INFINITY;
|
|
995
|
+
let maxX = Number.NEGATIVE_INFINITY;
|
|
996
|
+
let minY = Number.POSITIVE_INFINITY;
|
|
997
|
+
let maxY = Number.NEGATIVE_INFINITY;
|
|
998
|
+
let visibleCornerCount = 0;
|
|
999
|
+
|
|
1000
|
+
for (let i = 0; i < corners.length; i++) {
|
|
1001
|
+
const projected = corners[i].project(camera);
|
|
1002
|
+
if (!Number.isFinite(projected.x) || !Number.isFinite(projected.y) || !Number.isFinite(projected.z)) {
|
|
1003
|
+
continue;
|
|
1004
|
+
}
|
|
1005
|
+
|
|
1006
|
+
if (projected.z >= -1 && projected.z <= 1) {
|
|
1007
|
+
visibleCornerCount += 1;
|
|
1008
|
+
}
|
|
1009
|
+
|
|
1010
|
+
const screenX = (projected.x * 0.5 + 0.5) * viewportWidth;
|
|
1011
|
+
const screenY = (-projected.y * 0.5 + 0.5) * viewportHeight;
|
|
1012
|
+
minX = Math.min(minX, screenX);
|
|
1013
|
+
maxX = Math.max(maxX, screenX);
|
|
1014
|
+
minY = Math.min(minY, screenY);
|
|
1015
|
+
maxY = Math.max(maxY, screenY);
|
|
1016
|
+
}
|
|
1017
|
+
|
|
1018
|
+
if (visibleCornerCount > 0 &&
|
|
1019
|
+
Number.isFinite(minX) &&
|
|
1020
|
+
Number.isFinite(maxX) &&
|
|
1021
|
+
Number.isFinite(minY) &&
|
|
1022
|
+
Number.isFinite(maxY)) {
|
|
1023
|
+
return {
|
|
1024
|
+
left: minX,
|
|
1025
|
+
top: minY,
|
|
1026
|
+
width: Math.max(1, maxX - minX),
|
|
1027
|
+
height: Math.max(1, maxY - minY),
|
|
1028
|
+
baseWidth,
|
|
1029
|
+
baseHeight
|
|
1030
|
+
};
|
|
1031
|
+
}
|
|
1032
|
+
}
|
|
1033
|
+
|
|
1034
|
+
return null;
|
|
1035
|
+
}
|
|
1036
|
+
|
|
1037
|
+
function cloneSourceSubtree(entry, selector) {
|
|
1038
|
+
const host = getHostElement(entry);
|
|
1039
|
+
const source = host?.querySelector?.(selector) || null;
|
|
1040
|
+
if (!source) {
|
|
1041
|
+
return null;
|
|
1042
|
+
}
|
|
1043
|
+
|
|
1044
|
+
return prepareOverlayClone(source.cloneNode(true));
|
|
1045
|
+
}
|
|
1046
|
+
|
|
1047
|
+
function getReadonlyLivePortal(entry) {
|
|
1048
|
+
return entry?._readonlyOverlayLivePortal || null;
|
|
1049
|
+
}
|
|
1050
|
+
|
|
1051
|
+
function isReadonlyLivePortalActive(entry) {
|
|
1052
|
+
const portal = getReadonlyLivePortal(entry);
|
|
1053
|
+
return !!portal?.sourceElement && !!portal?.active;
|
|
1054
|
+
}
|
|
1055
|
+
|
|
1056
|
+
function clearReadonlyLivePortalStyles(sourceElement, portal) {
|
|
1057
|
+
if (!sourceElement?.style || !portal) {
|
|
1058
|
+
return;
|
|
1059
|
+
}
|
|
1060
|
+
|
|
1061
|
+
sourceElement.classList?.remove?.('mind-map-text-overlay-v2-live-source');
|
|
1062
|
+
sourceElement.style.width = portal.width ?? '';
|
|
1063
|
+
sourceElement.style.height = portal.height ?? '';
|
|
1064
|
+
sourceElement.style.transform = portal.transform ?? '';
|
|
1065
|
+
sourceElement.style.transformOrigin = portal.transformOrigin ?? '';
|
|
1066
|
+
sourceElement.style.zoom = portal.zoom ?? '';
|
|
1067
|
+
sourceElement.style.pointerEvents = portal.pointerEvents ?? '';
|
|
1068
|
+
sourceElement.style.userSelect = portal.userSelect ?? '';
|
|
1069
|
+
sourceElement.style.webkitUserSelect = portal.webkitUserSelect ?? '';
|
|
1070
|
+
}
|
|
1071
|
+
|
|
1072
|
+
function restoreReadonlyLivePortal(entry) {
|
|
1073
|
+
const portal = getReadonlyLivePortal(entry);
|
|
1074
|
+
if (!portal?.sourceElement) {
|
|
1075
|
+
return false;
|
|
1076
|
+
}
|
|
1077
|
+
|
|
1078
|
+
const sourceElement = portal.sourceElement;
|
|
1079
|
+
clearReadonlyLivePortalStyles(sourceElement, portal);
|
|
1080
|
+
|
|
1081
|
+
const parent = portal.parentElement || null;
|
|
1082
|
+
const nextSibling = portal.nextSibling || null;
|
|
1083
|
+
if (parent?.isConnected) {
|
|
1084
|
+
if (nextSibling?.parentElement === parent) {
|
|
1085
|
+
parent.insertBefore(sourceElement, nextSibling);
|
|
1086
|
+
} else {
|
|
1087
|
+
parent.appendChild(sourceElement);
|
|
1088
|
+
}
|
|
1089
|
+
}
|
|
1090
|
+
|
|
1091
|
+
if (portal.cardElement?.firstElementChild === sourceElement) {
|
|
1092
|
+
portal.cardElement.removeChild(sourceElement);
|
|
1093
|
+
}
|
|
1094
|
+
|
|
1095
|
+
entry._readonlyOverlayLivePortal = null;
|
|
1096
|
+
return true;
|
|
1097
|
+
}
|
|
1098
|
+
|
|
1099
|
+
function createReadonlyLiveSourcePortal(entry, card, options = {}) {
|
|
1100
|
+
if (!entry || !card || options.interactive === true) {
|
|
1101
|
+
return null;
|
|
1102
|
+
}
|
|
1103
|
+
|
|
1104
|
+
const existingPortal = getReadonlyLivePortal(entry);
|
|
1105
|
+
if (existingPortal?.active && existingPortal.sourceElement) {
|
|
1106
|
+
if (existingPortal.sourceElement.parentElement !== card) {
|
|
1107
|
+
card.appendChild(existingPortal.sourceElement);
|
|
1108
|
+
}
|
|
1109
|
+
|
|
1110
|
+
existingPortal.cardElement = card;
|
|
1111
|
+
return {
|
|
1112
|
+
container: existingPortal.sourceElement,
|
|
1113
|
+
sourceRoot: existingPortal.sourceElement,
|
|
1114
|
+
liveSource: true
|
|
1115
|
+
};
|
|
1116
|
+
}
|
|
1117
|
+
|
|
1118
|
+
const wrapper = entry?.cssObject?.element || null;
|
|
1119
|
+
const sourceElement = getReadonlySelectionSourceRoot(entry);
|
|
1120
|
+
if (!wrapper || !sourceElement || sourceElement === wrapper) {
|
|
1121
|
+
return null;
|
|
1122
|
+
}
|
|
1123
|
+
|
|
1124
|
+
if (existingPortal?.active) {
|
|
1125
|
+
restoreReadonlyLivePortal(entry);
|
|
1126
|
+
}
|
|
1127
|
+
|
|
1128
|
+
entry._readonlyOverlayLivePortal = {
|
|
1129
|
+
active: true,
|
|
1130
|
+
cardElement: card,
|
|
1131
|
+
parentElement: sourceElement.parentElement || null,
|
|
1132
|
+
nextSibling: sourceElement.nextSibling || null,
|
|
1133
|
+
sourceElement: sourceElement,
|
|
1134
|
+
width: sourceElement.style.width,
|
|
1135
|
+
height: sourceElement.style.height,
|
|
1136
|
+
transform: sourceElement.style.transform,
|
|
1137
|
+
transformOrigin: sourceElement.style.transformOrigin,
|
|
1138
|
+
zoom: sourceElement.style.zoom,
|
|
1139
|
+
pointerEvents: sourceElement.style.pointerEvents,
|
|
1140
|
+
userSelect: sourceElement.style.userSelect,
|
|
1141
|
+
webkitUserSelect: sourceElement.style.webkitUserSelect
|
|
1142
|
+
};
|
|
1143
|
+
|
|
1144
|
+
sourceElement.classList.add('mind-map-text-overlay-v2-live-source');
|
|
1145
|
+
sourceElement.style.pointerEvents = 'none';
|
|
1146
|
+
sourceElement.style.userSelect = 'none';
|
|
1147
|
+
sourceElement.style.webkitUserSelect = 'none';
|
|
1148
|
+
card.appendChild(sourceElement);
|
|
1149
|
+
|
|
1150
|
+
return {
|
|
1151
|
+
container: sourceElement,
|
|
1152
|
+
sourceRoot: sourceElement,
|
|
1153
|
+
liveSource: true
|
|
1154
|
+
};
|
|
1155
|
+
}
|
|
1156
|
+
|
|
1157
|
+
function resolveOverlayZIndex(entry, baseZIndex) {
|
|
1158
|
+
const candidate = getPassiveOverlayStackRank(entry, 0);
|
|
1159
|
+
|
|
1160
|
+
if (!Number.isFinite(candidate)) {
|
|
1161
|
+
return baseZIndex;
|
|
1162
|
+
}
|
|
1163
|
+
|
|
1164
|
+
return Math.max(baseZIndex, candidate + baseZIndex);
|
|
1165
|
+
}
|
|
1166
|
+
|
|
1167
|
+
function applyPlacement(module, element, rect, zIndex, entry = null) {
|
|
1168
|
+
if (!module || !element || !rect) {
|
|
1169
|
+
return;
|
|
1170
|
+
}
|
|
1171
|
+
|
|
1172
|
+
const baseWidth = Math.max(1, Number(rect.baseWidth || rect.width || 1));
|
|
1173
|
+
const baseHeight = Math.max(1, Number(rect.baseHeight || rect.height || 1));
|
|
1174
|
+
const scaleX = Number(rect.width || baseWidth) / baseWidth;
|
|
1175
|
+
const scaleY = Number(rect.height || baseHeight) / baseHeight;
|
|
1176
|
+
const preferCssZoom = shouldPreferOverlayCssZoom(module, entry);
|
|
1177
|
+
const canUseZoom =
|
|
1178
|
+
preferCssZoom &&
|
|
1179
|
+
Number.isFinite(scaleX) &&
|
|
1180
|
+
Number.isFinite(scaleY) &&
|
|
1181
|
+
scaleX > 0 &&
|
|
1182
|
+
scaleY > 0 &&
|
|
1183
|
+
Math.abs(scaleX - scaleY) < 0.02;
|
|
1184
|
+
const shell = element.firstElementChild || null;
|
|
1185
|
+
|
|
1186
|
+
element.style.display = 'block';
|
|
1187
|
+
element.style.left = `${Number(rect.left || 0)}px`;
|
|
1188
|
+
element.style.top = `${Number(rect.top || 0)}px`;
|
|
1189
|
+
element.style.width = `${Math.max(1, Number(rect.width || baseWidth || 1))}px`;
|
|
1190
|
+
element.style.height = `${Math.max(1, Number(rect.height || baseHeight || 1))}px`;
|
|
1191
|
+
element.style.transform = '';
|
|
1192
|
+
element.style.zoom = '';
|
|
1193
|
+
applyScrollbarScaleCompensation(element, scaleX, scaleY);
|
|
1194
|
+
applyScrollbarScaleCompensation(entry?.cssObject?.element || null, scaleX, scaleY);
|
|
1195
|
+
|
|
1196
|
+
if (shell?.style) {
|
|
1197
|
+
shell.style.width = `${baseWidth}px`;
|
|
1198
|
+
shell.style.height = `${baseHeight}px`;
|
|
1199
|
+
shell.style.transformOrigin = '0 0';
|
|
1200
|
+
shell.style.zoom = '';
|
|
1201
|
+
shell.style.transform = '';
|
|
1202
|
+
applyScrollbarScaleCompensation(shell, scaleX, scaleY);
|
|
1203
|
+
|
|
1204
|
+
if (canUseZoom) {
|
|
1205
|
+
shell.style.zoom = `${scaleX}`;
|
|
1206
|
+
module._overlayDebugPlacementZoomCount = Number(module._overlayDebugPlacementZoomCount || 0) + 1;
|
|
1207
|
+
} else {
|
|
1208
|
+
shell.style.transform = `scale(${scaleX}, ${scaleY})`;
|
|
1209
|
+
module._overlayDebugPlacementTransformCount = Number(module._overlayDebugPlacementTransformCount || 0) + 1;
|
|
1210
|
+
}
|
|
1211
|
+
} else if (!canUseZoom) {
|
|
1212
|
+
element.style.transform = `scale(${scaleX}, ${scaleY})`;
|
|
1213
|
+
module._overlayDebugPlacementTransformCount = Number(module._overlayDebugPlacementTransformCount || 0) + 1;
|
|
1214
|
+
}
|
|
1215
|
+
element.style.zIndex = String(resolveOverlayZIndex(entry, zIndex));
|
|
1216
|
+
}
|
|
1217
|
+
|
|
1218
|
+
function applyScrollbarScaleCompensation(target, scaleX, scaleY) {
|
|
1219
|
+
if (!target) {
|
|
1220
|
+
return;
|
|
1221
|
+
}
|
|
1222
|
+
|
|
1223
|
+
const scrollbarSizeX = 8;
|
|
1224
|
+
const scrollbarSizeY = 8;
|
|
1225
|
+
const scrollbarGutter = 14;
|
|
1226
|
+
|
|
1227
|
+
const applyVars = (element) => {
|
|
1228
|
+
const style = element?.style;
|
|
1229
|
+
if (!style) {
|
|
1230
|
+
return;
|
|
1231
|
+
}
|
|
1232
|
+
|
|
1233
|
+
style.setProperty('--mind-map-text-scrollbar-size', `${scrollbarSizeX}px`);
|
|
1234
|
+
style.setProperty('--mind-map-text-scrollbar-size-x', `${scrollbarSizeX}px`);
|
|
1235
|
+
style.setProperty('--mind-map-text-scrollbar-size-y', `${scrollbarSizeY}px`);
|
|
1236
|
+
style.setProperty('--mind-map-text-scrollbar-gutter', `${scrollbarGutter}px`);
|
|
1237
|
+
style.scrollbarWidth = 'thin';
|
|
1238
|
+
style.scrollbarColor = 'rgba(0, 0, 0, 0.2) transparent';
|
|
1239
|
+
};
|
|
1240
|
+
|
|
1241
|
+
applyVars(target);
|
|
1242
|
+
target.querySelectorAll?.(
|
|
1243
|
+
'.thin-scrollbar, .note-textarea, .note-content, .markdown-body, .prose, .code-body, .map-node-memo__body, .map-node-memo__body-view'
|
|
1244
|
+
)?.forEach?.(applyVars);
|
|
1245
|
+
}
|
|
1246
|
+
|
|
1247
|
+
function setSourceAgentConsoleOverlayMode(wrapper, enabled) {
|
|
1248
|
+
const consolePanel = wrapper?.querySelector?.('.map-node-memo__agent-console-panel') || null;
|
|
1249
|
+
if (!consolePanel) {
|
|
1250
|
+
return;
|
|
1251
|
+
}
|
|
1252
|
+
|
|
1253
|
+
const targets = [consolePanel, ...Array.from(consolePanel.querySelectorAll?.('*') || [])];
|
|
1254
|
+
targets.forEach(target => {
|
|
1255
|
+
if (!target?.style) {
|
|
1256
|
+
return;
|
|
1257
|
+
}
|
|
1258
|
+
|
|
1259
|
+
if (enabled) {
|
|
1260
|
+
target.style.pointerEvents = 'auto';
|
|
1261
|
+
return;
|
|
1262
|
+
}
|
|
1263
|
+
|
|
1264
|
+
target.style.pointerEvents = '';
|
|
1265
|
+
});
|
|
1266
|
+
}
|
|
1267
|
+
|
|
1268
|
+
function suspendSource(entry, options = {}) {
|
|
1269
|
+
const wrapper = entry?.cssObject?.element || null;
|
|
1270
|
+
if (!wrapper) {
|
|
1271
|
+
return;
|
|
1272
|
+
}
|
|
1273
|
+
|
|
1274
|
+
const disablePointerEvents = options.disablePointerEvents !== false;
|
|
1275
|
+
if (isReadonlyLivePortalActive(entry)) {
|
|
1276
|
+
wrapper.style.pointerEvents = disablePointerEvents ? 'none' : '';
|
|
1277
|
+
if (wrapper.firstElementChild) {
|
|
1278
|
+
wrapper.firstElementChild.style.pointerEvents = disablePointerEvents ? 'none' : '';
|
|
1279
|
+
}
|
|
1280
|
+
setSourceAgentConsoleOverlayMode(wrapper, true);
|
|
1281
|
+
return;
|
|
1282
|
+
}
|
|
1283
|
+
|
|
1284
|
+
window.MindMapCss3DManager?.setTextOverlaySourceActive?.(entry, true);
|
|
1285
|
+
wrapper.classList.add('mind-map-v2-source-suspended');
|
|
1286
|
+
if (disablePointerEvents) {
|
|
1287
|
+
wrapper.style.pointerEvents = 'none';
|
|
1288
|
+
if (wrapper.firstElementChild) {
|
|
1289
|
+
wrapper.firstElementChild.style.pointerEvents = 'none';
|
|
1290
|
+
}
|
|
1291
|
+
} else {
|
|
1292
|
+
wrapper.style.pointerEvents = '';
|
|
1293
|
+
if (wrapper.firstElementChild) {
|
|
1294
|
+
wrapper.firstElementChild.style.pointerEvents = '';
|
|
1295
|
+
}
|
|
1296
|
+
}
|
|
1297
|
+
setSourceAgentConsoleOverlayMode(wrapper, true);
|
|
1298
|
+
}
|
|
1299
|
+
|
|
1300
|
+
function resumeSource(entry) {
|
|
1301
|
+
const wrapper = entry?.cssObject?.element || null;
|
|
1302
|
+
if (!wrapper) {
|
|
1303
|
+
return;
|
|
1304
|
+
}
|
|
1305
|
+
|
|
1306
|
+
restoreReadonlyLivePortal(entry);
|
|
1307
|
+
window.MindMapCss3DManager?.setTextOverlaySourceActive?.(entry, false);
|
|
1308
|
+
wrapper.classList.remove('mind-map-v2-source-suspended');
|
|
1309
|
+
wrapper.style.pointerEvents = '';
|
|
1310
|
+
if (wrapper.firstElementChild) {
|
|
1311
|
+
wrapper.firstElementChild.style.pointerEvents = '';
|
|
1312
|
+
}
|
|
1313
|
+
setSourceAgentConsoleOverlayMode(wrapper, false);
|
|
1314
|
+
}
|
|
1315
|
+
|
|
1316
|
+
function selectionCardKey(nodeId) {
|
|
1317
|
+
return `selection:${normalizeId(nodeId)}`;
|
|
1318
|
+
}
|
|
1319
|
+
|
|
1320
|
+
function editingCardKey(nodeId) {
|
|
1321
|
+
return `editing:${normalizeId(nodeId)}`;
|
|
1322
|
+
}
|
|
1323
|
+
|
|
1324
|
+
function ensureCard(module, cardKey, nodeId, kind) {
|
|
1325
|
+
const state = ensureState(module);
|
|
1326
|
+
const layer = ensureLayer(module);
|
|
1327
|
+
if (!state || !layer || !cardKey) {
|
|
1328
|
+
return null;
|
|
1329
|
+
}
|
|
1330
|
+
|
|
1331
|
+
let card = state.cards.get(cardKey) || null;
|
|
1332
|
+
if (!card) {
|
|
1333
|
+
card = document.createElement('div');
|
|
1334
|
+
card.className = 'mind-map-text-overlay-v2-card';
|
|
1335
|
+
state.cards.set(cardKey, card);
|
|
1336
|
+
layer.appendChild(card);
|
|
1337
|
+
} else if (card.parentElement !== layer) {
|
|
1338
|
+
layer.appendChild(card);
|
|
1339
|
+
}
|
|
1340
|
+
|
|
1341
|
+
card.dataset.cardKey = cardKey;
|
|
1342
|
+
card.dataset.nodeId = normalizeId(nodeId);
|
|
1343
|
+
card.dataset.kind = kind;
|
|
1344
|
+
return card;
|
|
1345
|
+
}
|
|
1346
|
+
|
|
1347
|
+
function hideCard(card) {
|
|
1348
|
+
if (!card) {
|
|
1349
|
+
return;
|
|
1350
|
+
}
|
|
1351
|
+
|
|
1352
|
+
card.style.display = 'none';
|
|
1353
|
+
}
|
|
1354
|
+
|
|
1355
|
+
function removeCard(state, cardKey) {
|
|
1356
|
+
if (!state || !cardKey) {
|
|
1357
|
+
return false;
|
|
1358
|
+
}
|
|
1359
|
+
|
|
1360
|
+
const card = state.cards.get(cardKey) || null;
|
|
1361
|
+
if (!card) {
|
|
1362
|
+
return false;
|
|
1363
|
+
}
|
|
1364
|
+
|
|
1365
|
+
hideCard(card);
|
|
1366
|
+
card.replaceChildren?.();
|
|
1367
|
+
card.remove?.();
|
|
1368
|
+
state.cards.delete(cardKey);
|
|
1369
|
+
return true;
|
|
1370
|
+
}
|
|
1371
|
+
|
|
1372
|
+
function purgeMediaOverlayCards(module, state = ensureState(module), options = {}) {
|
|
1373
|
+
if (!module || !state) {
|
|
1374
|
+
return 0;
|
|
1375
|
+
}
|
|
1376
|
+
|
|
1377
|
+
const sourceIdsToResume = new Set();
|
|
1378
|
+
const cardKeysToRemove = [];
|
|
1379
|
+
state.cards.forEach((card, cardKey) => {
|
|
1380
|
+
const nodeId = normalizeId(card?.dataset?.nodeId);
|
|
1381
|
+
const entry = nodeId ? module?.nodeObjectsById?.get?.(nodeId) || null : null;
|
|
1382
|
+
const cardContentType = String(card?.dataset?.contentType || '').trim().toLowerCase();
|
|
1383
|
+
const isMediaCard =
|
|
1384
|
+
isMediaOverlayExcluded(entry) ||
|
|
1385
|
+
cardContentType === 'image' ||
|
|
1386
|
+
cardContentType === 'video' ||
|
|
1387
|
+
cardContentType === 'embed';
|
|
1388
|
+
if (!isMediaCard) {
|
|
1389
|
+
return;
|
|
1390
|
+
}
|
|
1391
|
+
|
|
1392
|
+
if (nodeId) {
|
|
1393
|
+
sourceIdsToResume.add(nodeId);
|
|
1394
|
+
state.passiveCandidateIds?.delete?.(nodeId);
|
|
1395
|
+
}
|
|
1396
|
+
cardKeysToRemove.push(cardKey);
|
|
1397
|
+
});
|
|
1398
|
+
|
|
1399
|
+
const knownCards = new Set(state.cards.values());
|
|
1400
|
+
state.layer?.querySelectorAll?.('.mind-map-text-overlay-v2-card')?.forEach?.(card => {
|
|
1401
|
+
if (knownCards.has(card)) {
|
|
1402
|
+
return;
|
|
1403
|
+
}
|
|
1404
|
+
|
|
1405
|
+
const nodeId = normalizeId(card?.dataset?.nodeId);
|
|
1406
|
+
const entry = nodeId ? module?.nodeObjectsById?.get?.(nodeId) || null : null;
|
|
1407
|
+
const cardContentType = String(card?.dataset?.contentType || '').trim().toLowerCase();
|
|
1408
|
+
const isMediaCard =
|
|
1409
|
+
isMediaOverlayExcluded(entry) ||
|
|
1410
|
+
cardContentType === 'image' ||
|
|
1411
|
+
cardContentType === 'video' ||
|
|
1412
|
+
cardContentType === 'embed';
|
|
1413
|
+
if (!isMediaCard) {
|
|
1414
|
+
return;
|
|
1415
|
+
}
|
|
1416
|
+
|
|
1417
|
+
if (entry) {
|
|
1418
|
+
resumeSource(entry);
|
|
1419
|
+
}
|
|
1420
|
+
hideCard(card);
|
|
1421
|
+
card.replaceChildren?.();
|
|
1422
|
+
card.remove?.();
|
|
1423
|
+
});
|
|
1424
|
+
|
|
1425
|
+
const selectedNodeId = normalizeId(module?.selectedNodeIdJs);
|
|
1426
|
+
const activeSelectionNodeId = normalizeId(state.selectionNodeId);
|
|
1427
|
+
const editingNodeId = normalizeId(state?.editing?.nodeId);
|
|
1428
|
+
[selectedNodeId, activeSelectionNodeId, editingNodeId].forEach(nodeId => {
|
|
1429
|
+
if (!nodeId) {
|
|
1430
|
+
return;
|
|
1431
|
+
}
|
|
1432
|
+
|
|
1433
|
+
const entry = module?.nodeObjectsById?.get?.(nodeId) || null;
|
|
1434
|
+
if (!isMediaOverlayExcluded(entry)) {
|
|
1435
|
+
return;
|
|
1436
|
+
}
|
|
1437
|
+
|
|
1438
|
+
sourceIdsToResume.add(nodeId);
|
|
1439
|
+
state.passiveCandidateIds?.delete?.(nodeId);
|
|
1440
|
+
cardKeysToRemove.push(selectionCardKey(nodeId), editingCardKey(nodeId));
|
|
1441
|
+
if (activeSelectionNodeId === nodeId) {
|
|
1442
|
+
state.selectionNodeId = '';
|
|
1443
|
+
}
|
|
1444
|
+
if (editingNodeId === nodeId) {
|
|
1445
|
+
state.editing = null;
|
|
1446
|
+
}
|
|
1447
|
+
});
|
|
1448
|
+
|
|
1449
|
+
if (options.resumeAllMedia === true && module?.nodeObjectsById?.forEach) {
|
|
1450
|
+
module.nodeObjectsById.forEach((entry, nodeId) => {
|
|
1451
|
+
if (isMediaOverlayExcluded(entry)) {
|
|
1452
|
+
sourceIdsToResume.add(normalizeId(nodeId || getNodeId(entry)));
|
|
1453
|
+
}
|
|
1454
|
+
});
|
|
1455
|
+
}
|
|
1456
|
+
|
|
1457
|
+
sourceIdsToResume.forEach(nodeId => {
|
|
1458
|
+
const entry = module?.nodeObjectsById?.get?.(nodeId) || null;
|
|
1459
|
+
if (entry) {
|
|
1460
|
+
resumeSource(entry);
|
|
1461
|
+
}
|
|
1462
|
+
});
|
|
1463
|
+
|
|
1464
|
+
let removedCount = 0;
|
|
1465
|
+
new Set(cardKeysToRemove).forEach(cardKey => {
|
|
1466
|
+
if (removeCard(state, cardKey)) {
|
|
1467
|
+
removedCount += 1;
|
|
1468
|
+
}
|
|
1469
|
+
});
|
|
1470
|
+
|
|
1471
|
+
if (removedCount > 0) {
|
|
1472
|
+
state.dirtyLayout = true;
|
|
1473
|
+
module._overlayDirty = true;
|
|
1474
|
+
module._lastOverlayKey = '';
|
|
1475
|
+
syncLayerVisibility(module);
|
|
1476
|
+
}
|
|
1477
|
+
|
|
1478
|
+
return removedCount;
|
|
1479
|
+
}
|
|
1480
|
+
|
|
1481
|
+
function setCardMode(card, mode, interactive = true) {
|
|
1482
|
+
if (!card) {
|
|
1483
|
+
return;
|
|
1484
|
+
}
|
|
1485
|
+
|
|
1486
|
+
const isInteractiveSelection = mode === 'selection' && interactive;
|
|
1487
|
+
card.classList.toggle('is-selection', mode === 'selection');
|
|
1488
|
+
card.classList.toggle('is-editing', mode === 'editing');
|
|
1489
|
+
card.classList.toggle('mind-map-text-overlay-selectable', isInteractiveSelection);
|
|
1490
|
+
card.classList.toggle('is-passive', mode === 'selection' && !interactive);
|
|
1491
|
+
card.dataset.overlayMode = String(mode || '');
|
|
1492
|
+
card.dataset.overlayInteractive = interactive ? 'true' : 'false';
|
|
1493
|
+
card.style.pointerEvents = (mode === 'selection' && !interactive) ? 'none' : 'auto';
|
|
1494
|
+
}
|
|
1495
|
+
|
|
1496
|
+
function preserveBodyScroll(card) {
|
|
1497
|
+
const body = card?.querySelector?.('.mind-map-text-overlay-v2-body');
|
|
1498
|
+
if (!body) {
|
|
1499
|
+
return null;
|
|
1500
|
+
}
|
|
1501
|
+
|
|
1502
|
+
const source = body._mindMapSourceScrollTarget || null;
|
|
1503
|
+
if (source) {
|
|
1504
|
+
return {
|
|
1505
|
+
top: source.scrollTop || 0,
|
|
1506
|
+
left: source.scrollLeft || 0
|
|
1507
|
+
};
|
|
1508
|
+
}
|
|
1509
|
+
|
|
1510
|
+
return {
|
|
1511
|
+
top: body.scrollTop,
|
|
1512
|
+
left: body.scrollLeft
|
|
1513
|
+
};
|
|
1514
|
+
}
|
|
1515
|
+
|
|
1516
|
+
function restoreBodyScroll(card, scrollState) {
|
|
1517
|
+
if (!scrollState) {
|
|
1518
|
+
return;
|
|
1519
|
+
}
|
|
1520
|
+
|
|
1521
|
+
const body = card?.querySelector?.('.mind-map-text-overlay-v2-body');
|
|
1522
|
+
if (!body) {
|
|
1523
|
+
return;
|
|
1524
|
+
}
|
|
1525
|
+
|
|
1526
|
+
const source = body._mindMapSourceScrollTarget || null;
|
|
1527
|
+
if (source) {
|
|
1528
|
+
syncScrollPositionByRatio(source, body);
|
|
1529
|
+
return;
|
|
1530
|
+
}
|
|
1531
|
+
|
|
1532
|
+
body.scrollTop = scrollState.top || 0;
|
|
1533
|
+
body.scrollLeft = scrollState.left || 0;
|
|
1534
|
+
}
|
|
1535
|
+
|
|
1536
|
+
function hashText(value) {
|
|
1537
|
+
const text = String(value ?? '');
|
|
1538
|
+
let hash = 0;
|
|
1539
|
+
for (let i = 0; i < text.length; i += 1) {
|
|
1540
|
+
hash = ((hash * 31) + text.charCodeAt(i)) | 0;
|
|
1541
|
+
}
|
|
1542
|
+
|
|
1543
|
+
return String(hash >>> 0);
|
|
1544
|
+
}
|
|
1545
|
+
|
|
1546
|
+
function getMemoSourceElement(entry) {
|
|
1547
|
+
const host = getHostElement(entry);
|
|
1548
|
+
if (!host) {
|
|
1549
|
+
return null;
|
|
1550
|
+
}
|
|
1551
|
+
|
|
1552
|
+
if (host.matches?.('.map-node-memo')) {
|
|
1553
|
+
return host;
|
|
1554
|
+
}
|
|
1555
|
+
|
|
1556
|
+
return host.querySelector?.('.map-node-memo') || host;
|
|
1557
|
+
}
|
|
1558
|
+
|
|
1559
|
+
function buildMemoAgentOverlayKey(entry) {
|
|
1560
|
+
const sourceRoot = getMemoSourceElement(entry);
|
|
1561
|
+
if (!sourceRoot) {
|
|
1562
|
+
return '';
|
|
1563
|
+
}
|
|
1564
|
+
|
|
1565
|
+
const planPanel = sourceRoot.querySelector?.('.map-node-memo__agent-plan-panel') || null;
|
|
1566
|
+
const consolePanel = sourceRoot.querySelector?.('.map-node-memo__agent-console-panel') || null;
|
|
1567
|
+
if (!planPanel && !consolePanel) {
|
|
1568
|
+
return '';
|
|
1569
|
+
}
|
|
1570
|
+
|
|
1571
|
+
return JSON.stringify({
|
|
1572
|
+
planOpen: String(sourceRoot.dataset?.agentPlanOpen || ''),
|
|
1573
|
+
planReviewed: String(sourceRoot.dataset?.agentPlanReviewed || ''),
|
|
1574
|
+
consoleOpen: String(sourceRoot.dataset?.agentConsoleOpen || ''),
|
|
1575
|
+
consoleHeight: String(sourceRoot.dataset?.agentConsoleHeight || consolePanel?.style?.height || ''),
|
|
1576
|
+
actionPending: String(sourceRoot.dataset?.agentActionPending || ''),
|
|
1577
|
+
pendingAction: String(sourceRoot.dataset?.agentPendingAction || ''),
|
|
1578
|
+
planDisplay: String(planPanel?.style?.display || ''),
|
|
1579
|
+
consoleDisplay: String(consolePanel?.style?.display || ''),
|
|
1580
|
+
planHash: hashText(planPanel?.textContent || ''),
|
|
1581
|
+
consoleHash: hashText(consolePanel?.textContent || '')
|
|
1582
|
+
});
|
|
1583
|
+
}
|
|
1584
|
+
|
|
1585
|
+
function stripCloneIds(root) {
|
|
1586
|
+
if (!root) {
|
|
1587
|
+
return;
|
|
1588
|
+
}
|
|
1589
|
+
|
|
1590
|
+
if (root.id) {
|
|
1591
|
+
root.removeAttribute('id');
|
|
1592
|
+
}
|
|
1593
|
+
|
|
1594
|
+
root.querySelectorAll?.('[id]').forEach(element => {
|
|
1595
|
+
element.removeAttribute('id');
|
|
1596
|
+
});
|
|
1597
|
+
}
|
|
1598
|
+
|
|
1599
|
+
function prepareOverlayClone(root) {
|
|
1600
|
+
if (!root) {
|
|
1601
|
+
return null;
|
|
1602
|
+
}
|
|
1603
|
+
|
|
1604
|
+
stripCloneIds(root);
|
|
1605
|
+
|
|
1606
|
+
const nodes = [root, ...Array.from(root.querySelectorAll?.('*') || [])];
|
|
1607
|
+
nodes.forEach(node => {
|
|
1608
|
+
if (!node?.style) {
|
|
1609
|
+
return;
|
|
1610
|
+
}
|
|
1611
|
+
|
|
1612
|
+
node.setAttribute?.('aria-hidden', 'true');
|
|
1613
|
+
node.style.pointerEvents = 'none';
|
|
1614
|
+
|
|
1615
|
+
if (node.tagName === 'INPUT' || node.tagName === 'TEXTAREA') {
|
|
1616
|
+
node.readOnly = true;
|
|
1617
|
+
node.tabIndex = -1;
|
|
1618
|
+
} else if (node.tagName === 'BUTTON') {
|
|
1619
|
+
node.tabIndex = -1;
|
|
1620
|
+
}
|
|
1621
|
+
});
|
|
1622
|
+
|
|
1623
|
+
return root;
|
|
1624
|
+
}
|
|
1625
|
+
|
|
1626
|
+
function clearSourcePresentationOverrides(root) {
|
|
1627
|
+
if (!root) {
|
|
1628
|
+
return null;
|
|
1629
|
+
}
|
|
1630
|
+
|
|
1631
|
+
const targets = [root, ...Array.from(root.querySelectorAll?.('*') || [])];
|
|
1632
|
+
targets.forEach(target => {
|
|
1633
|
+
if (!target?.style) {
|
|
1634
|
+
return;
|
|
1635
|
+
}
|
|
1636
|
+
|
|
1637
|
+
target.classList?.remove?.('mind-map-v2-source-suspended');
|
|
1638
|
+
target.classList?.remove?.('mind-map-text-overlay-source-suspended');
|
|
1639
|
+
target.removeAttribute?.('data-text-overlay-source-suspended');
|
|
1640
|
+
target.style.opacity = '';
|
|
1641
|
+
target.style.caretColor = '';
|
|
1642
|
+
target.style.contentVisibility = '';
|
|
1643
|
+
target.style.containIntrinsicSize = '';
|
|
1644
|
+
target.style.contain = '';
|
|
1645
|
+
});
|
|
1646
|
+
|
|
1647
|
+
return root;
|
|
1648
|
+
}
|
|
1649
|
+
|
|
1650
|
+
function cloneReadonlyFragment(sourceElement) {
|
|
1651
|
+
if (!sourceElement) {
|
|
1652
|
+
return null;
|
|
1653
|
+
}
|
|
1654
|
+
|
|
1655
|
+
const clone = sourceElement.cloneNode(true);
|
|
1656
|
+
if (clone && (sourceElement.tagName === 'TEXTAREA' || sourceElement.tagName === 'INPUT')) {
|
|
1657
|
+
clone.value = sourceElement.value ?? sourceElement.getAttribute?.('value') ?? '';
|
|
1658
|
+
}
|
|
1659
|
+
|
|
1660
|
+
clearSourcePresentationOverrides(clone);
|
|
1661
|
+
clone.querySelectorAll?.('.map-node-memo__icon-popover')?.forEach?.(element => element.remove());
|
|
1662
|
+
return prepareOverlayClone(clone);
|
|
1663
|
+
}
|
|
1664
|
+
|
|
1665
|
+
function readComputedStyleValue(computed, property, cssName = null) {
|
|
1666
|
+
if (!computed) {
|
|
1667
|
+
return '';
|
|
1668
|
+
}
|
|
1669
|
+
|
|
1670
|
+
const directValue = property ? computed[property] : '';
|
|
1671
|
+
if (directValue !== null && directValue !== undefined && directValue !== '') {
|
|
1672
|
+
return String(directValue);
|
|
1673
|
+
}
|
|
1674
|
+
|
|
1675
|
+
if (cssName && typeof computed.getPropertyValue === 'function') {
|
|
1676
|
+
const rawValue = computed.getPropertyValue(cssName);
|
|
1677
|
+
if (rawValue !== null && rawValue !== undefined && rawValue !== '') {
|
|
1678
|
+
return String(rawValue).trim();
|
|
1679
|
+
}
|
|
1680
|
+
}
|
|
1681
|
+
|
|
1682
|
+
return '';
|
|
1683
|
+
}
|
|
1684
|
+
|
|
1685
|
+
const TEXT_OVERLAY_LAYOUT_SYNC_CSS_PROPERTIES = [
|
|
1686
|
+
'padding-top',
|
|
1687
|
+
'padding-right',
|
|
1688
|
+
'padding-bottom',
|
|
1689
|
+
'padding-left',
|
|
1690
|
+
'overflow',
|
|
1691
|
+
'overflow-x',
|
|
1692
|
+
'overflow-y',
|
|
1693
|
+
'scrollbar-gutter',
|
|
1694
|
+
'scrollbar-width',
|
|
1695
|
+
'scrollbar-color',
|
|
1696
|
+
'text-decoration',
|
|
1697
|
+
'text-decoration-line',
|
|
1698
|
+
'text-decoration-thickness',
|
|
1699
|
+
'text-underline-offset',
|
|
1700
|
+
'text-shadow',
|
|
1701
|
+
'-webkit-text-fill-color',
|
|
1702
|
+
'-webkit-text-size-adjust'
|
|
1703
|
+
];
|
|
1704
|
+
|
|
1705
|
+
const TEXT_OVERLAY_LAYOUT_SYNC_CUSTOM_PROPERTIES = [
|
|
1706
|
+
'--mind-map-text-scrollbar-size',
|
|
1707
|
+
'--mind-map-text-scrollbar-size-x',
|
|
1708
|
+
'--mind-map-text-scrollbar-size-y',
|
|
1709
|
+
'--mind-map-text-scrollbar-gutter'
|
|
1710
|
+
];
|
|
1711
|
+
|
|
1712
|
+
function applyTextLayoutSurfaceFromSource(sourceElement, targetElement) {
|
|
1713
|
+
if (!sourceElement || !targetElement?.style || typeof window?.getComputedStyle !== 'function') {
|
|
1714
|
+
return;
|
|
1715
|
+
}
|
|
1716
|
+
|
|
1717
|
+
const computed = window.getComputedStyle(sourceElement);
|
|
1718
|
+
if (!computed) {
|
|
1719
|
+
return;
|
|
1720
|
+
}
|
|
1721
|
+
|
|
1722
|
+
TEXT_OVERLAY_LAYOUT_SYNC_CSS_PROPERTIES.forEach(cssName => {
|
|
1723
|
+
const value = readComputedStyleValue(computed, null, cssName);
|
|
1724
|
+
if (value) {
|
|
1725
|
+
targetElement.style.setProperty(cssName, value, 'important');
|
|
1726
|
+
}
|
|
1727
|
+
});
|
|
1728
|
+
|
|
1729
|
+
TEXT_OVERLAY_LAYOUT_SYNC_CUSTOM_PROPERTIES.forEach(cssName => {
|
|
1730
|
+
const value = readComputedStyleValue(computed, null, cssName);
|
|
1731
|
+
if (value) {
|
|
1732
|
+
targetElement.style.setProperty(cssName, value, 'important');
|
|
1733
|
+
}
|
|
1734
|
+
});
|
|
1735
|
+
}
|
|
1736
|
+
|
|
1737
|
+
function applyInheritedTypographyFromSource(sourceElement, targetElement) {
|
|
1738
|
+
if (!sourceElement || !targetElement?.style || typeof window?.getComputedStyle !== 'function') {
|
|
1739
|
+
return;
|
|
1740
|
+
}
|
|
1741
|
+
|
|
1742
|
+
const computed = window.getComputedStyle(sourceElement);
|
|
1743
|
+
if (!computed) {
|
|
1744
|
+
return;
|
|
1745
|
+
}
|
|
1746
|
+
|
|
1747
|
+
const copyStyle = (property, value, cssName = null) => {
|
|
1748
|
+
if (value === null || value === undefined || value === '') {
|
|
1749
|
+
return;
|
|
1750
|
+
}
|
|
1751
|
+
|
|
1752
|
+
if (cssName) {
|
|
1753
|
+
targetElement.style.setProperty(cssName, value);
|
|
1754
|
+
return;
|
|
1755
|
+
}
|
|
1756
|
+
|
|
1757
|
+
targetElement.style[property] = value;
|
|
1758
|
+
};
|
|
1759
|
+
|
|
1760
|
+
copyStyle('fontFamily', readComputedStyleValue(computed, 'fontFamily'));
|
|
1761
|
+
copyStyle('fontSize', readComputedStyleValue(computed, 'fontSize'));
|
|
1762
|
+
copyStyle('fontWeight', readComputedStyleValue(computed, 'fontWeight'));
|
|
1763
|
+
copyStyle('fontStyle', readComputedStyleValue(computed, 'fontStyle'));
|
|
1764
|
+
copyStyle('fontStretch', readComputedStyleValue(computed, 'fontStretch'));
|
|
1765
|
+
copyStyle('lineHeight', readComputedStyleValue(computed, 'lineHeight'));
|
|
1766
|
+
copyStyle('letterSpacing', readComputedStyleValue(computed, 'letterSpacing'));
|
|
1767
|
+
copyStyle('wordSpacing', readComputedStyleValue(computed, 'wordSpacing'));
|
|
1768
|
+
copyStyle('fontKerning', readComputedStyleValue(computed, 'fontKerning'));
|
|
1769
|
+
copyStyle('fontFeatureSettings', readComputedStyleValue(computed, 'fontFeatureSettings'));
|
|
1770
|
+
copyStyle('fontVariationSettings', readComputedStyleValue(computed, 'fontVariationSettings'));
|
|
1771
|
+
copyStyle('fontOpticalSizing', readComputedStyleValue(computed, 'fontOpticalSizing'));
|
|
1772
|
+
copyStyle('textRendering', readComputedStyleValue(computed, 'textRendering'));
|
|
1773
|
+
copyStyle('color', readComputedStyleValue(computed, 'color'));
|
|
1774
|
+
copyStyle('textSizeAdjust', readComputedStyleValue(computed, 'textSizeAdjust', 'text-size-adjust'));
|
|
1775
|
+
copyStyle('boxSizing', readComputedStyleValue(computed, 'boxSizing', 'box-sizing'));
|
|
1776
|
+
copyStyle('whiteSpace', readComputedStyleValue(computed, 'whiteSpace', 'white-space'));
|
|
1777
|
+
copyStyle('wordBreak', readComputedStyleValue(computed, 'wordBreak', 'word-break'));
|
|
1778
|
+
copyStyle('overflowWrap', readComputedStyleValue(computed, 'overflowWrap', 'overflow-wrap'));
|
|
1779
|
+
copyStyle('wordWrap', readComputedStyleValue(computed, 'wordWrap', 'word-wrap'));
|
|
1780
|
+
copyStyle('lineBreak', readComputedStyleValue(computed, 'lineBreak', 'line-break'));
|
|
1781
|
+
copyStyle('hyphens', readComputedStyleValue(computed, 'hyphens', 'hyphens'));
|
|
1782
|
+
copyStyle('tabSize', readComputedStyleValue(computed, 'tabSize', 'tab-size'));
|
|
1783
|
+
copyStyle('textAlign', readComputedStyleValue(computed, 'textAlign', 'text-align'));
|
|
1784
|
+
copyStyle('textIndent', readComputedStyleValue(computed, 'textIndent', 'text-indent'));
|
|
1785
|
+
copyStyle('textTransform', readComputedStyleValue(computed, 'textTransform', 'text-transform'));
|
|
1786
|
+
copyStyle('direction', readComputedStyleValue(computed, 'direction', 'direction'));
|
|
1787
|
+
copyStyle('unicodeBidi', readComputedStyleValue(computed, 'unicodeBidi', 'unicode-bidi'));
|
|
1788
|
+
copyStyle('writingMode', readComputedStyleValue(computed, 'writingMode', 'writing-mode'));
|
|
1789
|
+
copyStyle('textOrientation', readComputedStyleValue(computed, 'textOrientation', 'text-orientation'));
|
|
1790
|
+
copyStyle(null, readComputedStyleValue(computed, null, 'text-wrap'), 'text-wrap');
|
|
1791
|
+
copyStyle(null, readComputedStyleValue(computed, null, 'text-wrap-mode'), 'text-wrap-mode');
|
|
1792
|
+
copyStyle(null, readComputedStyleValue(computed, null, 'text-wrap-style'), 'text-wrap-style');
|
|
1793
|
+
targetElement.style.setProperty('-webkit-font-smoothing', 'antialiased');
|
|
1794
|
+
targetElement.style.setProperty('-moz-osx-font-smoothing', 'grayscale');
|
|
1795
|
+
}
|
|
1796
|
+
|
|
1797
|
+
function getTypographySyncChildren(element) {
|
|
1798
|
+
if (!element?.children?.length) {
|
|
1799
|
+
return [];
|
|
1800
|
+
}
|
|
1801
|
+
|
|
1802
|
+
return Array.from(element.children).filter(child =>
|
|
1803
|
+
!!child &&
|
|
1804
|
+
!child.classList?.contains?.('map-node-memo__icon-popover')
|
|
1805
|
+
);
|
|
1806
|
+
}
|
|
1807
|
+
|
|
1808
|
+
function applyTypographyTreeFromSource(sourceElement, targetElement) {
|
|
1809
|
+
if (!sourceElement || !targetElement) {
|
|
1810
|
+
return;
|
|
1811
|
+
}
|
|
1812
|
+
|
|
1813
|
+
applyInheritedTypographyFromSource(sourceElement, targetElement);
|
|
1814
|
+
applyTextLayoutSurfaceFromSource(sourceElement, targetElement);
|
|
1815
|
+
|
|
1816
|
+
const sourceChildren = getTypographySyncChildren(sourceElement);
|
|
1817
|
+
const targetChildren = getTypographySyncChildren(targetElement);
|
|
1818
|
+
const childCount = Math.min(sourceChildren.length, targetChildren.length);
|
|
1819
|
+
for (let index = 0; index < childCount; index += 1) {
|
|
1820
|
+
applyTypographyTreeFromSource(sourceChildren[index], targetChildren[index]);
|
|
1821
|
+
}
|
|
1822
|
+
}
|
|
1823
|
+
|
|
1824
|
+
function createReadonlyTextReplica(sourceElement) {
|
|
1825
|
+
if (!sourceElement) {
|
|
1826
|
+
return null;
|
|
1827
|
+
}
|
|
1828
|
+
|
|
1829
|
+
const replica = document.createElement('div');
|
|
1830
|
+
const computed = typeof window?.getComputedStyle === 'function'
|
|
1831
|
+
? window.getComputedStyle(sourceElement)
|
|
1832
|
+
: null;
|
|
1833
|
+
const isSingleLineInput = sourceElement.tagName === 'INPUT';
|
|
1834
|
+
replica.className = sourceElement.className || '';
|
|
1835
|
+
replica.textContent = sourceElement.value ?? sourceElement.textContent ?? '';
|
|
1836
|
+
replica.setAttribute('aria-hidden', 'true');
|
|
1837
|
+
replica.style.display = 'block';
|
|
1838
|
+
replica.style.width = '100%';
|
|
1839
|
+
replica.style.height = '100%';
|
|
1840
|
+
replica.style.boxSizing = 'border-box';
|
|
1841
|
+
replica.style.whiteSpace = isSingleLineInput
|
|
1842
|
+
? 'nowrap'
|
|
1843
|
+
: readComputedStyleValue(computed, 'whiteSpace', 'white-space') || 'pre-wrap';
|
|
1844
|
+
replica.style.overflow = isSingleLineInput
|
|
1845
|
+
? 'hidden'
|
|
1846
|
+
: readComputedStyleValue(computed, 'overflow', 'overflow') || 'hidden';
|
|
1847
|
+
replica.style.textOverflow = isSingleLineInput
|
|
1848
|
+
? readComputedStyleValue(computed, 'textOverflow', 'text-overflow') || 'ellipsis'
|
|
1849
|
+
: readComputedStyleValue(computed, 'textOverflow', 'text-overflow');
|
|
1850
|
+
replica.style.overflowWrap = readComputedStyleValue(computed, 'overflowWrap', 'overflow-wrap') || '';
|
|
1851
|
+
replica.style.wordBreak = readComputedStyleValue(computed, 'wordBreak', 'word-break') || '';
|
|
1852
|
+
replica.style.lineBreak = readComputedStyleValue(computed, 'lineBreak', 'line-break') || '';
|
|
1853
|
+
replica.style.hyphens = readComputedStyleValue(computed, 'hyphens', 'hyphens') || '';
|
|
1854
|
+
replica.style.pointerEvents = 'none';
|
|
1855
|
+
replica.style.userSelect = 'none';
|
|
1856
|
+
replica.style.webkitUserSelect = 'none';
|
|
1857
|
+
applyTypographyTreeFromSource(sourceElement, replica);
|
|
1858
|
+
clearSourcePresentationOverrides(replica);
|
|
1859
|
+
return replica;
|
|
1860
|
+
}
|
|
1861
|
+
|
|
1862
|
+
function getScrollableMax(element, axis) {
|
|
1863
|
+
if (!element) {
|
|
1864
|
+
return 0;
|
|
1865
|
+
}
|
|
1866
|
+
|
|
1867
|
+
const scrollSize = axis === 'x'
|
|
1868
|
+
? Number(element.scrollWidth || 0)
|
|
1869
|
+
: Number(element.scrollHeight || 0);
|
|
1870
|
+
const clientSize = axis === 'x'
|
|
1871
|
+
? Number(element.clientWidth || 0)
|
|
1872
|
+
: Number(element.clientHeight || 0);
|
|
1873
|
+
return Math.max(0, scrollSize - clientSize);
|
|
1874
|
+
}
|
|
1875
|
+
|
|
1876
|
+
function getMappedScrollPosition(fromElement, toElement, axis) {
|
|
1877
|
+
const fromValue = axis === 'x'
|
|
1878
|
+
? Number(fromElement?.scrollLeft || 0)
|
|
1879
|
+
: Number(fromElement?.scrollTop || 0);
|
|
1880
|
+
const fromMax = getScrollableMax(fromElement, axis);
|
|
1881
|
+
const toMax = getScrollableMax(toElement, axis);
|
|
1882
|
+
if (toMax <= 0) {
|
|
1883
|
+
return 0;
|
|
1884
|
+
}
|
|
1885
|
+
|
|
1886
|
+
if (fromMax <= 0) {
|
|
1887
|
+
return Math.max(0, Math.min(toMax, Math.round(fromValue)));
|
|
1888
|
+
}
|
|
1889
|
+
|
|
1890
|
+
const ratio = Math.max(0, Math.min(1, fromValue / fromMax));
|
|
1891
|
+
return Math.max(0, Math.min(toMax, Math.round(ratio * toMax)));
|
|
1892
|
+
}
|
|
1893
|
+
|
|
1894
|
+
function setScrollPositionIfNeeded(element, axis, value) {
|
|
1895
|
+
if (!element) {
|
|
1896
|
+
return false;
|
|
1897
|
+
}
|
|
1898
|
+
|
|
1899
|
+
const current = axis === 'x'
|
|
1900
|
+
? Number(element.scrollLeft || 0)
|
|
1901
|
+
: Number(element.scrollTop || 0);
|
|
1902
|
+
if (Math.abs(current - value) < 1) {
|
|
1903
|
+
return false;
|
|
1904
|
+
}
|
|
1905
|
+
|
|
1906
|
+
if (axis === 'x') {
|
|
1907
|
+
element.scrollLeft = value;
|
|
1908
|
+
} else {
|
|
1909
|
+
element.scrollTop = value;
|
|
1910
|
+
}
|
|
1911
|
+
return true;
|
|
1912
|
+
}
|
|
1913
|
+
|
|
1914
|
+
function syncScrollPositionByRatio(fromElement, toElement) {
|
|
1915
|
+
if (!fromElement || !toElement) {
|
|
1916
|
+
return false;
|
|
1917
|
+
}
|
|
1918
|
+
|
|
1919
|
+
const nextTop = getMappedScrollPosition(fromElement, toElement, 'y');
|
|
1920
|
+
const nextLeft = getMappedScrollPosition(fromElement, toElement, 'x');
|
|
1921
|
+
const changedTop = setScrollPositionIfNeeded(toElement, 'y', nextTop);
|
|
1922
|
+
const changedLeft = setScrollPositionIfNeeded(toElement, 'x', nextLeft);
|
|
1923
|
+
return changedTop || changedLeft;
|
|
1924
|
+
}
|
|
1925
|
+
|
|
1926
|
+
function getAllScrollableTargets(root) {
|
|
1927
|
+
if (!root?.querySelectorAll) {
|
|
1928
|
+
return [];
|
|
1929
|
+
}
|
|
1930
|
+
|
|
1931
|
+
const selector = getScrollableSelector();
|
|
1932
|
+
const targets = [];
|
|
1933
|
+
if (root.matches?.(selector)) {
|
|
1934
|
+
targets.push(root);
|
|
1935
|
+
}
|
|
1936
|
+
|
|
1937
|
+
root.querySelectorAll?.(selector)?.forEach?.(target => {
|
|
1938
|
+
targets.push(target);
|
|
1939
|
+
});
|
|
1940
|
+
|
|
1941
|
+
return Array.from(new Set(targets.filter(Boolean)));
|
|
1942
|
+
}
|
|
1943
|
+
|
|
1944
|
+
function linkOverlayScrollTarget(sourceTarget, cloneTarget) {
|
|
1945
|
+
if (!sourceTarget || !cloneTarget) {
|
|
1946
|
+
return;
|
|
1947
|
+
}
|
|
1948
|
+
|
|
1949
|
+
cloneTarget._mindMapSourceScrollTarget = sourceTarget;
|
|
1950
|
+
syncScrollPositionByRatio(sourceTarget, cloneTarget);
|
|
1951
|
+
}
|
|
1952
|
+
|
|
1953
|
+
function linkOverlayCloneScrollTargets(sourceRoot, cloneRoot) {
|
|
1954
|
+
const sourceTargets = getAllScrollableTargets(sourceRoot);
|
|
1955
|
+
const cloneTargets = getAllScrollableTargets(cloneRoot);
|
|
1956
|
+
const count = Math.min(sourceTargets.length, cloneTargets.length);
|
|
1957
|
+
for (let index = 0; index < count; index += 1) {
|
|
1958
|
+
linkOverlayScrollTarget(sourceTargets[index], cloneTargets[index]);
|
|
1959
|
+
}
|
|
1960
|
+
}
|
|
1961
|
+
|
|
1962
|
+
function syncCloneScrollPosition(sourceRoot, cloneRoot, selector) {
|
|
1963
|
+
const source = sourceRoot?.querySelector?.(selector) || null;
|
|
1964
|
+
const clone = cloneRoot?.querySelector?.(selector) || null;
|
|
1965
|
+
if (!source || !clone) {
|
|
1966
|
+
return;
|
|
1967
|
+
}
|
|
1968
|
+
|
|
1969
|
+
clone._mindMapSourceScrollTarget = source;
|
|
1970
|
+
syncScrollPositionByRatio(source, clone);
|
|
1971
|
+
}
|
|
1972
|
+
|
|
1973
|
+
function getOverlayCloneScrollableTargets(root) {
|
|
1974
|
+
if (!root?.querySelectorAll) {
|
|
1975
|
+
return [];
|
|
1976
|
+
}
|
|
1977
|
+
|
|
1978
|
+
const selector = getScrollableSelector();
|
|
1979
|
+
const rawTargets = Array.from(root.querySelectorAll(selector) || []);
|
|
1980
|
+
const targets = rawTargets.filter(target => {
|
|
1981
|
+
if (!target) {
|
|
1982
|
+
return false;
|
|
1983
|
+
}
|
|
1984
|
+
|
|
1985
|
+
const parentScrollable = target.parentElement?.closest?.(selector) || null;
|
|
1986
|
+
return !parentScrollable;
|
|
1987
|
+
});
|
|
1988
|
+
if (root.matches?.(selector)) {
|
|
1989
|
+
targets.unshift(root);
|
|
1990
|
+
}
|
|
1991
|
+
|
|
1992
|
+
return Array.from(new Set(targets.filter(Boolean)));
|
|
1993
|
+
}
|
|
1994
|
+
|
|
1995
|
+
function syncOverlayCloneScrollPositions(sourceRoot, cloneRoot) {
|
|
1996
|
+
if (!sourceRoot || !cloneRoot) {
|
|
1997
|
+
return;
|
|
1998
|
+
}
|
|
1999
|
+
|
|
2000
|
+
linkOverlayCloneScrollTargets(sourceRoot, cloneRoot);
|
|
2001
|
+
getScrollSyncSelectors().forEach(selector => syncCloneScrollPosition(sourceRoot, cloneRoot, selector));
|
|
2002
|
+
}
|
|
2003
|
+
|
|
2004
|
+
function syncReadonlyOverlayScrollTarget(module, target) {
|
|
2005
|
+
const source = target?._mindMapSourceScrollTarget || null;
|
|
2006
|
+
if (!target || !source) {
|
|
2007
|
+
return;
|
|
2008
|
+
}
|
|
2009
|
+
|
|
2010
|
+
if (target._mindMapReadonlyOverlayScrollSyncing === true) {
|
|
2011
|
+
return;
|
|
2012
|
+
}
|
|
2013
|
+
|
|
2014
|
+
source._mindMapReadonlyOverlayScrollSyncing = true;
|
|
2015
|
+
try {
|
|
2016
|
+
const changed = syncScrollPositionByRatio(target, source);
|
|
2017
|
+
if (changed) {
|
|
2018
|
+
const nodeId =
|
|
2019
|
+
normalizeId(source.dataset?.nodeId) ||
|
|
2020
|
+
normalizeId(source.closest?.('[data-node-id]')?.dataset?.nodeId) ||
|
|
2021
|
+
normalizeId(target.dataset?.nodeId) ||
|
|
2022
|
+
normalizeId(target.closest?.('[data-node-id]')?.dataset?.nodeId);
|
|
2023
|
+
if (nodeId) {
|
|
2024
|
+
window.MindMapCss3DManager?.syncCss3dScrollFromElement?.(module, nodeId, target);
|
|
2025
|
+
}
|
|
2026
|
+
syncReadonlySourceNodeScrollState(module, source);
|
|
2027
|
+
}
|
|
2028
|
+
} finally {
|
|
2029
|
+
requestAnimationFrame(() => {
|
|
2030
|
+
source._mindMapReadonlyOverlayScrollSyncing = false;
|
|
2031
|
+
});
|
|
2032
|
+
}
|
|
2033
|
+
}
|
|
2034
|
+
|
|
2035
|
+
function syncReadonlyOverlayCloneFromSource(target) {
|
|
2036
|
+
const source = target?._mindMapSourceScrollTarget || null;
|
|
2037
|
+
if (!target || !source) {
|
|
2038
|
+
return;
|
|
2039
|
+
}
|
|
2040
|
+
|
|
2041
|
+
if (source._mindMapReadonlyOverlayScrollSyncing === true) {
|
|
2042
|
+
return;
|
|
2043
|
+
}
|
|
2044
|
+
|
|
2045
|
+
target._mindMapReadonlyOverlayScrollSyncing = true;
|
|
2046
|
+
try {
|
|
2047
|
+
syncScrollPositionByRatio(source, target);
|
|
2048
|
+
} finally {
|
|
2049
|
+
requestAnimationFrame(() => {
|
|
2050
|
+
target._mindMapReadonlyOverlayScrollSyncing = false;
|
|
2051
|
+
});
|
|
2052
|
+
}
|
|
2053
|
+
}
|
|
2054
|
+
|
|
2055
|
+
function syncReadonlyOverlayCardScrollFromSource(card) {
|
|
2056
|
+
if (!card) {
|
|
2057
|
+
return false;
|
|
2058
|
+
}
|
|
2059
|
+
|
|
2060
|
+
let synced = false;
|
|
2061
|
+
const targets = getOverlayCloneScrollableTargets(card);
|
|
2062
|
+
targets.forEach(target => {
|
|
2063
|
+
if (!target?._mindMapSourceScrollTarget) {
|
|
2064
|
+
return;
|
|
2065
|
+
}
|
|
2066
|
+
|
|
2067
|
+
syncReadonlyOverlayCloneFromSource(target);
|
|
2068
|
+
synced = true;
|
|
2069
|
+
});
|
|
2070
|
+
|
|
2071
|
+
return synced;
|
|
2072
|
+
}
|
|
2073
|
+
|
|
2074
|
+
function scheduleReadonlyOverlayCardScrollSync(card) {
|
|
2075
|
+
if (!card || card._mindMapReadonlyOverlayCardScrollSyncScheduled === true) {
|
|
2076
|
+
return;
|
|
2077
|
+
}
|
|
2078
|
+
|
|
2079
|
+
card._mindMapReadonlyOverlayCardScrollSyncScheduled = true;
|
|
2080
|
+
requestAnimationFrame(() => {
|
|
2081
|
+
syncReadonlyOverlayCardScrollFromSource(card);
|
|
2082
|
+
requestAnimationFrame(() => {
|
|
2083
|
+
syncReadonlyOverlayCardScrollFromSource(card);
|
|
2084
|
+
card._mindMapReadonlyOverlayCardScrollSyncScheduled = false;
|
|
2085
|
+
});
|
|
2086
|
+
});
|
|
2087
|
+
}
|
|
2088
|
+
|
|
2089
|
+
function collectReadonlyOverlayMirrorTargets(sourceTarget) {
|
|
2090
|
+
const targets = sourceTarget?._mindMapReadonlyOverlayCloneTargets;
|
|
2091
|
+
if (!(targets instanceof Set) || targets.size === 0) {
|
|
2092
|
+
return [];
|
|
2093
|
+
}
|
|
2094
|
+
|
|
2095
|
+
const connectedTargets = [];
|
|
2096
|
+
targets.forEach(target => {
|
|
2097
|
+
if (!target || target.isConnected === false || target._mindMapSourceScrollTarget !== sourceTarget) {
|
|
2098
|
+
targets.delete(target);
|
|
2099
|
+
return;
|
|
2100
|
+
}
|
|
2101
|
+
|
|
2102
|
+
connectedTargets.push(target);
|
|
2103
|
+
});
|
|
2104
|
+
|
|
2105
|
+
return connectedTargets;
|
|
2106
|
+
}
|
|
2107
|
+
|
|
2108
|
+
function syncReadonlySourceNodeScrollState(module, sourceTarget) {
|
|
2109
|
+
if (!module?.nodeObjectsById || !sourceTarget) {
|
|
2110
|
+
return;
|
|
2111
|
+
}
|
|
2112
|
+
|
|
2113
|
+
const nodeId =
|
|
2114
|
+
normalizeId(sourceTarget.dataset?.nodeId) ||
|
|
2115
|
+
normalizeId(sourceTarget.closest?.('[data-node-id]')?.dataset?.nodeId);
|
|
2116
|
+
if (!nodeId) {
|
|
2117
|
+
return;
|
|
2118
|
+
}
|
|
2119
|
+
|
|
2120
|
+
const nodeEntry = module.nodeObjectsById.get(nodeId);
|
|
2121
|
+
if (!nodeEntry?.model) {
|
|
2122
|
+
return;
|
|
2123
|
+
}
|
|
2124
|
+
|
|
2125
|
+
window.MindMapCss3DManager?.syncCss3dScrollFromElement?.(module, nodeId, sourceTarget);
|
|
2126
|
+
|
|
2127
|
+
const sourceMaxScroll = Math.max(
|
|
2128
|
+
0,
|
|
2129
|
+
Number(sourceTarget.scrollHeight || 0) - Number(sourceTarget.clientHeight || 0)
|
|
2130
|
+
);
|
|
2131
|
+
const modelMaxScroll = Math.max(0, Number(nodeEntry.model.maxScroll || 0));
|
|
2132
|
+
if (sourceMaxScroll <= 0 || modelMaxScroll <= 0) {
|
|
2133
|
+
return;
|
|
2134
|
+
}
|
|
2135
|
+
|
|
2136
|
+
const scrollRatio = Math.max(0, Math.min(1, Number(sourceTarget.scrollTop || 0) / sourceMaxScroll));
|
|
2137
|
+
const nextOffset = Math.round(scrollRatio * modelMaxScroll);
|
|
2138
|
+
if (!Number.isFinite(nextOffset)) {
|
|
2139
|
+
return;
|
|
2140
|
+
}
|
|
2141
|
+
|
|
2142
|
+
window.MindMapPipeline?.setScrollPosition?.(module, nodeId, nextOffset);
|
|
2143
|
+
}
|
|
2144
|
+
|
|
2145
|
+
function syncReadonlySourceScroll(module, sourceTarget) {
|
|
2146
|
+
const resolvedSource = sourceTarget?._mindMapSourceScrollTarget || sourceTarget || null;
|
|
2147
|
+
if (!resolvedSource) {
|
|
2148
|
+
return false;
|
|
2149
|
+
}
|
|
2150
|
+
|
|
2151
|
+
const mirrorTargets = collectReadonlyOverlayMirrorTargets(resolvedSource);
|
|
2152
|
+
mirrorTargets.forEach(target => syncReadonlyOverlayCloneFromSource(target));
|
|
2153
|
+
syncReadonlySourceNodeScrollState(module, resolvedSource);
|
|
2154
|
+
return mirrorTargets.length > 0;
|
|
2155
|
+
}
|
|
2156
|
+
|
|
2157
|
+
function bindReadonlySourceScrollSync(module, sourceTarget, target) {
|
|
2158
|
+
if (!module || !sourceTarget || !target || typeof sourceTarget.addEventListener !== 'function') {
|
|
2159
|
+
return;
|
|
2160
|
+
}
|
|
2161
|
+
|
|
2162
|
+
if (!(sourceTarget._mindMapReadonlyOverlayCloneTargets instanceof Set)) {
|
|
2163
|
+
sourceTarget._mindMapReadonlyOverlayCloneTargets = new Set();
|
|
2164
|
+
}
|
|
2165
|
+
sourceTarget._mindMapReadonlyOverlayCloneTargets.add(target);
|
|
2166
|
+
|
|
2167
|
+
if (sourceTarget._mindMapReadonlyOverlaySourceScrollModule === module &&
|
|
2168
|
+
sourceTarget._mindMapReadonlyOverlaySourceScrollHandler) {
|
|
2169
|
+
return;
|
|
2170
|
+
}
|
|
2171
|
+
|
|
2172
|
+
if (sourceTarget._mindMapReadonlyOverlaySourceScrollHandler) {
|
|
2173
|
+
sourceTarget.removeEventListener('scroll', sourceTarget._mindMapReadonlyOverlaySourceScrollHandler);
|
|
2174
|
+
}
|
|
2175
|
+
|
|
2176
|
+
const handler = () => {
|
|
2177
|
+
syncReadonlySourceScroll(module, sourceTarget);
|
|
2178
|
+
};
|
|
2179
|
+
|
|
2180
|
+
sourceTarget._mindMapReadonlyOverlaySourceScrollModule = module;
|
|
2181
|
+
sourceTarget._mindMapReadonlyOverlaySourceScrollHandler = handler;
|
|
2182
|
+
sourceTarget.addEventListener('scroll', handler, { passive: true });
|
|
2183
|
+
}
|
|
2184
|
+
|
|
2185
|
+
function getWheelDeltaPixels(event) {
|
|
2186
|
+
const mode = Number(event?.deltaMode || 0);
|
|
2187
|
+
const multiplier = mode === 1
|
|
2188
|
+
? 16
|
|
2189
|
+
: mode === 2
|
|
2190
|
+
? Math.max(1, Number(window?.innerHeight || 800))
|
|
2191
|
+
: 1;
|
|
2192
|
+
return {
|
|
2193
|
+
x: Number(event?.deltaX || 0) * multiplier,
|
|
2194
|
+
y: Number(event?.deltaY || 0) * multiplier
|
|
2195
|
+
};
|
|
2196
|
+
}
|
|
2197
|
+
|
|
2198
|
+
function scrollSourceFromOverlayWheel(module, target, sourceTarget, event) {
|
|
2199
|
+
if (!sourceTarget || !event) {
|
|
2200
|
+
return false;
|
|
2201
|
+
}
|
|
2202
|
+
|
|
2203
|
+
const delta = getWheelDeltaPixels(event);
|
|
2204
|
+
const maxTop = getScrollableMax(sourceTarget, 'y');
|
|
2205
|
+
const maxLeft = getScrollableMax(sourceTarget, 'x');
|
|
2206
|
+
const horizontalDelta = event.shiftKey && Math.abs(delta.x) < Math.abs(delta.y)
|
|
2207
|
+
? delta.y
|
|
2208
|
+
: delta.x;
|
|
2209
|
+
const nextTop = Math.max(0, Math.min(maxTop, Number(sourceTarget.scrollTop || 0) + delta.y));
|
|
2210
|
+
const nextLeft = Math.max(0, Math.min(maxLeft, Number(sourceTarget.scrollLeft || 0) + horizontalDelta));
|
|
2211
|
+
const changedTop = setScrollPositionIfNeeded(sourceTarget, 'y', nextTop);
|
|
2212
|
+
const changedLeft = setScrollPositionIfNeeded(sourceTarget, 'x', nextLeft);
|
|
2213
|
+
const changed = changedTop || changedLeft;
|
|
2214
|
+
if (!changed) {
|
|
2215
|
+
return false;
|
|
2216
|
+
}
|
|
2217
|
+
|
|
2218
|
+
syncReadonlySourceNodeScrollState(module, sourceTarget);
|
|
2219
|
+
syncReadonlyOverlayCloneFromSource(target);
|
|
2220
|
+
requestAnimationFrame(() => syncReadonlyOverlayCloneFromSource(target));
|
|
2221
|
+
return true;
|
|
2222
|
+
}
|
|
2223
|
+
|
|
2224
|
+
function shouldRouteReadonlyOverlayWheelToZoom(module, event) {
|
|
2225
|
+
if (!event) {
|
|
2226
|
+
return false;
|
|
2227
|
+
}
|
|
2228
|
+
|
|
2229
|
+
if (window.MindMapInteractions?.isTrackpadPinchGesture?.(event) === true) {
|
|
2230
|
+
return true;
|
|
2231
|
+
}
|
|
2232
|
+
|
|
2233
|
+
if (typeof window.MindMapInteractions?.shouldZoomFromWheelEvent === 'function') {
|
|
2234
|
+
return window.MindMapInteractions.shouldZoomFromWheelEvent(module, event) === true;
|
|
2235
|
+
}
|
|
2236
|
+
|
|
2237
|
+
const nav = typeof navigator !== 'undefined' ? navigator : null;
|
|
2238
|
+
const isMacLike = /mac|iphone|ipad/i.test(String(nav?.platform || nav?.userAgent || ''));
|
|
2239
|
+
const modifierActive = isMacLike ? event.metaKey === true : event.ctrlKey === true;
|
|
2240
|
+
return module?.swapWheelZoomControls === true ? modifierActive : !modifierActive;
|
|
2241
|
+
}
|
|
2242
|
+
|
|
2243
|
+
function bindReadonlyOverlayScrollSync(module, target) {
|
|
2244
|
+
if (!target || typeof target.addEventListener !== 'function') {
|
|
2245
|
+
return;
|
|
2246
|
+
}
|
|
2247
|
+
|
|
2248
|
+
if (target._mindMapReadonlyOverlayScrollSyncModule === module &&
|
|
2249
|
+
target._mindMapReadonlyOverlayScrollSyncHandler) {
|
|
2250
|
+
return;
|
|
2251
|
+
}
|
|
2252
|
+
|
|
2253
|
+
if (target._mindMapReadonlyOverlayScrollSyncHandler) {
|
|
2254
|
+
target.removeEventListener('scroll', target._mindMapReadonlyOverlayScrollSyncHandler);
|
|
2255
|
+
}
|
|
2256
|
+
|
|
2257
|
+
const handler = () => {
|
|
2258
|
+
syncReadonlyOverlayScrollTarget(module, target);
|
|
2259
|
+
};
|
|
2260
|
+
|
|
2261
|
+
target._mindMapReadonlyOverlayScrollSyncModule = module;
|
|
2262
|
+
target._mindMapReadonlyOverlayScrollSyncHandler = handler;
|
|
2263
|
+
target.addEventListener('scroll', handler, { passive: true });
|
|
2264
|
+
}
|
|
2265
|
+
|
|
2266
|
+
function bindReadonlyOverlayWheelRouting(module, target) {
|
|
2267
|
+
if (!module || !target || typeof target.addEventListener !== 'function') {
|
|
2268
|
+
return;
|
|
2269
|
+
}
|
|
2270
|
+
|
|
2271
|
+
if (target._mindMapReadonlyOverlayWheelModule === module && target._mindMapReadonlyOverlayWheelHandler) {
|
|
2272
|
+
return;
|
|
2273
|
+
}
|
|
2274
|
+
|
|
2275
|
+
if (target._mindMapReadonlyOverlayWheelHandler) {
|
|
2276
|
+
target.removeEventListener('wheel', target._mindMapReadonlyOverlayWheelHandler);
|
|
2277
|
+
}
|
|
2278
|
+
|
|
2279
|
+
const routeToCss3dSource = (event) => {
|
|
2280
|
+
const sourceTarget = target?._mindMapSourceScrollTarget || null;
|
|
2281
|
+
if (!sourceTarget) {
|
|
2282
|
+
return false;
|
|
2283
|
+
}
|
|
2284
|
+
|
|
2285
|
+
if (scrollSourceFromOverlayWheel(module, target, sourceTarget, event)) {
|
|
2286
|
+
event.preventDefault();
|
|
2287
|
+
event.stopPropagation();
|
|
2288
|
+
return true;
|
|
2289
|
+
}
|
|
2290
|
+
|
|
2291
|
+
return false;
|
|
2292
|
+
};
|
|
2293
|
+
|
|
2294
|
+
const handler = (event) => {
|
|
2295
|
+
if (shouldRouteReadonlyOverlayWheelToZoom(module, event)) {
|
|
2296
|
+
window.MindMapInteractions?.routeWheelEventToZoom?.(module, event);
|
|
2297
|
+
return;
|
|
2298
|
+
}
|
|
2299
|
+
|
|
2300
|
+
if (routeToCss3dSource(event)) {
|
|
2301
|
+
return;
|
|
2302
|
+
}
|
|
2303
|
+
|
|
2304
|
+
const isScrollable = target.scrollHeight > target.clientHeight;
|
|
2305
|
+
if (isScrollable) {
|
|
2306
|
+
const handledByScroll =
|
|
2307
|
+
window.MindMapInteractions?.applyCtrlWheelToScrollableElement?.(
|
|
2308
|
+
module,
|
|
2309
|
+
target,
|
|
2310
|
+
event.deltaY,
|
|
2311
|
+
() => syncReadonlyOverlayScrollTarget(module, target)
|
|
2312
|
+
) === true;
|
|
2313
|
+
if (handledByScroll) {
|
|
2314
|
+
event.preventDefault();
|
|
2315
|
+
event.stopPropagation();
|
|
2316
|
+
return;
|
|
2317
|
+
}
|
|
2318
|
+
}
|
|
2319
|
+
|
|
2320
|
+
window.MindMapInteractions?.routeCtrlWheelEventToVerticalScroll?.(module, event);
|
|
2321
|
+
};
|
|
2322
|
+
|
|
2323
|
+
target._mindMapReadonlyOverlayWheelModule = module;
|
|
2324
|
+
target._mindMapReadonlyOverlayWheelHandler = handler;
|
|
2325
|
+
target.addEventListener('wheel', handler, { passive: false });
|
|
2326
|
+
}
|
|
2327
|
+
|
|
2328
|
+
function bindReadonlyOverlayPanRouting(module, target) {
|
|
2329
|
+
if (!module || !target || typeof target.addEventListener !== 'function') {
|
|
2330
|
+
return;
|
|
2331
|
+
}
|
|
2332
|
+
|
|
2333
|
+
if (target._mindMapReadonlyOverlayPanModule === module && target._mindMapReadonlyOverlayPanHandler) {
|
|
2334
|
+
return;
|
|
2335
|
+
}
|
|
2336
|
+
|
|
2337
|
+
if (target._mindMapReadonlyOverlayPanHandler) {
|
|
2338
|
+
target.removeEventListener('mousedown', target._mindMapReadonlyOverlayPanHandler);
|
|
2339
|
+
}
|
|
2340
|
+
|
|
2341
|
+
const handler = (event) => {
|
|
2342
|
+
if (event?.button !== 1 && event?.button !== 2) {
|
|
2343
|
+
return;
|
|
2344
|
+
}
|
|
2345
|
+
|
|
2346
|
+
window.MindMapInteractions?.beginPanFromMouseEvent?.(module, event, target);
|
|
2347
|
+
};
|
|
2348
|
+
|
|
2349
|
+
target._mindMapReadonlyOverlayPanModule = module;
|
|
2350
|
+
target._mindMapReadonlyOverlayPanHandler = handler;
|
|
2351
|
+
target.addEventListener('mousedown', handler, { passive: false });
|
|
2352
|
+
}
|
|
2353
|
+
|
|
2354
|
+
function bindReadonlyOverlayPrimaryPointerRouting(module, root, sourceRoot) {
|
|
2355
|
+
if (!module || !root || typeof root.addEventListener !== 'function') {
|
|
2356
|
+
return;
|
|
2357
|
+
}
|
|
2358
|
+
|
|
2359
|
+
root._mindMapReadonlyOverlaySourceRoot = sourceRoot || null;
|
|
2360
|
+
|
|
2361
|
+
if (root._mindMapReadonlyOverlayPrimaryPointerModule === module &&
|
|
2362
|
+
root._mindMapReadonlyOverlayPrimaryPointerHandler) {
|
|
2363
|
+
return;
|
|
2364
|
+
}
|
|
2365
|
+
|
|
2366
|
+
if (root._mindMapReadonlyOverlayPrimaryPointerHandler) {
|
|
2367
|
+
root.removeEventListener('mousedown', root._mindMapReadonlyOverlayPrimaryPointerHandler);
|
|
2368
|
+
root.removeEventListener('mouseup', root._mindMapReadonlyOverlayPrimaryPointerHandler);
|
|
2369
|
+
}
|
|
2370
|
+
|
|
2371
|
+
const handler = (event) => {
|
|
2372
|
+
if (!event || event.button !== 0) {
|
|
2373
|
+
return;
|
|
2374
|
+
}
|
|
2375
|
+
|
|
2376
|
+
const nodeId =
|
|
2377
|
+
normalizeId(root.dataset.nodeId) ||
|
|
2378
|
+
normalizeId(root._mindMapReadonlyOverlaySourceRoot?.dataset?.nodeId) ||
|
|
2379
|
+
normalizeId(root.closest?.('[data-node-id]')?.dataset?.nodeId);
|
|
2380
|
+
|
|
2381
|
+
if (!nodeId) {
|
|
2382
|
+
return;
|
|
2383
|
+
}
|
|
2384
|
+
|
|
2385
|
+
if (event.type === 'mousedown') {
|
|
2386
|
+
root._mindMapReadonlyOverlayPrimaryPointerStart = {
|
|
2387
|
+
x: Number(event.clientX || 0),
|
|
2388
|
+
y: Number(event.clientY || 0)
|
|
2389
|
+
};
|
|
2390
|
+
window.MindMapInteractions?.prepareOverlayPrimaryPointer?.(module);
|
|
2391
|
+
root._mindMapReadonlyOverlayDragStarted = false;
|
|
2392
|
+
if (root.dataset.overlayInteractive !== 'true') {
|
|
2393
|
+
root._mindMapReadonlyOverlayDragStarted =
|
|
2394
|
+
window.MindMapInteractions?.beginOverlayNodeDrag?.(module, event, nodeId) === true;
|
|
2395
|
+
}
|
|
2396
|
+
if (root.dataset.overlayInteractive !== 'true') {
|
|
2397
|
+
event.preventDefault();
|
|
2398
|
+
event.stopPropagation();
|
|
2399
|
+
}
|
|
2400
|
+
return;
|
|
2401
|
+
}
|
|
2402
|
+
|
|
2403
|
+
const start = root._mindMapReadonlyOverlayPrimaryPointerStart || null;
|
|
2404
|
+
|
|
2405
|
+
if (module?.isSelecting === true || !start) {
|
|
2406
|
+
root._mindMapReadonlyOverlayDragStarted = false;
|
|
2407
|
+
root._mindMapReadonlyOverlayPrimaryPointerStart = null;
|
|
2408
|
+
return;
|
|
2409
|
+
}
|
|
2410
|
+
|
|
2411
|
+
if (module?._overlayPointerDragActive === true ||
|
|
2412
|
+
module?.isDraggingNode === true ||
|
|
2413
|
+
module?.isDraggingMultipleNodes === true ||
|
|
2414
|
+
root._mindMapReadonlyOverlayDragStarted === true) {
|
|
2415
|
+
root._mindMapReadonlyOverlayDragStarted = false;
|
|
2416
|
+
root._mindMapReadonlyOverlayPrimaryPointerStart = null;
|
|
2417
|
+
return;
|
|
2418
|
+
}
|
|
2419
|
+
|
|
2420
|
+
const interactive = root.dataset.overlayInteractive === 'true';
|
|
2421
|
+
root._mindMapReadonlyOverlayPrimaryPointerStart = null;
|
|
2422
|
+
const movedEnough =
|
|
2423
|
+
!!start &&
|
|
2424
|
+
(Math.abs(Number(event.clientX || 0) - start.x) > 4 ||
|
|
2425
|
+
Math.abs(Number(event.clientY || 0) - start.y) > 4);
|
|
2426
|
+
if (interactive && movedEnough) {
|
|
2427
|
+
return;
|
|
2428
|
+
}
|
|
2429
|
+
|
|
2430
|
+
const result = window.MindMapInteractions?.handleOverlayPrimaryPointer?.(module, nodeId, {
|
|
2431
|
+
event,
|
|
2432
|
+
target: event.target,
|
|
2433
|
+
shiftKey: !!event.shiftKey,
|
|
2434
|
+
ctrlKey: !!event.ctrlKey,
|
|
2435
|
+
metaKey: !!event.metaKey
|
|
2436
|
+
});
|
|
2437
|
+
|
|
2438
|
+
if (!result?.handled) {
|
|
2439
|
+
return;
|
|
2440
|
+
}
|
|
2441
|
+
|
|
2442
|
+
if (result.suppressDefault !== false) {
|
|
2443
|
+
event.preventDefault();
|
|
2444
|
+
event.stopPropagation();
|
|
2445
|
+
}
|
|
2446
|
+
};
|
|
2447
|
+
|
|
2448
|
+
root._mindMapReadonlyOverlayPrimaryPointerModule = module;
|
|
2449
|
+
root._mindMapReadonlyOverlayPrimaryPointerHandler = handler;
|
|
2450
|
+
root.addEventListener('mousedown', handler, { passive: false });
|
|
2451
|
+
root.addEventListener('mouseup', handler, { passive: false });
|
|
2452
|
+
}
|
|
2453
|
+
|
|
2454
|
+
function applyPassiveAgentOverlayControlPassthrough(root, interactive) {
|
|
2455
|
+
if (!root?.classList?.contains?.('mind-map-text-overlay-v2-source-clone')) {
|
|
2456
|
+
return;
|
|
2457
|
+
}
|
|
2458
|
+
|
|
2459
|
+
if (String(root.dataset?.overlayCloneMode || '').trim().toLowerCase() !== 'agent-memo') {
|
|
2460
|
+
return;
|
|
2461
|
+
}
|
|
2462
|
+
|
|
2463
|
+
root.querySelectorAll?.([
|
|
2464
|
+
'.map-node-memo__icon-wrap',
|
|
2465
|
+
'.map-node-memo__icon-wrap *',
|
|
2466
|
+
'.map-node-memo__agent-actions',
|
|
2467
|
+
'.map-node-memo__agent-actions *',
|
|
2468
|
+
'.map-node-memo__agent-results',
|
|
2469
|
+
'.map-node-memo__agent-results *'
|
|
2470
|
+
].join(', '))?.forEach?.(element => {
|
|
2471
|
+
if (!element?.style) {
|
|
2472
|
+
return;
|
|
2473
|
+
}
|
|
2474
|
+
|
|
2475
|
+
element.style.pointerEvents = interactive ? 'auto' : 'none';
|
|
2476
|
+
element.style.userSelect = interactive ? 'text' : 'none';
|
|
2477
|
+
element.style.webkitUserSelect = interactive ? 'text' : 'none';
|
|
2478
|
+
});
|
|
2479
|
+
}
|
|
2480
|
+
|
|
2481
|
+
function refreshOverlayCloneInteractivity(module, root, interactive, fallbackSourceRoot = null) {
|
|
2482
|
+
if (!root) {
|
|
2483
|
+
return;
|
|
2484
|
+
}
|
|
2485
|
+
|
|
2486
|
+
const candidates = [root, ...Array.from(root.querySelectorAll?.('*') || [])];
|
|
2487
|
+
candidates.forEach(candidate => {
|
|
2488
|
+
if (!candidate) {
|
|
2489
|
+
return;
|
|
2490
|
+
}
|
|
2491
|
+
|
|
2492
|
+
const sourceRoot = candidate._mindMapReadonlyOverlaySourceRoot || (candidate === root ? fallbackSourceRoot : null);
|
|
2493
|
+
if (!sourceRoot) {
|
|
2494
|
+
return;
|
|
2495
|
+
}
|
|
2496
|
+
|
|
2497
|
+
applyOverlayCloneInteractivity(module, candidate, interactive, sourceRoot);
|
|
2498
|
+
});
|
|
2499
|
+
}
|
|
2500
|
+
|
|
2501
|
+
function applyOverlayCloneInteractivity(module, root, interactive, sourceRoot = null) {
|
|
2502
|
+
if (!root) {
|
|
2503
|
+
return;
|
|
2504
|
+
}
|
|
2505
|
+
|
|
2506
|
+
root.dataset.overlayInteractive = interactive ? 'true' : 'false';
|
|
2507
|
+
root._mindMapReadonlyOverlaySourceRoot = sourceRoot || root._mindMapReadonlyOverlaySourceRoot || null;
|
|
2508
|
+
if (root.classList?.contains?.('mind-map-text-overlay-v2-source-clone')) {
|
|
2509
|
+
root.style.pointerEvents = interactive ? 'auto' : 'none';
|
|
2510
|
+
root.style.userSelect = interactive ? 'text' : 'none';
|
|
2511
|
+
root.style.webkitUserSelect = interactive ? 'text' : 'none';
|
|
2512
|
+
}
|
|
2513
|
+
if (root.classList?.contains?.('mind-map-text-overlay-v2-content-shell')) {
|
|
2514
|
+
root.style.pointerEvents = 'none';
|
|
2515
|
+
}
|
|
2516
|
+
if (!interactive && root._mindMapReadonlyOverlaySourceRoot) {
|
|
2517
|
+
bindReadonlyOverlayPrimaryPointerRouting(module, root, root._mindMapReadonlyOverlaySourceRoot);
|
|
2518
|
+
}
|
|
2519
|
+
|
|
2520
|
+
if (root.classList?.contains?.('mind-map-text-overlay-v2-fragment')) {
|
|
2521
|
+
root.style.pointerEvents = interactive ? 'auto' : 'none';
|
|
2522
|
+
root.style.userSelect = interactive ? 'text' : 'none';
|
|
2523
|
+
root.style.webkitUserSelect = interactive ? 'text' : 'none';
|
|
2524
|
+
}
|
|
2525
|
+
|
|
2526
|
+
if (root.classList?.contains?.('mind-map-text-overlay-v2-content-shell')) {
|
|
2527
|
+
root.querySelectorAll?.('.mind-map-text-overlay-v2-fragment')?.forEach?.(fragment => {
|
|
2528
|
+
if (!fragment?.style) {
|
|
2529
|
+
return;
|
|
2530
|
+
}
|
|
2531
|
+
|
|
2532
|
+
fragment.style.pointerEvents = interactive ? 'auto' : 'none';
|
|
2533
|
+
fragment.style.userSelect = interactive ? 'text' : 'none';
|
|
2534
|
+
fragment.style.webkitUserSelect = interactive ? 'text' : 'none';
|
|
2535
|
+
});
|
|
2536
|
+
}
|
|
2537
|
+
|
|
2538
|
+
applyPassiveAgentOverlayControlPassthrough(root, interactive);
|
|
2539
|
+
|
|
2540
|
+
root.querySelectorAll?.('.node-prompt-copy-button, .node-prompt-copy-button *')?.forEach?.(element => {
|
|
2541
|
+
if (!element?.style) {
|
|
2542
|
+
return;
|
|
2543
|
+
}
|
|
2544
|
+
|
|
2545
|
+
element.style.pointerEvents = 'auto';
|
|
2546
|
+
element.style.userSelect = 'none';
|
|
2547
|
+
element.style.webkitUserSelect = 'none';
|
|
2548
|
+
element.style.cursor = 'pointer';
|
|
2549
|
+
});
|
|
2550
|
+
|
|
2551
|
+
const scrollTargets = getOverlayCloneScrollableTargets(root);
|
|
2552
|
+
scrollTargets.forEach(target => {
|
|
2553
|
+
target.classList.add('mind-map-text-overlay-v2-body');
|
|
2554
|
+
target.style.pointerEvents = 'auto';
|
|
2555
|
+
bindReadonlyOverlayScrollSync(module, target);
|
|
2556
|
+
bindReadonlyOverlayWheelRouting(module, target);
|
|
2557
|
+
bindReadonlyOverlayPanRouting(module, target);
|
|
2558
|
+
bindReadonlySourceScrollSync(module, target._mindMapSourceScrollTarget || null, target);
|
|
2559
|
+
if (!interactive) {
|
|
2560
|
+
target.style.cursor = '';
|
|
2561
|
+
target.style.userSelect = 'none';
|
|
2562
|
+
target.style.webkitUserSelect = 'none';
|
|
2563
|
+
return;
|
|
2564
|
+
}
|
|
2565
|
+
|
|
2566
|
+
target.style.cursor = 'text';
|
|
2567
|
+
target.style.userSelect = 'text';
|
|
2568
|
+
target.style.webkitUserSelect = 'text';
|
|
2569
|
+
|
|
2570
|
+
target.querySelectorAll?.('*')?.forEach?.(element => {
|
|
2571
|
+
if (!element?.style) {
|
|
2572
|
+
return;
|
|
2573
|
+
}
|
|
2574
|
+
|
|
2575
|
+
element.style.pointerEvents = 'auto';
|
|
2576
|
+
element.style.userSelect = 'text';
|
|
2577
|
+
element.style.webkitUserSelect = 'text';
|
|
2578
|
+
});
|
|
2579
|
+
});
|
|
2580
|
+
}
|
|
2581
|
+
|
|
2582
|
+
function applyReadonlyOverlayContainerStyles(clone, type, options = {}) {
|
|
2583
|
+
if (!clone) {
|
|
2584
|
+
return null;
|
|
2585
|
+
}
|
|
2586
|
+
|
|
2587
|
+
const renderMode = String(options.renderMode || '').trim().toLowerCase();
|
|
2588
|
+
const preserveAgentPanels = renderMode === 'agent-memo';
|
|
2589
|
+
|
|
2590
|
+
// CSS3D is the canonical readonly renderer. Source clones must not
|
|
2591
|
+
// receive legacy overlay shell layout classes, or they drift away
|
|
2592
|
+
// from CSS3D's DOM/CSS contract and markdown can collapse/clamp.
|
|
2593
|
+
clone.classList.add('mind-map-text-overlay-v2-source-clone');
|
|
2594
|
+
clone.dataset.overlayCloneType = String(type || '');
|
|
2595
|
+
clone.dataset.overlayCloneMode = renderMode;
|
|
2596
|
+
clone.classList.remove('mind-map-v2-source-suspended');
|
|
2597
|
+
clone.classList.remove('selected');
|
|
2598
|
+
clone.style.pointerEvents = '';
|
|
2599
|
+
clone.style.maxWidth = 'none';
|
|
2600
|
+
clone.style.minWidth = '0';
|
|
2601
|
+
clone.style.contentVisibility = 'visible';
|
|
2602
|
+
clone.style.containIntrinsicSize = 'auto';
|
|
2603
|
+
clone.style.contain = 'layout style';
|
|
2604
|
+
clone.style.setProperty('--mind-map-text-scrollbar-size', '8px');
|
|
2605
|
+
clone.style.setProperty('--mind-map-text-scrollbar-size-x', '8px');
|
|
2606
|
+
clone.style.setProperty('--mind-map-text-scrollbar-size-y', '8px');
|
|
2607
|
+
clone.style.setProperty('--mind-map-text-scrollbar-gutter', '14px');
|
|
2608
|
+
|
|
2609
|
+
const consolePanel = clone.querySelector?.('.map-node-memo__agent-console-panel') || null;
|
|
2610
|
+
if (consolePanel && !preserveAgentPanels) {
|
|
2611
|
+
// Agent console stays on the CSS3D source path because it is laid
|
|
2612
|
+
// out as an absolute panel outside the main shell. Duplicating it
|
|
2613
|
+
// inside the screen-space overlay drifts/clips the console body.
|
|
2614
|
+
consolePanel.style.display = 'none';
|
|
2615
|
+
consolePanel.setAttribute('aria-hidden', 'true');
|
|
2616
|
+
}
|
|
2617
|
+
|
|
2618
|
+
return clone;
|
|
2619
|
+
}
|
|
2620
|
+
|
|
2621
|
+
function finalizeReadonlySourceClone(module, sourceRoot, clone, type, interactive, options = {}) {
|
|
2622
|
+
const styledClone = applyReadonlyOverlayContainerStyles(clone, type, options);
|
|
2623
|
+
if (!styledClone) {
|
|
2624
|
+
return null;
|
|
2625
|
+
}
|
|
2626
|
+
|
|
2627
|
+
applyTypographyTreeFromSource(sourceRoot, styledClone);
|
|
2628
|
+
syncOverlayCloneScrollPositions(sourceRoot, styledClone);
|
|
2629
|
+
applyOverlayCloneInteractivity(module, styledClone, interactive);
|
|
2630
|
+
return { container: styledClone };
|
|
2631
|
+
}
|
|
2632
|
+
|
|
2633
|
+
function createReadonlyOverlayFromSource(module, entry, options = {}) {
|
|
2634
|
+
const sourceRoot = options.sourceRoot || getReadonlyCloneSourceElement(entry);
|
|
2635
|
+
if (!sourceRoot) {
|
|
2636
|
+
return null;
|
|
2637
|
+
}
|
|
2638
|
+
|
|
2639
|
+
const interactive = options.interactive === true;
|
|
2640
|
+
const type = getContentType(entry);
|
|
2641
|
+
const renderMode = String(options.renderMode || getReadonlySelectionMode(entry) || type || '').trim().toLowerCase();
|
|
2642
|
+
const clone = clearSourcePresentationOverrides(sourceRoot.cloneNode(true));
|
|
2643
|
+
const preparedClone = prepareOverlayClone(clone);
|
|
2644
|
+
if (!preparedClone) {
|
|
2645
|
+
return null;
|
|
2646
|
+
}
|
|
2647
|
+
|
|
2648
|
+
return finalizeReadonlySourceClone(module, sourceRoot, preparedClone, type, interactive, { renderMode: renderMode });
|
|
2649
|
+
}
|
|
2650
|
+
|
|
2651
|
+
function getRelativeFragmentPlacement(hostElement, sourceElement, hostBaseWidth, hostBaseHeight) {
|
|
2652
|
+
if (!hostElement || !sourceElement) {
|
|
2653
|
+
return null;
|
|
2654
|
+
}
|
|
2655
|
+
|
|
2656
|
+
const hostRect = hostElement.getBoundingClientRect();
|
|
2657
|
+
const sourceRect = sourceElement.getBoundingClientRect();
|
|
2658
|
+
const scaleX = Math.max(0.0001, Number(hostRect.width || 0) / Math.max(1, Number(hostBaseWidth || 1)));
|
|
2659
|
+
const scaleY = Math.max(0.0001, Number(hostRect.height || 0) / Math.max(1, Number(hostBaseHeight || 1)));
|
|
2660
|
+
const rawLeft = (sourceRect.left - hostRect.left) / scaleX;
|
|
2661
|
+
const rawTop = (sourceRect.top - hostRect.top) / scaleY;
|
|
2662
|
+
const left = Math.round(rawLeft);
|
|
2663
|
+
const top = Math.round(rawTop);
|
|
2664
|
+
const measuredWidth = Number(sourceElement.offsetWidth || 0);
|
|
2665
|
+
const measuredHeight = Number(sourceElement.offsetHeight || 0);
|
|
2666
|
+
const baseWidth = Math.max(
|
|
2667
|
+
1,
|
|
2668
|
+
Math.round(measuredWidth > 0 ? measuredWidth : Number(sourceRect.width / scaleX || 1))
|
|
2669
|
+
) + PASSIVE_OVERLAY_FRAGMENT_WIDTH_BIAS_PX;
|
|
2670
|
+
const baseHeight = Math.max(
|
|
2671
|
+
1,
|
|
2672
|
+
Math.round(measuredHeight > 0 ? measuredHeight : Number(sourceRect.height / scaleY || 1))
|
|
2673
|
+
);
|
|
2674
|
+
|
|
2675
|
+
return {
|
|
2676
|
+
left: left,
|
|
2677
|
+
top: top,
|
|
2678
|
+
width: baseWidth,
|
|
2679
|
+
height: baseHeight
|
|
2680
|
+
};
|
|
2681
|
+
}
|
|
2682
|
+
|
|
2683
|
+
function appendReadonlyFragment(shell, hostElement, sourceElement, cloneElement, hostBaseWidth, hostBaseHeight) {
|
|
2684
|
+
if (!shell || !hostElement || !sourceElement || !cloneElement) {
|
|
2685
|
+
return false;
|
|
2686
|
+
}
|
|
2687
|
+
|
|
2688
|
+
const placement = getRelativeFragmentPlacement(hostElement, sourceElement, hostBaseWidth, hostBaseHeight);
|
|
2689
|
+
if (!placement) {
|
|
2690
|
+
return false;
|
|
2691
|
+
}
|
|
2692
|
+
|
|
2693
|
+
cloneElement.classList.add('mind-map-text-overlay-v2-fragment');
|
|
2694
|
+
applyTypographyTreeFromSource(sourceElement, cloneElement);
|
|
2695
|
+
cloneElement.style.position = 'absolute';
|
|
2696
|
+
cloneElement.style.left = `${placement.left}px`;
|
|
2697
|
+
cloneElement.style.top = `${placement.top}px`;
|
|
2698
|
+
cloneElement.style.width = `${placement.width}px`;
|
|
2699
|
+
cloneElement.style.height = `${placement.height}px`;
|
|
2700
|
+
cloneElement.style.margin = '0';
|
|
2701
|
+
cloneElement.style.pointerEvents = 'none';
|
|
2702
|
+
linkOverlayCloneScrollTargets(sourceElement, cloneElement);
|
|
2703
|
+
shell.appendChild(cloneElement);
|
|
2704
|
+
return true;
|
|
2705
|
+
}
|
|
2706
|
+
|
|
2707
|
+
function appendReadonlyContentRootClone(shell, hostElement, sourceElement, hostBaseWidth, hostBaseHeight) {
|
|
2708
|
+
if (!shell || !hostElement || !sourceElement || sourceElement === hostElement) {
|
|
2709
|
+
return false;
|
|
2710
|
+
}
|
|
2711
|
+
|
|
2712
|
+
const clone = cloneReadonlyFragment(sourceElement);
|
|
2713
|
+
if (!clone) {
|
|
2714
|
+
return false;
|
|
2715
|
+
}
|
|
2716
|
+
|
|
2717
|
+
return appendReadonlyFragment(shell, hostElement, sourceElement, clone, hostBaseWidth, hostBaseHeight);
|
|
2718
|
+
}
|
|
2719
|
+
|
|
2720
|
+
function isVisibleOverlaySourceElement(element) {
|
|
2721
|
+
return !!element &&
|
|
2722
|
+
element.style?.display !== 'none' &&
|
|
2723
|
+
(Number(element.offsetWidth || 0) > 0 || Number(element.offsetHeight || 0) > 0);
|
|
2724
|
+
}
|
|
2725
|
+
|
|
2726
|
+
function createReadonlyContentOnlyShell(module, entry, options = {}) {
|
|
2727
|
+
const hostElement = getReadonlySelectionSourceRoot(entry);
|
|
2728
|
+
if (!hostElement) {
|
|
2729
|
+
return null;
|
|
2730
|
+
}
|
|
2731
|
+
|
|
2732
|
+
const contentSourceRoot =
|
|
2733
|
+
hostElement.querySelector?.('.node-content-wrapper, .node-content') || hostElement;
|
|
2734
|
+
const model = getModel(entry);
|
|
2735
|
+
const hostBaseWidth = Math.max(1, Number(hostElement.offsetWidth || model?.width || model?.Width || 1));
|
|
2736
|
+
const hostBaseHeight = Math.max(1, Number(hostElement.offsetHeight || model?.height || model?.Height || 1));
|
|
2737
|
+
const shell = document.createElement('div');
|
|
2738
|
+
const type = getContentType(entry);
|
|
2739
|
+
const interactive = options.interactive === true;
|
|
2740
|
+
let appended = false;
|
|
2741
|
+
|
|
2742
|
+
shell.className = 'mind-map-text-overlay-v2-source-clone mind-map-text-overlay-v2-content-shell';
|
|
2743
|
+
shell.dataset.overlayCloneType = String(type || '');
|
|
2744
|
+
shell.style.position = 'relative';
|
|
2745
|
+
shell.style.width = `${hostBaseWidth}px`;
|
|
2746
|
+
shell.style.height = `${hostBaseHeight}px`;
|
|
2747
|
+
shell.style.overflow = 'visible';
|
|
2748
|
+
shell.style.pointerEvents = 'none';
|
|
2749
|
+
shell.style.background = 'transparent';
|
|
2750
|
+
shell.style.border = '0';
|
|
2751
|
+
shell.style.boxShadow = 'none';
|
|
2752
|
+
shell.style.outline = 'none';
|
|
2753
|
+
applyInheritedTypographyFromSource(contentSourceRoot, shell);
|
|
2754
|
+
|
|
2755
|
+
const appendFragmentClone = (sourceElement) => {
|
|
2756
|
+
if (!isVisibleOverlaySourceElement(sourceElement)) {
|
|
2757
|
+
return;
|
|
2758
|
+
}
|
|
2759
|
+
|
|
2760
|
+
const clone = cloneReadonlyFragment(sourceElement);
|
|
2761
|
+
if (!clone) {
|
|
2762
|
+
return;
|
|
2763
|
+
}
|
|
2764
|
+
|
|
2765
|
+
appended = appendReadonlyFragment(
|
|
2766
|
+
shell,
|
|
2767
|
+
hostElement,
|
|
2768
|
+
sourceElement,
|
|
2769
|
+
clone,
|
|
2770
|
+
hostBaseWidth,
|
|
2771
|
+
hostBaseHeight
|
|
2772
|
+
) || appended;
|
|
2773
|
+
};
|
|
2774
|
+
|
|
2775
|
+
const appendCustomFragmentClone = (sourceElement, clone) => {
|
|
2776
|
+
if (!isVisibleOverlaySourceElement(sourceElement) || !clone) {
|
|
2777
|
+
return;
|
|
2778
|
+
}
|
|
2779
|
+
|
|
2780
|
+
appended = appendReadonlyFragment(
|
|
2781
|
+
shell,
|
|
2782
|
+
hostElement,
|
|
2783
|
+
sourceElement,
|
|
2784
|
+
clone,
|
|
2785
|
+
hostBaseWidth,
|
|
2786
|
+
hostBaseHeight
|
|
2787
|
+
) || appended;
|
|
2788
|
+
};
|
|
2789
|
+
|
|
2790
|
+
if (type === 'memo') {
|
|
2791
|
+
appendFragmentClone(hostElement.querySelector?.('.map-node-memo__icon-wrap') || null);
|
|
2792
|
+
|
|
2793
|
+
const titleInput = hostElement.querySelector?.('.map-node-memo__title') || null;
|
|
2794
|
+
appendCustomFragmentClone(titleInput, createReadonlyTextReplica(titleInput));
|
|
2795
|
+
|
|
2796
|
+
const primarySelectors = getPrimaryContentSelector();
|
|
2797
|
+
const primaryElements = primarySelectors
|
|
2798
|
+
? Array.from(hostElement.querySelectorAll?.(primarySelectors) || [])
|
|
2799
|
+
: [];
|
|
2800
|
+
primaryElements.forEach(appendFragmentClone);
|
|
2801
|
+
} else {
|
|
2802
|
+
appended = appendReadonlyContentRootClone(
|
|
2803
|
+
shell,
|
|
2804
|
+
hostElement,
|
|
2805
|
+
contentSourceRoot,
|
|
2806
|
+
hostBaseWidth,
|
|
2807
|
+
hostBaseHeight
|
|
2808
|
+
) || appended;
|
|
2809
|
+
|
|
2810
|
+
if (!appended) {
|
|
2811
|
+
const visibleContentChildren = Array.from(contentSourceRoot.children || [])
|
|
2812
|
+
.filter(isVisibleOverlaySourceElement);
|
|
2813
|
+
|
|
2814
|
+
if (visibleContentChildren.length > 0) {
|
|
2815
|
+
visibleContentChildren.forEach(appendFragmentClone);
|
|
2816
|
+
} else {
|
|
2817
|
+
const primarySelectors = getPrimaryContentSelector();
|
|
2818
|
+
const primaryElements = primarySelectors
|
|
2819
|
+
? Array.from(contentSourceRoot.querySelectorAll?.(primarySelectors) || [])
|
|
2820
|
+
: [];
|
|
2821
|
+
primaryElements.forEach(appendFragmentClone);
|
|
2822
|
+
}
|
|
2823
|
+
}
|
|
2824
|
+
}
|
|
2825
|
+
|
|
2826
|
+
if (!appended) {
|
|
2827
|
+
return null;
|
|
2828
|
+
}
|
|
2829
|
+
|
|
2830
|
+
syncOverlayCloneScrollPositions(hostElement, shell);
|
|
2831
|
+
applyOverlayCloneInteractivity(module, shell, interactive, hostElement);
|
|
2832
|
+
return { container: shell, sourceRoot: hostElement };
|
|
2833
|
+
}
|
|
2834
|
+
|
|
2835
|
+
function createReadonlyMemoShellClone(module, entry, options = {}) {
|
|
2836
|
+
const hostElement = getReadonlySelectionSourceRoot(entry);
|
|
2837
|
+
if (!hostElement) {
|
|
2838
|
+
return null;
|
|
2839
|
+
}
|
|
2840
|
+
|
|
2841
|
+
const sourceRoot = hostElement.querySelector?.('.map-node-memo__shell') || null;
|
|
2842
|
+
if (!sourceRoot) {
|
|
2843
|
+
return null;
|
|
2844
|
+
}
|
|
2845
|
+
|
|
2846
|
+
const interactive = options.interactive === true;
|
|
2847
|
+
const clone = cloneReadonlyFragment(sourceRoot);
|
|
2848
|
+
if (!clone) {
|
|
2849
|
+
return null;
|
|
2850
|
+
}
|
|
2851
|
+
|
|
2852
|
+
clone.classList.add('mind-map-text-overlay-v2-readonly-memo-surface');
|
|
2853
|
+
clone.querySelectorAll?.([
|
|
2854
|
+
'.map-node-memo__icon-popover',
|
|
2855
|
+
'.map-node-memo__agent-actions',
|
|
2856
|
+
'.map-node-memo__agent-console-panel',
|
|
2857
|
+
'.map-node-memo__agent-running-indicator'
|
|
2858
|
+
].join(', '))?.forEach?.(element => element.remove());
|
|
2859
|
+
|
|
2860
|
+
const titleInput = clone.querySelector?.('.map-node-memo__title') || null;
|
|
2861
|
+
if (titleInput) {
|
|
2862
|
+
titleInput.readOnly = true;
|
|
2863
|
+
titleInput.disabled = false;
|
|
2864
|
+
titleInput.tabIndex = interactive ? 0 : -1;
|
|
2865
|
+
titleInput.style.pointerEvents = interactive ? 'auto' : 'none';
|
|
2866
|
+
titleInput.style.userSelect = interactive ? 'text' : 'none';
|
|
2867
|
+
titleInput.style.webkitUserSelect = interactive ? 'text' : 'none';
|
|
2868
|
+
}
|
|
2869
|
+
|
|
2870
|
+
const bodyView = clone.querySelector?.('.map-node-memo__body-view') || null;
|
|
2871
|
+
if (bodyView) {
|
|
2872
|
+
bodyView.style.display = '';
|
|
2873
|
+
bodyView.setAttribute('aria-hidden', 'false');
|
|
2874
|
+
}
|
|
2875
|
+
|
|
2876
|
+
clone.querySelectorAll?.('.map-node-memo__body')?.forEach?.(element => element.remove());
|
|
2877
|
+
syncOverlayCloneScrollPositions(sourceRoot, clone);
|
|
2878
|
+
applyOverlayCloneInteractivity(module, clone, interactive, hostElement);
|
|
2879
|
+
return { container: clone, sourceRoot: hostElement };
|
|
2880
|
+
}
|
|
2881
|
+
|
|
2882
|
+
function createReadonlyAgentMemoSourceClone(module, entry, options = {}) {
|
|
2883
|
+
const hostElement = getReadonlySelectionSourceRoot(entry);
|
|
2884
|
+
if (!hostElement) {
|
|
2885
|
+
return null;
|
|
2886
|
+
}
|
|
2887
|
+
|
|
2888
|
+
return createReadonlyOverlayFromSource(module, entry, {
|
|
2889
|
+
...options,
|
|
2890
|
+
sourceRoot: hostElement,
|
|
2891
|
+
renderMode: 'agent-memo'
|
|
2892
|
+
});
|
|
2893
|
+
}
|
|
2894
|
+
|
|
2895
|
+
function createReadonlySelectionShell(module, entry, options = {}) {
|
|
2896
|
+
const mode = getReadonlySelectionMode(entry);
|
|
2897
|
+
if (mode === 'agent-memo') {
|
|
2898
|
+
// Agent memo nodes must mirror the CSS3D source as-is. Their
|
|
2899
|
+
// auxiliary plan/console panels live outside the simplified memo
|
|
2900
|
+
// shell, so the readonly overlay needs the full host clone.
|
|
2901
|
+
return createReadonlyAgentMemoSourceClone(module, entry, options);
|
|
2902
|
+
}
|
|
2903
|
+
|
|
2904
|
+
if (mode === 'memo') {
|
|
2905
|
+
// Memo headers collapse too easily when reconstructed from
|
|
2906
|
+
// independent fragments. Clone the canonical shell but strip the
|
|
2907
|
+
// visual chrome so CSS3D keeps ownership of card background/edge.
|
|
2908
|
+
return createReadonlyMemoShellClone(module, entry, options);
|
|
2909
|
+
}
|
|
2910
|
+
|
|
2911
|
+
if (mode !== 'none') {
|
|
2912
|
+
// Passive readonly overlays only need the text surface.
|
|
2913
|
+
// Keep card chrome/background/borders in CSS3D to avoid duplicate
|
|
2914
|
+
// painting and reduce DOM work during zoom/pan.
|
|
2915
|
+
return createReadonlyContentOnlyShell(module, entry, options);
|
|
2916
|
+
}
|
|
2917
|
+
|
|
2918
|
+
return null;
|
|
2919
|
+
}
|
|
2920
|
+
|
|
2921
|
+
function buildOverlayViewKey(module, snapshot) {
|
|
2922
|
+
if (!snapshot) {
|
|
2923
|
+
return '';
|
|
2924
|
+
}
|
|
2925
|
+
|
|
2926
|
+
const isInteractive =
|
|
2927
|
+
!!module?.isZooming ||
|
|
2928
|
+
!!module?.isPanning ||
|
|
2929
|
+
!!module?.isDraggingNode ||
|
|
2930
|
+
!!module?.isDraggingMultipleNodes ||
|
|
2931
|
+
!!module?.isResizing ||
|
|
2932
|
+
!!module?.isWindowResizing;
|
|
2933
|
+
const precision = isInteractive ? 4 : 2;
|
|
2934
|
+
const round = value => Number(value || 0).toFixed(precision);
|
|
2935
|
+
|
|
2936
|
+
return [
|
|
2937
|
+
round(snapshot.x),
|
|
2938
|
+
round(snapshot.y),
|
|
2939
|
+
round(snapshot.z),
|
|
2940
|
+
round(snapshot.cursorX),
|
|
2941
|
+
round(snapshot.cursorY)
|
|
2942
|
+
].join('|');
|
|
2943
|
+
}
|
|
2944
|
+
|
|
2945
|
+
function isCameraViewTransformCompatible(module) {
|
|
2946
|
+
const camera = module?.camera || null;
|
|
2947
|
+
if (!camera) {
|
|
2948
|
+
return false;
|
|
2949
|
+
}
|
|
2950
|
+
|
|
2951
|
+
const rotation = camera.rotation || null;
|
|
2952
|
+
const tolerance = 0.0001;
|
|
2953
|
+
return !!rotation &&
|
|
2954
|
+
Math.abs(Number(rotation.x || 0)) < tolerance &&
|
|
2955
|
+
Math.abs(Number(rotation.y || 0)) < tolerance &&
|
|
2956
|
+
Math.abs(Number(rotation.z || 0)) < tolerance;
|
|
2957
|
+
}
|
|
2958
|
+
|
|
2959
|
+
function buildLayerLayoutSnapshot(module, snapshot = null) {
|
|
2960
|
+
const container = module?.container || null;
|
|
2961
|
+
const camera = module?.camera || null;
|
|
2962
|
+
const view = snapshot || (typeof module?.buildViewStateSnapshot === 'function'
|
|
2963
|
+
? module.buildViewStateSnapshot()
|
|
2964
|
+
: null);
|
|
2965
|
+
if (!container || !camera || !view) {
|
|
2966
|
+
return null;
|
|
2967
|
+
}
|
|
2968
|
+
|
|
2969
|
+
const width = Math.max(1, Number(container.clientWidth || container.offsetWidth || 0));
|
|
2970
|
+
const height = Math.max(1, Number(container.clientHeight || container.offsetHeight || 0));
|
|
2971
|
+
const fov = Number(camera.fov || 0);
|
|
2972
|
+
if (!(fov > 0) || !(view.z > 0)) {
|
|
2973
|
+
return null;
|
|
2974
|
+
}
|
|
2975
|
+
|
|
2976
|
+
const vfov = (fov * Math.PI) / 180;
|
|
2977
|
+
const viewHeight = 2 * Math.tan(vfov / 2) * Number(view.z || 0);
|
|
2978
|
+
if (!(viewHeight > 0)) {
|
|
2979
|
+
return null;
|
|
2980
|
+
}
|
|
2981
|
+
|
|
2982
|
+
return {
|
|
2983
|
+
x: Number(view.x || 0),
|
|
2984
|
+
y: Number(view.y || 0),
|
|
2985
|
+
z: Number(view.z || 0),
|
|
2986
|
+
width,
|
|
2987
|
+
height,
|
|
2988
|
+
fov,
|
|
2989
|
+
pixelsPerWorld: height / viewHeight
|
|
2990
|
+
};
|
|
2991
|
+
}
|
|
2992
|
+
|
|
2993
|
+
function clearLayerTransform(layer) {
|
|
2994
|
+
if (!layer?.style) {
|
|
2995
|
+
return;
|
|
2996
|
+
}
|
|
2997
|
+
|
|
2998
|
+
layer.style.transformOrigin = '';
|
|
2999
|
+
layer.style.transform = '';
|
|
3000
|
+
}
|
|
3001
|
+
|
|
3002
|
+
function applyLayerViewTransform(layer, baseSnapshot, nextSnapshot) {
|
|
3003
|
+
if (!layer?.style || !baseSnapshot || !nextSnapshot) {
|
|
3004
|
+
return false;
|
|
3005
|
+
}
|
|
3006
|
+
|
|
3007
|
+
const basePixelsPerWorld = Number(baseSnapshot.pixelsPerWorld || 0);
|
|
3008
|
+
const nextPixelsPerWorld = Number(nextSnapshot.pixelsPerWorld || 0);
|
|
3009
|
+
if (!(basePixelsPerWorld > 0) || !(nextPixelsPerWorld > 0)) {
|
|
3010
|
+
return false;
|
|
3011
|
+
}
|
|
3012
|
+
|
|
3013
|
+
const scale = nextPixelsPerWorld / basePixelsPerWorld;
|
|
3014
|
+
const centerX = nextSnapshot.width * 0.5;
|
|
3015
|
+
const centerY = nextSnapshot.height * 0.5;
|
|
3016
|
+
const translateX =
|
|
3017
|
+
(centerX * (1 - scale)) +
|
|
3018
|
+
((Number(baseSnapshot.x || 0) - Number(nextSnapshot.x || 0)) * nextPixelsPerWorld);
|
|
3019
|
+
const translateY =
|
|
3020
|
+
(centerY * (1 - scale)) +
|
|
3021
|
+
((Number(nextSnapshot.y || 0) - Number(baseSnapshot.y || 0)) * nextPixelsPerWorld);
|
|
3022
|
+
|
|
3023
|
+
layer.style.transformOrigin = '0 0';
|
|
3024
|
+
layer.style.transform = `translate(${translateX}px, ${translateY}px) scale(${scale})`;
|
|
3025
|
+
return true;
|
|
3026
|
+
}
|
|
3027
|
+
|
|
3028
|
+
function canUseLayerTransformFastPath(module, state, snapshot, visibilityVersion, contentChanged, forceRefresh) {
|
|
3029
|
+
if (!state?.layer || !snapshot) {
|
|
3030
|
+
return false;
|
|
3031
|
+
}
|
|
3032
|
+
|
|
3033
|
+
if (contentChanged || forceRefresh || state.dirtyLayout === true) {
|
|
3034
|
+
return false;
|
|
3035
|
+
}
|
|
3036
|
+
|
|
3037
|
+
if (!shouldRenderPassiveDomOverlays(module)) {
|
|
3038
|
+
return false;
|
|
3039
|
+
}
|
|
3040
|
+
|
|
3041
|
+
if (!!normalizeId(state.selectionNodeId) || !!normalizeId(state.editing?.nodeId)) {
|
|
3042
|
+
return false;
|
|
3043
|
+
}
|
|
3044
|
+
|
|
3045
|
+
const allowDeferredVisibilityRefresh =
|
|
3046
|
+
module?._deferPassiveOverlayRefresh === true &&
|
|
3047
|
+
(module?.isZooming === true || module?.isPanning === true);
|
|
3048
|
+
if (!allowDeferredVisibilityRefresh &&
|
|
3049
|
+
Number(state.lastVisibilityVersion || 0) !== Number(visibilityVersion || 0)) {
|
|
3050
|
+
return false;
|
|
3051
|
+
}
|
|
3052
|
+
|
|
3053
|
+
if (!isCameraViewTransformCompatible(module)) {
|
|
3054
|
+
return false;
|
|
3055
|
+
}
|
|
3056
|
+
|
|
3057
|
+
const hasVisibleCard = state.cards.size > 0 &&
|
|
3058
|
+
Array.from(state.cards.values()).some(card => !!card && card.style.display !== 'none');
|
|
3059
|
+
if (!hasVisibleCard) {
|
|
3060
|
+
return false;
|
|
3061
|
+
}
|
|
3062
|
+
|
|
3063
|
+
const baseSnapshot = state.layoutSnapshot;
|
|
3064
|
+
const nextSnapshot = buildLayerLayoutSnapshot(module, snapshot);
|
|
3065
|
+
if (!baseSnapshot || !nextSnapshot) {
|
|
3066
|
+
return false;
|
|
3067
|
+
}
|
|
3068
|
+
|
|
3069
|
+
const tolerance = 0.01;
|
|
3070
|
+
if (Math.abs(Number(baseSnapshot.width || 0) - Number(nextSnapshot.width || 0)) > tolerance ||
|
|
3071
|
+
Math.abs(Number(baseSnapshot.height || 0) - Number(nextSnapshot.height || 0)) > tolerance ||
|
|
3072
|
+
Math.abs(Number(baseSnapshot.fov || 0) - Number(nextSnapshot.fov || 0)) > tolerance) {
|
|
3073
|
+
return false;
|
|
3074
|
+
}
|
|
3075
|
+
|
|
3076
|
+
return applyLayerViewTransform(state.layer, baseSnapshot, nextSnapshot);
|
|
3077
|
+
}
|
|
3078
|
+
|
|
3079
|
+
function syncPassiveViewTransform(module) {
|
|
3080
|
+
if (!shouldRenderPassiveDomOverlays(module)) {
|
|
3081
|
+
return false;
|
|
3082
|
+
}
|
|
3083
|
+
|
|
3084
|
+
const state = ensureState(module);
|
|
3085
|
+
const snapshot = typeof module?.buildViewStateSnapshot === 'function'
|
|
3086
|
+
? module.buildViewStateSnapshot()
|
|
3087
|
+
: null;
|
|
3088
|
+
const visibilityVersion = Number(module?._visibilityVersion || 0);
|
|
3089
|
+
return canUseLayerTransformFastPath(
|
|
3090
|
+
module,
|
|
3091
|
+
state,
|
|
3092
|
+
snapshot,
|
|
3093
|
+
visibilityVersion,
|
|
3094
|
+
false,
|
|
3095
|
+
false
|
|
3096
|
+
);
|
|
3097
|
+
}
|
|
3098
|
+
|
|
3099
|
+
function updateNodePlacement(module, nodeId) {
|
|
3100
|
+
const state = ensureState(module);
|
|
3101
|
+
const layer = state?.layer || ensureLayer(module);
|
|
3102
|
+
const normalizedNodeId = normalizeId(nodeId);
|
|
3103
|
+
if (!state || !layer || !normalizedNodeId) {
|
|
3104
|
+
return false;
|
|
3105
|
+
}
|
|
3106
|
+
|
|
3107
|
+
const entry = module?.nodeObjectsById?.get?.(normalizedNodeId) || null;
|
|
3108
|
+
if (!entry) {
|
|
3109
|
+
return false;
|
|
3110
|
+
}
|
|
3111
|
+
|
|
3112
|
+
const rect = getPlacementRect(module, entry);
|
|
3113
|
+
if (!rect) {
|
|
3114
|
+
return false;
|
|
3115
|
+
}
|
|
3116
|
+
|
|
3117
|
+
let moved = false;
|
|
3118
|
+
const selectionCard = state.cards.get(selectionCardKey(normalizedNodeId)) || null;
|
|
3119
|
+
if (selectionCard && selectionCard.style.display !== 'none') {
|
|
3120
|
+
applyPlacement(module, selectionCard, rect, 8, entry);
|
|
3121
|
+
moved = true;
|
|
3122
|
+
}
|
|
3123
|
+
|
|
3124
|
+
const editingCard = state.cards.get(editingCardKey(normalizedNodeId)) || null;
|
|
3125
|
+
if (editingCard && editingCard.style.display !== 'none') {
|
|
3126
|
+
applyPlacement(module, editingCard, rect, 12, entry);
|
|
3127
|
+
moved = true;
|
|
3128
|
+
}
|
|
3129
|
+
|
|
3130
|
+
if (!moved) {
|
|
3131
|
+
return false;
|
|
3132
|
+
}
|
|
3133
|
+
|
|
3134
|
+
// Node dragging changes card placement while the camera snapshot stays
|
|
3135
|
+
// stable. Reset any passive fast-path transform so text tracks the node.
|
|
3136
|
+
clearLayerTransform(layer);
|
|
3137
|
+
const snapshot = typeof module?.buildViewStateSnapshot === 'function'
|
|
3138
|
+
? module.buildViewStateSnapshot()
|
|
3139
|
+
: null;
|
|
3140
|
+
state.layoutSnapshot = buildLayerLayoutSnapshot(module, snapshot);
|
|
3141
|
+
state.lastViewKey = snapshot ? buildOverlayViewKey(module, snapshot) : state.lastViewKey;
|
|
3142
|
+
state.lastVisibilityVersion = Number(module?._visibilityVersion || 0);
|
|
3143
|
+
state.dirtyLayout = false;
|
|
3144
|
+
module._overlayDebugLayoutChanged = true;
|
|
3145
|
+
return true;
|
|
3146
|
+
}
|
|
3147
|
+
|
|
3148
|
+
function canOverlayCssEntry(entry) {
|
|
3149
|
+
return !!(
|
|
3150
|
+
entry &&
|
|
3151
|
+
entry.currentType === 'CSS' &&
|
|
3152
|
+
entry.cssObject?.visible === true &&
|
|
3153
|
+
entry.cssObject?.element &&
|
|
3154
|
+
supportsPassiveDisplay(entry)
|
|
3155
|
+
);
|
|
3156
|
+
}
|
|
3157
|
+
|
|
3158
|
+
function shouldSkipCss3dRender(module) {
|
|
3159
|
+
if (!shouldRenderPassiveDomOverlays(module)) {
|
|
3160
|
+
return false;
|
|
3161
|
+
}
|
|
3162
|
+
|
|
3163
|
+
if (!!normalizeId(module?._textOverlayV2State?.editing?.nodeId)) {
|
|
3164
|
+
return false;
|
|
3165
|
+
}
|
|
3166
|
+
|
|
3167
|
+
const visibleIds = module?._visibleIds || module?._prevVisibleIds || null;
|
|
3168
|
+
if (!visibleIds?.forEach || visibleIds.size === 0) {
|
|
3169
|
+
return false;
|
|
3170
|
+
}
|
|
3171
|
+
|
|
3172
|
+
let sawCoveredCssNode = false;
|
|
3173
|
+
let foundUnsupportedVisibleCssNode = false;
|
|
3174
|
+
|
|
3175
|
+
visibleIds.forEach(nodeId => {
|
|
3176
|
+
if (foundUnsupportedVisibleCssNode) {
|
|
3177
|
+
return;
|
|
3178
|
+
}
|
|
3179
|
+
|
|
3180
|
+
const entry = module?.nodeObjectsById?.get?.(nodeId) || null;
|
|
3181
|
+
if (!entry || entry.currentType !== 'CSS' || entry.cssObject?.visible !== true) {
|
|
3182
|
+
return;
|
|
3183
|
+
}
|
|
3184
|
+
|
|
3185
|
+
if (!canOverlayCssEntry(entry)) {
|
|
3186
|
+
foundUnsupportedVisibleCssNode = true;
|
|
3187
|
+
return;
|
|
3188
|
+
}
|
|
3189
|
+
|
|
3190
|
+
sawCoveredCssNode = true;
|
|
3191
|
+
});
|
|
3192
|
+
|
|
3193
|
+
return sawCoveredCssNode && !foundUnsupportedVisibleCssNode;
|
|
3194
|
+
}
|
|
3195
|
+
|
|
3196
|
+
function buildSelectionContentKey(entry) {
|
|
3197
|
+
const model = getModel(entry);
|
|
3198
|
+
const metadata = getMetadata(model);
|
|
3199
|
+
return JSON.stringify({
|
|
3200
|
+
kind: 'selection',
|
|
3201
|
+
type: getContentType(model),
|
|
3202
|
+
width: Number(model?.width || model?.Width || 0),
|
|
3203
|
+
height: Number(model?.height || model?.Height || 0),
|
|
3204
|
+
prompt: getPrompt(model),
|
|
3205
|
+
response: getResponse(model),
|
|
3206
|
+
isWordWrap: model?.isWordWrap !== false,
|
|
3207
|
+
memoColor: metadata?.memoColor || metadata?.MemoColor || '',
|
|
3208
|
+
semanticType: metadata?.semanticType || metadata?.SemanticType || '',
|
|
3209
|
+
memoAgentOverlay: getContentType(model) === 'memo' ? buildMemoAgentOverlayKey(entry) : ''
|
|
3210
|
+
});
|
|
3211
|
+
}
|
|
3212
|
+
|
|
3213
|
+
function applyEditingSurfaceTransparencyClasses(surface, kind) {
|
|
3214
|
+
if (!surface?.classList) {
|
|
3215
|
+
return null;
|
|
3216
|
+
}
|
|
3217
|
+
|
|
3218
|
+
surface.classList.add('mind-map-text-overlay-v2-editing-surface');
|
|
3219
|
+
if (kind === 'memo') {
|
|
3220
|
+
surface.classList.add('mind-map-text-overlay-v2-editing-memo-surface');
|
|
3221
|
+
} else if (kind === 'note') {
|
|
3222
|
+
surface.classList.add('mind-map-text-overlay-v2-editing-note-surface');
|
|
3223
|
+
}
|
|
3224
|
+
|
|
3225
|
+
return surface;
|
|
3226
|
+
}
|
|
3227
|
+
|
|
3228
|
+
// Editing overlays must come from the CSS3D manager's canonical builder.
|
|
3229
|
+
// Overlay V2 is only responsible for placement and focus routing.
|
|
3230
|
+
function createEditingCardFromCss3dSource(module, entry, expectedKind) {
|
|
3231
|
+
const nodeId = getNodeId(entry);
|
|
3232
|
+
const card = ensureCard(module, editingCardKey(nodeId), nodeId, `editing-${expectedKind}`);
|
|
3233
|
+
if (!card) {
|
|
3234
|
+
return null;
|
|
3235
|
+
}
|
|
3236
|
+
|
|
3237
|
+
card.replaceChildren();
|
|
3238
|
+
setCardMode(card, 'editing');
|
|
3239
|
+
|
|
3240
|
+
const created = getCss3dManager()?.createEditingOverlayContent?.(entry) || null;
|
|
3241
|
+
if (!created?.card) {
|
|
3242
|
+
return null;
|
|
3243
|
+
}
|
|
3244
|
+
|
|
3245
|
+
const kind = String(created.kind || expectedKind || '').trim().toLowerCase();
|
|
3246
|
+
const editingSurface = applyEditingSurfaceTransparencyClasses(created.card, kind);
|
|
3247
|
+
if (!editingSurface) {
|
|
3248
|
+
return null;
|
|
3249
|
+
}
|
|
3250
|
+
|
|
3251
|
+
card.appendChild(editingSurface);
|
|
3252
|
+
|
|
3253
|
+
if (kind === 'note' && created.textarea) {
|
|
3254
|
+
getCss3dManager()?.bindNoteEditingWheelZoom?.(module, created.textarea);
|
|
3255
|
+
}
|
|
3256
|
+
if (kind === 'memo') {
|
|
3257
|
+
getCss3dManager()?.bindMemoWheelRouting?.(module, card);
|
|
3258
|
+
}
|
|
3259
|
+
if (created.textarea) {
|
|
3260
|
+
getCss3dManager()?.restoreEditingScrollState?.(entry, created.textarea);
|
|
3261
|
+
}
|
|
3262
|
+
getCss3dManager()?.bindEditingOverlayPan?.(module, card);
|
|
3263
|
+
|
|
3264
|
+
return {
|
|
3265
|
+
card,
|
|
3266
|
+
focusTarget: created.focusTarget || created.textarea || created.titleInput || null,
|
|
3267
|
+
titleInput: created.titleInput || null,
|
|
3268
|
+
textarea: created.textarea || null,
|
|
3269
|
+
initialTitle: created.initialTitle,
|
|
3270
|
+
initialValue: created.initialValue
|
|
3271
|
+
};
|
|
3272
|
+
}
|
|
3273
|
+
|
|
3274
|
+
function renderSelectionCard(module, entry, options = {}) {
|
|
3275
|
+
const nodeId = getNodeId(entry);
|
|
3276
|
+
if (!nodeId) {
|
|
3277
|
+
return null;
|
|
3278
|
+
}
|
|
3279
|
+
|
|
3280
|
+
const interactive = options.interactive === true;
|
|
3281
|
+
const forceRebuild = options.forceRebuild === true;
|
|
3282
|
+
const card = ensureCard(module, selectionCardKey(nodeId), nodeId, 'selection');
|
|
3283
|
+
if (!card) {
|
|
3284
|
+
return null;
|
|
3285
|
+
}
|
|
3286
|
+
card.style.pointerEvents = 'none';
|
|
3287
|
+
card.dataset.contentType = getContentType(entry);
|
|
3288
|
+
|
|
3289
|
+
const contentKey = buildSelectionContentKey(entry);
|
|
3290
|
+
const sourceEpoch = String(getReadonlySourceEpoch(module));
|
|
3291
|
+
const sourceRoot = getReadonlySelectionSourceRoot(entry);
|
|
3292
|
+
if (!forceRebuild &&
|
|
3293
|
+
card.dataset.contentKey === contentKey &&
|
|
3294
|
+
card.dataset.sourceEpoch === sourceEpoch &&
|
|
3295
|
+
card.childElementCount > 0) {
|
|
3296
|
+
setCardMode(card, 'selection', interactive);
|
|
3297
|
+
if (card.dataset.sourceKind !== 'live') {
|
|
3298
|
+
bindReadonlyOverlayPrimaryPointerRouting(module, card, sourceRoot);
|
|
3299
|
+
refreshOverlayCloneInteractivity(module, card.firstElementChild || card, interactive, sourceRoot);
|
|
3300
|
+
syncReadonlyOverlayCardScrollFromSource(card);
|
|
3301
|
+
scheduleReadonlyOverlayCardScrollSync(card);
|
|
3302
|
+
}
|
|
3303
|
+
return card;
|
|
3304
|
+
}
|
|
3305
|
+
|
|
3306
|
+
if (card.dataset.sourceKind === 'live') {
|
|
3307
|
+
resumeSource(entry);
|
|
3308
|
+
}
|
|
3309
|
+
|
|
3310
|
+
const previousScroll = preserveBodyScroll(card);
|
|
3311
|
+
card.replaceChildren();
|
|
3312
|
+
setCardMode(card, 'selection', interactive);
|
|
3313
|
+
card.dataset.contentKey = contentKey;
|
|
3314
|
+
card.dataset.sourceEpoch = sourceEpoch;
|
|
3315
|
+
|
|
3316
|
+
// Keep CSS3D as the single readonly source of truth. If the source
|
|
3317
|
+
// shell is unavailable, skip the overlay instead of rebuilding a
|
|
3318
|
+
// second, divergent readonly DOM path.
|
|
3319
|
+
const shellResult = createReadonlySelectionShell(module, entry, { interactive: interactive, cardElement: card }) || null;
|
|
3320
|
+
const shell = shellResult?.container || null;
|
|
3321
|
+
const shellSourceRoot = shellResult?.sourceRoot || sourceRoot;
|
|
3322
|
+
if (!shell) {
|
|
3323
|
+
card.dataset.contentKey = '';
|
|
3324
|
+
card.dataset.sourceEpoch = '';
|
|
3325
|
+
card.dataset.sourceKind = '';
|
|
3326
|
+
return null;
|
|
3327
|
+
}
|
|
3328
|
+
|
|
3329
|
+
card.dataset.sourceKind = shellResult?.liveSource === true ? 'live' : 'clone';
|
|
3330
|
+
card.appendChild(shell);
|
|
3331
|
+
if (card.dataset.sourceKind !== 'live') {
|
|
3332
|
+
bindReadonlyOverlayPrimaryPointerRouting(module, card, shellSourceRoot);
|
|
3333
|
+
syncReadonlyOverlayCardScrollFromSource(card);
|
|
3334
|
+
scheduleReadonlyOverlayCardScrollSync(card);
|
|
3335
|
+
}
|
|
3336
|
+
restoreBodyScroll(card, previousScroll);
|
|
3337
|
+
if (card.dataset.sourceKind !== 'live') {
|
|
3338
|
+
syncReadonlyOverlayCardScrollFromSource(card);
|
|
3339
|
+
scheduleReadonlyOverlayCardScrollSync(card);
|
|
3340
|
+
}
|
|
3341
|
+
return card;
|
|
3342
|
+
}
|
|
3343
|
+
|
|
3344
|
+
function createNoteEditingCard(module, entry) {
|
|
3345
|
+
return createEditingCardFromCss3dSource(module, entry, 'note');
|
|
3346
|
+
}
|
|
3347
|
+
|
|
3348
|
+
function createMemoEditingCard(module, entry) {
|
|
3349
|
+
return createEditingCardFromCss3dSource(module, entry, 'memo');
|
|
3350
|
+
}
|
|
3351
|
+
|
|
3352
|
+
function commitEditing(module) {
|
|
3353
|
+
const state = ensureState(module);
|
|
3354
|
+
const editing = state?.editing;
|
|
3355
|
+
if (!editing?.nodeId) {
|
|
3356
|
+
return false;
|
|
3357
|
+
}
|
|
3358
|
+
|
|
3359
|
+
const entry = module?.nodeObjectsById?.get?.(editing.nodeId) || null;
|
|
3360
|
+
if (!entry?.model) {
|
|
3361
|
+
return false;
|
|
3362
|
+
}
|
|
3363
|
+
|
|
3364
|
+
if (editing.textarea) {
|
|
3365
|
+
getCss3dManager()?.rememberEditingScrollState?.(entry, editing.textarea);
|
|
3366
|
+
getCss3dManager()?.syncCss3dScrollFromElement?.(module, editing.nodeId, editing.textarea);
|
|
3367
|
+
}
|
|
3368
|
+
|
|
3369
|
+
if (editing.kind === 'memo') {
|
|
3370
|
+
const title = String(editing.titleInput?.value || '');
|
|
3371
|
+
const content = String(editing.textarea?.value || '');
|
|
3372
|
+
const previousTitle = String(editing.initialTitle ?? getPrompt(entry));
|
|
3373
|
+
const previousContent = String(editing.initialValue ?? getResponse(entry));
|
|
3374
|
+
|
|
3375
|
+
if (title === previousTitle && content === previousContent) {
|
|
3376
|
+
return false;
|
|
3377
|
+
}
|
|
3378
|
+
|
|
3379
|
+
entry.model.prompt = title;
|
|
3380
|
+
entry.model.Prompt = title;
|
|
3381
|
+
entry.model.response = content;
|
|
3382
|
+
entry.model.Response = content;
|
|
3383
|
+
editing.initialTitle = title;
|
|
3384
|
+
editing.initialValue = content;
|
|
3385
|
+
window.MindMapTextLOD?.invalidateNodeCache?.(String(entry.model.id), false);
|
|
3386
|
+
module.dotNetHelper?.invokeMethodAsync?.('UpdateMemoNodeFields', String(entry.model.id), title, content).catch(() => { });
|
|
3387
|
+
} else {
|
|
3388
|
+
const value = String(editing.textarea?.value || '');
|
|
3389
|
+
const previousValue = String(editing.initialValue ?? getResponse(entry));
|
|
3390
|
+
|
|
3391
|
+
if (value === previousValue) {
|
|
3392
|
+
return false;
|
|
3393
|
+
}
|
|
3394
|
+
|
|
3395
|
+
entry.model.response = value;
|
|
3396
|
+
entry.model.Response = value;
|
|
3397
|
+
entry.model.content = value;
|
|
3398
|
+
entry.model.Content = value;
|
|
3399
|
+
editing.initialValue = value;
|
|
3400
|
+
|
|
3401
|
+
if (window.MindMapNodes?.pendingNodeUpdates) {
|
|
3402
|
+
window.MindMapNodes.pendingNodeUpdates.set(entry.model.id, {
|
|
3403
|
+
content: value,
|
|
3404
|
+
width: entry.model.width,
|
|
3405
|
+
height: entry.model.height
|
|
3406
|
+
});
|
|
3407
|
+
}
|
|
3408
|
+
|
|
3409
|
+
window.MindMapTextLOD?.invalidateNodeCache?.(String(entry.model.id), false);
|
|
3410
|
+
module.dotNetHelper?.invokeMethodAsync?.('UpdateNodeContent', entry.model.id, value).catch(() => { });
|
|
3411
|
+
}
|
|
3412
|
+
|
|
3413
|
+
if (entry.cssObject && window.MindMapCss3DManager?.syncCss3dContent) {
|
|
3414
|
+
window.MindMapCss3DManager.syncCss3dContent(entry.model, entry.cssObject);
|
|
3415
|
+
}
|
|
3416
|
+
|
|
3417
|
+
return true;
|
|
3418
|
+
}
|
|
3419
|
+
|
|
3420
|
+
function activateSelection(module, nodeId) {
|
|
3421
|
+
if (!isEnabled(module)) {
|
|
3422
|
+
return false;
|
|
3423
|
+
}
|
|
3424
|
+
|
|
3425
|
+
const id = normalizeId(nodeId);
|
|
3426
|
+
if (!id) {
|
|
3427
|
+
return false;
|
|
3428
|
+
}
|
|
3429
|
+
|
|
3430
|
+
const entry = module?.nodeObjectsById?.get?.(id) || null;
|
|
3431
|
+
if (!entry || !supportsSelection(entry)) {
|
|
3432
|
+
return false;
|
|
3433
|
+
}
|
|
3434
|
+
|
|
3435
|
+
const state = ensureState(module);
|
|
3436
|
+
if (!state) {
|
|
3437
|
+
return false;
|
|
3438
|
+
}
|
|
3439
|
+
|
|
3440
|
+
if (state.selectionNodeId === id) {
|
|
3441
|
+
state.dirtyLayout = true;
|
|
3442
|
+
module._overlayDirty = true;
|
|
3443
|
+
return true;
|
|
3444
|
+
}
|
|
3445
|
+
|
|
3446
|
+
clearSelection(module);
|
|
3447
|
+
state.selectionNodeId = id;
|
|
3448
|
+
state.dirtySelection = true;
|
|
3449
|
+
state.dirtyLayout = true;
|
|
3450
|
+
module._overlayDirty = true;
|
|
3451
|
+
module._lastOverlayKey = '';
|
|
3452
|
+
syncLayerVisibility(module);
|
|
3453
|
+
return true;
|
|
3454
|
+
}
|
|
3455
|
+
|
|
3456
|
+
function clearSelection(module, nodeId = null) {
|
|
3457
|
+
const state = ensureState(module);
|
|
3458
|
+
const activeId = normalizeId(state?.selectionNodeId);
|
|
3459
|
+
const requestedId = nodeId === null ? activeId : normalizeId(nodeId);
|
|
3460
|
+
if (!state || !activeId || !requestedId || requestedId !== activeId) {
|
|
3461
|
+
return false;
|
|
3462
|
+
}
|
|
3463
|
+
|
|
3464
|
+
const entry = module?.nodeObjectsById?.get?.(activeId) || null;
|
|
3465
|
+
if (entry) {
|
|
3466
|
+
resumeSource(entry);
|
|
3467
|
+
}
|
|
3468
|
+
|
|
3469
|
+
hideCard(state.cards.get(selectionCardKey(activeId)));
|
|
3470
|
+
state.selectionNodeId = '';
|
|
3471
|
+
state.dirtySelection = true;
|
|
3472
|
+
state.dirtyLayout = true;
|
|
3473
|
+
module._overlayDirty = true;
|
|
3474
|
+
module._lastOverlayKey = '';
|
|
3475
|
+
return true;
|
|
3476
|
+
}
|
|
3477
|
+
|
|
3478
|
+
function beginEditing(module, nodeEntry) {
|
|
3479
|
+
if (!isEnabled(module) || !supportsEditing(nodeEntry)) {
|
|
3480
|
+
return false;
|
|
3481
|
+
}
|
|
3482
|
+
|
|
3483
|
+
const state = ensureState(module);
|
|
3484
|
+
const nodeId = getNodeId(nodeEntry);
|
|
3485
|
+
const kind = getContentType(nodeEntry) === 'memo' ? 'memo' : 'note';
|
|
3486
|
+
if (!state || !nodeId) {
|
|
3487
|
+
return false;
|
|
3488
|
+
}
|
|
3489
|
+
|
|
3490
|
+
if (state.editing?.nodeId === nodeId) {
|
|
3491
|
+
state.editing.shouldFocus = true;
|
|
3492
|
+
state.dirtyLayout = true;
|
|
3493
|
+
module._overlayDirty = true;
|
|
3494
|
+
return true;
|
|
3495
|
+
}
|
|
3496
|
+
|
|
3497
|
+
if (state.editing?.nodeId) {
|
|
3498
|
+
clearEditing(module, { commit: true, preserveEditingFlag: true });
|
|
3499
|
+
}
|
|
3500
|
+
|
|
3501
|
+
clearSelection(module);
|
|
3502
|
+
|
|
3503
|
+
state.editing = {
|
|
3504
|
+
nodeId,
|
|
3505
|
+
kind,
|
|
3506
|
+
element: null,
|
|
3507
|
+
titleInput: null,
|
|
3508
|
+
textarea: null,
|
|
3509
|
+
focusTarget: null,
|
|
3510
|
+
initialTitle: kind === 'memo' ? getPrompt(nodeEntry) : null,
|
|
3511
|
+
initialValue: getResponse(nodeEntry),
|
|
3512
|
+
shouldFocus: true
|
|
3513
|
+
};
|
|
3514
|
+
state.dirtyEditing = true;
|
|
3515
|
+
state.dirtyLayout = true;
|
|
3516
|
+
module.isEditingNote = true;
|
|
3517
|
+
module._overlayDirty = true;
|
|
3518
|
+
module._lastOverlayKey = '';
|
|
3519
|
+
return true;
|
|
3520
|
+
}
|
|
3521
|
+
|
|
3522
|
+
function clearEditing(module, options = {}) {
|
|
3523
|
+
const state = ensureState(module);
|
|
3524
|
+
const editing = state?.editing;
|
|
3525
|
+
if (!editing?.nodeId) {
|
|
3526
|
+
return false;
|
|
3527
|
+
}
|
|
3528
|
+
|
|
3529
|
+
const { commit = true, nodeId = null, preserveEditingFlag = false } = options;
|
|
3530
|
+
const activeId = normalizeId(editing.nodeId);
|
|
3531
|
+
const requestedId = nodeId === null ? activeId : normalizeId(nodeId);
|
|
3532
|
+
if (!requestedId || requestedId !== activeId) {
|
|
3533
|
+
return false;
|
|
3534
|
+
}
|
|
3535
|
+
|
|
3536
|
+
const entry = module?.nodeObjectsById?.get?.(activeId) || null;
|
|
3537
|
+
if (entry && editing.textarea) {
|
|
3538
|
+
getCss3dManager()?.rememberEditingScrollState?.(entry, editing.textarea);
|
|
3539
|
+
getCss3dManager()?.syncCss3dScrollFromElement?.(module, activeId, editing.textarea);
|
|
3540
|
+
}
|
|
3541
|
+
|
|
3542
|
+
if (commit) {
|
|
3543
|
+
commitEditing(module);
|
|
3544
|
+
}
|
|
3545
|
+
|
|
3546
|
+
if (entry) {
|
|
3547
|
+
resumeSource(entry);
|
|
3548
|
+
}
|
|
3549
|
+
|
|
3550
|
+
hideCard(state.cards.get(editingCardKey(activeId)));
|
|
3551
|
+
state.editing = null;
|
|
3552
|
+
state.dirtyEditing = true;
|
|
3553
|
+
state.dirtyLayout = true;
|
|
3554
|
+
if (!preserveEditingFlag) {
|
|
3555
|
+
module.isEditingNote = false;
|
|
3556
|
+
}
|
|
3557
|
+
module._overlayDirty = true;
|
|
3558
|
+
module._lastOverlayKey = '';
|
|
3559
|
+
syncLayerVisibility(module);
|
|
3560
|
+
return true;
|
|
3561
|
+
}
|
|
3562
|
+
|
|
3563
|
+
function invalidateNode(module, nodeId, reason = 'content') {
|
|
3564
|
+
const state = ensureState(module);
|
|
3565
|
+
const id = normalizeId(nodeId);
|
|
3566
|
+
if (!state || !id) {
|
|
3567
|
+
return;
|
|
3568
|
+
}
|
|
3569
|
+
|
|
3570
|
+
const entry = module?.nodeObjectsById?.get?.(id) || null;
|
|
3571
|
+
if (isMediaOverlayExcluded(entry)) {
|
|
3572
|
+
purgeMediaOverlayCards(module, state);
|
|
3573
|
+
}
|
|
3574
|
+
|
|
3575
|
+
state.dirtyNodes.add(id);
|
|
3576
|
+
if (reason === 'layout') {
|
|
3577
|
+
state.dirtyLayout = true;
|
|
3578
|
+
}
|
|
3579
|
+
module._overlayDirty = true;
|
|
3580
|
+
module._lastOverlayKey = '';
|
|
3581
|
+
}
|
|
3582
|
+
|
|
3583
|
+
function invalidateView(module) {
|
|
3584
|
+
const state = ensureState(module);
|
|
3585
|
+
if (!state) {
|
|
3586
|
+
return;
|
|
3587
|
+
}
|
|
3588
|
+
|
|
3589
|
+
if (hasBlockingPassiveOverlayInteraction(module, state)) {
|
|
3590
|
+
hidePassiveSelectionCards(module, state);
|
|
3591
|
+
}
|
|
3592
|
+
state.dirtyLayout = true;
|
|
3593
|
+
module._overlayDirty = true;
|
|
3594
|
+
module._lastOverlayKey = '';
|
|
3595
|
+
}
|
|
3596
|
+
|
|
3597
|
+
function hidePassiveSelectionCards(module, state = ensureState(module), options = {}) {
|
|
3598
|
+
if (!module || !state) {
|
|
3599
|
+
return 0;
|
|
3600
|
+
}
|
|
3601
|
+
|
|
3602
|
+
const onlyNodeIds = options?.onlyNodeIds instanceof Set
|
|
3603
|
+
? options.onlyNodeIds
|
|
3604
|
+
: null;
|
|
3605
|
+
let hiddenCount = 0;
|
|
3606
|
+
state.cards.forEach(card => {
|
|
3607
|
+
if (!card || card.style.display === 'none') {
|
|
3608
|
+
return;
|
|
3609
|
+
}
|
|
3610
|
+
|
|
3611
|
+
const isPassiveSelectionCard =
|
|
3612
|
+
String(card.dataset?.overlayMode || '') === 'selection' &&
|
|
3613
|
+
String(card.dataset?.overlayInteractive || '') !== 'true';
|
|
3614
|
+
if (!isPassiveSelectionCard) {
|
|
3615
|
+
return;
|
|
3616
|
+
}
|
|
3617
|
+
|
|
3618
|
+
const nodeId = normalizeId(card.dataset?.nodeId);
|
|
3619
|
+
if (onlyNodeIds && (!nodeId || !onlyNodeIds.has(nodeId))) {
|
|
3620
|
+
return;
|
|
3621
|
+
}
|
|
3622
|
+
if (nodeId) {
|
|
3623
|
+
const entry = module?.nodeObjectsById?.get?.(nodeId) || null;
|
|
3624
|
+
if (entry) {
|
|
3625
|
+
resumeSource(entry);
|
|
3626
|
+
}
|
|
3627
|
+
}
|
|
3628
|
+
|
|
3629
|
+
hideCard(card);
|
|
3630
|
+
hiddenCount += 1;
|
|
3631
|
+
});
|
|
3632
|
+
|
|
3633
|
+
if (hiddenCount > 0) {
|
|
3634
|
+
if (onlyNodeIds) {
|
|
3635
|
+
onlyNodeIds.forEach(nodeId => state.passiveCandidateIds.delete(normalizeId(nodeId)));
|
|
3636
|
+
} else {
|
|
3637
|
+
state.passiveCandidateIds.clear();
|
|
3638
|
+
state.passiveCandidateVisibleUntil = 0;
|
|
3639
|
+
}
|
|
3640
|
+
const hasVisibleCard = Array.from(state.cards.values()).some(card =>
|
|
3641
|
+
!!card && card.style.display !== 'none');
|
|
3642
|
+
if (!hasVisibleCard) {
|
|
3643
|
+
clearLayerTransform(state.layer);
|
|
3644
|
+
if (state.layer?.style) {
|
|
3645
|
+
state.layer.style.display = 'none';
|
|
3646
|
+
}
|
|
3647
|
+
}
|
|
3648
|
+
}
|
|
3649
|
+
|
|
3650
|
+
return hiddenCount;
|
|
3651
|
+
}
|
|
3652
|
+
|
|
3653
|
+
function hideUnusedCards(module, keepCardKeys) {
|
|
3654
|
+
const state = ensureState(module);
|
|
3655
|
+
if (!state) {
|
|
3656
|
+
return;
|
|
3657
|
+
}
|
|
3658
|
+
|
|
3659
|
+
const keptNodeIds = new Set();
|
|
3660
|
+
keepCardKeys.forEach(cardKey => {
|
|
3661
|
+
const keptCard = state.cards.get(cardKey);
|
|
3662
|
+
const keptNodeId = normalizeId(keptCard?.dataset?.nodeId);
|
|
3663
|
+
if (keptNodeId) {
|
|
3664
|
+
keptNodeIds.add(keptNodeId);
|
|
3665
|
+
}
|
|
3666
|
+
});
|
|
3667
|
+
|
|
3668
|
+
state.cards.forEach((card, cardKey) => {
|
|
3669
|
+
if (!keepCardKeys.has(cardKey)) {
|
|
3670
|
+
const nodeId = normalizeId(card?.dataset?.nodeId);
|
|
3671
|
+
if (nodeId && !keptNodeIds.has(nodeId)) {
|
|
3672
|
+
const entry = module?.nodeObjectsById?.get?.(nodeId) || null;
|
|
3673
|
+
if (entry) {
|
|
3674
|
+
resumeSource(entry);
|
|
3675
|
+
}
|
|
3676
|
+
}
|
|
3677
|
+
const staleEntry = nodeId ? module?.nodeObjectsById?.get?.(nodeId) || null : null;
|
|
3678
|
+
if (isMediaOverlayExcluded(staleEntry)) {
|
|
3679
|
+
removeCard(state, cardKey);
|
|
3680
|
+
} else {
|
|
3681
|
+
hideCard(card);
|
|
3682
|
+
}
|
|
3683
|
+
}
|
|
3684
|
+
});
|
|
3685
|
+
}
|
|
3686
|
+
|
|
3687
|
+
function syncLayerVisibility(module) {
|
|
3688
|
+
const state = ensureState(module);
|
|
3689
|
+
const layer = state?.layer;
|
|
3690
|
+
if (!layer) {
|
|
3691
|
+
return;
|
|
3692
|
+
}
|
|
3693
|
+
|
|
3694
|
+
if (!normalizeId(state.selectionNodeId) && !normalizeId(state.editing?.nodeId)) {
|
|
3695
|
+
const hasVisibleCards = Array.from(state.cards.values()).some(card =>
|
|
3696
|
+
!!card && card.style.display !== 'none');
|
|
3697
|
+
layer.style.display = hasVisibleCards ? '' : 'none';
|
|
3698
|
+
}
|
|
3699
|
+
}
|
|
3700
|
+
|
|
3701
|
+
function setPassiveOverlaySuppressed(module, suppressed) {
|
|
3702
|
+
const state = ensureState(module);
|
|
3703
|
+
const layer = state?.layer;
|
|
3704
|
+
if (!state || !layer) {
|
|
3705
|
+
if (module) {
|
|
3706
|
+
module._suppressPassiveDomOverlayDuringZoom = suppressed === true;
|
|
3707
|
+
}
|
|
3708
|
+
return false;
|
|
3709
|
+
}
|
|
3710
|
+
|
|
3711
|
+
const wasSuppressed = module?._suppressPassiveDomOverlayDuringZoom === true;
|
|
3712
|
+
const nextSuppressed = suppressed === true &&
|
|
3713
|
+
!normalizeId(state.editing?.nodeId);
|
|
3714
|
+
module._suppressPassiveDomOverlayDuringZoom = nextSuppressed;
|
|
3715
|
+
|
|
3716
|
+
if (wasSuppressed === nextSuppressed) {
|
|
3717
|
+
return nextSuppressed;
|
|
3718
|
+
}
|
|
3719
|
+
|
|
3720
|
+
if (nextSuppressed) {
|
|
3721
|
+
state.cards.forEach(card => {
|
|
3722
|
+
if (!card || card.style.display === 'none') {
|
|
3723
|
+
return;
|
|
3724
|
+
}
|
|
3725
|
+
|
|
3726
|
+
const nodeId = normalizeId(card.dataset?.nodeId);
|
|
3727
|
+
if (!nodeId) {
|
|
3728
|
+
return;
|
|
3729
|
+
}
|
|
3730
|
+
|
|
3731
|
+
const entry = module?.nodeObjectsById?.get?.(nodeId) || null;
|
|
3732
|
+
if (entry) {
|
|
3733
|
+
resumeSource(entry);
|
|
3734
|
+
}
|
|
3735
|
+
});
|
|
3736
|
+
clearLayerTransform(layer);
|
|
3737
|
+
layer.style.display = 'none';
|
|
3738
|
+
return true;
|
|
3739
|
+
}
|
|
3740
|
+
|
|
3741
|
+
layer.style.display = Array.from(state.cards.values()).some(card =>
|
|
3742
|
+
!!card && card.style.display !== 'none') ? '' : 'none';
|
|
3743
|
+
return true;
|
|
3744
|
+
}
|
|
3745
|
+
|
|
3746
|
+
function setMotionHint(module, active) {
|
|
3747
|
+
const state = ensureState(module);
|
|
3748
|
+
if (!state) {
|
|
3749
|
+
return false;
|
|
3750
|
+
}
|
|
3751
|
+
|
|
3752
|
+
const nextActive = active === true;
|
|
3753
|
+
const layer = state.layer;
|
|
3754
|
+
if (state.motionHintActive === nextActive && layer?.style) {
|
|
3755
|
+
return nextActive;
|
|
3756
|
+
}
|
|
3757
|
+
state.motionHintActive = nextActive;
|
|
3758
|
+
|
|
3759
|
+
if (!layer?.style) {
|
|
3760
|
+
return nextActive;
|
|
3761
|
+
}
|
|
3762
|
+
|
|
3763
|
+
layer.classList.toggle('is-motion-hint', nextActive);
|
|
3764
|
+
layer.style.willChange = nextActive ? 'transform' : 'auto';
|
|
3765
|
+
layer.style.backfaceVisibility = nextActive ? 'hidden' : '';
|
|
3766
|
+
layer.style.webkitBackfaceVisibility = nextActive ? 'hidden' : '';
|
|
3767
|
+
return nextActive;
|
|
3768
|
+
}
|
|
3769
|
+
|
|
3770
|
+
function cleanupDisabledOverlay(module, state = ensureState(module)) {
|
|
3771
|
+
if (!module || !state) {
|
|
3772
|
+
return;
|
|
3773
|
+
}
|
|
3774
|
+
|
|
3775
|
+
if (normalizeId(state.editing?.nodeId)) {
|
|
3776
|
+
clearEditing(module, { commit: true });
|
|
3777
|
+
}
|
|
3778
|
+
|
|
3779
|
+
state.cards.forEach(card => {
|
|
3780
|
+
const nodeId = normalizeId(card?.dataset?.nodeId);
|
|
3781
|
+
if (nodeId) {
|
|
3782
|
+
const entry = module?.nodeObjectsById?.get?.(nodeId) || null;
|
|
3783
|
+
if (entry) {
|
|
3784
|
+
resumeSource(entry);
|
|
3785
|
+
}
|
|
3786
|
+
}
|
|
3787
|
+
hideCard(card);
|
|
3788
|
+
});
|
|
3789
|
+
|
|
3790
|
+
clearLayerTransform(state.layer);
|
|
3791
|
+
if (state.layer?.style) {
|
|
3792
|
+
state.layer.style.display = 'none';
|
|
3793
|
+
}
|
|
3794
|
+
|
|
3795
|
+
state.layoutSnapshot = null;
|
|
3796
|
+
state.lastPassiveRenderEnabled = null;
|
|
3797
|
+
state.lastViewKey = '';
|
|
3798
|
+
state.lastVisibilityVersion = -1;
|
|
3799
|
+
state.lastInteractionKey = '';
|
|
3800
|
+
state.dirtyLayout = false;
|
|
3801
|
+
state.dirtySelection = false;
|
|
3802
|
+
state.dirtyEditing = false;
|
|
3803
|
+
state.dirtyNodes.clear();
|
|
3804
|
+
module._overlayDirty = false;
|
|
3805
|
+
module._lastOverlayKey = '';
|
|
3806
|
+
module._usedPassiveOverlayCameraFastPathLastFrame = false;
|
|
3807
|
+
module._suppressPassiveDomOverlayDuringZoom = false;
|
|
3808
|
+
module._overlayDebugPassiveVisibleCandidateCount = 0;
|
|
3809
|
+
module._overlayDebugPassiveVisibleSupportedCount = 0;
|
|
3810
|
+
module._overlayDebugPassiveViewportCandidateCount = 0;
|
|
3811
|
+
module._overlayDebugPassiveCardLimit = 0;
|
|
3812
|
+
module._overlayDebugPassiveOverlapSuppressedCount = 0;
|
|
3813
|
+
module._overlayDebugKeepCardCount = 0;
|
|
3814
|
+
module._overlayDebugPlacementZoomCount = 0;
|
|
3815
|
+
module._overlayDebugPlacementTransformCount = 0;
|
|
3816
|
+
module._overlayDebugLayoutChanged = false;
|
|
3817
|
+
module._overlayDebugContentChanged = false;
|
|
3818
|
+
module._overlayDebugForceRefresh = false;
|
|
3819
|
+
setMotionHint(module, false);
|
|
3820
|
+
}
|
|
3821
|
+
|
|
3822
|
+
function updateSelectionCard(module, state, keepCardKeys) {
|
|
3823
|
+
const activeSelectionNodeId = normalizeId(state?.selectionNodeId);
|
|
3824
|
+
const selectedNodeId = normalizeId(module?.selectedNodeIdJs);
|
|
3825
|
+
const visibleIds = module?._visibleIds || module?._prevVisibleIds || null;
|
|
3826
|
+
const shouldRenderPassive = shouldRenderPassiveDomOverlays(module);
|
|
3827
|
+
if (activeSelectionNodeId && selectedNodeId !== activeSelectionNodeId) {
|
|
3828
|
+
clearSelection(module, activeSelectionNodeId);
|
|
3829
|
+
}
|
|
3830
|
+
|
|
3831
|
+
const candidateIds = new Set();
|
|
3832
|
+
let passiveVisibleCandidateCount = 0;
|
|
3833
|
+
module._overlayDebugPassiveVisibleSupportedCount = 0;
|
|
3834
|
+
module._overlayDebugPassiveViewportCandidateCount = 0;
|
|
3835
|
+
module._overlayDebugPassiveCardLimit = 0;
|
|
3836
|
+
module._overlayDebugPassiveOverlapSuppressedCount = 0;
|
|
3837
|
+
module._overlayDebugPassiveOccluderCount = 0;
|
|
3838
|
+
module._overlaySuppressedPassiveNodeIds = new Set();
|
|
3839
|
+
if (shouldRenderPassive && shouldUseVisiblePassiveOverlayCandidates(module) && visibleIds?.forEach) {
|
|
3840
|
+
const passiveCandidateIds = collectVisiblePassiveCandidateIds(module, state, visibleIds);
|
|
3841
|
+
passiveVisibleCandidateCount = passiveCandidateIds.size;
|
|
3842
|
+
passiveCandidateIds.forEach(nodeId => candidateIds.add(nodeId));
|
|
3843
|
+
}
|
|
3844
|
+
const suppressedPassiveIds = module._overlaySuppressedPassiveNodeIds instanceof Set
|
|
3845
|
+
? module._overlaySuppressedPassiveNodeIds
|
|
3846
|
+
: new Set();
|
|
3847
|
+
const now = nowMs();
|
|
3848
|
+
if (shouldRenderPassive && candidateIds.size > 0) {
|
|
3849
|
+
state.passiveCandidateIds = new Set(candidateIds);
|
|
3850
|
+
state.passiveCandidateVisibleUntil = now + PASSIVE_OVERLAY_CANDIDATE_GRACE_MS;
|
|
3851
|
+
} else if (shouldRenderPassive &&
|
|
3852
|
+
state.passiveCandidateIds?.size > 0 &&
|
|
3853
|
+
Number(state.passiveCandidateVisibleUntil || 0) > now) {
|
|
3854
|
+
state.passiveCandidateIds.forEach(nodeId => {
|
|
3855
|
+
const normalizedId = normalizeId(nodeId);
|
|
3856
|
+
if (normalizedId && !suppressedPassiveIds.has(normalizedId)) {
|
|
3857
|
+
candidateIds.add(normalizedId);
|
|
3858
|
+
}
|
|
3859
|
+
});
|
|
3860
|
+
} else if (!shouldRenderPassive) {
|
|
3861
|
+
state.passiveCandidateIds.clear();
|
|
3862
|
+
state.passiveCandidateVisibleUntil = 0;
|
|
3863
|
+
}
|
|
3864
|
+
module._overlayDebugPassiveVisibleCandidateCount = passiveVisibleCandidateCount;
|
|
3865
|
+
if (shouldRenderPassive && selectedNodeId) {
|
|
3866
|
+
candidateIds.add(selectedNodeId);
|
|
3867
|
+
}
|
|
3868
|
+
if (activeSelectionNodeId) {
|
|
3869
|
+
candidateIds.add(activeSelectionNodeId);
|
|
3870
|
+
}
|
|
3871
|
+
|
|
3872
|
+
candidateIds.forEach(nodeId => {
|
|
3873
|
+
const interactive = activeSelectionNodeId === nodeId;
|
|
3874
|
+
if (!interactive && normalizeId(state?.editing?.nodeId) === nodeId) {
|
|
3875
|
+
return;
|
|
3876
|
+
}
|
|
3877
|
+
|
|
3878
|
+
const entry = module?.nodeObjectsById?.get?.(nodeId) || null;
|
|
3879
|
+
const existingCard = state.cards.get(selectionCardKey(nodeId)) || null;
|
|
3880
|
+
if (isMediaOverlayExcluded(entry)) {
|
|
3881
|
+
if (entry) {
|
|
3882
|
+
resumeSource(entry);
|
|
3883
|
+
}
|
|
3884
|
+
if (existingCard) {
|
|
3885
|
+
removeCard(state, selectionCardKey(nodeId));
|
|
3886
|
+
}
|
|
3887
|
+
removeCard(state, editingCardKey(nodeId));
|
|
3888
|
+
state.passiveCandidateIds?.delete?.(nodeId);
|
|
3889
|
+
if (interactive) {
|
|
3890
|
+
state.selectionNodeId = '';
|
|
3891
|
+
state.dirtySelection = true;
|
|
3892
|
+
module._overlayDirty = true;
|
|
3893
|
+
module._lastOverlayKey = '';
|
|
3894
|
+
}
|
|
3895
|
+
return;
|
|
3896
|
+
}
|
|
3897
|
+
|
|
3898
|
+
const isSelectedPassiveNode = !interactive && selectedNodeId === nodeId;
|
|
3899
|
+
const keepPassiveCard = isSelectedPassiveNode && shouldKeepPassiveCardWhenSelected(entry);
|
|
3900
|
+
if (isSelectedPassiveNode) {
|
|
3901
|
+
if (!keepPassiveCard) {
|
|
3902
|
+
if (entry) {
|
|
3903
|
+
resumeSource(entry);
|
|
3904
|
+
}
|
|
3905
|
+
hideCard(state.cards.get(selectionCardKey(nodeId)));
|
|
3906
|
+
return;
|
|
3907
|
+
}
|
|
3908
|
+
}
|
|
3909
|
+
|
|
3910
|
+
const isSupported = interactive ? supportsSelection(entry) : supportsPassiveDisplay(entry);
|
|
3911
|
+
const canRenderFromSource = !!(entry?.cssObject?.element && entry.currentType === 'CSS' && entry.cssObject.visible);
|
|
3912
|
+
const canReuseExistingPassiveCard = !interactive &&
|
|
3913
|
+
shouldRenderPassive &&
|
|
3914
|
+
!!existingCard &&
|
|
3915
|
+
existingCard.childElementCount > 0;
|
|
3916
|
+
if (!entry || !isSupported || (!canRenderFromSource && !canReuseExistingPassiveCard)) {
|
|
3917
|
+
hideCard(existingCard);
|
|
3918
|
+
if (interactive) {
|
|
3919
|
+
clearSelection(module, nodeId);
|
|
3920
|
+
} else if (entry) {
|
|
3921
|
+
resumeSource(entry);
|
|
3922
|
+
}
|
|
3923
|
+
return;
|
|
3924
|
+
}
|
|
3925
|
+
|
|
3926
|
+
const forceRebuild = canRenderFromSource && state?.dirtyNodes?.has?.(nodeId) === true;
|
|
3927
|
+
const card = renderSelectionCard(module, entry, {
|
|
3928
|
+
interactive: interactive,
|
|
3929
|
+
forceRebuild: forceRebuild
|
|
3930
|
+
});
|
|
3931
|
+
const rect = getPlacementRect(module, entry);
|
|
3932
|
+
if (!card || !rect) {
|
|
3933
|
+
if (interactive) {
|
|
3934
|
+
clearSelection(module, nodeId);
|
|
3935
|
+
}
|
|
3936
|
+
return;
|
|
3937
|
+
}
|
|
3938
|
+
|
|
3939
|
+
applyPlacement(module, card, rect, 8, entry);
|
|
3940
|
+
if (canRenderFromSource) {
|
|
3941
|
+
suspendSource(entry, { disablePointerEvents: interactive });
|
|
3942
|
+
}
|
|
3943
|
+
keepCardKeys.add(selectionCardKey(nodeId));
|
|
3944
|
+
});
|
|
3945
|
+
}
|
|
3946
|
+
|
|
3947
|
+
function updateEditingCard(module, state, keepCardKeys) {
|
|
3948
|
+
const editing = state?.editing;
|
|
3949
|
+
const nodeId = normalizeId(editing?.nodeId);
|
|
3950
|
+
if (!nodeId) {
|
|
3951
|
+
return;
|
|
3952
|
+
}
|
|
3953
|
+
|
|
3954
|
+
const entry = module?.nodeObjectsById?.get?.(nodeId) || null;
|
|
3955
|
+
const canRenderFromSource = !!(entry?.cssObject?.element && entry.currentType === 'CSS' && entry.cssObject.visible);
|
|
3956
|
+
if (!entry || !supportsEditing(entry) || !canRenderFromSource) {
|
|
3957
|
+
clearEditing(module, { commit: true });
|
|
3958
|
+
return;
|
|
3959
|
+
}
|
|
3960
|
+
|
|
3961
|
+
if (!editing.element || !editing.element.isConnected) {
|
|
3962
|
+
const created = editing.kind === 'memo'
|
|
3963
|
+
? createMemoEditingCard(module, entry)
|
|
3964
|
+
: createNoteEditingCard(module, entry);
|
|
3965
|
+
|
|
3966
|
+
if (!created?.card) {
|
|
3967
|
+
clearEditing(module, { commit: true });
|
|
3968
|
+
return;
|
|
3969
|
+
}
|
|
3970
|
+
|
|
3971
|
+
editing.element = created.card;
|
|
3972
|
+
editing.titleInput = created.titleInput || null;
|
|
3973
|
+
editing.textarea = created.textarea || null;
|
|
3974
|
+
editing.focusTarget = created.focusTarget || created.textarea || created.titleInput || null;
|
|
3975
|
+
editing.initialTitle = created.initialTitle ?? editing.initialTitle ?? null;
|
|
3976
|
+
editing.initialValue = created.initialValue ?? editing.initialValue ?? '';
|
|
3977
|
+
}
|
|
3978
|
+
|
|
3979
|
+
const rect = getPlacementRect(module, entry);
|
|
3980
|
+
if (!rect) {
|
|
3981
|
+
clearEditing(module, { commit: true });
|
|
3982
|
+
return;
|
|
3983
|
+
}
|
|
3984
|
+
|
|
3985
|
+
applyPlacement(module, editing.element, rect, 12, entry);
|
|
3986
|
+
suspendSource(entry);
|
|
3987
|
+
keepCardKeys.add(editingCardKey(nodeId));
|
|
3988
|
+
|
|
3989
|
+
if (editing.shouldFocus && editing.focusTarget) {
|
|
3990
|
+
editing.shouldFocus = false;
|
|
3991
|
+
setTimeout(() => {
|
|
3992
|
+
try {
|
|
3993
|
+
editing.focusTarget.focus({ preventScroll: true });
|
|
3994
|
+
} catch {
|
|
3995
|
+
try { editing.focusTarget.focus(); } catch { }
|
|
3996
|
+
}
|
|
3997
|
+
|
|
3998
|
+
if (typeof editing.focusTarget.setSelectionRange === 'function') {
|
|
3999
|
+
const nextValue = String(editing.focusTarget.value || '');
|
|
4000
|
+
editing.focusTarget.setSelectionRange(nextValue.length, nextValue.length);
|
|
4001
|
+
}
|
|
4002
|
+
if (editing.textarea) {
|
|
4003
|
+
getCss3dManager()?.restoreEditingScrollState?.(entry, editing.textarea);
|
|
4004
|
+
}
|
|
4005
|
+
}, 0);
|
|
4006
|
+
}
|
|
4007
|
+
}
|
|
4008
|
+
|
|
4009
|
+
function updateFrame(module) {
|
|
4010
|
+
const state = ensureState(module);
|
|
4011
|
+
if (!state) {
|
|
4012
|
+
return;
|
|
4013
|
+
}
|
|
4014
|
+
|
|
4015
|
+
if (!isEnabled(module)) {
|
|
4016
|
+
cleanupDisabledOverlay(module, state);
|
|
4017
|
+
return;
|
|
4018
|
+
}
|
|
4019
|
+
|
|
4020
|
+
const selectedMediaEntry = normalizeId(module?.selectedNodeIdJs)
|
|
4021
|
+
? module?.nodeObjectsById?.get?.(normalizeId(module.selectedNodeIdJs)) || null
|
|
4022
|
+
: null;
|
|
4023
|
+
const shouldAuditMediaSources =
|
|
4024
|
+
state.cards.size > 0 ||
|
|
4025
|
+
state.dirtyNodes.size > 0 ||
|
|
4026
|
+
module?._overlayDirty === true ||
|
|
4027
|
+
isMediaOverlayExcluded(selectedMediaEntry);
|
|
4028
|
+
purgeMediaOverlayCards(module, state, { resumeAllMedia: shouldAuditMediaSources });
|
|
4029
|
+
|
|
4030
|
+
const interactionKey = buildInteractionKey(module, state);
|
|
4031
|
+
const interactionChanged = state.lastInteractionKey !== interactionKey;
|
|
4032
|
+
if (interactionChanged) {
|
|
4033
|
+
state.dirtyLayout = true;
|
|
4034
|
+
}
|
|
4035
|
+
|
|
4036
|
+
if (hasBlockingPassiveOverlayInteraction(module, state)) {
|
|
4037
|
+
hidePassiveSelectionCards(module, state);
|
|
4038
|
+
}
|
|
4039
|
+
|
|
4040
|
+
const passiveRenderEnabled = shouldRenderPassiveDomOverlays(module);
|
|
4041
|
+
if (state.lastPassiveRenderEnabled !== passiveRenderEnabled) {
|
|
4042
|
+
if (passiveRenderEnabled === true) {
|
|
4043
|
+
// Re-entering passive overlay should always re-clone from the
|
|
4044
|
+
// current CSS3D source instead of reusing an old readonly DOM.
|
|
4045
|
+
bumpReadonlySourceEpoch(module);
|
|
4046
|
+
}
|
|
4047
|
+
state.dirtyLayout = true;
|
|
4048
|
+
state.lastPassiveRenderEnabled = passiveRenderEnabled;
|
|
4049
|
+
}
|
|
4050
|
+
|
|
4051
|
+
if (module?._suppressPassiveDomOverlayDuringZoom === true &&
|
|
4052
|
+
!normalizeId(state.editing?.nodeId)) {
|
|
4053
|
+
setPassiveOverlaySuppressed(module, true);
|
|
4054
|
+
return;
|
|
4055
|
+
}
|
|
4056
|
+
|
|
4057
|
+
const layer = ensureLayer(module);
|
|
4058
|
+
if (!state || !layer) {
|
|
4059
|
+
return;
|
|
4060
|
+
}
|
|
4061
|
+
|
|
4062
|
+
setPassiveOverlaySuppressed(module, false);
|
|
4063
|
+
|
|
4064
|
+
const snapshot = typeof module.buildViewStateSnapshot === 'function'
|
|
4065
|
+
? module.buildViewStateSnapshot()
|
|
4066
|
+
: null;
|
|
4067
|
+
const viewKey = snapshot
|
|
4068
|
+
? buildOverlayViewKey(module, snapshot)
|
|
4069
|
+
: '';
|
|
4070
|
+
const visibilityVersion = Number(module?._visibilityVersion || 0);
|
|
4071
|
+
const layoutChanged =
|
|
4072
|
+
interactionChanged ||
|
|
4073
|
+
state.lastViewKey !== viewKey ||
|
|
4074
|
+
state.lastVisibilityVersion !== visibilityVersion ||
|
|
4075
|
+
state.dirtyLayout === true;
|
|
4076
|
+
const contentChanged =
|
|
4077
|
+
state.dirtySelection === true ||
|
|
4078
|
+
state.dirtyEditing === true ||
|
|
4079
|
+
state.dirtyNodes.size > 0;
|
|
4080
|
+
const hasActiveOverlayCard =
|
|
4081
|
+
!!normalizeId(state.selectionNodeId) ||
|
|
4082
|
+
!!normalizeId(state.editing?.nodeId);
|
|
4083
|
+
const hasVisibleOverlayCard =
|
|
4084
|
+
state.cards.size > 0 &&
|
|
4085
|
+
Array.from(state.cards.values()).some(card => !!card && card.style.display !== 'none');
|
|
4086
|
+
const forceRefresh =
|
|
4087
|
+
module?._overlayDirty === true &&
|
|
4088
|
+
(
|
|
4089
|
+
contentChanged ||
|
|
4090
|
+
!hasVisibleOverlayCard ||
|
|
4091
|
+
state.lastVisibilityVersion !== visibilityVersion
|
|
4092
|
+
);
|
|
4093
|
+
module._overlayDebugLayoutChanged = layoutChanged;
|
|
4094
|
+
module._overlayDebugContentChanged = contentChanged;
|
|
4095
|
+
module._overlayDebugForceRefresh = forceRefresh;
|
|
4096
|
+
const shouldKeepPassiveOverlayWarm =
|
|
4097
|
+
shouldRenderPassiveDomOverlays(module) &&
|
|
4098
|
+
((module?._visibleIds?.size || module?._prevVisibleIds?.size || 0) > 0);
|
|
4099
|
+
|
|
4100
|
+
if (!hasActiveOverlayCard && !hasVisibleOverlayCard && !contentChanged && !shouldKeepPassiveOverlayWarm) {
|
|
4101
|
+
state.lastViewKey = viewKey;
|
|
4102
|
+
state.lastVisibilityVersion = visibilityVersion;
|
|
4103
|
+
state.lastInteractionKey = interactionKey;
|
|
4104
|
+
state.dirtyLayout = false;
|
|
4105
|
+
state.layoutSnapshot = null;
|
|
4106
|
+
clearLayerTransform(layer);
|
|
4107
|
+
if (layer.style.display !== 'none') {
|
|
4108
|
+
layer.style.display = 'none';
|
|
4109
|
+
}
|
|
4110
|
+
return;
|
|
4111
|
+
}
|
|
4112
|
+
|
|
4113
|
+
if (canUseLayerTransformFastPath(module, state, snapshot, visibilityVersion, contentChanged, forceRefresh)) {
|
|
4114
|
+
state.lastViewKey = viewKey;
|
|
4115
|
+
state.lastVisibilityVersion = visibilityVersion;
|
|
4116
|
+
state.lastInteractionKey = interactionKey;
|
|
4117
|
+
if (layer.style.display === 'none') {
|
|
4118
|
+
layer.style.display = '';
|
|
4119
|
+
}
|
|
4120
|
+
return;
|
|
4121
|
+
}
|
|
4122
|
+
|
|
4123
|
+
if (!layoutChanged && !contentChanged && !forceRefresh) {
|
|
4124
|
+
state.lastInteractionKey = interactionKey;
|
|
4125
|
+
return;
|
|
4126
|
+
}
|
|
4127
|
+
|
|
4128
|
+
state.lastViewKey = viewKey;
|
|
4129
|
+
state.lastVisibilityVersion = visibilityVersion;
|
|
4130
|
+
state.lastInteractionKey = interactionKey;
|
|
4131
|
+
clearLayerTransform(layer);
|
|
4132
|
+
module._overlayDebugPlacementZoomCount = 0;
|
|
4133
|
+
module._overlayDebugPlacementTransformCount = 0;
|
|
4134
|
+
|
|
4135
|
+
const keepCardKeys = new Set();
|
|
4136
|
+
updateSelectionCard(module, state, keepCardKeys);
|
|
4137
|
+
updateEditingCard(module, state, keepCardKeys);
|
|
4138
|
+
hideUnusedCards(module, keepCardKeys);
|
|
4139
|
+
module._overlayDebugKeepCardCount = keepCardKeys.size;
|
|
4140
|
+
|
|
4141
|
+
layer.style.display = keepCardKeys.size > 0 ? '' : 'none';
|
|
4142
|
+
state.layoutSnapshot = keepCardKeys.size > 0
|
|
4143
|
+
? buildLayerLayoutSnapshot(module, snapshot)
|
|
4144
|
+
: null;
|
|
4145
|
+
state.dirtyNodes.clear();
|
|
4146
|
+
state.dirtyLayout = false;
|
|
4147
|
+
state.dirtySelection = false;
|
|
4148
|
+
state.dirtyEditing = false;
|
|
4149
|
+
state.lastInteractionKey = interactionKey;
|
|
4150
|
+
}
|
|
4151
|
+
|
|
4152
|
+
function hasSelection(module, nodeId = null) {
|
|
4153
|
+
const state = ensureState(module);
|
|
4154
|
+
const activeId = normalizeId(state?.selectionNodeId);
|
|
4155
|
+
if (!activeId) {
|
|
4156
|
+
return false;
|
|
4157
|
+
}
|
|
4158
|
+
|
|
4159
|
+
return nodeId === null ? true : activeId === normalizeId(nodeId);
|
|
4160
|
+
}
|
|
4161
|
+
|
|
4162
|
+
function hasEditing(module, nodeId = null) {
|
|
4163
|
+
const state = ensureState(module);
|
|
4164
|
+
const activeId = normalizeId(state?.editing?.nodeId);
|
|
4165
|
+
if (!activeId) {
|
|
4166
|
+
return false;
|
|
4167
|
+
}
|
|
4168
|
+
|
|
4169
|
+
return nodeId === null ? true : activeId === normalizeId(nodeId);
|
|
4170
|
+
}
|
|
4171
|
+
|
|
4172
|
+
function getDebugResponseElement(root) {
|
|
4173
|
+
if (!root?.querySelector) {
|
|
4174
|
+
return null;
|
|
4175
|
+
}
|
|
4176
|
+
|
|
4177
|
+
return root.querySelector(getPrimaryContentSelector()) || null;
|
|
4178
|
+
}
|
|
4179
|
+
|
|
4180
|
+
function normalizeDebugHtml(value) {
|
|
4181
|
+
return String(value || '')
|
|
4182
|
+
.replace(/\s+/g, ' ')
|
|
4183
|
+
.replace(/>\s+</g, '><')
|
|
4184
|
+
.trim();
|
|
4185
|
+
}
|
|
4186
|
+
|
|
4187
|
+
function truncateDebugText(value, maxLength = 4000) {
|
|
4188
|
+
const text = String(value || '');
|
|
4189
|
+
if (text.length <= maxLength) {
|
|
4190
|
+
return text;
|
|
4191
|
+
}
|
|
4192
|
+
|
|
4193
|
+
return `${text.slice(0, maxLength)}\n... [truncated ${text.length - maxLength} chars]`;
|
|
4194
|
+
}
|
|
4195
|
+
|
|
4196
|
+
function buildOverlayDebugSnapshot(module) {
|
|
4197
|
+
const state = ensureState(module);
|
|
4198
|
+
if (!module || !state) {
|
|
4199
|
+
return null;
|
|
4200
|
+
}
|
|
4201
|
+
|
|
4202
|
+
let nodeId = normalizeId(state.selectionNodeId);
|
|
4203
|
+
let card = nodeId ? state.cards.get(selectionCardKey(nodeId)) || null : null;
|
|
4204
|
+
|
|
4205
|
+
if ((!nodeId || !card || card.style.display === 'none') && normalizeId(module?.selectedNodeIdJs)) {
|
|
4206
|
+
nodeId = normalizeId(module.selectedNodeIdJs);
|
|
4207
|
+
card = state.cards.get(selectionCardKey(nodeId)) || null;
|
|
4208
|
+
}
|
|
4209
|
+
|
|
4210
|
+
if (!nodeId || !card || card.style.display === 'none') {
|
|
4211
|
+
for (const candidateCard of state.cards.values()) {
|
|
4212
|
+
if (!candidateCard || candidateCard.style.display === 'none') {
|
|
4213
|
+
continue;
|
|
4214
|
+
}
|
|
4215
|
+
|
|
4216
|
+
const candidateNodeId = normalizeId(candidateCard.dataset?.nodeId);
|
|
4217
|
+
if (!candidateNodeId) {
|
|
4218
|
+
continue;
|
|
4219
|
+
}
|
|
4220
|
+
|
|
4221
|
+
nodeId = candidateNodeId;
|
|
4222
|
+
card = candidateCard;
|
|
4223
|
+
break;
|
|
4224
|
+
}
|
|
4225
|
+
}
|
|
4226
|
+
|
|
4227
|
+
if (!nodeId || !card) {
|
|
4228
|
+
return {
|
|
4229
|
+
available: false,
|
|
4230
|
+
reason: 'No visible overlay card',
|
|
4231
|
+
selectedNodeId: normalizeId(module?.selectedNodeIdJs),
|
|
4232
|
+
overlaySuppressed: module?._suppressPassiveDomOverlayDuringZoom === true
|
|
4233
|
+
};
|
|
4234
|
+
}
|
|
4235
|
+
|
|
4236
|
+
const entry = module?.nodeObjectsById?.get?.(nodeId) || null;
|
|
4237
|
+
const sourceRoot = entry ? getReadonlyCloneSourceElement(entry) : null;
|
|
4238
|
+
const overlayRoot = card.firstElementChild || null;
|
|
4239
|
+
const sourceResponse = getDebugResponseElement(sourceRoot);
|
|
4240
|
+
const overlayResponse = getDebugResponseElement(overlayRoot);
|
|
4241
|
+
const sourceHtml = sourceResponse?.innerHTML || '';
|
|
4242
|
+
const overlayHtml = overlayResponse?.innerHTML || '';
|
|
4243
|
+
const normalizedSourceHtml = normalizeDebugHtml(sourceHtml);
|
|
4244
|
+
const normalizedOverlayHtml = normalizeDebugHtml(overlayHtml);
|
|
4245
|
+
const sourceText = sourceResponse?.textContent || '';
|
|
4246
|
+
const overlayText = overlayResponse?.textContent || '';
|
|
4247
|
+
|
|
4248
|
+
return {
|
|
4249
|
+
available: true,
|
|
4250
|
+
nodeId,
|
|
4251
|
+
contentType: getContentType(entry),
|
|
4252
|
+
overlayCardKey: String(card.dataset?.cardKey || ''),
|
|
4253
|
+
overlayCardKind: String(card.dataset?.kind || ''),
|
|
4254
|
+
overlayContentKey: String(card.dataset?.contentKey || ''),
|
|
4255
|
+
overlaySourceEpoch: String(card.dataset?.sourceEpoch || ''),
|
|
4256
|
+
sourceExists: !!sourceRoot,
|
|
4257
|
+
overlayExists: !!overlayRoot,
|
|
4258
|
+
sourceRootClass: sourceRoot?.className || '',
|
|
4259
|
+
overlayRootClass: overlayRoot?.className || '',
|
|
4260
|
+
sourceResponseClass: sourceResponse?.className || '',
|
|
4261
|
+
overlayResponseClass: overlayResponse?.className || '',
|
|
4262
|
+
sourceSuspended: sourceRoot?.classList?.contains?.('mind-map-v2-source-suspended') === true,
|
|
4263
|
+
overlaySuppressed: module?._suppressPassiveDomOverlayDuringZoom === true,
|
|
4264
|
+
htmlMatches: normalizedSourceHtml === normalizedOverlayHtml,
|
|
4265
|
+
textMatches: String(sourceText).trim() === String(overlayText).trim(),
|
|
4266
|
+
sourceHtmlLength: sourceHtml.length,
|
|
4267
|
+
overlayHtmlLength: overlayHtml.length,
|
|
4268
|
+
sourceTextLength: sourceText.length,
|
|
4269
|
+
overlayTextLength: overlayText.length,
|
|
4270
|
+
sourceChildCount: Number(sourceResponse?.childElementCount || 0),
|
|
4271
|
+
overlayChildCount: Number(overlayResponse?.childElementCount || 0),
|
|
4272
|
+
sourceScrollHeight: Number(sourceResponse?.scrollHeight || 0),
|
|
4273
|
+
overlayScrollHeight: Number(overlayResponse?.scrollHeight || 0),
|
|
4274
|
+
sourceClientHeight: Number(sourceResponse?.clientHeight || 0),
|
|
4275
|
+
overlayClientHeight: Number(overlayResponse?.clientHeight || 0),
|
|
4276
|
+
sourceHtmlSnippet: truncateDebugText(sourceHtml),
|
|
4277
|
+
overlayHtmlSnippet: truncateDebugText(overlayHtml),
|
|
4278
|
+
sourceTextSnippet: truncateDebugText(sourceText, 1200),
|
|
4279
|
+
overlayTextSnippet: truncateDebugText(overlayText, 1200)
|
|
4280
|
+
};
|
|
4281
|
+
}
|
|
4282
|
+
|
|
4283
|
+
function init(module) {
|
|
4284
|
+
if (!module) {
|
|
4285
|
+
return;
|
|
4286
|
+
}
|
|
4287
|
+
|
|
4288
|
+
const state = ensureState(module);
|
|
4289
|
+
ensureLayer(module);
|
|
4290
|
+
window.MindMapCss3DManager?.injectMarkdownStyles?.();
|
|
4291
|
+
if (state) {
|
|
4292
|
+
state.dirtyLayout = true;
|
|
4293
|
+
state.dirtySelection = true;
|
|
4294
|
+
state.dirtyEditing = true;
|
|
4295
|
+
}
|
|
4296
|
+
module._overlayDirty = true;
|
|
4297
|
+
log('initialized');
|
|
4298
|
+
}
|
|
4299
|
+
|
|
4300
|
+
window.MindMapTextOverlayV2 = {
|
|
4301
|
+
init: init,
|
|
4302
|
+
updateFrame: updateFrame,
|
|
4303
|
+
syncPassiveViewTransform: syncPassiveViewTransform,
|
|
4304
|
+
setPassiveOverlaySuppressed: setPassiveOverlaySuppressed,
|
|
4305
|
+
setMotionHint: setMotionHint,
|
|
4306
|
+
invalidateNode: invalidateNode,
|
|
4307
|
+
invalidateView: invalidateView,
|
|
4308
|
+
updateNodePlacement: updateNodePlacement,
|
|
4309
|
+
shouldRenderPassiveDomOverlays: shouldRenderPassiveDomOverlays,
|
|
4310
|
+
shouldSkipCss3dRender: shouldSkipCss3dRender,
|
|
4311
|
+
activateSelection: activateSelection,
|
|
4312
|
+
clearSelection: clearSelection,
|
|
4313
|
+
beginEditing: beginEditing,
|
|
4314
|
+
clearEditing: clearEditing,
|
|
4315
|
+
hasSelection: hasSelection,
|
|
4316
|
+
hasEditing: hasEditing,
|
|
4317
|
+
getDebugSnapshot: buildOverlayDebugSnapshot,
|
|
4318
|
+
purgeMediaOverlayCards: purgeMediaOverlayCards,
|
|
4319
|
+
suspendSource: suspendSource,
|
|
4320
|
+
resumeSource: resumeSource,
|
|
4321
|
+
syncReadonlySourceScroll: syncReadonlySourceScroll
|
|
4322
|
+
};
|
|
4323
|
+
})();
|