@eclipse-docks/core 0.7.127 → 0.7.130
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/dist/api/index.js +3 -3
- package/dist/api/services.d.ts +3 -1
- package/dist/api/services.d.ts.map +1 -1
- package/dist/{api-Da9zQcfd.js → api-oPg3Bv1S.js} +243 -264
- package/dist/api-oPg3Bv1S.js.map +1 -0
- package/dist/components/attribution.d.ts +1 -0
- package/dist/components/attribution.d.ts.map +1 -1
- package/dist/components/command.d.ts +0 -1
- package/dist/components/command.d.ts.map +1 -1
- package/dist/components/extensions.d.ts +3 -0
- package/dist/components/extensions.d.ts.map +1 -1
- package/dist/components/language-selector.d.ts.map +1 -1
- package/dist/components/layout-switcher.d.ts +1 -1
- package/dist/components/layout-switcher.d.ts.map +1 -1
- package/dist/components/npm-packages.d.ts +1 -0
- package/dist/components/npm-packages.d.ts.map +1 -1
- package/dist/components/release-history.d.ts +9 -2
- package/dist/components/release-history.d.ts.map +1 -1
- package/dist/components/tasks.d.ts.map +1 -1
- package/dist/core/apploader.d.ts +2 -9
- package/dist/core/apploader.d.ts.map +1 -1
- package/dist/core/contribution-targets.d.ts +1 -0
- package/dist/core/contribution-targets.d.ts.map +1 -1
- package/dist/core/dialogservice.d.ts +3 -1
- package/dist/core/dialogservice.d.ts.map +1 -1
- package/dist/core/dropdown-item.d.ts +8 -0
- package/dist/core/dropdown-item.d.ts.map +1 -1
- package/dist/core/layout-panels.d.ts +25 -0
- package/dist/core/layout-panels.d.ts.map +1 -0
- package/dist/dialogs/navigable-info-dialog.d.ts.map +1 -1
- package/dist/dialogs/version-info-dialog.d.ts +18 -2
- package/dist/dialogs/version-info-dialog.d.ts.map +1 -1
- package/dist/externals/lit.js +1 -1
- package/dist/externals/webawesome.js +1 -1
- package/dist/index.js +3 -3
- package/dist/layouts/standard-layout.d.ts +9 -1
- package/dist/layouts/standard-layout.d.ts.map +1 -1
- package/dist/parts/contextmenu.d.ts.map +1 -1
- package/dist/parts/index.js +1 -1
- package/dist/parts/part.d.ts +2 -0
- package/dist/parts/part.d.ts.map +1 -1
- package/dist/parts/resizable-grid.d.ts +10 -3
- package/dist/parts/resizable-grid.d.ts.map +1 -1
- package/dist/parts/tabs.d.ts +6 -0
- package/dist/parts/tabs.d.ts.map +1 -1
- package/dist/{parts-CRVxaDd-.js → parts-CAt8aeU8.js} +1050 -586
- package/dist/parts-CAt8aeU8.js.map +1 -0
- package/dist/{webawesome-Y1_HnKa_.js → webawesome-BGXn04Mw.js} +18 -10
- package/dist/webawesome-BGXn04Mw.js.map +1 -0
- package/package.json +1 -1
- package/src/api/services.ts +12 -0
- package/src/components/attribution.ts +2 -0
- package/src/components/command.ts +2 -8
- package/src/components/extensions.ts +20 -3
- package/src/components/language-selector.ts +0 -1
- package/src/components/layout-switcher.ts +39 -26
- package/src/components/npm-packages.ts +2 -0
- package/src/components/release-history.ts +29 -40
- package/src/components/tasks.ts +0 -1
- package/src/contributions/default-layout-contributions.ts +7 -43
- package/src/contributions/default-ui-contributions.ts +4 -4
- package/src/core/apploader.ts +7 -54
- package/src/core/contribution-targets.ts +1 -0
- package/src/core/dialogservice.ts +76 -19
- package/src/core/dropdown-item.ts +52 -17
- package/src/core/layout-panels.ts +121 -0
- package/src/dialogs/navigable-info-dialog.ts +5 -2
- package/src/dialogs/version-info-dialog.ts +163 -21
- package/src/icons/icons.txt +4 -2
- package/src/icons/layout-standard-bottom-panel.svg +4 -4
- package/src/icons/layout-standard-full.svg +4 -4
- package/src/icons/layout-standard-left-aux.svg +8 -0
- package/src/icons/layout-standard-left-sidebar.svg +5 -0
- package/src/icons/layout-standard-right-aux.svg +8 -0
- package/src/icons/layout-standard-right-sidebar.svg +5 -0
- package/src/layouts/standard-layout.ts +81 -5
- package/src/parts/contextmenu.ts +2 -1
- package/src/parts/part.ts +24 -0
- package/src/parts/resizable-grid.ts +125 -57
- package/src/parts/tabs.ts +103 -0
- package/dist/api-Da9zQcfd.js.map +0 -1
- package/dist/parts-CRVxaDd-.js.map +0 -1
- package/dist/webawesome-Y1_HnKa_.js.map +0 -1
- package/src/icons/layout-standard-bottom-sidebar.svg +0 -6
- package/src/icons/layout-standard.svg +0 -6
|
@@ -2,18 +2,18 @@ import { n as defaultLogger, o as rootContext, s as uiContext, t as createLogger
|
|
|
2
2
|
import { T as toastInfo, _ as getContributionDisabled, a as TOPIC_COMMAND_REGISTERED, f as activeTasksSignal, g as contributionRegistry, h as TOPIC_CONTRIBUTEIONS_CHANGED, l as activeEditorSignal, n as watchSignal, o as commandRegistry, p as partDirtySignal, t as DocksWidget, u as activePartSignal, v as getContributionVisible, w as toastError, x as contributionTargetMappingRegistry, y as readReactiveBoolean } from "./widget-BqQtioK1.js";
|
|
3
3
|
import { n as subscribe, t as publish } from "./events-B_ZxkU_G.js";
|
|
4
4
|
import { a as File, i as Directory, l as TOPIC_WORKSPACE_CHANGED, m as persistenceService, o as FileContentType, p as workspaceService } from "./fs-access-DTXPsV1W.js";
|
|
5
|
-
import "./webawesome-
|
|
5
|
+
import "./webawesome-BGXn04Mw.js";
|
|
6
6
|
import { css, html, nothing, render } from "lit";
|
|
7
7
|
import { unsafeHTML } from "lit/directives/unsafe-html.js";
|
|
8
8
|
import DOMPurify from "dompurify";
|
|
9
9
|
import { marked } from "marked";
|
|
10
10
|
import { customElement, property, state } from "lit/decorators.js";
|
|
11
11
|
import _decorate from "@oxc-project/runtime/helpers/decorate";
|
|
12
|
+
import { ifDefined } from "lit/directives/if-defined.js";
|
|
12
13
|
import { styleMap } from "lit/directives/style-map.js";
|
|
13
14
|
import { createRef, ref } from "lit/directives/ref.js";
|
|
14
15
|
import { when } from "lit/directives/when.js";
|
|
15
16
|
import { repeat } from "lit/directives/repeat.js";
|
|
16
|
-
import { ifDefined } from "lit/directives/if-defined.js";
|
|
17
17
|
//#region \0rolldown/runtime.js
|
|
18
18
|
var __defProp = Object.defineProperty;
|
|
19
19
|
var __exportAll = (all, no_symbols) => {
|
|
@@ -45,6 +45,7 @@ var EDITOR_AREA_MAIN = "editor-area-main";
|
|
|
45
45
|
var SIDEBAR_MAIN = "sidebar-main";
|
|
46
46
|
var SIDEBAR_MAIN_BOTTOM = "sidebar-main-bottom";
|
|
47
47
|
var SIDEBAR_AUXILIARY = "sidebar-auxiliary";
|
|
48
|
+
var SIDEBAR_AUXILIARY_BOTTOM = "sidebar-auxiliary-bottom";
|
|
48
49
|
var PANEL_BOTTOM = "panel-bottom";
|
|
49
50
|
//#endregion
|
|
50
51
|
//#region src/core/constants.ts
|
|
@@ -56,6 +57,7 @@ var constants_exports = /* @__PURE__ */ __exportAll({
|
|
|
56
57
|
MouseButton: () => MouseButton,
|
|
57
58
|
PANEL_BOTTOM: () => PANEL_BOTTOM,
|
|
58
59
|
SIDEBAR_AUXILIARY: () => SIDEBAR_AUXILIARY,
|
|
60
|
+
SIDEBAR_AUXILIARY_BOTTOM: () => SIDEBAR_AUXILIARY_BOTTOM,
|
|
59
61
|
SIDEBAR_MAIN: () => SIDEBAR_MAIN,
|
|
60
62
|
SIDEBAR_MAIN_BOTTOM: () => SIDEBAR_MAIN_BOTTOM,
|
|
61
63
|
SIDEBAR_MAIN_TOOLBAR: () => SIDEBAR_MAIN_TOOLBAR,
|
|
@@ -271,7 +273,7 @@ var taskService = new TaskService();
|
|
|
271
273
|
rootContext.put("taskService", taskService);
|
|
272
274
|
//#endregion
|
|
273
275
|
//#region src/core/esmsh-service.ts
|
|
274
|
-
var logger$
|
|
276
|
+
var logger$4 = createLogger("EsmShService");
|
|
275
277
|
var esmShService = new class EsmShService {
|
|
276
278
|
static {
|
|
277
279
|
this.ESM_SH_BASE = "https://esm.sh";
|
|
@@ -435,7 +437,7 @@ var esmShService = new class EsmShService {
|
|
|
435
437
|
if (this.isHttpUrl(source)) return source;
|
|
436
438
|
const parsed = this.parseSource(source);
|
|
437
439
|
if (!parsed) {
|
|
438
|
-
logger$
|
|
440
|
+
logger$4.warn(`Could not parse source identifier: ${source}`);
|
|
439
441
|
return source;
|
|
440
442
|
}
|
|
441
443
|
return this.buildEsmShUrl(parsed, options);
|
|
@@ -1080,7 +1082,7 @@ var DocksDialogContent = class extends DocksElement {
|
|
|
1080
1082
|
};
|
|
1081
1083
|
//#endregion
|
|
1082
1084
|
//#region src/core/dialogservice.ts
|
|
1083
|
-
var logger$
|
|
1085
|
+
var logger$3 = createLogger("DialogService");
|
|
1084
1086
|
var DIALOG_CONTRIBUTION_TARGET = "dialogs";
|
|
1085
1087
|
var OK_BUTTON = {
|
|
1086
1088
|
id: "ok",
|
|
@@ -1106,6 +1108,20 @@ function getDialogContainer() {
|
|
|
1106
1108
|
}
|
|
1107
1109
|
return dialogContainer;
|
|
1108
1110
|
}
|
|
1111
|
+
function findWaDialog(root) {
|
|
1112
|
+
if (root instanceof Element && root.tagName.toLowerCase() === "wa-dialog") return root;
|
|
1113
|
+
const children = root instanceof Document || root instanceof DocumentFragment || root instanceof Element ? Array.from(root.children) : root instanceof ShadowRoot ? Array.from(root.children) : [];
|
|
1114
|
+
for (const child of children) {
|
|
1115
|
+
if (child instanceof Element && child.tagName.toLowerCase() === "wa-dialog") return child;
|
|
1116
|
+
if (child instanceof Element && child.shadowRoot) {
|
|
1117
|
+
const nested = findWaDialog(child.shadowRoot);
|
|
1118
|
+
if (nested) return nested;
|
|
1119
|
+
}
|
|
1120
|
+
const nested = findWaDialog(child);
|
|
1121
|
+
if (nested) return nested;
|
|
1122
|
+
}
|
|
1123
|
+
return null;
|
|
1124
|
+
}
|
|
1109
1125
|
var DialogService = class {
|
|
1110
1126
|
constructor() {
|
|
1111
1127
|
this.contributions = /* @__PURE__ */ new Map();
|
|
@@ -1126,15 +1142,15 @@ var DialogService = class {
|
|
|
1126
1142
|
this.contributions.clear();
|
|
1127
1143
|
for (const contribution of contributions) {
|
|
1128
1144
|
if (!contribution.id) {
|
|
1129
|
-
logger$
|
|
1145
|
+
logger$3.warn("Dialog contribution missing id, skipping");
|
|
1130
1146
|
continue;
|
|
1131
1147
|
}
|
|
1132
1148
|
if (!contribution.component) {
|
|
1133
|
-
logger$
|
|
1149
|
+
logger$3.warn(`Dialog contribution "${contribution.id}" has no component function, skipping`);
|
|
1134
1150
|
continue;
|
|
1135
1151
|
}
|
|
1136
|
-
if (!contribution.onButton) {
|
|
1137
|
-
logger$
|
|
1152
|
+
if (!contribution.onButton && !contribution.selfContained) {
|
|
1153
|
+
logger$3.warn(`Dialog contribution "${contribution.id}" has no onButton callback, skipping`);
|
|
1138
1154
|
continue;
|
|
1139
1155
|
}
|
|
1140
1156
|
this.contributions.set(contribution.id, contribution);
|
|
@@ -1143,50 +1159,68 @@ var DialogService = class {
|
|
|
1143
1159
|
async open(dialogId, state) {
|
|
1144
1160
|
const contribution = this.contributions.get(dialogId);
|
|
1145
1161
|
if (!contribution) {
|
|
1146
|
-
logger$
|
|
1162
|
+
logger$3.error(`Dialog "${dialogId}" not found`);
|
|
1147
1163
|
throw new Error(`Dialog "${dialogId}" not found`);
|
|
1148
1164
|
}
|
|
1149
1165
|
return new Promise((resolve) => {
|
|
1150
1166
|
const container = getDialogContainer();
|
|
1151
|
-
let
|
|
1167
|
+
let closed = false;
|
|
1152
1168
|
let dialogContentElement = null;
|
|
1153
1169
|
const cleanup = async () => {
|
|
1154
|
-
if (
|
|
1155
|
-
|
|
1170
|
+
if (closed) return;
|
|
1171
|
+
closed = true;
|
|
1156
1172
|
if (dialogContentElement) try {
|
|
1157
1173
|
await dialogContentElement.dispose();
|
|
1158
1174
|
} catch (error) {
|
|
1159
1175
|
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
1160
|
-
logger$
|
|
1176
|
+
logger$3.error(`Error disposing dialog content for "${dialogId}": ${errorMessage}`);
|
|
1161
1177
|
}
|
|
1162
1178
|
try {
|
|
1163
1179
|
const result = dialogContentElement ? dialogContentElement.getResult() : void 0;
|
|
1164
|
-
await contribution.onButton("close", result, stateWithClose);
|
|
1180
|
+
if (contribution.onButton) await contribution.onButton("close", result, stateWithClose);
|
|
1165
1181
|
} catch (error) {
|
|
1166
1182
|
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
1167
|
-
logger$
|
|
1183
|
+
logger$3.error(`Error executing close callback for dialog "${dialogId}": ${errorMessage}`);
|
|
1168
1184
|
}
|
|
1169
1185
|
render(html``, container);
|
|
1170
1186
|
resolve();
|
|
1171
1187
|
};
|
|
1188
|
+
const closeDialog = () => {
|
|
1189
|
+
if (closed) return;
|
|
1190
|
+
const dialog = findWaDialog(container);
|
|
1191
|
+
if (dialog && dialog.open !== false) {
|
|
1192
|
+
dialog.open = false;
|
|
1193
|
+
return;
|
|
1194
|
+
}
|
|
1195
|
+
cleanup();
|
|
1196
|
+
};
|
|
1197
|
+
const handleAfterHide = () => {
|
|
1198
|
+
cleanup();
|
|
1199
|
+
};
|
|
1172
1200
|
const handleButtonClick = async (buttonId) => {
|
|
1201
|
+
if (!contribution.onButton) return;
|
|
1173
1202
|
try {
|
|
1174
1203
|
const result = dialogContentElement ? dialogContentElement.getResult() : void 0;
|
|
1175
|
-
if (await contribution.onButton(buttonId, result, stateWithClose) !== false)
|
|
1204
|
+
if (await contribution.onButton(buttonId, result, stateWithClose) !== false) closeDialog();
|
|
1176
1205
|
} catch (error) {
|
|
1177
1206
|
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
1178
|
-
logger$
|
|
1179
|
-
|
|
1207
|
+
logger$3.error(`Error executing button callback for dialog "${dialogId}": ${errorMessage}`);
|
|
1208
|
+
closeDialog();
|
|
1180
1209
|
}
|
|
1181
1210
|
};
|
|
1182
1211
|
const buttons = contribution.buttons && contribution.buttons.length > 0 ? contribution.buttons : [OK_BUTTON];
|
|
1183
|
-
if (state && typeof state === "object") state.close = cleanup;
|
|
1184
1212
|
const stateWithClose = {
|
|
1185
1213
|
...state,
|
|
1186
|
-
close:
|
|
1214
|
+
close: closeDialog,
|
|
1215
|
+
onAfterHide: handleAfterHide
|
|
1187
1216
|
};
|
|
1188
|
-
|
|
1189
|
-
|
|
1217
|
+
if (state && typeof state === "object") {
|
|
1218
|
+
state.close = closeDialog;
|
|
1219
|
+
state.onAfterHide = handleAfterHide;
|
|
1220
|
+
}
|
|
1221
|
+
const dialogLabel = state && typeof state === "object" && typeof state.label === "string" ? state.label : contribution.label || dialogId;
|
|
1222
|
+
render(contribution.selfContained ? contribution.component(stateWithClose) : html`
|
|
1223
|
+
<wa-dialog label="${dialogLabel}" open @wa-after-hide=${handleAfterHide}>
|
|
1190
1224
|
<style>
|
|
1191
1225
|
.dialog-service-content {
|
|
1192
1226
|
display: flex;
|
|
@@ -1218,13 +1252,14 @@ var DialogService = class {
|
|
|
1218
1252
|
@dialog-cancel=${() => {
|
|
1219
1253
|
const cancelButton = buttons.find((b) => b.id === "cancel");
|
|
1220
1254
|
if (cancelButton) handleButtonClick(cancelButton.id);
|
|
1221
|
-
else
|
|
1255
|
+
else closeDialog();
|
|
1222
1256
|
}}>
|
|
1223
1257
|
${contribution.component(state)}
|
|
1224
1258
|
|
|
1225
1259
|
<div class="dialog-service-footer">
|
|
1226
1260
|
${buttons.map((button) => html`
|
|
1227
1261
|
<wa-button
|
|
1262
|
+
data-dialog-button="${button.id}"
|
|
1228
1263
|
variant="${button.variant || "default"}"
|
|
1229
1264
|
?disabled=${button.disabled}
|
|
1230
1265
|
@click=${() => handleButtonClick(button.id)}
|
|
@@ -1747,7 +1782,7 @@ async function deleteIndexedDbWorkspaceData(directory) {
|
|
|
1747
1782
|
}
|
|
1748
1783
|
//#endregion
|
|
1749
1784
|
//#region src/core/marketplaceregistry.ts
|
|
1750
|
-
var logger$
|
|
1785
|
+
var logger$2 = createLogger("MarketplaceRegistry");
|
|
1751
1786
|
var TOPIC_MARKETPLACE_CHANGED = "events/marketplaceregistry/changed";
|
|
1752
1787
|
var KEY_CATALOG_URLS = "marketplace.catalogUrls";
|
|
1753
1788
|
var MarketplaceRegistry = class {
|
|
@@ -1756,7 +1791,7 @@ var MarketplaceRegistry = class {
|
|
|
1756
1791
|
this.loadingPromises = /* @__PURE__ */ new Map();
|
|
1757
1792
|
this.loadCatalogUrls().then(() => {
|
|
1758
1793
|
this.refreshCatalogs().catch((err) => {
|
|
1759
|
-
logger$
|
|
1794
|
+
logger$2.error(`Failed to refresh catalogs on init: ${err.message}`);
|
|
1760
1795
|
});
|
|
1761
1796
|
});
|
|
1762
1797
|
}
|
|
@@ -1765,7 +1800,7 @@ var MarketplaceRegistry = class {
|
|
|
1765
1800
|
const urls = await appSettings.get(KEY_CATALOG_URLS);
|
|
1766
1801
|
this.catalogUrls = Array.isArray(urls) ? urls : [];
|
|
1767
1802
|
} catch (error) {
|
|
1768
|
-
logger$
|
|
1803
|
+
logger$2.error(`Failed to load catalog URLs: ${error}`);
|
|
1769
1804
|
this.catalogUrls = [];
|
|
1770
1805
|
}
|
|
1771
1806
|
}
|
|
@@ -1779,28 +1814,28 @@ var MarketplaceRegistry = class {
|
|
|
1779
1814
|
async addCatalogUrl(url) {
|
|
1780
1815
|
if (!this.isValidUrl(url)) throw new Error(`Invalid catalog URL: ${url}`);
|
|
1781
1816
|
if (this.catalogUrls.includes(url)) {
|
|
1782
|
-
logger$
|
|
1817
|
+
logger$2.debug(`Catalog URL already exists: ${url}`);
|
|
1783
1818
|
return;
|
|
1784
1819
|
}
|
|
1785
1820
|
this.catalogUrls.push(url);
|
|
1786
1821
|
await this.saveCatalogUrls();
|
|
1787
|
-
logger$
|
|
1822
|
+
logger$2.debug(`Added catalog URL: ${url}`);
|
|
1788
1823
|
try {
|
|
1789
1824
|
await this.refreshCatalogs();
|
|
1790
1825
|
} catch (error) {
|
|
1791
|
-
logger$
|
|
1826
|
+
logger$2.warn(`Failed to refresh catalogs immediately after adding: ${error}`);
|
|
1792
1827
|
}
|
|
1793
1828
|
}
|
|
1794
1829
|
async addCatalogUrls(urls) {
|
|
1795
1830
|
let added = 0;
|
|
1796
1831
|
for (const url of urls) {
|
|
1797
1832
|
if (!this.isValidUrl(url)) {
|
|
1798
|
-
logger$
|
|
1833
|
+
logger$2.warn(`Skipping invalid catalog URL: ${url}`);
|
|
1799
1834
|
continue;
|
|
1800
1835
|
}
|
|
1801
1836
|
if (this.catalogUrls.includes(url)) continue;
|
|
1802
1837
|
this.catalogUrls.push(url);
|
|
1803
|
-
logger$
|
|
1838
|
+
logger$2.debug(`Added catalog URL: ${url}`);
|
|
1804
1839
|
added++;
|
|
1805
1840
|
}
|
|
1806
1841
|
if (added === 0) return;
|
|
@@ -1808,7 +1843,7 @@ var MarketplaceRegistry = class {
|
|
|
1808
1843
|
try {
|
|
1809
1844
|
await this.refreshCatalogs();
|
|
1810
1845
|
} catch (error) {
|
|
1811
|
-
logger$
|
|
1846
|
+
logger$2.warn(`Failed to refresh catalogs after adding URLs: ${error}`);
|
|
1812
1847
|
}
|
|
1813
1848
|
}
|
|
1814
1849
|
async removeCatalogUrl(url) {
|
|
@@ -1816,7 +1851,7 @@ var MarketplaceRegistry = class {
|
|
|
1816
1851
|
if (index === -1) return;
|
|
1817
1852
|
this.catalogUrls.splice(index, 1);
|
|
1818
1853
|
await this.saveCatalogUrls();
|
|
1819
|
-
logger$
|
|
1854
|
+
logger$2.info(`Removed catalog URL: ${url}`);
|
|
1820
1855
|
}
|
|
1821
1856
|
getCatalogUrls() {
|
|
1822
1857
|
return [...this.catalogUrls];
|
|
@@ -1847,7 +1882,7 @@ var MarketplaceRegistry = class {
|
|
|
1847
1882
|
extensions: data.extensions || []
|
|
1848
1883
|
};
|
|
1849
1884
|
} catch (error) {
|
|
1850
|
-
logger$
|
|
1885
|
+
logger$2.error(`Failed to fetch catalog from ${url}: ${error}`);
|
|
1851
1886
|
throw error;
|
|
1852
1887
|
} finally {
|
|
1853
1888
|
this.loadingPromises.delete(url);
|
|
@@ -1858,7 +1893,7 @@ var MarketplaceRegistry = class {
|
|
|
1858
1893
|
}
|
|
1859
1894
|
async refreshCatalogs() {
|
|
1860
1895
|
const promises = this.catalogUrls.map((url) => this.fetchCatalog(url).catch((error) => {
|
|
1861
|
-
logger$
|
|
1896
|
+
logger$2.warn(`Failed to refresh catalog ${url}: ${error.message}`);
|
|
1862
1897
|
return null;
|
|
1863
1898
|
}));
|
|
1864
1899
|
const catalogs = await Promise.allSettled(promises);
|
|
@@ -1878,8 +1913,8 @@ var MarketplaceRegistry = class {
|
|
|
1878
1913
|
});
|
|
1879
1914
|
}
|
|
1880
1915
|
});
|
|
1881
|
-
logger$
|
|
1882
|
-
if (registeredCount > 0) logger$
|
|
1916
|
+
logger$2.debug(`Refreshed ${this.catalogUrls.length} catalogs, ${registeredCount} extensions registered`);
|
|
1917
|
+
if (registeredCount > 0) logger$2.info(`Marketplace: ${registeredCount} new extension(s) available`);
|
|
1883
1918
|
publish(TOPIC_MARKETPLACE_CHANGED, { type: "refreshed" });
|
|
1884
1919
|
}
|
|
1885
1920
|
getMarketplaceExtension(extensionId) {
|
|
@@ -1908,16 +1943,10 @@ rootContext.put("marketplaceRegistry", marketplaceRegistry);
|
|
|
1908
1943
|
* - Application: App-specific code, gs-* components, contributions
|
|
1909
1944
|
* - App Loader: Bridge between framework and application
|
|
1910
1945
|
*/
|
|
1911
|
-
var logger = createLogger("AppLoader");
|
|
1946
|
+
var logger$1 = createLogger("AppLoader");
|
|
1912
1947
|
function getLayoutIdFromApp(app) {
|
|
1913
|
-
|
|
1914
|
-
|
|
1915
|
-
return typeof l === "object" ? l.id : l ?? "standard";
|
|
1916
|
-
}
|
|
1917
|
-
function propsToAttributes(props) {
|
|
1918
|
-
const out = {};
|
|
1919
|
-
for (const [k, v] of Object.entries(props)) out[k] = typeof v === "boolean" ? v ? "true" : "false" : v;
|
|
1920
|
-
return out;
|
|
1948
|
+
const layout = app?.layout ?? "standard";
|
|
1949
|
+
return typeof layout === "object" ? layout.id : layout;
|
|
1921
1950
|
}
|
|
1922
1951
|
/**
|
|
1923
1952
|
* Extracts error message from an error object.
|
|
@@ -1946,9 +1975,6 @@ var appLoaderService = new class AppLoaderService {
|
|
|
1946
1975
|
static {
|
|
1947
1976
|
this.PREFERRED_APP_KEY = "preferredAppName";
|
|
1948
1977
|
}
|
|
1949
|
-
static {
|
|
1950
|
-
this.PREFERRED_LAYOUT_KEY = "preferredLayoutId";
|
|
1951
|
-
}
|
|
1952
1978
|
/**
|
|
1953
1979
|
* Register an application with the framework.
|
|
1954
1980
|
* Optionally starts the apploader automatically after registration.
|
|
@@ -1967,7 +1993,8 @@ var appLoaderService = new class AppLoaderService {
|
|
|
1967
1993
|
}
|
|
1968
1994
|
app.name = app.name ?? "app";
|
|
1969
1995
|
app.version = app.version ?? "0.0.0";
|
|
1970
|
-
|
|
1996
|
+
app.layout = app.layout ?? "standard";
|
|
1997
|
+
if (this.apps.has(app.name)) logger$1.warn(`App '${app.name}' is already registered. Overwriting.`);
|
|
1971
1998
|
if (app.marketplaceCatalogUrls?.length) marketplaceRegistry.addCatalogUrls(app.marketplaceCatalogUrls).catch(() => {});
|
|
1972
1999
|
this.apps.set(app.name, app);
|
|
1973
2000
|
if (options?.defaultAppName) this.defaultAppName = options.defaultAppName;
|
|
@@ -1984,13 +2011,13 @@ var appLoaderService = new class AppLoaderService {
|
|
|
1984
2011
|
*/
|
|
1985
2012
|
async start() {
|
|
1986
2013
|
if (this.started) {
|
|
1987
|
-
logger.debug("AppLoader already started");
|
|
2014
|
+
logger$1.debug("AppLoader already started");
|
|
1988
2015
|
return;
|
|
1989
2016
|
}
|
|
1990
2017
|
this.started = true;
|
|
1991
2018
|
const appIdFromUrl = new URLSearchParams(window.location.search).get("appId");
|
|
1992
2019
|
const appIdFromPath = extractAppIdFromPath();
|
|
1993
|
-
if (appIdFromPath) logger.info(`Extracted app ID from current page path: ${appIdFromPath}`);
|
|
2020
|
+
if (appIdFromPath) logger$1.info(`Extracted app ID from current page path: ${appIdFromPath}`);
|
|
1994
2021
|
const appToLoad = await this.selectAppToLoad({
|
|
1995
2022
|
appIdFromUrl,
|
|
1996
2023
|
appIdFromPath
|
|
@@ -2018,10 +2045,10 @@ var appLoaderService = new class AppLoaderService {
|
|
|
2018
2045
|
if (!app) throw new Error(`App '${appName}' not found. Make sure it's registered.`);
|
|
2019
2046
|
this.dispatchLoadProgress("Starting…");
|
|
2020
2047
|
if (this.currentApp) {
|
|
2021
|
-
logger.info(`Disposing current app: ${this.currentApp.name}`);
|
|
2048
|
+
logger$1.info(`Disposing current app: ${this.currentApp.name}`);
|
|
2022
2049
|
if (this.currentApp.dispose) await this.currentApp.dispose();
|
|
2023
2050
|
if (this.currentApp.extensions && this.currentApp.extensions.length > 0) {
|
|
2024
|
-
logger.info(`Disabling ${this.currentApp.extensions.length} extensions...`);
|
|
2051
|
+
logger$1.info(`Disabling ${this.currentApp.extensions.length} extensions...`);
|
|
2025
2052
|
this.currentApp.extensions.forEach((extId) => {
|
|
2026
2053
|
extensionRegistry.disable(extId);
|
|
2027
2054
|
});
|
|
@@ -2037,19 +2064,19 @@ var appLoaderService = new class AppLoaderService {
|
|
|
2037
2064
|
});
|
|
2038
2065
|
}
|
|
2039
2066
|
if (app.contributions) {
|
|
2040
|
-
logger.info("Registering app contributions...");
|
|
2067
|
+
logger$1.info("Registering app contributions...");
|
|
2041
2068
|
if (app.contributions.ui) {
|
|
2042
2069
|
app.contributions.ui.forEach((contribution) => {
|
|
2043
2070
|
const target = contribution.target;
|
|
2044
2071
|
if (target) contributionRegistry.registerContribution(target, contribution);
|
|
2045
2072
|
});
|
|
2046
|
-
logger.info(`Registered ${app.contributions.ui.length} UI contributions`);
|
|
2073
|
+
logger$1.info(`Registered ${app.contributions.ui.length} UI contributions`);
|
|
2047
2074
|
}
|
|
2048
2075
|
if (app.contributions.extensions) {
|
|
2049
2076
|
app.contributions.extensions.forEach((extension) => {
|
|
2050
2077
|
extensionRegistry.registerExtension(extension);
|
|
2051
2078
|
});
|
|
2052
|
-
logger.info(`Registered ${app.contributions.extensions.length} app extensions`);
|
|
2079
|
+
logger$1.info(`Registered ${app.contributions.extensions.length} app extensions`);
|
|
2053
2080
|
}
|
|
2054
2081
|
}
|
|
2055
2082
|
const extensionsSet = new Set(app.extensions || []);
|
|
@@ -2058,19 +2085,18 @@ var appLoaderService = new class AppLoaderService {
|
|
|
2058
2085
|
if (app.extensions.length > 0) {
|
|
2059
2086
|
this.dispatchLoadProgress("Enabling extensions…");
|
|
2060
2087
|
await Promise.all(app.extensions.map((extId) => extensionRegistry.enableAsync(extId).catch((e) => {
|
|
2061
|
-
logger.error(`Failed to load extension ${extId}: ${getErrorMessage(e)}`);
|
|
2088
|
+
logger$1.error(`Failed to load extension ${extId}: ${getErrorMessage(e)}`);
|
|
2062
2089
|
})));
|
|
2063
2090
|
}
|
|
2064
2091
|
this.dispatchLoadProgress("Loading extensions…");
|
|
2065
2092
|
await extensionRegistry.loadEnabledExtensions();
|
|
2066
2093
|
if (app.initialize) {
|
|
2067
2094
|
this.dispatchLoadProgress("Initializing…");
|
|
2068
|
-
logger.info(`Initializing ${app.name}...`);
|
|
2095
|
+
logger$1.info(`Initializing ${app.name}...`);
|
|
2069
2096
|
await app.initialize();
|
|
2070
2097
|
}
|
|
2071
2098
|
this.currentApp = app;
|
|
2072
|
-
logger.info(`App ${app.name} loaded successfully`);
|
|
2073
|
-
this.preferredLayoutId = await this.getPreferredLayoutId();
|
|
2099
|
+
logger$1.info(`App ${app.name} loaded successfully`);
|
|
2074
2100
|
this.updateDocumentMetadata(app);
|
|
2075
2101
|
if (container) {
|
|
2076
2102
|
this.dispatchLoadProgress("Rendering layout…");
|
|
@@ -2103,19 +2129,17 @@ var appLoaderService = new class AppLoaderService {
|
|
|
2103
2129
|
*/
|
|
2104
2130
|
renderApp(container) {
|
|
2105
2131
|
if (!this.currentApp) throw new Error("No app loaded. Call loadApp() first.");
|
|
2106
|
-
const layoutId =
|
|
2132
|
+
const layoutId = getLayoutIdFromApp(this.currentApp);
|
|
2107
2133
|
const layouts = contributionRegistry.getContributions(SYSTEM_LAYOUTS);
|
|
2108
2134
|
let layout = layouts.find((c) => c.id === layoutId);
|
|
2109
2135
|
if (!layout) {
|
|
2110
|
-
logger.warn(`Layout '${layoutId}' not found, falling back to 'standard'`);
|
|
2136
|
+
logger$1.warn(`Layout '${layoutId}' not found, falling back to 'standard'`);
|
|
2111
2137
|
layout = layouts.find((c) => c.id === "standard");
|
|
2112
2138
|
}
|
|
2113
2139
|
if (!layout) throw new Error(`No layout found for layoutId '${layoutId}' and no 'standard' layout registered.`);
|
|
2114
2140
|
const r = layout.component;
|
|
2115
2141
|
let effectiveAttributes = {};
|
|
2116
2142
|
if (r && typeof r === "object" && "tag" in r && r.attributes) effectiveAttributes = { ...r.attributes };
|
|
2117
|
-
const appLayout = this.currentApp?.layout;
|
|
2118
|
-
if (typeof appLayout === "object" && appLayout.id === layoutId && appLayout.props) Object.assign(effectiveAttributes, propsToAttributes(appLayout.props));
|
|
2119
2143
|
container.innerHTML = "";
|
|
2120
2144
|
if (typeof r === "string") {
|
|
2121
2145
|
const el = document.createElement(r);
|
|
@@ -2128,7 +2152,7 @@ var appLoaderService = new class AppLoaderService {
|
|
|
2128
2152
|
} else if (typeof r === "function") render(r(), container);
|
|
2129
2153
|
else throw new Error(`Layout '${layout.id}' has invalid component.`);
|
|
2130
2154
|
if (layout.onShow) requestAnimationFrame(() => {
|
|
2131
|
-
Promise.resolve(layout.onShow()).catch((err) => logger.error(`Layout onShow failed for '${layout.id}': ${getErrorMessage(err)}`));
|
|
2155
|
+
Promise.resolve(layout.onShow()).catch((err) => logger$1.error(`Layout onShow failed for '${layout.id}': ${getErrorMessage(err)}`));
|
|
2132
2156
|
});
|
|
2133
2157
|
}
|
|
2134
2158
|
/**
|
|
@@ -2150,7 +2174,7 @@ var appLoaderService = new class AppLoaderService {
|
|
|
2150
2174
|
try {
|
|
2151
2175
|
return await appSettings.get(AppLoaderService.PREFERRED_APP_KEY);
|
|
2152
2176
|
} catch (error) {
|
|
2153
|
-
logger.debug(`Failed to get preferred app ID from settings: ${getErrorMessage(error)}`);
|
|
2177
|
+
logger$1.debug(`Failed to get preferred app ID from settings: ${getErrorMessage(error)}`);
|
|
2154
2178
|
return;
|
|
2155
2179
|
}
|
|
2156
2180
|
}
|
|
@@ -2162,9 +2186,9 @@ var appLoaderService = new class AppLoaderService {
|
|
|
2162
2186
|
try {
|
|
2163
2187
|
await appSettings.set(AppLoaderService.PREFERRED_APP_KEY, appId);
|
|
2164
2188
|
this.defaultAppName = appId;
|
|
2165
|
-
logger.info(`Set preferred app to: ${appId}`);
|
|
2189
|
+
logger$1.info(`Set preferred app to: ${appId}`);
|
|
2166
2190
|
} catch (error) {
|
|
2167
|
-
logger.error(`Failed to persist preferred app: ${getErrorMessage(error)}`);
|
|
2191
|
+
logger$1.error(`Failed to persist preferred app: ${getErrorMessage(error)}`);
|
|
2168
2192
|
throw error;
|
|
2169
2193
|
}
|
|
2170
2194
|
}
|
|
@@ -2172,28 +2196,7 @@ var appLoaderService = new class AppLoaderService {
|
|
|
2172
2196
|
return contributionRegistry.getContributions(SYSTEM_LAYOUTS);
|
|
2173
2197
|
}
|
|
2174
2198
|
getCurrentLayoutId() {
|
|
2175
|
-
return
|
|
2176
|
-
}
|
|
2177
|
-
async getPreferredLayoutId() {
|
|
2178
|
-
try {
|
|
2179
|
-
return await appSettings.get(AppLoaderService.PREFERRED_LAYOUT_KEY);
|
|
2180
|
-
} catch (error) {
|
|
2181
|
-
logger.debug(`Failed to get preferred layout ID: ${getErrorMessage(error)}`);
|
|
2182
|
-
return;
|
|
2183
|
-
}
|
|
2184
|
-
}
|
|
2185
|
-
async setPreferredLayoutId(layoutId) {
|
|
2186
|
-
if (!this.getRegisteredLayouts().some((l) => l.id === layoutId)) throw new Error(`Layout '${layoutId}' not found.`);
|
|
2187
|
-
try {
|
|
2188
|
-
await appSettings.set(AppLoaderService.PREFERRED_LAYOUT_KEY, layoutId);
|
|
2189
|
-
this.preferredLayoutId = layoutId;
|
|
2190
|
-
logger.info(`Set preferred layout to: ${layoutId}`);
|
|
2191
|
-
if (this.currentApp && this.container) this.renderApp(this.container);
|
|
2192
|
-
window.dispatchEvent(new CustomEvent("layout-changed", { detail: { layoutId } }));
|
|
2193
|
-
} catch (error) {
|
|
2194
|
-
logger.error(`Failed to persist preferred layout: ${getErrorMessage(error)}`);
|
|
2195
|
-
throw error;
|
|
2196
|
-
}
|
|
2199
|
+
return getLayoutIdFromApp(this.currentApp);
|
|
2197
2200
|
}
|
|
2198
2201
|
/**
|
|
2199
2202
|
* Select which app to load based on priority:
|
|
@@ -2208,26 +2211,26 @@ var appLoaderService = new class AppLoaderService {
|
|
|
2208
2211
|
if (appIdFromUrl) {
|
|
2209
2212
|
const name = this.findAppNameBySegment(appIdFromUrl) ?? appIdFromUrl;
|
|
2210
2213
|
if (this.apps.has(name)) {
|
|
2211
|
-
logger.info(`Loading app specified by URL parameter 'appId': ${name}`);
|
|
2214
|
+
logger$1.info(`Loading app specified by URL parameter 'appId': ${name}`);
|
|
2212
2215
|
return name;
|
|
2213
2216
|
}
|
|
2214
|
-
logger.warn(`App '${appIdFromUrl}' from URL parameter not found`);
|
|
2217
|
+
logger$1.warn(`App '${appIdFromUrl}' from URL parameter not found`);
|
|
2215
2218
|
}
|
|
2216
2219
|
if (appIdFromPath) {
|
|
2217
2220
|
const name = this.findAppNameBySegment(appIdFromPath);
|
|
2218
2221
|
if (name) {
|
|
2219
|
-
logger.info(`Loading app from URL path: ${appIdFromPath}`);
|
|
2222
|
+
logger$1.info(`Loading app from URL path: ${appIdFromPath}`);
|
|
2220
2223
|
return name;
|
|
2221
2224
|
}
|
|
2222
|
-
logger.debug(`App for path '${appIdFromPath}' not found, continuing search`);
|
|
2225
|
+
logger$1.debug(`App for path '${appIdFromPath}' not found, continuing search`);
|
|
2223
2226
|
}
|
|
2224
2227
|
const preferred = await this.getPreferredAppId();
|
|
2225
2228
|
if (preferred && this.apps.has(preferred)) {
|
|
2226
|
-
logger.info(`Loading preferred app from settings: ${preferred}`);
|
|
2229
|
+
logger$1.info(`Loading preferred app from settings: ${preferred}`);
|
|
2227
2230
|
return preferred;
|
|
2228
2231
|
}
|
|
2229
2232
|
if (this.defaultAppName && this.apps.has(this.defaultAppName)) return this.defaultAppName;
|
|
2230
|
-
if (this.defaultAppName) logger.warn(`Default app '${this.defaultAppName}' not found`);
|
|
2233
|
+
if (this.defaultAppName) logger$1.warn(`Default app '${this.defaultAppName}' not found`);
|
|
2231
2234
|
const registeredApps = this.getRegisteredApps();
|
|
2232
2235
|
if (registeredApps.length > 0) return registeredApps[0].name;
|
|
2233
2236
|
}
|
|
@@ -2642,7 +2645,9 @@ var DocksNavigableInfoDialogContent = class DocksNavigableInfoDialogContent exte
|
|
|
2642
2645
|
action.callback();
|
|
2643
2646
|
}
|
|
2644
2647
|
handleClose() {
|
|
2645
|
-
if (this.
|
|
2648
|
+
if (this.resolveCallback) this.resolveCallback();
|
|
2649
|
+
const dialog = this.closest("wa-dialog");
|
|
2650
|
+
if (dialog && dialog.open !== false) dialog.open = false;
|
|
2646
2651
|
}
|
|
2647
2652
|
static {
|
|
2648
2653
|
this.styles = [...DocksDialogContent.styles, css`
|
|
@@ -2983,85 +2988,641 @@ function filebrowserDialog(mode = "either") {
|
|
|
2983
2988
|
});
|
|
2984
2989
|
}
|
|
2985
2990
|
//#endregion
|
|
2986
|
-
//#region src/
|
|
2987
|
-
var
|
|
2988
|
-
|
|
2989
|
-
|
|
2990
|
-
|
|
2991
|
-
var
|
|
2992
|
-
|
|
2993
|
-
|
|
2994
|
-
|
|
2995
|
-
|
|
2996
|
-
|
|
2997
|
-
|
|
2998
|
-
|
|
2999
|
-
|
|
3000
|
-
|
|
3001
|
-
|
|
3002
|
-
|
|
3003
|
-
|
|
3004
|
-
|
|
3005
|
-
|
|
3006
|
-
|
|
3007
|
-
|
|
3008
|
-
|
|
3009
|
-
|
|
3010
|
-
|
|
2991
|
+
//#region src/core/contribution-names.ts
|
|
2992
|
+
var VIEW_FILEBROWSER = "view.filebrowser";
|
|
2993
|
+
var VIEW_LOG_TERMINAL = "view.logTerminal";
|
|
2994
|
+
var TOOLBAR_INFO = "toolbar.info";
|
|
2995
|
+
var TOOLBAR_FAST_VIEWS = "toolbar.fastViews";
|
|
2996
|
+
var TOOLBAR_LANGUAGE_SELECTOR = "toolbar.languageSelector";
|
|
2997
|
+
/** Main toolbar (right): layout picker (`docks-layout-switcher`). */
|
|
2998
|
+
var TOOLBAR_LAYOUT_SWITCHER = "toolbar.layoutSwitcher";
|
|
2999
|
+
/** Main toolbar (right): dark/light theme toggle (`switch_theme`). */
|
|
3000
|
+
var TOOLBAR_THEME_SWITCHER = "toolbar.themeSwitcher";
|
|
3001
|
+
/** Main toolbar (right): document fullscreen toggle (`fullscreen`). */
|
|
3002
|
+
var TOOLBAR_FULLSCREEN = "toolbar.fullscreen";
|
|
3003
|
+
/** Bottom-center toolbar: focused part title / active part indicator (`docks-part-name`). */
|
|
3004
|
+
var TOOLBAR_ACTIVE_PART_NAME = "toolbar.activePartName";
|
|
3005
|
+
/** Bottom-center toolbar: background tasks / progress (`docks-tasks`). */
|
|
3006
|
+
var TOOLBAR_TASKS = "toolbar.tasks";
|
|
3007
|
+
/** Main sidebar header toolbar: open extensions (`open_extensions` command). */
|
|
3008
|
+
var SIDEBAR_TOOLBAR_EXTENSIONS = "sidebar.toolbar.extensions";
|
|
3009
|
+
/** Default file-type → icon mappings on `system.icons`. */
|
|
3010
|
+
var SYSTEM_DEFAULT_FILE_ICONS = "system.icons.default";
|
|
3011
|
+
var ABOUT_TAB_RELEASE = "about.tab.release";
|
|
3012
|
+
var ABOUT_TAB_PACKAGES = "about.tab.packages";
|
|
3013
|
+
var ABOUT_TAB_ATTRIBUTIONS = "about.tab.attributions";
|
|
3014
|
+
var ATTRIBUTION_ECLIPSE_DOCKS = "attribution.eclipse-docks";
|
|
3015
|
+
var CTXMENU_FILEBROWSER_RENAME = "contextmenu.filebrowser.rename";
|
|
3016
|
+
var CTXMENU_FILEBROWSER_DELETE = "contextmenu.filebrowser.delete";
|
|
3017
|
+
//#endregion
|
|
3018
|
+
//#region src/parts/container.ts
|
|
3019
|
+
var DocksContainer = class extends DocksElement {};
|
|
3020
|
+
//#endregion
|
|
3021
|
+
//#region src/parts/part.ts
|
|
3022
|
+
var DocksPart = class DocksPart extends DocksContainer {
|
|
3023
|
+
constructor(..._args) {
|
|
3024
|
+
super(..._args);
|
|
3025
|
+
this.scrollMode = "scroller";
|
|
3026
|
+
this.dirty = false;
|
|
3027
|
+
this.isEditor = false;
|
|
3028
|
+
this.embedded = false;
|
|
3029
|
+
this.onContentContextMenu = async (event) => {
|
|
3030
|
+
const contextMenu = this.renderRoot.querySelector("docks-contextmenu");
|
|
3031
|
+
if (!contextMenu) return;
|
|
3032
|
+
if (await contextMenu.show({
|
|
3033
|
+
x: event.clientX,
|
|
3034
|
+
y: event.clientY
|
|
3035
|
+
}, event)) event.preventDefault();
|
|
3036
|
+
};
|
|
3011
3037
|
}
|
|
3012
|
-
|
|
3013
|
-
|
|
3014
|
-
|
|
3015
|
-
|
|
3016
|
-
|
|
3017
|
-
|
|
3038
|
+
getCommandStack() {
|
|
3039
|
+
return this.commandStack;
|
|
3040
|
+
}
|
|
3041
|
+
/**
|
|
3042
|
+
* Override this method to provide toolbar content for this part.
|
|
3043
|
+
* This is a lightweight alternative to registering toolbar contributions
|
|
3044
|
+
* for actions that are scoped to this part instance.
|
|
3045
|
+
*
|
|
3046
|
+
* IMPORTANT: Event handlers MUST use arrow functions to preserve the component's 'this' context.
|
|
3047
|
+
* The toolbar template is rendered in a different component (docks-toolbar), so direct method
|
|
3048
|
+
* references lose their binding.
|
|
3049
|
+
*
|
|
3050
|
+
* ✅ Correct:
|
|
3051
|
+
* @click=${() => this.myMethod()}
|
|
3052
|
+
* @click=${(e) => this.handleClick(e)}
|
|
3053
|
+
*
|
|
3054
|
+
* ❌ Wrong (this will be bound to the toolbar, not your component):
|
|
3055
|
+
* @click=${this.myMethod}
|
|
3056
|
+
*
|
|
3057
|
+
* Example:
|
|
3058
|
+
* ```typescript
|
|
3059
|
+
* protected renderToolbar() {
|
|
3060
|
+
* return html`
|
|
3061
|
+
* <wa-button @click=${() => this.save()} title="Save">
|
|
3062
|
+
* <wa-icon name="save"></wa-icon>
|
|
3063
|
+
* </wa-button>
|
|
3064
|
+
* `;
|
|
3065
|
+
* }
|
|
3066
|
+
* ```
|
|
3067
|
+
*
|
|
3068
|
+
* @returns TemplateResult with toolbar items, or nothing if no toolbar needed
|
|
3069
|
+
*/
|
|
3070
|
+
renderToolbar() {
|
|
3071
|
+
return nothing;
|
|
3072
|
+
}
|
|
3073
|
+
/**
|
|
3074
|
+
* Activates the tab that contains this part by walking up the DOM to the first
|
|
3075
|
+
* docks-tabs ancestor and activating the tab panel that contains this part.
|
|
3076
|
+
* Crosses Shadow DOM boundaries (e.g. wa-tab-group) via getRootNode().host.
|
|
3077
|
+
* No-op if this part is not inside a docks-tabs / wa-tab-panel.
|
|
3078
|
+
*/
|
|
3079
|
+
activateContainingTab() {
|
|
3080
|
+
let el = this;
|
|
3081
|
+
let panelName = null;
|
|
3082
|
+
let tabsEl = null;
|
|
3083
|
+
while (el) {
|
|
3084
|
+
const tag = el.tagName?.toLowerCase();
|
|
3085
|
+
if (tag === "wa-tab-panel") panelName = el.getAttribute("name");
|
|
3086
|
+
if (tag === "docks-tabs") {
|
|
3087
|
+
tabsEl = el;
|
|
3088
|
+
break;
|
|
3089
|
+
}
|
|
3090
|
+
const parent = el.parentElement;
|
|
3091
|
+
if (parent) el = parent;
|
|
3092
|
+
else {
|
|
3093
|
+
const root = el.getRootNode();
|
|
3094
|
+
el = root instanceof ShadowRoot ? root.host : null;
|
|
3095
|
+
}
|
|
3018
3096
|
}
|
|
3097
|
+
if (tabsEl && panelName != null && panelName !== "") tabsEl.activate(panelName);
|
|
3098
|
+
}
|
|
3099
|
+
/**
|
|
3100
|
+
* Override this method to provide context menu content for this part.
|
|
3101
|
+
* This is a lightweight alternative to registering context menu contributions
|
|
3102
|
+
* for actions that are scoped to this part instance.
|
|
3103
|
+
*
|
|
3104
|
+
* IMPORTANT: Event handlers MUST use arrow functions to preserve the component's 'this' context.
|
|
3105
|
+
* The context menu is rendered in a different component (contextmenu), so direct method
|
|
3106
|
+
* references lose their binding.
|
|
3107
|
+
*
|
|
3108
|
+
* ✅ Correct:
|
|
3109
|
+
* @click=${() => this.myMethod()}
|
|
3110
|
+
* @click=${(e) => this.handleClick(e)}
|
|
3111
|
+
*
|
|
3112
|
+
* ❌ Wrong (this will be bound to the context menu, not your component):
|
|
3113
|
+
* @click=${this.myMethod}
|
|
3114
|
+
*
|
|
3115
|
+
* Example:
|
|
3116
|
+
* ```typescript
|
|
3117
|
+
* protected renderContextMenu() {
|
|
3118
|
+
* return html`
|
|
3119
|
+
* <wa-dropdown-item @click=${() => this.open()}>
|
|
3120
|
+
* <wa-icon name="folder-open"></wa-icon>
|
|
3121
|
+
* Open
|
|
3122
|
+
* </wa-dropdown-item>
|
|
3123
|
+
* <wa-divider></wa-divider>
|
|
3124
|
+
* <wa-dropdown-item @click=${() => this.delete()}>
|
|
3125
|
+
* <wa-icon name="trash"></wa-icon>
|
|
3126
|
+
* Delete
|
|
3127
|
+
* </wa-dropdown-item>
|
|
3128
|
+
* `;
|
|
3129
|
+
* }
|
|
3130
|
+
* ```
|
|
3131
|
+
*
|
|
3132
|
+
* @returns TemplateResult with context menu items, or nothing if no context menu needed
|
|
3133
|
+
*/
|
|
3134
|
+
renderContextMenu() {
|
|
3135
|
+
return nothing;
|
|
3136
|
+
}
|
|
3137
|
+
renderContent() {
|
|
3138
|
+
return nothing;
|
|
3139
|
+
}
|
|
3140
|
+
/** Part-level toolbar contributions (`toolbar:${partId}`). */
|
|
3141
|
+
getToolbarTarget() {
|
|
3142
|
+
const contributionKey = this.tabContribution?.editorId ?? this.id ?? this.tabContribution?.name;
|
|
3143
|
+
return contributionKey ? `toolbar:${contributionKey}` : void 0;
|
|
3144
|
+
}
|
|
3145
|
+
/** Part-level context-menu contributions (`contextmenu:${partId}`). */
|
|
3146
|
+
getContextMenuTarget() {
|
|
3147
|
+
const contributionKey = this.tabContribution?.editorId ?? this.id ?? this.tabContribution?.name;
|
|
3148
|
+
return contributionKey ? `contextmenu:${contributionKey}` : void 0;
|
|
3149
|
+
}
|
|
3150
|
+
syncIsEditorCapability() {
|
|
3151
|
+
const next = this.save !== DocksPart.prototype.save;
|
|
3152
|
+
if (next === this.isEditor) return;
|
|
3153
|
+
this.isEditor = next;
|
|
3154
|
+
}
|
|
3155
|
+
maybeActivateForCoupledEditors() {
|
|
3156
|
+
const coupled = this.tabContribution?.coupledEditors;
|
|
3157
|
+
if (!coupled?.length) return;
|
|
3158
|
+
const active = activeEditorSignal.get();
|
|
3159
|
+
if (!(active instanceof DocksPart)) return;
|
|
3160
|
+
const editorId = active.tabContribution?.editorId;
|
|
3161
|
+
if (!editorId || !coupled.includes(editorId)) return;
|
|
3162
|
+
this.activateContainingTab();
|
|
3019
3163
|
}
|
|
3020
3164
|
render() {
|
|
3021
|
-
const
|
|
3165
|
+
const toolbarTarget = this.getToolbarTarget();
|
|
3166
|
+
const contextMenuTarget = this.getContextMenuTarget();
|
|
3167
|
+
const toolbarEnabled = this.tabContribution?.toolbar !== false;
|
|
3168
|
+
const contextMenuEnabled = this.tabContribution?.contextMenu !== false;
|
|
3169
|
+
const scrollMode = this.scrollMode;
|
|
3170
|
+
const scopeTokens = this.isEditor ? ["system.editors", ".system.editors"] : [];
|
|
3171
|
+
const content = this.renderContent();
|
|
3172
|
+
const contentNode = scrollMode === "scroller" ? html`
|
|
3173
|
+
<wa-scroller class="part-content-scroll" orientation="vertical">
|
|
3174
|
+
<div class="part-content-inner">${content}</div>
|
|
3175
|
+
</wa-scroller>
|
|
3176
|
+
` : html`<div class="part-content-inner">${content}</div>`;
|
|
3022
3177
|
return html`
|
|
3023
|
-
<div class="
|
|
3024
|
-
${
|
|
3025
|
-
|
|
3178
|
+
<div class="part-shell">
|
|
3179
|
+
${toolbarEnabled ? html`
|
|
3180
|
+
<docks-toolbar
|
|
3181
|
+
class="part-toolbar"
|
|
3182
|
+
id=${ifDefined(toolbarTarget)}
|
|
3183
|
+
.scopeTokens=${scopeTokens}
|
|
3184
|
+
.partToolbarRenderer=${() => this.renderToolbar()}>
|
|
3185
|
+
</docks-toolbar>
|
|
3186
|
+
` : nothing}
|
|
3187
|
+
<div class="part-content ${scrollMode === "native" ? "native-scroll" : ""}" @contextmenu=${contextMenuEnabled ? this.onContentContextMenu : void 0}>
|
|
3188
|
+
${contentNode}
|
|
3189
|
+
</div>
|
|
3190
|
+
${contextMenuEnabled ? html`
|
|
3191
|
+
<docks-contextmenu
|
|
3192
|
+
id=${ifDefined(contextMenuTarget)}
|
|
3193
|
+
.scopeTokens=${scopeTokens}
|
|
3194
|
+
.partContextMenuRenderer=${() => this.renderContextMenu()}>
|
|
3195
|
+
</docks-contextmenu>
|
|
3196
|
+
` : nothing}
|
|
3026
3197
|
</div>
|
|
3027
3198
|
`;
|
|
3028
3199
|
}
|
|
3029
|
-
|
|
3030
|
-
|
|
3031
|
-
|
|
3032
|
-
|
|
3033
|
-
|
|
3034
|
-
|
|
3035
|
-
|
|
3036
|
-
|
|
3037
|
-
});
|
|
3038
|
-
|
|
3039
|
-
|
|
3040
|
-
|
|
3041
|
-
|
|
3042
|
-
|
|
3043
|
-
|
|
3044
|
-
|
|
3045
|
-
|
|
3046
|
-
|
|
3047
|
-
|
|
3048
|
-
|
|
3049
|
-
|
|
3050
|
-
|
|
3051
|
-
|
|
3052
|
-
|
|
3053
|
-
|
|
3054
|
-
|
|
3055
|
-
|
|
3056
|
-
|
|
3057
|
-
|
|
3058
|
-
|
|
3059
|
-
|
|
3060
|
-
|
|
3061
|
-
|
|
3062
|
-
|
|
3063
|
-
}
|
|
3064
|
-
|
|
3200
|
+
updated(_changedProperties) {
|
|
3201
|
+
super.updated(_changedProperties);
|
|
3202
|
+
this.syncIsEditorCapability();
|
|
3203
|
+
if (_changedProperties.has("tabContribution")) this.maybeActivateForCoupledEditors();
|
|
3204
|
+
if (_changedProperties.has("dirty")) {
|
|
3205
|
+
if (_changedProperties.get("dirty") !== void 0) this.dispatchEvent(new CustomEvent("dirty", {
|
|
3206
|
+
detail: this.dirty,
|
|
3207
|
+
bubbles: true
|
|
3208
|
+
}));
|
|
3209
|
+
}
|
|
3210
|
+
}
|
|
3211
|
+
doClose() {}
|
|
3212
|
+
disconnectedCallback() {
|
|
3213
|
+
super.disconnectedCallback();
|
|
3214
|
+
}
|
|
3215
|
+
close() {
|
|
3216
|
+
this.doClose();
|
|
3217
|
+
}
|
|
3218
|
+
connectedCallback() {
|
|
3219
|
+
super.connectedCallback();
|
|
3220
|
+
this.syncIsEditorCapability();
|
|
3221
|
+
queueMicrotask(() => this.syncIsEditorCapability());
|
|
3222
|
+
this.watch(activeEditorSignal, () => this.maybeActivateForCoupledEditors());
|
|
3223
|
+
}
|
|
3224
|
+
save() {}
|
|
3225
|
+
isDirty() {
|
|
3226
|
+
return this.dirty;
|
|
3227
|
+
}
|
|
3228
|
+
markDirty(dirty) {
|
|
3229
|
+
this.dirty = dirty;
|
|
3230
|
+
partDirtySignal.set(null);
|
|
3231
|
+
partDirtySignal.set(this);
|
|
3232
|
+
activePartSignal.set(null);
|
|
3233
|
+
activePartSignal.set(this);
|
|
3234
|
+
}
|
|
3235
|
+
static {
|
|
3236
|
+
this.baseStyles = css`
|
|
3237
|
+
:host {
|
|
3238
|
+
display: block;
|
|
3239
|
+
}
|
|
3240
|
+
|
|
3241
|
+
.part-shell {
|
|
3242
|
+
display: grid;
|
|
3243
|
+
grid-template-rows: auto minmax(0, 1fr);
|
|
3244
|
+
height: 100%;
|
|
3245
|
+
width: 100%;
|
|
3246
|
+
position: relative;
|
|
3247
|
+
overflow: hidden;
|
|
3248
|
+
}
|
|
3249
|
+
|
|
3250
|
+
.part-content {
|
|
3251
|
+
min-height: 0;
|
|
3252
|
+
overflow: hidden;
|
|
3253
|
+
position: relative;
|
|
3254
|
+
}
|
|
3255
|
+
|
|
3256
|
+
.part-content.native-scroll {
|
|
3257
|
+
overflow: auto;
|
|
3258
|
+
}
|
|
3259
|
+
|
|
3260
|
+
.part-content-scroll {
|
|
3261
|
+
width: 100%;
|
|
3262
|
+
height: 100%;
|
|
3263
|
+
}
|
|
3264
|
+
|
|
3265
|
+
.part-content-inner {
|
|
3266
|
+
height: 100%;
|
|
3267
|
+
min-height: 100%;
|
|
3268
|
+
}
|
|
3269
|
+
|
|
3270
|
+
:host([embedded]) {
|
|
3271
|
+
height: auto;
|
|
3272
|
+
}
|
|
3273
|
+
|
|
3274
|
+
:host([embedded]) .part-shell {
|
|
3275
|
+
height: auto;
|
|
3276
|
+
overflow: visible;
|
|
3277
|
+
grid-template-rows: auto;
|
|
3278
|
+
}
|
|
3279
|
+
|
|
3280
|
+
:host([embedded]) .part-content {
|
|
3281
|
+
overflow: visible;
|
|
3282
|
+
min-height: 0;
|
|
3283
|
+
}
|
|
3284
|
+
|
|
3285
|
+
:host([embedded]) .part-content-inner {
|
|
3286
|
+
height: auto;
|
|
3287
|
+
min-height: 0;
|
|
3288
|
+
}
|
|
3289
|
+
|
|
3290
|
+
.part-toolbar {
|
|
3291
|
+
min-height: 0;
|
|
3292
|
+
}
|
|
3293
|
+
`;
|
|
3294
|
+
}
|
|
3295
|
+
static finalizeStyles(styles) {
|
|
3296
|
+
const own = super.finalizeStyles(styles);
|
|
3297
|
+
return [DocksPart.baseStyles, ...own];
|
|
3298
|
+
}
|
|
3299
|
+
};
|
|
3300
|
+
_decorate([property()], DocksPart.prototype, "dirty", void 0);
|
|
3301
|
+
_decorate([property({ attribute: false })], DocksPart.prototype, "tabContribution", void 0);
|
|
3302
|
+
_decorate([property({
|
|
3303
|
+
type: Boolean,
|
|
3304
|
+
attribute: false
|
|
3305
|
+
})], DocksPart.prototype, "isEditor", void 0);
|
|
3306
|
+
_decorate([property({
|
|
3307
|
+
type: Boolean,
|
|
3308
|
+
reflect: true
|
|
3309
|
+
})], DocksPart.prototype, "embedded", void 0);
|
|
3310
|
+
//#endregion
|
|
3311
|
+
//#region src/components/release-history.ts
|
|
3312
|
+
var logger = createLogger("ReleaseHistory");
|
|
3313
|
+
async function loadReleases(releaseHistory) {
|
|
3314
|
+
if (!releaseHistory) return [];
|
|
3315
|
+
if (typeof releaseHistory !== "function") return releaseHistory;
|
|
3316
|
+
try {
|
|
3317
|
+
return await releaseHistory();
|
|
3318
|
+
} catch (error) {
|
|
3319
|
+
logger.error(`Failed to load release history from app: ${error instanceof Error ? error.message : String(error)}`);
|
|
3320
|
+
return [];
|
|
3321
|
+
}
|
|
3322
|
+
}
|
|
3323
|
+
function semverEqual(a, b) {
|
|
3324
|
+
return a.replace(/^v/i, "") === b.replace(/^v/i, "");
|
|
3325
|
+
}
|
|
3326
|
+
function isNewerThan(releaseTag, currentVersion) {
|
|
3327
|
+
const currentParts = currentVersion.replace(/^v/i, "").split(".").map(Number);
|
|
3328
|
+
const releaseParts = releaseTag.replace(/^v/i, "").split(".").map(Number);
|
|
3329
|
+
for (let i = 0; i < Math.max(currentParts.length, releaseParts.length); i++) {
|
|
3330
|
+
const current = currentParts[i] || 0;
|
|
3331
|
+
const releasePart = releaseParts[i] || 0;
|
|
3332
|
+
if (releasePart > current) return true;
|
|
3333
|
+
if (releasePart < current) return false;
|
|
3334
|
+
}
|
|
3335
|
+
return false;
|
|
3336
|
+
}
|
|
3337
|
+
var DocksReleaseHistory = class DocksReleaseHistory extends DocksPart {
|
|
3338
|
+
constructor(..._args) {
|
|
3339
|
+
super(..._args);
|
|
3340
|
+
this.scrollMode = "none";
|
|
3341
|
+
this.appVersion = "0.0.0";
|
|
3342
|
+
this.releases = [];
|
|
3343
|
+
this.currentReleaseIndex = 0;
|
|
3344
|
+
}
|
|
3345
|
+
static {
|
|
3346
|
+
this.styles = [css`
|
|
3347
|
+
.release-panel {
|
|
3348
|
+
display: flex;
|
|
3349
|
+
flex-direction: column;
|
|
3350
|
+
gap: 0.5rem;
|
|
3351
|
+
padding: 0.75rem;
|
|
3352
|
+
box-sizing: border-box;
|
|
3353
|
+
}
|
|
3354
|
+
|
|
3355
|
+
.release-body {
|
|
3356
|
+
white-space: normal;
|
|
3357
|
+
}
|
|
3358
|
+
`];
|
|
3359
|
+
}
|
|
3360
|
+
doInitUI() {
|
|
3361
|
+
this.load();
|
|
3362
|
+
}
|
|
3363
|
+
async load() {
|
|
3364
|
+
const app = appLoaderService.getCurrentApp();
|
|
3365
|
+
this.appVersion = app?.version ?? "0.0.0";
|
|
3366
|
+
this.releases = await loadReleases(app?.releaseHistory);
|
|
3367
|
+
const currentIndex = this.releases.findIndex((release) => semverEqual(release.tag_name, this.appVersion));
|
|
3368
|
+
this.currentReleaseIndex = currentIndex >= 0 ? currentIndex : 0;
|
|
3369
|
+
this.notifyChanged();
|
|
3370
|
+
}
|
|
3371
|
+
getNavState() {
|
|
3372
|
+
return {
|
|
3373
|
+
hasMultiple: this.releases.length > 1,
|
|
3374
|
+
atOldest: this.currentReleaseIndex >= this.releases.length - 1,
|
|
3375
|
+
atNewest: this.currentReleaseIndex <= 0
|
|
3376
|
+
};
|
|
3377
|
+
}
|
|
3378
|
+
showOlder() {
|
|
3379
|
+
if (this.currentReleaseIndex < this.releases.length - 1) {
|
|
3380
|
+
this.currentReleaseIndex += 1;
|
|
3381
|
+
this.notifyChanged();
|
|
3382
|
+
}
|
|
3383
|
+
}
|
|
3384
|
+
showNewer() {
|
|
3385
|
+
if (this.currentReleaseIndex > 0) {
|
|
3386
|
+
this.currentReleaseIndex -= 1;
|
|
3387
|
+
this.notifyChanged();
|
|
3388
|
+
}
|
|
3389
|
+
}
|
|
3390
|
+
notifyChanged() {
|
|
3391
|
+
this.dispatchEvent(new CustomEvent("release-history-changed", {
|
|
3392
|
+
bubbles: true,
|
|
3393
|
+
composed: true
|
|
3394
|
+
}));
|
|
3395
|
+
}
|
|
3396
|
+
renderContent() {
|
|
3397
|
+
const release = this.releases[this.currentReleaseIndex];
|
|
3398
|
+
if (!release) return html`<div class="release-panel">No release history available.</div>`;
|
|
3399
|
+
const isCurrent = semverEqual(release.tag_name, this.appVersion);
|
|
3400
|
+
const showUpdateHint = !isCurrent && isNewerThan(release.tag_name, this.appVersion);
|
|
3401
|
+
const bodyHtml = release.body ? parseMarkdownHtml(release.body) : "";
|
|
3402
|
+
return html`
|
|
3403
|
+
<div class="release-panel">
|
|
3404
|
+
<p>
|
|
3405
|
+
<strong>Version:</strong> ${release.tag_name}${isCurrent ? " (Current)" : ""}
|
|
3406
|
+
</p>
|
|
3407
|
+
<p>
|
|
3408
|
+
<strong>Released:</strong>
|
|
3409
|
+
<wa-format-date
|
|
3410
|
+
.date=${release.published_at}
|
|
3411
|
+
month="short"
|
|
3412
|
+
day="numeric"
|
|
3413
|
+
year="numeric"
|
|
3414
|
+
></wa-format-date>
|
|
3415
|
+
</p>
|
|
3416
|
+
${showUpdateHint ? html`
|
|
3417
|
+
<wa-callout variant="warning">
|
|
3418
|
+
<wa-icon slot="icon" name="triangle-exclamation"></wa-icon>
|
|
3419
|
+
A newer release is available than the version you are running.
|
|
3420
|
+
Use <strong>Update Available</strong> in the toolbar when it appears.
|
|
3421
|
+
</wa-callout>
|
|
3422
|
+
` : ""}
|
|
3423
|
+
${bodyHtml ? html`<div class="release-body">${unsafeHTML(bodyHtml)}</div>` : ""}
|
|
3424
|
+
</div>
|
|
3425
|
+
`;
|
|
3426
|
+
}
|
|
3427
|
+
};
|
|
3428
|
+
_decorate([state()], DocksReleaseHistory.prototype, "appVersion", void 0);
|
|
3429
|
+
_decorate([state()], DocksReleaseHistory.prototype, "releases", void 0);
|
|
3430
|
+
_decorate([state()], DocksReleaseHistory.prototype, "currentReleaseIndex", void 0);
|
|
3431
|
+
DocksReleaseHistory = _decorate([customElement("docks-release-history")], DocksReleaseHistory);
|
|
3432
|
+
//#endregion
|
|
3433
|
+
//#region src/dialogs/version-info-dialog.ts
|
|
3434
|
+
var EMPTY_NAV = {
|
|
3435
|
+
hasMultiple: false,
|
|
3436
|
+
atOldest: true,
|
|
3437
|
+
atNewest: true
|
|
3438
|
+
};
|
|
3439
|
+
var DocksVersionInfoDialog = class DocksVersionInfoDialog extends DocksDialogContent {
|
|
3440
|
+
constructor(..._args) {
|
|
3441
|
+
super(..._args);
|
|
3442
|
+
this.label = "";
|
|
3443
|
+
this.activeTab = null;
|
|
3444
|
+
this.releaseNav = EMPTY_NAV;
|
|
3445
|
+
this.onReleaseHistoryChanged = () => {
|
|
3446
|
+
this.syncReleaseNav();
|
|
3447
|
+
};
|
|
3448
|
+
}
|
|
3449
|
+
static {
|
|
3450
|
+
this.styles = [...DocksDialogContent.styles, css`
|
|
3451
|
+
:host {
|
|
3452
|
+
display: block;
|
|
3453
|
+
}
|
|
3454
|
+
|
|
3455
|
+
wa-dialog {
|
|
3456
|
+
--width: 600px;
|
|
3457
|
+
}
|
|
3458
|
+
|
|
3459
|
+
wa-dialog::part(body) {
|
|
3460
|
+
display: flex;
|
|
3461
|
+
flex-direction: column;
|
|
3462
|
+
min-height: 0;
|
|
3463
|
+
overflow: hidden;
|
|
3464
|
+
}
|
|
3465
|
+
|
|
3466
|
+
.dialog-body {
|
|
3467
|
+
display: flex;
|
|
3468
|
+
flex-direction: column;
|
|
3469
|
+
gap: 0.75rem;
|
|
3470
|
+
min-width: 32rem;
|
|
3471
|
+
height: min(70vh, 36rem);
|
|
3472
|
+
min-height: min(70vh, 36rem);
|
|
3473
|
+
overflow: hidden;
|
|
3474
|
+
}
|
|
3475
|
+
|
|
3476
|
+
.dialog-body docks-tabs {
|
|
3477
|
+
flex: 1 1 auto;
|
|
3478
|
+
min-height: 0;
|
|
3479
|
+
overflow: hidden;
|
|
3480
|
+
}
|
|
3481
|
+
|
|
3482
|
+
.dialog-footer {
|
|
3483
|
+
display: flex;
|
|
3484
|
+
gap: 0.5rem;
|
|
3485
|
+
justify-content: flex-end;
|
|
3486
|
+
width: 100%;
|
|
3487
|
+
}
|
|
3488
|
+
`];
|
|
3489
|
+
}
|
|
3490
|
+
firstUpdated(changed) {
|
|
3491
|
+
super.firstUpdated(changed);
|
|
3492
|
+
this.addEventListener("release-history-changed", this.onReleaseHistoryChanged);
|
|
3493
|
+
this.updateComplete.then(() => {
|
|
3494
|
+
this.attachTabListener();
|
|
3495
|
+
this.syncActiveTab();
|
|
3496
|
+
this.syncReleaseNav();
|
|
3497
|
+
});
|
|
3498
|
+
}
|
|
3499
|
+
disconnectedCallback() {
|
|
3500
|
+
this.removeEventListener("release-history-changed", this.onReleaseHistoryChanged);
|
|
3501
|
+
super.disconnectedCallback();
|
|
3502
|
+
}
|
|
3503
|
+
attachTabListener() {
|
|
3504
|
+
const tabGroup = this.getAboutTabs()?.shadowRoot?.querySelector("wa-tab-group");
|
|
3505
|
+
if (!tabGroup || tabGroup.hasAttribute("data-version-info-listener")) return;
|
|
3506
|
+
tabGroup.setAttribute("data-version-info-listener", "");
|
|
3507
|
+
tabGroup.addEventListener("wa-tab-show", (event) => {
|
|
3508
|
+
const name = event.detail?.name;
|
|
3509
|
+
if (name) this.activeTab = name;
|
|
3510
|
+
});
|
|
3511
|
+
}
|
|
3512
|
+
getAboutTabs() {
|
|
3513
|
+
return this.renderRoot.querySelector("docks-tabs");
|
|
3514
|
+
}
|
|
3515
|
+
getReleaseHistory() {
|
|
3516
|
+
const part = this.getAboutTabs()?.getTabPart(ABOUT_TAB_RELEASE);
|
|
3517
|
+
return part instanceof DocksReleaseHistory ? part : null;
|
|
3518
|
+
}
|
|
3519
|
+
syncActiveTab() {
|
|
3520
|
+
const tabGroup = this.getAboutTabs()?.shadowRoot?.querySelector("wa-tab-group");
|
|
3521
|
+
this.activeTab = tabGroup?.getAttribute("active") || tabGroup?.active || null;
|
|
3522
|
+
}
|
|
3523
|
+
syncReleaseNav() {
|
|
3524
|
+
this.releaseNav = this.getReleaseHistory()?.getNavState() ?? EMPTY_NAV;
|
|
3525
|
+
}
|
|
3526
|
+
handleClose() {
|
|
3527
|
+
const dialog = this.renderRoot.querySelector("wa-dialog");
|
|
3528
|
+
if (dialog && dialog.open !== false) {
|
|
3529
|
+
dialog.open = false;
|
|
3530
|
+
return;
|
|
3531
|
+
}
|
|
3532
|
+
this.close?.();
|
|
3533
|
+
}
|
|
3534
|
+
handleAfterHide() {
|
|
3535
|
+
this.onAfterHide?.();
|
|
3536
|
+
}
|
|
3537
|
+
showOlderRelease() {
|
|
3538
|
+
this.getReleaseHistory()?.showOlder();
|
|
3539
|
+
}
|
|
3540
|
+
showNewerRelease() {
|
|
3541
|
+
this.getReleaseHistory()?.showNewer();
|
|
3542
|
+
}
|
|
3543
|
+
render() {
|
|
3544
|
+
const app = appLoaderService.getCurrentApp();
|
|
3545
|
+
const showReleaseNav = this.activeTab === "about.tab.release" && this.releaseNav.hasMultiple;
|
|
3546
|
+
return html`
|
|
3547
|
+
<wa-dialog
|
|
3548
|
+
label=${this.label}
|
|
3549
|
+
open
|
|
3550
|
+
light-dismiss
|
|
3551
|
+
with-footer
|
|
3552
|
+
@wa-after-hide=${this.handleAfterHide}
|
|
3553
|
+
>
|
|
3554
|
+
<div class="dialog-body">
|
|
3555
|
+
${app?.description ? html`<small>${app.description}</small>` : ""}
|
|
3556
|
+
<docks-tabs id=${ABOUT_TABS} fill-height></docks-tabs>
|
|
3557
|
+
</div>
|
|
3558
|
+
<div slot="footer" class="dialog-footer">
|
|
3559
|
+
${showReleaseNav ? html`
|
|
3560
|
+
<wa-button
|
|
3561
|
+
variant="default"
|
|
3562
|
+
?disabled=${this.releaseNav.atOldest}
|
|
3563
|
+
@click=${this.showOlderRelease}
|
|
3564
|
+
>
|
|
3565
|
+
← Previous
|
|
3566
|
+
</wa-button>
|
|
3567
|
+
<wa-button
|
|
3568
|
+
variant="default"
|
|
3569
|
+
?disabled=${this.releaseNav.atNewest}
|
|
3570
|
+
@click=${this.showNewerRelease}
|
|
3571
|
+
>
|
|
3572
|
+
Next →
|
|
3573
|
+
</wa-button>
|
|
3574
|
+
` : nothing}
|
|
3575
|
+
<wa-button variant="primary" @click=${this.handleClose}>Close</wa-button>
|
|
3576
|
+
</div>
|
|
3577
|
+
</wa-dialog>
|
|
3578
|
+
`;
|
|
3579
|
+
}
|
|
3580
|
+
};
|
|
3581
|
+
_decorate([property({ type: String })], DocksVersionInfoDialog.prototype, "label", void 0);
|
|
3582
|
+
_decorate([property({ attribute: false })], DocksVersionInfoDialog.prototype, "close", void 0);
|
|
3583
|
+
_decorate([property({ attribute: false })], DocksVersionInfoDialog.prototype, "onAfterHide", void 0);
|
|
3584
|
+
_decorate([state()], DocksVersionInfoDialog.prototype, "activeTab", void 0);
|
|
3585
|
+
_decorate([state()], DocksVersionInfoDialog.prototype, "releaseNav", void 0);
|
|
3586
|
+
DocksVersionInfoDialog = _decorate([customElement("docks-version-info-dialog")], DocksVersionInfoDialog);
|
|
3587
|
+
contributionRegistry.registerContribution(DIALOG_CONTRIBUTION_TARGET, {
|
|
3588
|
+
id: "version-info",
|
|
3589
|
+
label: "About",
|
|
3590
|
+
selfContained: true,
|
|
3591
|
+
component: (state) => html`
|
|
3592
|
+
<docks-version-info-dialog
|
|
3593
|
+
.label=${state?.label ?? ""}
|
|
3594
|
+
.close=${state?.close}
|
|
3595
|
+
.onAfterHide=${state?.onAfterHide}
|
|
3596
|
+
></docks-version-info-dialog>
|
|
3597
|
+
`
|
|
3598
|
+
});
|
|
3599
|
+
function versionInfoDialog() {
|
|
3600
|
+
const app = appLoaderService.getCurrentApp();
|
|
3601
|
+
return dialogService.open("version-info", { label: `About ${app?.name ?? ""} - ${app?.version ?? "0.0.0"}` });
|
|
3602
|
+
}
|
|
3603
|
+
//#endregion
|
|
3604
|
+
//#region src/core/dropdown-menu-utils.ts
|
|
3605
|
+
function isOpenDropdown(element) {
|
|
3606
|
+
if (element.localName !== "wa-dropdown") return false;
|
|
3607
|
+
const dropdown = element;
|
|
3608
|
+
return dropdown.open === true || dropdown.hasAttribute("open");
|
|
3609
|
+
}
|
|
3610
|
+
function elementsFromEventPath(event) {
|
|
3611
|
+
const fromComposedPath = event.composedPath().filter((node) => node instanceof Element);
|
|
3612
|
+
if (fromComposedPath.length > 0) return fromComposedPath;
|
|
3613
|
+
if (!(event.target instanceof Element)) return [];
|
|
3614
|
+
const path = [];
|
|
3615
|
+
let current = event.target;
|
|
3616
|
+
while (current) {
|
|
3617
|
+
path.push(current);
|
|
3618
|
+
const root = current.getRootNode();
|
|
3619
|
+
if (root instanceof ShadowRoot) {
|
|
3620
|
+
current = root.host;
|
|
3621
|
+
continue;
|
|
3622
|
+
}
|
|
3623
|
+
current = current.parentElement;
|
|
3624
|
+
}
|
|
3625
|
+
return path;
|
|
3065
3626
|
}
|
|
3066
3627
|
function elementTargetsOpenDropdown(element) {
|
|
3067
3628
|
if (isOpenDropdown(element)) return true;
|
|
@@ -3358,21 +3919,36 @@ DocksToolbar = _decorate([customElement("docks-toolbar")], DocksToolbar);
|
|
|
3358
3919
|
* A part can expose both surfaces with the same part id but different prefixes, registering
|
|
3359
3920
|
* different contributions on each. Feature-scoped targets (e.g. `filebrowser.create`) may also
|
|
3360
3921
|
* be referenced explicitly from either surface when several controls share the same item set.
|
|
3922
|
+
*
|
|
3923
|
+
* Command-backed items rely on the parent {@link https://webawesome.com/docs/components/dropdown | wa-dropdown}
|
|
3924
|
+
* `wa-select` event (see {@link handleDropdownWaSelect}) so the popup closes cleanly before
|
|
3925
|
+
* native dialogs such as `showDirectoryPicker` open.
|
|
3361
3926
|
*/
|
|
3362
|
-
function
|
|
3363
|
-
const
|
|
3364
|
-
if (
|
|
3927
|
+
function parseDropdownItemParams(item) {
|
|
3928
|
+
const raw = item.getAttribute("data-params");
|
|
3929
|
+
if (!raw) return {};
|
|
3930
|
+
try {
|
|
3931
|
+
return JSON.parse(raw);
|
|
3932
|
+
} catch {
|
|
3933
|
+
return {};
|
|
3934
|
+
}
|
|
3935
|
+
}
|
|
3936
|
+
function getDropdownItemCommand(item) {
|
|
3937
|
+
return item.getAttribute("data-cmd") || item.getAttribute("value") || void 0;
|
|
3938
|
+
}
|
|
3939
|
+
/** Handles `wa-select` from a parent `wa-dropdown` and runs the backing command. */
|
|
3940
|
+
function handleDropdownWaSelect(event) {
|
|
3941
|
+
const item = event.detail?.item;
|
|
3942
|
+
if (!item || item.disabled || item.hasAttribute("disabled")) return;
|
|
3943
|
+
const cmd = getDropdownItemCommand(item);
|
|
3944
|
+
if (!cmd) return;
|
|
3945
|
+
commandRegistry.execute(cmd, commandRegistry.createExecutionContext(parseDropdownItemParams(item)));
|
|
3365
3946
|
}
|
|
3366
|
-
function
|
|
3947
|
+
function onDropdownActionClick(options) {
|
|
3367
3948
|
return (event) => {
|
|
3368
3949
|
if (readReactiveBoolean(options.disabled, false)) return;
|
|
3369
3950
|
event.stopPropagation();
|
|
3370
|
-
|
|
3371
|
-
if (options.action) {
|
|
3372
|
-
options.action(event);
|
|
3373
|
-
return;
|
|
3374
|
-
}
|
|
3375
|
-
if (options.cmd) commandRegistry.execute(options.cmd, commandRegistry.createExecutionContext(options.params ?? {}));
|
|
3951
|
+
options.action?.(event);
|
|
3376
3952
|
};
|
|
3377
3953
|
}
|
|
3378
3954
|
function keybindingDetails(cmd) {
|
|
@@ -3384,12 +3960,16 @@ function keybindingDetails(cmd) {
|
|
|
3384
3960
|
/** Renders a native {@link https://webawesome.com/docs/components/dropdown-item | wa-dropdown-item}. */
|
|
3385
3961
|
function renderDropdownItem(options) {
|
|
3386
3962
|
const iconSpec = options.icon ?? "";
|
|
3963
|
+
const paramsJson = options.params && Object.keys(options.params).length > 0 ? JSON.stringify(options.params) : void 0;
|
|
3387
3964
|
return html`
|
|
3388
3965
|
<wa-dropdown-item
|
|
3389
3966
|
slot=${options.slot ?? nothing}
|
|
3390
3967
|
variant=${options.variant ?? "default"}
|
|
3968
|
+
value=${options.cmd ?? nothing}
|
|
3969
|
+
data-cmd=${options.cmd ?? nothing}
|
|
3970
|
+
data-params=${paramsJson ?? nothing}
|
|
3391
3971
|
?disabled=${readReactiveBoolean(options.disabled, false)}
|
|
3392
|
-
@click=${
|
|
3972
|
+
@click=${options.action ? onDropdownActionClick(options) : nothing}>
|
|
3393
3973
|
${iconSpec ? icon(iconSpec, {
|
|
3394
3974
|
label: options.title ?? options.label,
|
|
3395
3975
|
slot: "icon"
|
|
@@ -3567,385 +4147,118 @@ var DocksContextMenu = class DocksContextMenu extends DocksElement {
|
|
|
3567
4147
|
}
|
|
3568
4148
|
return element;
|
|
3569
4149
|
}
|
|
3570
|
-
getHostPart() {
|
|
3571
|
-
const root = this.getRootNode();
|
|
3572
|
-
if (root instanceof ShadowRoot && root.host instanceof HTMLElement) return root.host;
|
|
3573
|
-
return null;
|
|
3574
|
-
}
|
|
3575
|
-
/**
|
|
3576
|
-
* Triggers a click on the element under the cursor to update selection before showing context menu.
|
|
3577
|
-
*/
|
|
3578
|
-
triggerClickUnderCursor(mouseEvent) {
|
|
3579
|
-
const elementUnderCursor = this.getElementFromPoint(mouseEvent.clientX, mouseEvent.clientY);
|
|
3580
|
-
if (elementUnderCursor) {
|
|
3581
|
-
const clickEvent = new MouseEvent("click", {
|
|
3582
|
-
bubbles: true,
|
|
3583
|
-
cancelable: true,
|
|
3584
|
-
view: window,
|
|
3585
|
-
clientX: mouseEvent.clientX,
|
|
3586
|
-
clientY: mouseEvent.clientY,
|
|
3587
|
-
screenX: mouseEvent.screenX,
|
|
3588
|
-
screenY: mouseEvent.screenY,
|
|
3589
|
-
button: 0,
|
|
3590
|
-
buttons: 0,
|
|
3591
|
-
detail: 1,
|
|
3592
|
-
which: 1
|
|
3593
|
-
});
|
|
3594
|
-
elementUnderCursor.dispatchEvent(clickEvent);
|
|
3595
|
-
}
|
|
3596
|
-
}
|
|
3597
|
-
/** Opens the menu at `position`. Returns false when there is nothing to show (no thin empty panel). */
|
|
3598
|
-
async show(position, mouseEvent) {
|
|
3599
|
-
if (!this.hasMenuBody()) return false;
|
|
3600
|
-
if (mouseEvent) {
|
|
3601
|
-
this.triggerClickUnderCursor(mouseEvent);
|
|
3602
|
-
await this.getHostPart()?.updateComplete;
|
|
3603
|
-
}
|
|
3604
|
-
if (this.isOpen) {
|
|
3605
|
-
this.isOpen = false;
|
|
3606
|
-
await this.updateComplete;
|
|
3607
|
-
}
|
|
3608
|
-
this.menuPosition = position;
|
|
3609
|
-
this.isOpen = true;
|
|
3610
|
-
await this.updateComplete;
|
|
3611
|
-
this.syncVirtualPopupAnchor();
|
|
3612
|
-
document.addEventListener("pointerdown", this.boundHandleDocumentPointerDown, { capture: true });
|
|
3613
|
-
return true;
|
|
3614
|
-
}
|
|
3615
|
-
/** Points wa-dropdown's internal wa-popup at the pointer via a VirtualElement anchor. */
|
|
3616
|
-
syncVirtualPopupAnchor() {
|
|
3617
|
-
const popup = this.dropdownRef.value?.shadowRoot?.querySelector("wa-popup");
|
|
3618
|
-
if (!popup) return;
|
|
3619
|
-
popup.anchor = this.virtualAnchor;
|
|
3620
|
-
popup.reposition();
|
|
3621
|
-
}
|
|
3622
|
-
onClose() {
|
|
3623
|
-
if (!this.isOpen) return;
|
|
3624
|
-
this.isOpen = false;
|
|
3625
|
-
document.removeEventListener("pointerdown", this.boundHandleDocumentPointerDown, { capture: true });
|
|
3626
|
-
}
|
|
3627
|
-
updated(changedProperties) {
|
|
3628
|
-
super.updated(changedProperties);
|
|
3629
|
-
if (changedProperties.has("isOpen") && this.isOpen) this.syncVirtualPopupAnchor();
|
|
3630
|
-
}
|
|
3631
|
-
renderContribution(contribution) {
|
|
3632
|
-
return renderDropdownContribution(contribution);
|
|
3633
|
-
}
|
|
3634
|
-
render() {
|
|
3635
|
-
const partContent = this.partContextMenuRenderer ? this.partContextMenuRenderer() : nothing;
|
|
3636
|
-
return html`
|
|
3637
|
-
<wa-dropdown
|
|
3638
|
-
${ref(this.dropdownRef)}
|
|
3639
|
-
?open=${this.isOpen}
|
|
3640
|
-
@submenu-opening=${this.handleSubmenuOpening}
|
|
3641
|
-
@wa-after-hide=${this.onClose}>
|
|
3642
|
-
<span slot="trigger" hidden aria-hidden="true"></span>
|
|
3643
|
-
|
|
3644
|
-
${partContent}
|
|
3645
|
-
${this.contributions.map((c) => this.renderContribution(c))}
|
|
3646
|
-
</wa-dropdown>
|
|
3647
|
-
`;
|
|
3648
|
-
}
|
|
3649
|
-
static {
|
|
3650
|
-
this.styles = css`
|
|
3651
|
-
:host {
|
|
3652
|
-
position: fixed;
|
|
3653
|
-
top: 0;
|
|
3654
|
-
left: 0;
|
|
3655
|
-
width: 0;
|
|
3656
|
-
height: 0;
|
|
3657
|
-
pointer-events: none;
|
|
3658
|
-
z-index: 10000;
|
|
3659
|
-
}
|
|
3660
|
-
|
|
3661
|
-
wa-dropdown {
|
|
3662
|
-
pointer-events: none;
|
|
3663
|
-
min-width: 200px;
|
|
3664
|
-
}
|
|
3665
|
-
|
|
3666
|
-
wa-dropdown:state(open) {
|
|
3667
|
-
pointer-events: auto;
|
|
3668
|
-
}
|
|
3669
|
-
|
|
3670
|
-
wa-dropdown::part(menu) {
|
|
3671
|
-
min-width: 200px;
|
|
3672
|
-
}
|
|
3673
|
-
`;
|
|
3674
|
-
}
|
|
3675
|
-
};
|
|
3676
|
-
_decorate([property({ attribute: false })], DocksContextMenu.prototype, "scopeTokens", void 0);
|
|
3677
|
-
_decorate([property({ attribute: false })], DocksContextMenu.prototype, "partContextMenuRenderer", void 0);
|
|
3678
|
-
_decorate([state()], DocksContextMenu.prototype, "contributions", void 0);
|
|
3679
|
-
_decorate([state()], DocksContextMenu.prototype, "isOpen", void 0);
|
|
3680
|
-
DocksContextMenu = _decorate([customElement("docks-contextmenu")], DocksContextMenu);
|
|
3681
|
-
//#endregion
|
|
3682
|
-
//#region src/parts/container.ts
|
|
3683
|
-
var DocksContainer = class extends DocksElement {};
|
|
3684
|
-
//#endregion
|
|
3685
|
-
//#region src/parts/part.ts
|
|
3686
|
-
var DocksPart = class DocksPart extends DocksContainer {
|
|
3687
|
-
constructor(..._args) {
|
|
3688
|
-
super(..._args);
|
|
3689
|
-
this.scrollMode = "scroller";
|
|
3690
|
-
this.dirty = false;
|
|
3691
|
-
this.isEditor = false;
|
|
3692
|
-
this.onContentContextMenu = async (event) => {
|
|
3693
|
-
const contextMenu = this.renderRoot.querySelector("docks-contextmenu");
|
|
3694
|
-
if (!contextMenu) return;
|
|
3695
|
-
if (await contextMenu.show({
|
|
3696
|
-
x: event.clientX,
|
|
3697
|
-
y: event.clientY
|
|
3698
|
-
}, event)) event.preventDefault();
|
|
3699
|
-
};
|
|
3700
|
-
}
|
|
3701
|
-
getCommandStack() {
|
|
3702
|
-
return this.commandStack;
|
|
3703
|
-
}
|
|
3704
|
-
/**
|
|
3705
|
-
* Override this method to provide toolbar content for this part.
|
|
3706
|
-
* This is a lightweight alternative to registering toolbar contributions
|
|
3707
|
-
* for actions that are scoped to this part instance.
|
|
3708
|
-
*
|
|
3709
|
-
* IMPORTANT: Event handlers MUST use arrow functions to preserve the component's 'this' context.
|
|
3710
|
-
* The toolbar template is rendered in a different component (docks-toolbar), so direct method
|
|
3711
|
-
* references lose their binding.
|
|
3712
|
-
*
|
|
3713
|
-
* ✅ Correct:
|
|
3714
|
-
* @click=${() => this.myMethod()}
|
|
3715
|
-
* @click=${(e) => this.handleClick(e)}
|
|
3716
|
-
*
|
|
3717
|
-
* ❌ Wrong (this will be bound to the toolbar, not your component):
|
|
3718
|
-
* @click=${this.myMethod}
|
|
3719
|
-
*
|
|
3720
|
-
* Example:
|
|
3721
|
-
* ```typescript
|
|
3722
|
-
* protected renderToolbar() {
|
|
3723
|
-
* return html`
|
|
3724
|
-
* <wa-button @click=${() => this.save()} title="Save">
|
|
3725
|
-
* <wa-icon name="save"></wa-icon>
|
|
3726
|
-
* </wa-button>
|
|
3727
|
-
* `;
|
|
3728
|
-
* }
|
|
3729
|
-
* ```
|
|
3730
|
-
*
|
|
3731
|
-
* @returns TemplateResult with toolbar items, or nothing if no toolbar needed
|
|
3732
|
-
*/
|
|
3733
|
-
renderToolbar() {
|
|
3734
|
-
return nothing;
|
|
3735
|
-
}
|
|
3736
|
-
/**
|
|
3737
|
-
* Activates the tab that contains this part by walking up the DOM to the first
|
|
3738
|
-
* docks-tabs ancestor and activating the tab panel that contains this part.
|
|
3739
|
-
* Crosses Shadow DOM boundaries (e.g. wa-tab-group) via getRootNode().host.
|
|
3740
|
-
* No-op if this part is not inside a docks-tabs / wa-tab-panel.
|
|
3741
|
-
*/
|
|
3742
|
-
activateContainingTab() {
|
|
3743
|
-
let el = this;
|
|
3744
|
-
let panelName = null;
|
|
3745
|
-
let tabsEl = null;
|
|
3746
|
-
while (el) {
|
|
3747
|
-
const tag = el.tagName?.toLowerCase();
|
|
3748
|
-
if (tag === "wa-tab-panel") panelName = el.getAttribute("name");
|
|
3749
|
-
if (tag === "docks-tabs") {
|
|
3750
|
-
tabsEl = el;
|
|
3751
|
-
break;
|
|
3752
|
-
}
|
|
3753
|
-
const parent = el.parentElement;
|
|
3754
|
-
if (parent) el = parent;
|
|
3755
|
-
else {
|
|
3756
|
-
const root = el.getRootNode();
|
|
3757
|
-
el = root instanceof ShadowRoot ? root.host : null;
|
|
3758
|
-
}
|
|
3759
|
-
}
|
|
3760
|
-
if (tabsEl && panelName != null && panelName !== "") tabsEl.activate(panelName);
|
|
3761
|
-
}
|
|
3762
|
-
/**
|
|
3763
|
-
* Override this method to provide context menu content for this part.
|
|
3764
|
-
* This is a lightweight alternative to registering context menu contributions
|
|
3765
|
-
* for actions that are scoped to this part instance.
|
|
3766
|
-
*
|
|
3767
|
-
* IMPORTANT: Event handlers MUST use arrow functions to preserve the component's 'this' context.
|
|
3768
|
-
* The context menu is rendered in a different component (contextmenu), so direct method
|
|
3769
|
-
* references lose their binding.
|
|
3770
|
-
*
|
|
3771
|
-
* ✅ Correct:
|
|
3772
|
-
* @click=${() => this.myMethod()}
|
|
3773
|
-
* @click=${(e) => this.handleClick(e)}
|
|
3774
|
-
*
|
|
3775
|
-
* ❌ Wrong (this will be bound to the context menu, not your component):
|
|
3776
|
-
* @click=${this.myMethod}
|
|
3777
|
-
*
|
|
3778
|
-
* Example:
|
|
3779
|
-
* ```typescript
|
|
3780
|
-
* protected renderContextMenu() {
|
|
3781
|
-
* return html`
|
|
3782
|
-
* <wa-dropdown-item @click=${() => this.open()}>
|
|
3783
|
-
* <wa-icon name="folder-open"></wa-icon>
|
|
3784
|
-
* Open
|
|
3785
|
-
* </wa-dropdown-item>
|
|
3786
|
-
* <wa-divider></wa-divider>
|
|
3787
|
-
* <wa-dropdown-item @click=${() => this.delete()}>
|
|
3788
|
-
* <wa-icon name="trash"></wa-icon>
|
|
3789
|
-
* Delete
|
|
3790
|
-
* </wa-dropdown-item>
|
|
3791
|
-
* `;
|
|
3792
|
-
* }
|
|
3793
|
-
* ```
|
|
3794
|
-
*
|
|
3795
|
-
* @returns TemplateResult with context menu items, or nothing if no context menu needed
|
|
3796
|
-
*/
|
|
3797
|
-
renderContextMenu() {
|
|
3798
|
-
return nothing;
|
|
3799
|
-
}
|
|
3800
|
-
renderContent() {
|
|
3801
|
-
return nothing;
|
|
3802
|
-
}
|
|
3803
|
-
/** Part-level toolbar contributions (`toolbar:${partId}`). */
|
|
3804
|
-
getToolbarTarget() {
|
|
3805
|
-
const contributionKey = this.tabContribution?.editorId ?? this.id ?? this.tabContribution?.name;
|
|
3806
|
-
return contributionKey ? `toolbar:${contributionKey}` : void 0;
|
|
3807
|
-
}
|
|
3808
|
-
/** Part-level context-menu contributions (`contextmenu:${partId}`). */
|
|
3809
|
-
getContextMenuTarget() {
|
|
3810
|
-
const contributionKey = this.tabContribution?.editorId ?? this.id ?? this.tabContribution?.name;
|
|
3811
|
-
return contributionKey ? `contextmenu:${contributionKey}` : void 0;
|
|
3812
|
-
}
|
|
3813
|
-
syncIsEditorCapability() {
|
|
3814
|
-
const next = this.save !== DocksPart.prototype.save;
|
|
3815
|
-
if (next === this.isEditor) return;
|
|
3816
|
-
this.isEditor = next;
|
|
3817
|
-
}
|
|
3818
|
-
maybeActivateForCoupledEditors() {
|
|
3819
|
-
const coupled = this.tabContribution?.coupledEditors;
|
|
3820
|
-
if (!coupled?.length) return;
|
|
3821
|
-
const active = activeEditorSignal.get();
|
|
3822
|
-
if (!(active instanceof DocksPart)) return;
|
|
3823
|
-
const editorId = active.tabContribution?.editorId;
|
|
3824
|
-
if (!editorId || !coupled.includes(editorId)) return;
|
|
3825
|
-
this.activateContainingTab();
|
|
3826
|
-
}
|
|
3827
|
-
render() {
|
|
3828
|
-
const toolbarTarget = this.getToolbarTarget();
|
|
3829
|
-
const contextMenuTarget = this.getContextMenuTarget();
|
|
3830
|
-
const toolbarEnabled = this.tabContribution?.toolbar !== false;
|
|
3831
|
-
const contextMenuEnabled = this.tabContribution?.contextMenu !== false;
|
|
3832
|
-
const scrollMode = this.scrollMode;
|
|
3833
|
-
const scopeTokens = this.isEditor ? ["system.editors", ".system.editors"] : [];
|
|
3834
|
-
const content = this.renderContent();
|
|
3835
|
-
const contentNode = scrollMode === "scroller" ? html`
|
|
3836
|
-
<wa-scroller class="part-content-scroll" orientation="vertical">
|
|
3837
|
-
<div class="part-content-inner">${content}</div>
|
|
3838
|
-
</wa-scroller>
|
|
3839
|
-
` : html`<div class="part-content-inner">${content}</div>`;
|
|
3840
|
-
return html`
|
|
3841
|
-
<div class="part-shell">
|
|
3842
|
-
${toolbarEnabled ? html`
|
|
3843
|
-
<docks-toolbar
|
|
3844
|
-
class="part-toolbar"
|
|
3845
|
-
id=${ifDefined(toolbarTarget)}
|
|
3846
|
-
.scopeTokens=${scopeTokens}
|
|
3847
|
-
.partToolbarRenderer=${() => this.renderToolbar()}>
|
|
3848
|
-
</docks-toolbar>
|
|
3849
|
-
` : nothing}
|
|
3850
|
-
<div class="part-content ${scrollMode === "native" ? "native-scroll" : ""}" @contextmenu=${contextMenuEnabled ? this.onContentContextMenu : void 0}>
|
|
3851
|
-
${contentNode}
|
|
3852
|
-
</div>
|
|
3853
|
-
${contextMenuEnabled ? html`
|
|
3854
|
-
<docks-contextmenu
|
|
3855
|
-
id=${ifDefined(contextMenuTarget)}
|
|
3856
|
-
.scopeTokens=${scopeTokens}
|
|
3857
|
-
.partContextMenuRenderer=${() => this.renderContextMenu()}>
|
|
3858
|
-
</docks-contextmenu>
|
|
3859
|
-
` : nothing}
|
|
3860
|
-
</div>
|
|
3861
|
-
`;
|
|
4150
|
+
getHostPart() {
|
|
4151
|
+
const root = this.getRootNode();
|
|
4152
|
+
if (root instanceof ShadowRoot && root.host instanceof HTMLElement) return root.host;
|
|
4153
|
+
return null;
|
|
3862
4154
|
}
|
|
3863
|
-
|
|
3864
|
-
|
|
3865
|
-
|
|
3866
|
-
|
|
3867
|
-
|
|
3868
|
-
|
|
3869
|
-
|
|
3870
|
-
bubbles: true
|
|
3871
|
-
|
|
4155
|
+
/**
|
|
4156
|
+
* Triggers a click on the element under the cursor to update selection before showing context menu.
|
|
4157
|
+
*/
|
|
4158
|
+
triggerClickUnderCursor(mouseEvent) {
|
|
4159
|
+
const elementUnderCursor = this.getElementFromPoint(mouseEvent.clientX, mouseEvent.clientY);
|
|
4160
|
+
if (elementUnderCursor) {
|
|
4161
|
+
const clickEvent = new MouseEvent("click", {
|
|
4162
|
+
bubbles: true,
|
|
4163
|
+
cancelable: true,
|
|
4164
|
+
view: window,
|
|
4165
|
+
clientX: mouseEvent.clientX,
|
|
4166
|
+
clientY: mouseEvent.clientY,
|
|
4167
|
+
screenX: mouseEvent.screenX,
|
|
4168
|
+
screenY: mouseEvent.screenY,
|
|
4169
|
+
button: 0,
|
|
4170
|
+
buttons: 0,
|
|
4171
|
+
detail: 1,
|
|
4172
|
+
which: 1
|
|
4173
|
+
});
|
|
4174
|
+
elementUnderCursor.dispatchEvent(clickEvent);
|
|
3872
4175
|
}
|
|
3873
4176
|
}
|
|
3874
|
-
|
|
3875
|
-
|
|
3876
|
-
|
|
4177
|
+
/** Opens the menu at `position`. Returns false when there is nothing to show (no thin empty panel). */
|
|
4178
|
+
async show(position, mouseEvent) {
|
|
4179
|
+
if (!this.hasMenuBody()) return false;
|
|
4180
|
+
if (mouseEvent) {
|
|
4181
|
+
this.triggerClickUnderCursor(mouseEvent);
|
|
4182
|
+
await this.getHostPart()?.updateComplete;
|
|
4183
|
+
}
|
|
4184
|
+
if (this.isOpen) {
|
|
4185
|
+
this.isOpen = false;
|
|
4186
|
+
await this.updateComplete;
|
|
4187
|
+
}
|
|
4188
|
+
this.menuPosition = position;
|
|
4189
|
+
this.isOpen = true;
|
|
4190
|
+
await this.updateComplete;
|
|
4191
|
+
this.syncVirtualPopupAnchor();
|
|
4192
|
+
document.addEventListener("pointerdown", this.boundHandleDocumentPointerDown, { capture: true });
|
|
4193
|
+
return true;
|
|
3877
4194
|
}
|
|
3878
|
-
|
|
3879
|
-
|
|
4195
|
+
/** Points wa-dropdown's internal wa-popup at the pointer via a VirtualElement anchor. */
|
|
4196
|
+
syncVirtualPopupAnchor() {
|
|
4197
|
+
const popup = this.dropdownRef.value?.shadowRoot?.querySelector("wa-popup");
|
|
4198
|
+
if (!popup) return;
|
|
4199
|
+
popup.anchor = this.virtualAnchor;
|
|
4200
|
+
popup.reposition();
|
|
3880
4201
|
}
|
|
3881
|
-
|
|
3882
|
-
|
|
3883
|
-
this.
|
|
3884
|
-
|
|
3885
|
-
this.watch(activeEditorSignal, () => this.maybeActivateForCoupledEditors());
|
|
4202
|
+
onClose() {
|
|
4203
|
+
if (!this.isOpen) return;
|
|
4204
|
+
this.isOpen = false;
|
|
4205
|
+
document.removeEventListener("pointerdown", this.boundHandleDocumentPointerDown, { capture: true });
|
|
3886
4206
|
}
|
|
3887
|
-
|
|
3888
|
-
|
|
3889
|
-
|
|
4207
|
+
updated(changedProperties) {
|
|
4208
|
+
super.updated(changedProperties);
|
|
4209
|
+
if (changedProperties.has("isOpen") && this.isOpen) this.syncVirtualPopupAnchor();
|
|
3890
4210
|
}
|
|
3891
|
-
|
|
3892
|
-
|
|
3893
|
-
|
|
3894
|
-
|
|
3895
|
-
|
|
3896
|
-
|
|
4211
|
+
renderContribution(contribution) {
|
|
4212
|
+
return renderDropdownContribution(contribution);
|
|
4213
|
+
}
|
|
4214
|
+
render() {
|
|
4215
|
+
const partContent = this.partContextMenuRenderer ? this.partContextMenuRenderer() : nothing;
|
|
4216
|
+
return html`
|
|
4217
|
+
<wa-dropdown
|
|
4218
|
+
${ref(this.dropdownRef)}
|
|
4219
|
+
?open=${this.isOpen}
|
|
4220
|
+
@submenu-opening=${this.handleSubmenuOpening}
|
|
4221
|
+
@wa-select=${handleDropdownWaSelect}
|
|
4222
|
+
@wa-after-hide=${this.onClose}>
|
|
4223
|
+
<span slot="trigger" hidden aria-hidden="true"></span>
|
|
4224
|
+
|
|
4225
|
+
${partContent}
|
|
4226
|
+
${this.contributions.map((c) => this.renderContribution(c))}
|
|
4227
|
+
</wa-dropdown>
|
|
4228
|
+
`;
|
|
3897
4229
|
}
|
|
3898
4230
|
static {
|
|
3899
|
-
this.
|
|
4231
|
+
this.styles = css`
|
|
3900
4232
|
:host {
|
|
3901
|
-
|
|
3902
|
-
|
|
3903
|
-
|
|
3904
|
-
|
|
3905
|
-
|
|
3906
|
-
|
|
3907
|
-
|
|
3908
|
-
width: 100%;
|
|
3909
|
-
position: relative;
|
|
3910
|
-
overflow: hidden;
|
|
3911
|
-
}
|
|
3912
|
-
|
|
3913
|
-
.part-content {
|
|
3914
|
-
min-height: 0;
|
|
3915
|
-
overflow: hidden;
|
|
3916
|
-
position: relative;
|
|
3917
|
-
}
|
|
3918
|
-
|
|
3919
|
-
.part-content.native-scroll {
|
|
3920
|
-
overflow: auto;
|
|
4233
|
+
position: fixed;
|
|
4234
|
+
top: 0;
|
|
4235
|
+
left: 0;
|
|
4236
|
+
width: 0;
|
|
4237
|
+
height: 0;
|
|
4238
|
+
pointer-events: none;
|
|
4239
|
+
z-index: 10000;
|
|
3921
4240
|
}
|
|
3922
4241
|
|
|
3923
|
-
|
|
3924
|
-
|
|
3925
|
-
|
|
4242
|
+
wa-dropdown {
|
|
4243
|
+
pointer-events: none;
|
|
4244
|
+
min-width: 200px;
|
|
3926
4245
|
}
|
|
3927
4246
|
|
|
3928
|
-
|
|
3929
|
-
|
|
3930
|
-
min-height: 100%;
|
|
4247
|
+
wa-dropdown:state(open) {
|
|
4248
|
+
pointer-events: auto;
|
|
3931
4249
|
}
|
|
3932
|
-
|
|
3933
|
-
|
|
3934
|
-
min-
|
|
4250
|
+
|
|
4251
|
+
wa-dropdown::part(menu) {
|
|
4252
|
+
min-width: 200px;
|
|
3935
4253
|
}
|
|
3936
4254
|
`;
|
|
3937
4255
|
}
|
|
3938
|
-
static finalizeStyles(styles) {
|
|
3939
|
-
const own = super.finalizeStyles(styles);
|
|
3940
|
-
return [DocksPart.baseStyles, ...own];
|
|
3941
|
-
}
|
|
3942
4256
|
};
|
|
3943
|
-
_decorate([property()],
|
|
3944
|
-
_decorate([property({ attribute: false })],
|
|
3945
|
-
_decorate([
|
|
3946
|
-
|
|
3947
|
-
|
|
3948
|
-
})], DocksPart.prototype, "isEditor", void 0);
|
|
4257
|
+
_decorate([property({ attribute: false })], DocksContextMenu.prototype, "scopeTokens", void 0);
|
|
4258
|
+
_decorate([property({ attribute: false })], DocksContextMenu.prototype, "partContextMenuRenderer", void 0);
|
|
4259
|
+
_decorate([state()], DocksContextMenu.prototype, "contributions", void 0);
|
|
4260
|
+
_decorate([state()], DocksContextMenu.prototype, "isOpen", void 0);
|
|
4261
|
+
DocksContextMenu = _decorate([customElement("docks-contextmenu")], DocksContextMenu);
|
|
3949
4262
|
//#endregion
|
|
3950
4263
|
//#region src/parts/tabs.ts
|
|
3951
4264
|
var _DocksTabs;
|
|
@@ -3959,6 +4272,8 @@ var DocksTabs = class DocksTabs extends DocksContainer {
|
|
|
3959
4272
|
this.iconOnly = false;
|
|
3960
4273
|
this.withToolbar = false;
|
|
3961
4274
|
this.hideTabs = false;
|
|
4275
|
+
this.fitContent = false;
|
|
4276
|
+
this.fillHeight = false;
|
|
3962
4277
|
this.itemSize = "m";
|
|
3963
4278
|
this.contributions = [];
|
|
3964
4279
|
this.tabGroup = createRef();
|
|
@@ -4011,6 +4326,11 @@ var DocksTabs = class DocksTabs extends DocksContainer {
|
|
|
4011
4326
|
if (!this.tabGroup.value) return null;
|
|
4012
4327
|
return this.tabGroup.value.getAttribute("active");
|
|
4013
4328
|
}
|
|
4329
|
+
getTabPart(tabName) {
|
|
4330
|
+
const tabPanel = this.getTabPanel(tabName);
|
|
4331
|
+
if (!tabPanel) return null;
|
|
4332
|
+
return this.getPartFromPanel(tabPanel);
|
|
4333
|
+
}
|
|
4014
4334
|
open(contribution) {
|
|
4015
4335
|
if (this.contributions.find((c) => c.name === contribution.name)) {
|
|
4016
4336
|
this.activate(contribution.name);
|
|
@@ -4260,6 +4580,95 @@ var DocksTabs = class DocksTabs extends DocksContainer {
|
|
|
4260
4580
|
width: 100%;
|
|
4261
4581
|
}
|
|
4262
4582
|
|
|
4583
|
+
:host([fit-content]) {
|
|
4584
|
+
display: flex;
|
|
4585
|
+
flex-direction: column;
|
|
4586
|
+
height: auto;
|
|
4587
|
+
max-height: 100%;
|
|
4588
|
+
min-height: 0;
|
|
4589
|
+
}
|
|
4590
|
+
|
|
4591
|
+
:host([fit-content]) wa-tab-group {
|
|
4592
|
+
display: flex;
|
|
4593
|
+
flex-direction: column;
|
|
4594
|
+
flex: 1 1 auto;
|
|
4595
|
+
min-height: 0;
|
|
4596
|
+
height: auto;
|
|
4597
|
+
max-height: 100%;
|
|
4598
|
+
}
|
|
4599
|
+
|
|
4600
|
+
:host([fit-content]) wa-tab-group::part(base) {
|
|
4601
|
+
display: flex;
|
|
4602
|
+
flex-direction: column;
|
|
4603
|
+
flex: 1 1 auto;
|
|
4604
|
+
min-height: 0;
|
|
4605
|
+
max-height: 100%;
|
|
4606
|
+
height: auto;
|
|
4607
|
+
}
|
|
4608
|
+
|
|
4609
|
+
:host([fit-content]) wa-tab-group::part(body) {
|
|
4610
|
+
flex: 1 1 auto;
|
|
4611
|
+
min-height: 0;
|
|
4612
|
+
height: auto;
|
|
4613
|
+
overflow-x: hidden;
|
|
4614
|
+
overflow-y: auto;
|
|
4615
|
+
}
|
|
4616
|
+
|
|
4617
|
+
:host([fit-content]) wa-tab-panel[active] {
|
|
4618
|
+
display: block;
|
|
4619
|
+
height: auto;
|
|
4620
|
+
overflow: visible;
|
|
4621
|
+
}
|
|
4622
|
+
|
|
4623
|
+
:host([fit-content]) wa-tab-panel > * {
|
|
4624
|
+
height: auto;
|
|
4625
|
+
min-height: 0;
|
|
4626
|
+
}
|
|
4627
|
+
|
|
4628
|
+
:host([fill-height]) {
|
|
4629
|
+
display: flex;
|
|
4630
|
+
flex-direction: column;
|
|
4631
|
+
height: 100%;
|
|
4632
|
+
min-height: 0;
|
|
4633
|
+
max-height: 100%;
|
|
4634
|
+
}
|
|
4635
|
+
|
|
4636
|
+
:host([fill-height]) wa-tab-group {
|
|
4637
|
+
display: flex;
|
|
4638
|
+
flex-direction: column;
|
|
4639
|
+
flex: 1 1 auto;
|
|
4640
|
+
min-height: 0;
|
|
4641
|
+
height: 100%;
|
|
4642
|
+
max-height: 100%;
|
|
4643
|
+
}
|
|
4644
|
+
|
|
4645
|
+
:host([fill-height]) wa-tab-group::part(base) {
|
|
4646
|
+
display: flex;
|
|
4647
|
+
flex-direction: column;
|
|
4648
|
+
flex: 1 1 auto;
|
|
4649
|
+
min-height: 0;
|
|
4650
|
+
max-height: 100%;
|
|
4651
|
+
height: 100%;
|
|
4652
|
+
}
|
|
4653
|
+
|
|
4654
|
+
:host([fill-height]) wa-tab-group::part(body) {
|
|
4655
|
+
flex: 1 1 auto;
|
|
4656
|
+
min-height: 0;
|
|
4657
|
+
overflow-x: hidden;
|
|
4658
|
+
overflow-y: auto;
|
|
4659
|
+
}
|
|
4660
|
+
|
|
4661
|
+
:host([fill-height]) wa-tab-panel[active] {
|
|
4662
|
+
display: block;
|
|
4663
|
+
height: auto;
|
|
4664
|
+
overflow: visible;
|
|
4665
|
+
}
|
|
4666
|
+
|
|
4667
|
+
:host([fill-height]) wa-tab-panel > * {
|
|
4668
|
+
height: auto;
|
|
4669
|
+
min-height: 0;
|
|
4670
|
+
}
|
|
4671
|
+
|
|
4263
4672
|
wa-tab-group {
|
|
4264
4673
|
height: 100%;
|
|
4265
4674
|
width: 100%;
|
|
@@ -4487,6 +4896,16 @@ _decorate([property({
|
|
|
4487
4896
|
reflect: true,
|
|
4488
4897
|
attribute: "hide-tabs"
|
|
4489
4898
|
})], DocksTabs.prototype, "hideTabs", void 0);
|
|
4899
|
+
_decorate([property({
|
|
4900
|
+
type: Boolean,
|
|
4901
|
+
reflect: true,
|
|
4902
|
+
attribute: "fit-content"
|
|
4903
|
+
})], DocksTabs.prototype, "fitContent", void 0);
|
|
4904
|
+
_decorate([property({
|
|
4905
|
+
type: Boolean,
|
|
4906
|
+
reflect: true,
|
|
4907
|
+
attribute: "fill-height"
|
|
4908
|
+
})], DocksTabs.prototype, "fillHeight", void 0);
|
|
4490
4909
|
_decorate([property({
|
|
4491
4910
|
reflect: true,
|
|
4492
4911
|
attribute: "item-size"
|
|
@@ -4526,9 +4945,9 @@ var DocksResizableGrid = class DocksResizableGrid extends DocksElement {
|
|
|
4526
4945
|
this.gridChildren = [];
|
|
4527
4946
|
this.resizing = null;
|
|
4528
4947
|
this.resizeOverlay = null;
|
|
4529
|
-
this.childrenLoaded = false;
|
|
4530
4948
|
this.childStylesApplied = false;
|
|
4531
|
-
this.
|
|
4949
|
+
this.refreshScheduled = false;
|
|
4950
|
+
this.layoutGeneration = 0;
|
|
4532
4951
|
this.handleResize = (e) => {
|
|
4533
4952
|
if (!this.resizing) return;
|
|
4534
4953
|
const delta = (this.orientation === "horizontal" ? e.clientX : e.clientY) - this.resizing.startPos;
|
|
@@ -4578,56 +4997,108 @@ var DocksResizableGrid = class DocksResizableGrid extends DocksElement {
|
|
|
4578
4997
|
return this;
|
|
4579
4998
|
}
|
|
4580
4999
|
doBeforeUI() {
|
|
4581
|
-
|
|
4582
|
-
this.
|
|
4583
|
-
|
|
4584
|
-
|
|
4585
|
-
|
|
4586
|
-
|
|
4587
|
-
|
|
4588
|
-
|
|
4589
|
-
|
|
4590
|
-
|
|
5000
|
+
this.mutationObserver = new MutationObserver(() => {
|
|
5001
|
+
this.scheduleRefreshGridLayout();
|
|
5002
|
+
});
|
|
5003
|
+
this.mutationObserver.observe(this, {
|
|
5004
|
+
childList: true,
|
|
5005
|
+
subtree: false
|
|
5006
|
+
});
|
|
5007
|
+
this.scheduleRefreshGridLayout();
|
|
5008
|
+
}
|
|
5009
|
+
scheduleRefreshGridLayout() {
|
|
5010
|
+
if (this.refreshScheduled) return;
|
|
5011
|
+
this.refreshScheduled = true;
|
|
5012
|
+
queueMicrotask(() => {
|
|
5013
|
+
this.refreshScheduled = false;
|
|
5014
|
+
this.refreshGridLayout();
|
|
5015
|
+
});
|
|
4591
5016
|
}
|
|
4592
|
-
|
|
4593
|
-
|
|
4594
|
-
|
|
4595
|
-
|
|
4596
|
-
|
|
4597
|
-
|
|
4598
|
-
|
|
4599
|
-
|
|
4600
|
-
|
|
4601
|
-
|
|
4602
|
-
|
|
4603
|
-
|
|
4604
|
-
|
|
4605
|
-
|
|
4606
|
-
|
|
4607
|
-
|
|
5017
|
+
getGridChildrenFromDom() {
|
|
5018
|
+
return Array.from(this.children).filter((child) => child.tagName !== "STYLE" && child.tagName !== "SCRIPT" && !child.classList.contains("resize-handle"));
|
|
5019
|
+
}
|
|
5020
|
+
static isNestedResizableGrid(child) {
|
|
5021
|
+
return child.tagName.toLowerCase() === "docks-resizable-grid";
|
|
5022
|
+
}
|
|
5023
|
+
applyChildLayoutStyles() {
|
|
5024
|
+
this.gridChildren.forEach((child, index) => {
|
|
5025
|
+
child.style.overflow = "hidden";
|
|
5026
|
+
child.style.height = "100%";
|
|
5027
|
+
child.style.width = "100%";
|
|
5028
|
+
child.style.gridColumn = this.orientation === "horizontal" ? `${index * 2 + 1}` : "1";
|
|
5029
|
+
child.style.gridRow = this.orientation === "vertical" ? `${index * 2 + 1}` : "1";
|
|
5030
|
+
if (!_DocksResizableGrid.isNestedResizableGrid(child)) {
|
|
5031
|
+
child.style.display = "flex";
|
|
5032
|
+
child.style.flexDirection = "column";
|
|
4608
5033
|
}
|
|
5034
|
+
});
|
|
5035
|
+
}
|
|
5036
|
+
resolveGridSizes(childCount) {
|
|
5037
|
+
const parsedSizes = this.sizes?.split(",").map((s) => s.trim()).filter(Boolean) ?? [];
|
|
5038
|
+
if (parsedSizes.length === childCount) return parsedSizes;
|
|
5039
|
+
const equalSize = `${100 / childCount}%`;
|
|
5040
|
+
return Array.from({ length: childCount }, () => equalSize);
|
|
5041
|
+
}
|
|
5042
|
+
resolvePersistedSizes(persisted, childCount) {
|
|
5043
|
+
if (!persisted || typeof persisted !== "object") return null;
|
|
5044
|
+
const record = persisted;
|
|
5045
|
+
const byCount = record.sizesByCount?.[String(childCount)];
|
|
5046
|
+
if (Array.isArray(byCount) && byCount.length === childCount && byCount.every((size) => typeof size === "string")) return byCount;
|
|
5047
|
+
if (Array.isArray(record.sizes) && record.sizes.length === childCount && record.sizes.every((size) => typeof size === "string")) return record.sizes;
|
|
5048
|
+
return null;
|
|
5049
|
+
}
|
|
5050
|
+
async refreshGridLayout() {
|
|
5051
|
+
const generation = ++this.layoutGeneration;
|
|
5052
|
+
const potentialChildren = this.getGridChildrenFromDom();
|
|
5053
|
+
if (potentialChildren.length === 0) {
|
|
5054
|
+
this.gridChildren = [];
|
|
5055
|
+
this.gridSizes = [];
|
|
5056
|
+
this.childStylesApplied = false;
|
|
5057
|
+
this.requestUpdate();
|
|
5058
|
+
return;
|
|
4609
5059
|
}
|
|
4610
|
-
|
|
4611
|
-
|
|
4612
|
-
|
|
4613
|
-
|
|
5060
|
+
const identityChanged = potentialChildren.length !== this.gridChildren.length || potentialChildren.some((child, index) => child !== this.gridChildren[index]);
|
|
5061
|
+
this.gridChildren = potentialChildren;
|
|
5062
|
+
const persisted = await this.getDialogSetting();
|
|
5063
|
+
if (generation !== this.layoutGeneration) return;
|
|
5064
|
+
const restoredSizes = this.resolvePersistedSizes(persisted, this.gridChildren.length);
|
|
5065
|
+
if (restoredSizes) {
|
|
5066
|
+
const sizesChanged = restoredSizes.join("|") !== this.gridSizes.join("|");
|
|
5067
|
+
this.gridSizes = restoredSizes;
|
|
5068
|
+
if (identityChanged || sizesChanged) this.childStylesApplied = false;
|
|
5069
|
+
this.requestUpdate();
|
|
5070
|
+
return;
|
|
4614
5071
|
}
|
|
5072
|
+
const nextSizes = this.resolveGridSizes(this.gridChildren.length);
|
|
5073
|
+
const sizesChanged = nextSizes.join("|") !== this.gridSizes.join("|");
|
|
5074
|
+
this.gridSizes = nextSizes;
|
|
5075
|
+
if (identityChanged || sizesChanged) this.childStylesApplied = false;
|
|
4615
5076
|
this.requestUpdate();
|
|
4616
5077
|
}
|
|
5078
|
+
doInitUI() {
|
|
5079
|
+
this.scheduleRefreshGridLayout();
|
|
5080
|
+
}
|
|
4617
5081
|
async saveSizes() {
|
|
4618
5082
|
if (this.gridSizes.length === 0) return;
|
|
5083
|
+
const persisted = await this.getDialogSetting();
|
|
5084
|
+
const existingByCount = persisted && typeof persisted === "object" ? persisted.sizesByCount ?? {} : {};
|
|
4619
5085
|
await this.setDialogSetting({
|
|
4620
5086
|
sizes: this.gridSizes,
|
|
5087
|
+
sizesByCount: {
|
|
5088
|
+
...existingByCount,
|
|
5089
|
+
[String(this.gridSizes.length)]: this.gridSizes
|
|
5090
|
+
},
|
|
4621
5091
|
orientation: this.orientation
|
|
4622
5092
|
});
|
|
4623
5093
|
}
|
|
4624
5094
|
updated(changedProperties) {
|
|
4625
5095
|
super.updated(changedProperties);
|
|
4626
|
-
if (changedProperties.has("
|
|
5096
|
+
if (changedProperties.has("sizes")) this.scheduleRefreshGridLayout();
|
|
5097
|
+
if (!this.childStylesApplied && this.gridChildren.length > 0) {
|
|
4627
5098
|
this.childStylesApplied = true;
|
|
4628
5099
|
/**
|
|
4629
5100
|
* Direct style manipulation is intentionally used here.
|
|
4630
|
-
*
|
|
5101
|
+
*
|
|
4631
5102
|
* Reasoning:
|
|
4632
5103
|
* - Grid positioning (gridColumn/gridRow) must be computed dynamically based on
|
|
4633
5104
|
* the number of children and orientation at runtime
|
|
@@ -4637,16 +5108,9 @@ var DocksResizableGrid = class DocksResizableGrid extends DocksElement {
|
|
|
4637
5108
|
* (e.g., child at index 0 → column 1, index 1 → column 3, etc.)
|
|
4638
5109
|
* - This is a layout container whose primary job is to programmatically position
|
|
4639
5110
|
* its children within a CSS grid system
|
|
5111
|
+
* - Nested resizable grids manage their own display mode and must not receive flex
|
|
4640
5112
|
*/
|
|
4641
|
-
this.
|
|
4642
|
-
child.style.overflow = "hidden";
|
|
4643
|
-
child.style.height = "100%";
|
|
4644
|
-
child.style.width = "100%";
|
|
4645
|
-
child.style.gridColumn = this.orientation === "horizontal" ? `${index * 2 + 1}` : "1";
|
|
4646
|
-
child.style.gridRow = this.orientation === "vertical" ? `${index * 2 + 1}` : "1";
|
|
4647
|
-
child.style.display = "flex";
|
|
4648
|
-
child.style.flexDirection = "column";
|
|
4649
|
-
});
|
|
5113
|
+
this.applyChildLayoutStyles();
|
|
4650
5114
|
}
|
|
4651
5115
|
}
|
|
4652
5116
|
startResize(e, handleIndex) {
|
|
@@ -4765,6 +5229,6 @@ DocksResizableGrid = _DocksResizableGrid = _decorate([customElement("docks-resiz
|
|
|
4765
5229
|
//#region src/parts/index.ts
|
|
4766
5230
|
installOpenDropdownNativeContextMenuGuard();
|
|
4767
5231
|
//#endregion
|
|
4768
|
-
export {
|
|
5232
|
+
export { HIDE_DOT_RESOURCE as $, filebrowserDialog as A, dialogService as B, TOOLBAR_INFO as C, TOOLBAR_THEME_SWITCHER as D, TOOLBAR_TASKS as E, formDialogRequired as F, keyBindingManager as G, DocksElement as H, validateFormDialogFields as I, esmShService as J, TOPIC_EXTENSIONS_CHANGED as K, promptDialog as L, confirmDialog as M, infoDialog as N, VIEW_FILEBROWSER as O, formDialog as P, COMMAND_SAVE as Q, appLoaderService as R, TOOLBAR_FULLSCREEN as S, TOOLBAR_LAYOUT_SWITCHER as T, parseMarkdownHtml as U, DocksDialogContent as V, sanitizeHtml as W, TOPIC_SETTINGS_CHANGED as X, taskService as Y, appSettings as Z, CTXMENU_FILEBROWSER_RENAME as _, TOOLBAR_MAIN_CENTER as _t, renderDropdownItem as a, SIDEBAR_AUXILIARY as at, TOOLBAR_ACTIVE_PART_NAME as b, parseIconSpec as c, SIDEBAR_MAIN_BOTTOM as ct, DocksContainer as d, SYSTEM_LAYOUTS as dt, MouseButton as et, ABOUT_TAB_ATTRIBUTIONS as f, SYSTEM_VIEWS as ft, CTXMENU_FILEBROWSER_DELETE as g, TOOLBAR_MAIN as gt, ATTRIBUTION_ECLIPSE_DOCKS as h, TOOLBAR_BOTTOM_END as ht, renderDropdownContributions as i, PANEL_BOTTOM as it, navigableInfoDialog as j, VIEW_LOG_TERMINAL as k, versionInfoDialog as l, SIDEBAR_MAIN_TOOLBAR as lt, ABOUT_TAB_RELEASE as m, TOOLBAR_BOTTOM_CENTER as mt, renderCommandContribution as n, ABOUT_TABS as nt, renderDropdownSubmenu as o, SIDEBAR_AUXILIARY_BOTTOM as ot, ABOUT_TAB_PACKAGES as p, TOOLBAR_BOTTOM as pt, extensionRegistry as q, renderDropdownContribution as r, EDITOR_AREA_MAIN as rt, icon as s, SIDEBAR_MAIN as st, handleDropdownWaSelect as t, constants_exports as tt, DocksPart as u, SYSTEM_ATTRIBUTIONS as ut, SIDEBAR_TOOLBAR_EXTENSIONS as v, TOOLBAR_MAIN_RIGHT as vt, TOOLBAR_LANGUAGE_SELECTOR as w, TOOLBAR_FAST_VIEWS as x, SYSTEM_DEFAULT_FILE_ICONS as y, deleteIndexedDbWorkspaceData as z };
|
|
4769
5233
|
|
|
4770
|
-
//# sourceMappingURL=parts-
|
|
5234
|
+
//# sourceMappingURL=parts-CAt8aeU8.js.map
|