bruce-cesium 7.1.0 → 7.1.2

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.
Files changed (24) hide show
  1. package/dist/bruce-cesium.es5.js +1831 -131
  2. package/dist/bruce-cesium.es5.js.map +1 -1
  3. package/dist/bruce-cesium.umd.js +1942 -245
  4. package/dist/bruce-cesium.umd.js.map +1 -1
  5. package/dist/lib/bruce-cesium.js +3 -1
  6. package/dist/lib/bruce-cesium.js.map +1 -1
  7. package/dist/lib/widgets/tabs-left-panel/widget-left-panel-tab-bookmarks.js +427 -63
  8. package/dist/lib/widgets/tabs-left-panel/widget-left-panel-tab-bookmarks.js.map +1 -1
  9. package/dist/lib/widgets/tabs-left-panel/widget-left-panel-tab-dashboard.js +516 -0
  10. package/dist/lib/widgets/tabs-left-panel/widget-left-panel-tab-dashboard.js.map +1 -0
  11. package/dist/lib/widgets/tabs-left-panel/widget-left-panel-tab-menu-items.js +759 -0
  12. package/dist/lib/widgets/tabs-left-panel/widget-left-panel-tab-menu-items.js.map +1 -0
  13. package/dist/lib/widgets/widget-bookmarks.js +9 -7
  14. package/dist/lib/widgets/widget-bookmarks.js.map +1 -1
  15. package/dist/lib/widgets/widget-info-view.js +68 -40
  16. package/dist/lib/widgets/widget-info-view.js.map +1 -1
  17. package/dist/lib/widgets/widget-left-panel.js +65 -18
  18. package/dist/lib/widgets/widget-left-panel.js.map +1 -1
  19. package/dist/types/bruce-cesium.d.ts +3 -1
  20. package/dist/types/widgets/tabs-left-panel/widget-left-panel-tab-bookmarks.d.ts +14 -0
  21. package/dist/types/widgets/tabs-left-panel/widget-left-panel-tab-dashboard.d.ts +44 -0
  22. package/dist/types/widgets/tabs-left-panel/widget-left-panel-tab-menu-items.d.ts +77 -0
  23. package/dist/types/widgets/widget-left-panel.d.ts +10 -2
  24. package/package.json +1 -1
@@ -0,0 +1,759 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.WidgetLeftPanelTabMenuItems = exports.EMenuItemState = void 0;
4
+ const Cesium = require("cesium");
5
+ const bruce_models_1 = require("bruce-models");
6
+ const widget_left_panel_tab_1 = require("./widget-left-panel-tab");
7
+ const entity_utils_1 = require("../../utils/entity-utils");
8
+ /**
9
+ * Enabled state of a menu item row.
10
+ * Folders roll up their children, so they can sit between fully on and fully off.
11
+ */
12
+ var EMenuItemState;
13
+ (function (EMenuItemState) {
14
+ EMenuItemState["Enabled"] = "enabled";
15
+ EMenuItemState["Disabled"] = "disabled";
16
+ EMenuItemState["ChildEnabled"] = "child-enabled";
17
+ })(EMenuItemState = exports.EMenuItemState || (exports.EMenuItemState = {}));
18
+ // Icons are inline so the library stays dependency free.
19
+ const ICON_CHECK = `<svg viewBox="0 0 11 8" fill="none" xmlns="http://www.w3.org/2000/svg"><path d="M1 4L4 7L10 1" stroke="white" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/></svg>`;
20
+ const ICON_PARTIAL_CHECK = `<svg viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg"><path d="M8 12H16" stroke="white" stroke-width="4" stroke-linecap="round" stroke-linejoin="round"/></svg>`;
21
+ const ICON_CHEV_DOWN = `<svg viewBox="0 0 16 9" fill="none" xmlns="http://www.w3.org/2000/svg"><path d="M15 1L8 8L1 1" stroke="white" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/></svg>`;
22
+ const ICON_CHEV_RIGHT = `<svg viewBox="0 0 10 17" fill="none" xmlns="http://www.w3.org/2000/svg"><path d="M1.5 1.5L8.5 8.5L1.5 15.5" stroke="white" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/></svg>`;
23
+ const ICON_FLY_TO = `<svg viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg"><path d="M20.5926 2.12617L2.49072 12.5694C1.78383 12.9756 1.87366 13.9597 2.57664 14.2566L6.72815 15.9984L17.9486 6.10975C18.1634 5.91838 18.468 6.21129 18.2844 6.4339L8.87616 17.8964V21.0403C8.87616 21.962 9.98921 22.3252 10.536 21.6574L13.016 18.6385L17.8822 20.6771C18.4367 20.9115 19.0694 20.5639 19.171 19.9663L21.9829 3.09473C22.1157 2.30583 21.2682 1.73563 20.5926 2.12617Z" fill="white"/></svg>`;
24
+ // Elbow connector drawn instead of a chevron on leaf rows below the root level.
25
+ const ICON_BRACKET = `<svg viewBox="0 0 11 13" fill="none" xmlns="http://www.w3.org/2000/svg"><path d="M1 1V10C1 11.1046 1.89543 12 3 12H10" stroke="rgb(131, 141, 150)" stroke-linecap="round" stroke-linejoin="round"/></svg>`;
26
+ // Menu item types backed by a tileset, so a fly-to can fall back to the tileset's bounding sphere.
27
+ const TILESET_TYPES = [
28
+ bruce_models_1.MenuItem.EType.CadTileset,
29
+ bruce_models_1.MenuItem.EType.PointCloud,
30
+ bruce_models_1.MenuItem.EType.EntityTileset,
31
+ bruce_models_1.MenuItem.EType.ArbTileset,
32
+ bruce_models_1.MenuItem.EType.IonTileset,
33
+ bruce_models_1.MenuItem.EType.Osm,
34
+ bruce_models_1.MenuItem.EType.GooglePhotoTileset
35
+ ];
36
+ const OPEN_STATE_STORAGE_PREFIX = "NextspaceMenuItemOpen_";
37
+ // How long to wait for a view before declaring there isn't one.
38
+ const NO_VIEW_GRACE_MS = 5000;
39
+ const PANEL_WIDTH_STORAGE_KEY = "NextspaceMenuItemsPanelWidth";
40
+ // Matches the panel's resize range in the full Navigator experience.
41
+ const PANEL_DEFAULT_WIDTH = 320;
42
+ const PANEL_MIN_WIDTH = 280;
43
+ const PANEL_MAX_WIDTH = 700;
44
+ /**
45
+ * Left panel tab listing the project view's menu items as a checkbox tree.
46
+ * Toggling a row renders or removes that layer in the scene.
47
+ */
48
+ class WidgetLeftPanelTabMenuItems extends widget_left_panel_tab_1.WidgetLeftPanelTab.ATab {
49
+ constructor(params) {
50
+ var _a, _b, _c, _d;
51
+ super(params);
52
+ this.STYLESHEET_ID = "nextspace-left-panel-tab-menu-items-stylesheet";
53
+ this._menuItems = [];
54
+ // Every menu item the manager has rendered while this tab has been alive.
55
+ this._managerItems = new Map();
56
+ // Set once the grace period for a view to appear has elapsed.
57
+ this._waitedForView = false;
58
+ this._rows = new Map();
59
+ // Identifies the newest load, so a slow response for an older view can't overwrite a newer one.
60
+ this._loadToken = 0;
61
+ // Rows currently mid fly-to, so a double click doesn't stack camera moves.
62
+ this._flying = new Set();
63
+ this._disposed = false;
64
+ this._generateStyles();
65
+ this._generateElement();
66
+ this._stateQueue = new bruce_models_1.DelayQueue(() => {
67
+ this._updateStates();
68
+ });
69
+ this._countQueue = new bruce_models_1.DelayQueue(() => {
70
+ this._updateCounts();
71
+ });
72
+ this._viewIdChangeRemoval = (_b = (_a = this._widget) === null || _a === void 0 ? void 0 : _a.OnViewIdChange) === null || _b === void 0 ? void 0 : _b.Subscribe(() => {
73
+ this._loadMenuItems();
74
+ });
75
+ const manager = (_c = this._widget) === null || _c === void 0 ? void 0 : _c._getManager();
76
+ if (manager) {
77
+ this._menuUpdateRemoval = manager.OnUpdate.Subscribe(() => {
78
+ // A newly rendered item can add a row, not just change an existing one's state.
79
+ if (this._snapshotManagerItems() && !this._menuItems.length) {
80
+ this._renderTree();
81
+ }
82
+ this._stateQueue.Call();
83
+ });
84
+ this._visualUpdateRemoval = (_d = manager.VisualsRegister) === null || _d === void 0 ? void 0 : _d.OnUpdate.Subscribe(() => {
85
+ this._countQueue.Call();
86
+ });
87
+ }
88
+ this._snapshotManagerItems();
89
+ this._loadMenuItems();
90
+ this._applyPanelWidth(this._getStoredWidth());
91
+ // Without a view we can't tell "still starting up" from "there is no view", so give it a moment.
92
+ this._noViewTimer = setTimeout(() => {
93
+ this._waitedForView = true;
94
+ if (!this._disposed && !this._menuItems.length && !this._managerItems.size) {
95
+ this._renderTree();
96
+ }
97
+ }, NO_VIEW_GRACE_MS);
98
+ }
99
+ Dispose() {
100
+ var _a, _b, _c, _d, _e;
101
+ this._disposed = true;
102
+ clearTimeout(this._noViewTimer);
103
+ this._endResize();
104
+ // The panel container is shared with the other tabs, so its overrides don't outlive this one.
105
+ if (this.Container) {
106
+ this.Container.style.padding = "";
107
+ }
108
+ (_a = this._viewIdChangeRemoval) === null || _a === void 0 ? void 0 : _a.call(this);
109
+ (_b = this._menuUpdateRemoval) === null || _b === void 0 ? void 0 : _b.call(this);
110
+ (_c = this._visualUpdateRemoval) === null || _c === void 0 ? void 0 : _c.call(this);
111
+ (_d = this._stateQueue) === null || _d === void 0 ? void 0 : _d.Dispose();
112
+ (_e = this._countQueue) === null || _e === void 0 ? void 0 : _e.Dispose();
113
+ this._rows.clear();
114
+ super.Dispose();
115
+ }
116
+ _generateStyles() {
117
+ if (document.getElementById(this.STYLESHEET_ID)) {
118
+ return;
119
+ }
120
+ const style = document.createElement("style");
121
+ style.id = this.STYLESHEET_ID;
122
+ style.innerHTML = `
123
+ .NextspaceLeftPanelTabMenuItems * {
124
+ box-sizing: border-box;
125
+ }
126
+
127
+ .NextspaceLeftPanelTabMenuItems {
128
+ color: #fff;
129
+ display: flex;
130
+ flex-direction: column;
131
+ flex-grow: 1;
132
+ flex-shrink: 1;
133
+ font-family: Arial, sans-serif;
134
+ overflow: hidden;
135
+ padding: 30px 20px 12px 20px;
136
+ width: 100%;
137
+ }
138
+
139
+ .NextspaceLeftPanelTabMenuItems >.NextspaceLeftPanelTabMenuItemsTitleBar {
140
+ align-items: center;
141
+ color: #fff;
142
+ display: flex;
143
+ font-size: 17px;
144
+ font-weight: 500;
145
+ justify-content: center;
146
+ letter-spacing: -.005em;
147
+ line-height: 20px;
148
+ margin-bottom: 15px;
149
+ }
150
+
151
+ .NextspaceLeftPanelTabMenuItems >.NextspaceLeftPanelTabMenuItemsTitleBreaker {
152
+ background-color: #000;
153
+ flex-shrink: 0;
154
+ height: 2px;
155
+ margin-bottom: 15px;
156
+ }
157
+
158
+ .NextspaceLeftPanelTabMenuItems >.NextspaceLeftPanelTabMenuItemsScrollBox {
159
+ flex-grow: 1;
160
+ flex-shrink: 1;
161
+ overflow: auto;
162
+ padding-right: 10px;
163
+ }
164
+
165
+ .NextspaceLeftPanelTabMenuItems >.NextspaceLeftPanelTabMenuItemsTip {
166
+ color: #fff;
167
+ font-size: 13px;
168
+ opacity: .7;
169
+ }
170
+
171
+ .NextspaceLeftPanelTabMenuItemsResizeHandle {
172
+ bottom: 0;
173
+ cursor: col-resize;
174
+ position: absolute;
175
+ right: 0;
176
+ top: 0;
177
+ width: 8px;
178
+ z-index: 3;
179
+ }
180
+
181
+ .NextspaceMenuItemRow {
182
+ border-bottom: 2px solid #121619;
183
+ width: 100%;
184
+ }
185
+
186
+ .NextspaceMenuItemRow[show-children="true"] {
187
+ border-bottom: none;
188
+ }
189
+
190
+ .NextspaceMenuItemRow >.NextspaceMenuItemRowItem {
191
+ align-items: center;
192
+ display: flex;
193
+ height: 40px;
194
+ user-select: none;
195
+ }
196
+
197
+ .NextspaceMenuItemRow >.NextspaceMenuItemRowItem >.NextspaceMenuItemRowCheckbox,
198
+ .NextspaceMenuItemRow >.NextspaceMenuItemRowItem >.NextspaceMenuItemRowToggle,
199
+ .NextspaceMenuItemRow >.NextspaceMenuItemRowItem >.NextspaceMenuItemRowBracket {
200
+ align-items: center;
201
+ color: #fff;
202
+ cursor: pointer;
203
+ display: flex;
204
+ flex-shrink: 0;
205
+ height: 18px;
206
+ justify-content: center;
207
+ width: 18px;
208
+ }
209
+
210
+ .NextspaceMenuItemRow >.NextspaceMenuItemRowItem >.NextspaceMenuItemRowCheckbox >svg,
211
+ .NextspaceMenuItemRow >.NextspaceMenuItemRowItem >.NextspaceMenuItemRowToggle >svg,
212
+ .NextspaceMenuItemRow >.NextspaceMenuItemRowItem >.NextspaceMenuItemRowBracket >svg {
213
+ height: 12px;
214
+ width: 12px;
215
+ }
216
+
217
+ .NextspaceMenuItemRow >.NextspaceMenuItemRowItem >.NextspaceMenuItemRowCheckbox {
218
+ border: 1.5px solid #fff;
219
+ border-radius: 2px;
220
+ margin-right: 8px;
221
+ }
222
+
223
+ .NextspaceMenuItemRow >.NextspaceMenuItemRowItem >.NextspaceMenuItemRowToggle {
224
+ margin-right: 3px;
225
+ }
226
+
227
+ .NextspaceMenuItemRow >.NextspaceMenuItemRowItem >.NextspaceMenuItemRowTitle {
228
+ color: #fff;
229
+ font-size: 14px;
230
+ margin-right: 8px;
231
+ overflow: hidden;
232
+ text-overflow: ellipsis;
233
+ white-space: nowrap;
234
+ }
235
+
236
+ .NextspaceMenuItemRow >.NextspaceMenuItemRowItem >.NextspaceMenuItemRowCount {
237
+ background: rgba(0, 175, 250, .2);
238
+ border-radius: 11px;
239
+ color: #18ffff;
240
+ cursor: pointer;
241
+ flex-shrink: 0;
242
+ font-size: 12px;
243
+ margin-right: 3px;
244
+ padding: 5px 8px;
245
+ }
246
+
247
+ .NextspaceMenuItemRow >.NextspaceMenuItemRowItem >.NextspaceMenuItemRowQuickBar {
248
+ display: flex;
249
+ flex-shrink: 0;
250
+ margin-left: auto;
251
+ }
252
+
253
+ .NextspaceMenuItemRow >.NextspaceMenuItemRowItem >.NextspaceMenuItemRowQuickBar >.NextspaceMenuItemRowQuickBarButton {
254
+ align-items: center;
255
+ cursor: pointer;
256
+ display: flex;
257
+ height: 20px;
258
+ justify-content: center;
259
+ margin-left: 4px;
260
+ opacity: .7;
261
+ transition: .3s ease;
262
+ width: 20px;
263
+ }
264
+
265
+ .NextspaceMenuItemRow >.NextspaceMenuItemRowItem >.NextspaceMenuItemRowQuickBar >.NextspaceMenuItemRowQuickBarButton:hover {
266
+ opacity: 1;
267
+ }
268
+
269
+ .NextspaceMenuItemRow >.NextspaceMenuItemRowItem >.NextspaceMenuItemRowQuickBar >.NextspaceMenuItemRowQuickBarButton[is-disabled="true"] {
270
+ cursor: default;
271
+ opacity: .3;
272
+ }
273
+
274
+ .NextspaceMenuItemRow >.NextspaceMenuItemRowItem >.NextspaceMenuItemRowQuickBar svg {
275
+ height: 18px;
276
+ width: 18px;
277
+ }
278
+
279
+ .NextspaceMenuItemRow >.NextspaceMenuItemRowItem[is-enabled="false"] >.NextspaceMenuItemRowCount,
280
+ .NextspaceMenuItemRow >.NextspaceMenuItemRowItem[is-enabled="false"] >.NextspaceMenuItemRowTitle,
281
+ .NextspaceMenuItemRow >.NextspaceMenuItemRowItem[is-enabled="false"] >.NextspaceMenuItemRowCheckbox,
282
+ .NextspaceMenuItemRow >.NextspaceMenuItemRowItem[is-enabled="false"] >.NextspaceMenuItemRowToggle {
283
+ opacity: .5;
284
+ }
285
+
286
+ .NextspaceMenuItemRow >.NextspaceMenuItemRowItem[is-enabled="false"] >.NextspaceMenuItemRowQuickBar {
287
+ opacity: 0;
288
+ pointer-events: none;
289
+ }
290
+
291
+ .NextspaceMenuItemRow >.NextspaceMenuItemRowDescription {
292
+ font-size: 12px;
293
+ margin: 0 0 8px 0;
294
+ opacity: .7;
295
+ }
296
+
297
+ .NextspaceMenuItemRow >.NextspaceMenuItemRowChildren {
298
+ border-top: 2px solid #121619;
299
+ display: flex;
300
+ flex-direction: column;
301
+ }
302
+
303
+ .NextspaceMenuItemRow[show-children="false"] >.NextspaceMenuItemRowChildren {
304
+ display: none;
305
+ }
306
+ `;
307
+ document.head.appendChild(style);
308
+ }
309
+ _generateElement() {
310
+ const element = document.createElement("div");
311
+ element.className = "NextspaceLeftPanelTabMenuItems";
312
+ const titleBar = document.createElement("div");
313
+ titleBar.className = "NextspaceLeftPanelTabMenuItemsTitleBar";
314
+ titleBar.textContent = "Menu";
315
+ element.appendChild(titleBar);
316
+ const breaker = document.createElement("div");
317
+ breaker.className = "NextspaceLeftPanelTabMenuItemsTitleBreaker";
318
+ element.appendChild(breaker);
319
+ const tip = document.createElement("div");
320
+ tip.className = "NextspaceLeftPanelTabMenuItemsTip";
321
+ tip.textContent = "Loading...";
322
+ element.appendChild(tip);
323
+ this._tip = tip;
324
+ const scrollBox = document.createElement("div");
325
+ scrollBox.className = "NextspaceLeftPanelTabMenuItemsScrollBox";
326
+ element.appendChild(scrollBox);
327
+ this._scrollBox = scrollBox;
328
+ // Positions against the panel container, which is the nearest positioned ancestor.
329
+ const resizeHandle = document.createElement("div");
330
+ resizeHandle.className = "NextspaceLeftPanelTabMenuItemsResizeHandle";
331
+ resizeHandle.onmousedown = (e) => {
332
+ this._startResize(e);
333
+ };
334
+ element.appendChild(resizeHandle);
335
+ this.Container.appendChild(element);
336
+ this._element = element;
337
+ }
338
+ _getStoredWidth() {
339
+ try {
340
+ const stored = parseInt(window.localStorage.getItem(PANEL_WIDTH_STORAGE_KEY), 10);
341
+ if (!isNaN(stored)) {
342
+ return stored;
343
+ }
344
+ }
345
+ catch (e) {
346
+ // Storage can be unavailable (private mode, blocked cookies). The default width still works.
347
+ }
348
+ return PANEL_DEFAULT_WIDTH;
349
+ }
350
+ /**
351
+ * Sizes the shared panel container to this tab's width, clamped to the allowed range.
352
+ */
353
+ _applyPanelWidth(width) {
354
+ const clamped = Math.min(PANEL_MAX_WIDTH, Math.max(PANEL_MIN_WIDTH, width));
355
+ if (this.Container) {
356
+ this.Container.style.width = clamped + "px";
357
+ // Padding lives on this tab's own element instead, so the resize handle can reach the panel edge.
358
+ this.Container.style.padding = "0";
359
+ }
360
+ return clamped;
361
+ }
362
+ _startResize(e) {
363
+ e.preventDefault();
364
+ const startX = e.clientX;
365
+ const startWidth = this.Container ? this.Container.offsetWidth : PANEL_DEFAULT_WIDTH;
366
+ this._onResizeMove = (moveEvent) => {
367
+ this._applyPanelWidth(startWidth + (moveEvent.clientX - startX));
368
+ };
369
+ this._onResizeUp = () => {
370
+ const finalWidth = this._applyPanelWidth(this.Container ? this.Container.offsetWidth : PANEL_DEFAULT_WIDTH);
371
+ try {
372
+ window.localStorage.setItem(PANEL_WIDTH_STORAGE_KEY, String(finalWidth));
373
+ }
374
+ catch (err) {
375
+ console.warn(err);
376
+ }
377
+ this._endResize();
378
+ };
379
+ window.addEventListener("mousemove", this._onResizeMove);
380
+ window.addEventListener("mouseup", this._onResizeUp);
381
+ }
382
+ _endResize() {
383
+ if (this._onResizeMove) {
384
+ window.removeEventListener("mousemove", this._onResizeMove);
385
+ this._onResizeMove = null;
386
+ }
387
+ if (this._onResizeUp) {
388
+ window.removeEventListener("mouseup", this._onResizeUp);
389
+ this._onResizeUp = null;
390
+ }
391
+ }
392
+ async _loadMenuItems() {
393
+ var _a, _b, _c, _d;
394
+ const viewId = (_a = this._widget) === null || _a === void 0 ? void 0 : _a.ViewId;
395
+ const token = ++this._loadToken;
396
+ let menuItems = [];
397
+ try {
398
+ if (viewId) {
399
+ const api = (_b = this._widget._getApiGetters()) === null || _b === void 0 ? void 0 : _b.GetBruceApi();
400
+ const data = await bruce_models_1.ProjectView.Get({
401
+ viewId,
402
+ api
403
+ });
404
+ const settings = (_c = data === null || data === void 0 ? void 0 : data.view) === null || _c === void 0 ? void 0 : _c.Settings;
405
+ menuItems = (_d = settings === null || settings === void 0 ? void 0 : settings.menuItems) !== null && _d !== void 0 ? _d : [];
406
+ }
407
+ }
408
+ catch (e) {
409
+ console.error(e);
410
+ menuItems = [];
411
+ }
412
+ if (this._disposed || token !== this._loadToken) {
413
+ return;
414
+ }
415
+ this._menuItems = menuItems;
416
+ this._renderTree();
417
+ this._updateStates();
418
+ this._updateCounts();
419
+ }
420
+ /**
421
+ * Records any menu items the manager has rendered that we haven't seen before.
422
+ * Returns whether anything new was added.
423
+ */
424
+ _snapshotManagerItems() {
425
+ var _a, _b, _c;
426
+ const manager = (_a = this._widget) === null || _a === void 0 ? void 0 : _a._getManager();
427
+ if (!manager) {
428
+ return false;
429
+ }
430
+ let added = false;
431
+ for (const id of (_b = manager.GetEnabledItemIds()) !== null && _b !== void 0 ? _b : []) {
432
+ if (this._managerItems.has(id)) {
433
+ continue;
434
+ }
435
+ const item = (_c = manager.GetEnabledItem(id)) === null || _c === void 0 ? void 0 : _c.item;
436
+ if (item === null || item === void 0 ? void 0 : item.id) {
437
+ this._managerItems.set(id, item);
438
+ added = true;
439
+ }
440
+ }
441
+ return added;
442
+ }
443
+ /**
444
+ * The view's menu items once there are any, otherwise whatever the manager has rendered.
445
+ */
446
+ _getTreeItems() {
447
+ if (this._menuItems.length) {
448
+ return this._menuItems;
449
+ }
450
+ return Array.from(this._managerItems.values());
451
+ }
452
+ _renderTree() {
453
+ this._rows.clear();
454
+ this._scrollBox.innerHTML = "";
455
+ const items = this._getTreeItems();
456
+ if (!items.length) {
457
+ this._tip.textContent = this._getEmptyText();
458
+ this._tip.style.display = "block";
459
+ return;
460
+ }
461
+ this._tip.style.display = "none";
462
+ for (const item of items) {
463
+ this._renderRow(item, 0, this._scrollBox);
464
+ }
465
+ }
466
+ _getEmptyText() {
467
+ var _a;
468
+ if ((_a = this._widget) === null || _a === void 0 ? void 0 : _a.ViewId) {
469
+ return "This project view has no menu items.";
470
+ }
471
+ return this._waitedForView ? "No view is loaded." : "Loading..";
472
+ }
473
+ _renderRow(item, depth, parent) {
474
+ var _a;
475
+ if (!(item === null || item === void 0 ? void 0 : item.id)) {
476
+ return;
477
+ }
478
+ const isFolder = !item.Type || item.Type === bruce_models_1.MenuItem.EType.None;
479
+ const children = item.hideChildren ? [] : ((_a = item.Children) !== null && _a !== void 0 ? _a : []);
480
+ const hasChildren = children.length > 0;
481
+ const row = document.createElement("div");
482
+ row.className = "NextspaceMenuItemRow";
483
+ row.setAttribute("menu-item-id", item.id);
484
+ const itemElement = document.createElement("div");
485
+ itemElement.className = "NextspaceMenuItemRowItem";
486
+ itemElement.style.paddingLeft = (depth * 15) + "px";
487
+ row.appendChild(itemElement);
488
+ if (hasChildren) {
489
+ const toggle = document.createElement("div");
490
+ toggle.className = "NextspaceMenuItemRowToggle";
491
+ toggle.onclick = () => {
492
+ this._setOpen(item.id, depth, row.getAttribute("show-children") !== "true", row, toggle);
493
+ };
494
+ itemElement.appendChild(toggle);
495
+ const opened = this._getOpen(item.id, depth);
496
+ row.setAttribute("show-children", opened ? "true" : "false");
497
+ toggle.innerHTML = opened ? ICON_CHEV_DOWN : ICON_CHEV_RIGHT;
498
+ }
499
+ else if (depth > 0) {
500
+ const bracket = document.createElement("div");
501
+ bracket.className = "NextspaceMenuItemRowBracket";
502
+ bracket.innerHTML = ICON_BRACKET;
503
+ itemElement.appendChild(bracket);
504
+ row.setAttribute("show-children", "false");
505
+ }
506
+ else {
507
+ row.setAttribute("show-children", "false");
508
+ }
509
+ const checkbox = document.createElement("div");
510
+ checkbox.className = "NextspaceMenuItemRowCheckbox";
511
+ checkbox.onclick = () => {
512
+ this._toggleItem(item);
513
+ };
514
+ itemElement.appendChild(checkbox);
515
+ const title = document.createElement("div");
516
+ title.className = "NextspaceMenuItemRowTitle";
517
+ title.textContent = item.Caption || "Unnamed Menu Item";
518
+ title.title = item.Caption || "Unnamed Menu Item";
519
+ itemElement.appendChild(title);
520
+ // Folders have no visuals of their own, so a count would always read zero.
521
+ let count = null;
522
+ if (!isFolder) {
523
+ count = document.createElement("div");
524
+ count.className = "NextspaceMenuItemRowCount";
525
+ count.style.display = "none";
526
+ count.onclick = () => {
527
+ this._selectItemEntities(item);
528
+ };
529
+ itemElement.appendChild(count);
530
+ }
531
+ const quickBar = document.createElement("div");
532
+ quickBar.className = "NextspaceMenuItemRowQuickBar";
533
+ itemElement.appendChild(quickBar);
534
+ if (!isFolder) {
535
+ const flyTo = document.createElement("div");
536
+ flyTo.className = "NextspaceMenuItemRowQuickBarButton";
537
+ flyTo.title = "Fly to";
538
+ flyTo.innerHTML = ICON_FLY_TO;
539
+ flyTo.onclick = () => {
540
+ this._flyToItem(item, flyTo);
541
+ };
542
+ quickBar.appendChild(flyTo);
543
+ }
544
+ if (item.Description) {
545
+ const description = document.createElement("p");
546
+ description.className = "NextspaceMenuItemRowDescription";
547
+ description.style.paddingLeft = (depth * 15) + "px";
548
+ description.textContent = item.Description;
549
+ row.appendChild(description);
550
+ }
551
+ const childrenElement = document.createElement("div");
552
+ childrenElement.className = "NextspaceMenuItemRowChildren";
553
+ row.appendChild(childrenElement);
554
+ parent.appendChild(row);
555
+ this._rows.set(item.id, {
556
+ item,
557
+ depth,
558
+ element: row,
559
+ itemElement,
560
+ checkboxElement: checkbox,
561
+ countElement: count,
562
+ childrenElement
563
+ });
564
+ for (const child of children) {
565
+ this._renderRow(child, depth + 1, childrenElement);
566
+ }
567
+ }
568
+ _getOpen(itemId, depth) {
569
+ try {
570
+ return window.localStorage.getItem(OPEN_STATE_STORAGE_PREFIX + itemId + depth) === "true";
571
+ }
572
+ catch (e) {
573
+ // Storage can be unavailable (private mode, blocked cookies). Not worth failing the tree over.
574
+ return false;
575
+ }
576
+ }
577
+ _setOpen(itemId, depth, open, row, toggle) {
578
+ row.setAttribute("show-children", open ? "true" : "false");
579
+ toggle.innerHTML = open ? ICON_CHEV_DOWN : ICON_CHEV_RIGHT;
580
+ try {
581
+ window.localStorage.setItem(OPEN_STATE_STORAGE_PREFIX + itemId + depth, open ? "true" : "false");
582
+ }
583
+ catch (e) {
584
+ console.warn(e);
585
+ }
586
+ }
587
+ /**
588
+ * Resolves each row's state from what the manager currently has rendered.
589
+ */
590
+ _updateStates() {
591
+ var _a;
592
+ const manager = (_a = this._widget) === null || _a === void 0 ? void 0 : _a._getManager();
593
+ if (!manager || this._disposed) {
594
+ return;
595
+ }
596
+ const enabledIds = new Set(manager.GetEnabledItemIds());
597
+ for (const row of Array.from(this._rows.values())) {
598
+ const state = this._resolveState(row.item, enabledIds);
599
+ row.itemElement.setAttribute("is-enabled", state === EMenuItemState.Disabled ? "false" : "true");
600
+ if (state === EMenuItemState.Enabled) {
601
+ row.checkboxElement.innerHTML = ICON_CHECK;
602
+ }
603
+ else if (state === EMenuItemState.ChildEnabled) {
604
+ row.checkboxElement.innerHTML = ICON_PARTIAL_CHECK;
605
+ }
606
+ else {
607
+ row.checkboxElement.innerHTML = "";
608
+ }
609
+ }
610
+ }
611
+ /**
612
+ * Works out a single item's state, rolling up children so a folder can report a partial state.
613
+ */
614
+ _resolveState(item, enabledIds) {
615
+ var _a;
616
+ const isFolder = !item.Type || item.Type === bruce_models_1.MenuItem.EType.None;
617
+ if (!isFolder) {
618
+ return enabledIds.has(item.id) ? EMenuItemState.Enabled : EMenuItemState.Disabled;
619
+ }
620
+ // Folders derive from the leaves below them rather than their own enabled flag.
621
+ let actionCount = 0;
622
+ let enabledActionCount = 0;
623
+ const traverse = (current) => {
624
+ var _a;
625
+ const currentIsFolder = !current.Type || current.Type === bruce_models_1.MenuItem.EType.None;
626
+ if (!currentIsFolder) {
627
+ actionCount += 1;
628
+ if (enabledIds.has(current.id)) {
629
+ enabledActionCount += 1;
630
+ }
631
+ return;
632
+ }
633
+ if ((_a = current.Children) === null || _a === void 0 ? void 0 : _a.length) {
634
+ current.Children.forEach(traverse);
635
+ }
636
+ };
637
+ (_a = item.Children) === null || _a === void 0 ? void 0 : _a.forEach(traverse);
638
+ if (actionCount <= 0) {
639
+ return enabledIds.has(item.id) ? EMenuItemState.Enabled : EMenuItemState.Disabled;
640
+ }
641
+ if (enabledActionCount <= 0) {
642
+ return EMenuItemState.Disabled;
643
+ }
644
+ return enabledActionCount >= actionCount ? EMenuItemState.Enabled : EMenuItemState.ChildEnabled;
645
+ }
646
+ _updateCounts() {
647
+ var _a, _b;
648
+ const register = (_b = (_a = this._widget) === null || _a === void 0 ? void 0 : _a._getManager()) === null || _b === void 0 ? void 0 : _b.VisualsRegister;
649
+ if (!register || this._disposed) {
650
+ return;
651
+ }
652
+ for (const row of Array.from(this._rows.values())) {
653
+ if (!row.countElement) {
654
+ continue;
655
+ }
656
+ const count = register.GetRegos({
657
+ menuItemId: row.item.id
658
+ }).length;
659
+ row.countElement.style.display = count > 0 ? "block" : "none";
660
+ row.countElement.textContent = count.toLocaleString();
661
+ }
662
+ }
663
+ _toggleItem(item) {
664
+ var _a;
665
+ const manager = (_a = this._widget) === null || _a === void 0 ? void 0 : _a._getManager();
666
+ if (!manager) {
667
+ return;
668
+ }
669
+ const enabledIds = new Set(manager.GetEnabledItemIds());
670
+ const state = this._resolveState(item, enabledIds);
671
+ if (state === EMenuItemState.Enabled) {
672
+ this._disableItem(item);
673
+ }
674
+ else {
675
+ manager.RenderItem({
676
+ item
677
+ });
678
+ }
679
+ this._stateQueue.Call(true);
680
+ }
681
+ _disableItem(item) {
682
+ var _a, _b;
683
+ const manager = (_a = this._widget) === null || _a === void 0 ? void 0 : _a._getManager();
684
+ if (!manager) {
685
+ return;
686
+ }
687
+ if ((_b = item.Children) === null || _b === void 0 ? void 0 : _b.length) {
688
+ item.Children.forEach((child) => this._disableItem(child));
689
+ }
690
+ manager.RemoveItemById({
691
+ menuItemId: item.id
692
+ });
693
+ }
694
+ _selectItemEntities(item) {
695
+ var _a, _b;
696
+ const register = (_b = (_a = this._widget) === null || _a === void 0 ? void 0 : _a._getManager()) === null || _b === void 0 ? void 0 : _b.VisualsRegister;
697
+ if (!register) {
698
+ return;
699
+ }
700
+ const entityIds = register.GetRegos({
701
+ menuItemId: item.id
702
+ }).map(x => x.entityId);
703
+ if (!entityIds.length) {
704
+ return;
705
+ }
706
+ register.ClearSelected();
707
+ register.SetSelected({
708
+ selected: true,
709
+ entityIds,
710
+ menuItemId: item.id
711
+ });
712
+ }
713
+ /**
714
+ * Flies the camera to a menu item's contents.
715
+ * Tileset-backed items fall back to the tileset's own bounds when no entity visuals are registered.
716
+ */
717
+ async _flyToItem(item, button) {
718
+ var _a, _b, _c, _d;
719
+ if (this._flying.has(item.id)) {
720
+ return;
721
+ }
722
+ const manager = (_a = this._widget) === null || _a === void 0 ? void 0 : _a._getManager();
723
+ const viewer = (_b = this._widget) === null || _b === void 0 ? void 0 : _b._getViewer();
724
+ if (!manager || !viewer) {
725
+ return;
726
+ }
727
+ this._flying.add(item.id);
728
+ button.setAttribute("is-disabled", "true");
729
+ try {
730
+ const regos = manager.VisualsRegister.GetRegos({
731
+ menuItemId: item.id
732
+ }).filter(x => !!(x === null || x === void 0 ? void 0 : x.visual) && !(x.visual instanceof Cesium.Cesium3DTileFeature));
733
+ let tileset = null;
734
+ if (!regos.length && TILESET_TYPES.indexOf(item.Type) >= 0) {
735
+ const enabled = manager.GetEnabledItem(item.id);
736
+ tileset = (_d = (_c = enabled === null || enabled === void 0 ? void 0 : enabled.renderManager) === null || _c === void 0 ? void 0 : _c.Tileset) !== null && _d !== void 0 ? _d : null;
737
+ }
738
+ const entityIds = regos.map(x => x.entityId);
739
+ if (!entityIds.length && !tileset) {
740
+ return;
741
+ }
742
+ await entity_utils_1.EntityUtils.FlyTo({
743
+ viewer,
744
+ manager,
745
+ entityIds: entityIds.length ? entityIds : null,
746
+ tileset
747
+ });
748
+ }
749
+ catch (e) {
750
+ console.error(e);
751
+ }
752
+ finally {
753
+ this._flying.delete(item.id);
754
+ button.setAttribute("is-disabled", "false");
755
+ }
756
+ }
757
+ }
758
+ exports.WidgetLeftPanelTabMenuItems = WidgetLeftPanelTabMenuItems;
759
+ //# sourceMappingURL=widget-left-panel-tab-menu-items.js.map