@matdata/yasgui 5.2.0 → 5.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,5 +1,16 @@
1
+ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
2
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
3
+ return new (P || (P = Promise))(function (resolve, reject) {
4
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
5
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
6
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
7
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
8
+ });
9
+ };
1
10
  import { addClass, removeClass } from "@matdata/yasgui-utils";
2
11
  import "./TabSettingsModal.scss";
12
+ import * as ConfigExportImport from "./ConfigExportImport";
13
+ import { VERSION } from "./version";
3
14
  const MOON_ICON = `<svg viewBox="0 0 24 24" fill="currentColor">
4
15
  <path d="M12 3c-4.97 0-9 4.03-9 9s4.03 9 9 9 9-4.03 9-9c0-.46-.04-.92-.1-1.36-.98 1.37-2.58 2.26-4.4 2.26-2.98 0-5.4-2.42-5.4-5.4 0-1.81.89-3.42 2.26-4.4-.44-.06-.9-.1-1.36-.1z"/>
5
16
  </svg>`;
@@ -89,13 +100,33 @@ export default class TabSettingsModal {
89
100
  prefixTab.textContent = "Prefixes";
90
101
  addClass(prefixTab, "modalTabButton");
91
102
  prefixTab.onclick = () => this.switchTab("prefix");
103
+ const editorTab = document.createElement("button");
104
+ editorTab.textContent = "Editor";
105
+ addClass(editorTab, "modalTabButton");
106
+ editorTab.onclick = () => this.switchTab("editor");
92
107
  const endpointsTab = document.createElement("button");
93
108
  endpointsTab.textContent = "Endpoint Buttons";
94
109
  addClass(endpointsTab, "modalTabButton");
95
110
  endpointsTab.onclick = () => this.switchTab("endpoints");
111
+ const importExportTab = document.createElement("button");
112
+ importExportTab.textContent = "Import/Export";
113
+ addClass(importExportTab, "modalTabButton");
114
+ importExportTab.onclick = () => this.switchTab("importexport");
115
+ const shortcutsTab = document.createElement("button");
116
+ shortcutsTab.textContent = "Keyboard Shortcuts";
117
+ addClass(shortcutsTab, "modalTabButton");
118
+ shortcutsTab.onclick = () => this.switchTab("shortcuts");
119
+ const aboutTab = document.createElement("button");
120
+ aboutTab.textContent = "About";
121
+ addClass(aboutTab, "modalTabButton");
122
+ aboutTab.onclick = () => this.switchTab("about");
96
123
  tabsContainer.appendChild(requestTab);
97
124
  tabsContainer.appendChild(prefixTab);
125
+ tabsContainer.appendChild(editorTab);
98
126
  tabsContainer.appendChild(endpointsTab);
127
+ tabsContainer.appendChild(importExportTab);
128
+ tabsContainer.appendChild(shortcutsTab);
129
+ tabsContainer.appendChild(aboutTab);
99
130
  body.appendChild(tabsContainer);
100
131
  const requestContent = document.createElement("div");
101
132
  addClass(requestContent, "modalTabContent", "active");
@@ -105,13 +136,33 @@ export default class TabSettingsModal {
105
136
  addClass(prefixContent, "modalTabContent");
106
137
  prefixContent.id = "prefix-content";
107
138
  this.drawPrefixSettings(prefixContent);
139
+ const editorContent = document.createElement("div");
140
+ addClass(editorContent, "modalTabContent");
141
+ editorContent.id = "editor-content";
142
+ this.drawEditorSettings(editorContent);
108
143
  const endpointsContent = document.createElement("div");
109
144
  addClass(endpointsContent, "modalTabContent");
110
145
  endpointsContent.id = "endpoints-content";
111
146
  this.drawEndpointButtonsSettings(endpointsContent);
147
+ const importExportContent = document.createElement("div");
148
+ addClass(importExportContent, "modalTabContent");
149
+ importExportContent.id = "importexport-content";
150
+ this.drawImportExportSettings(importExportContent);
151
+ const shortcutsContent = document.createElement("div");
152
+ addClass(shortcutsContent, "modalTabContent");
153
+ shortcutsContent.id = "shortcuts-content";
154
+ this.drawKeyboardShortcuts(shortcutsContent);
155
+ const aboutContent = document.createElement("div");
156
+ addClass(aboutContent, "modalTabContent");
157
+ aboutContent.id = "about-content";
158
+ this.drawAboutSettings(aboutContent);
112
159
  body.appendChild(requestContent);
113
160
  body.appendChild(prefixContent);
161
+ body.appendChild(editorContent);
114
162
  body.appendChild(endpointsContent);
163
+ body.appendChild(importExportContent);
164
+ body.appendChild(shortcutsContent);
165
+ body.appendChild(aboutContent);
115
166
  this.modalContent.appendChild(body);
116
167
  const footer = document.createElement("div");
117
168
  addClass(footer, "modalFooter");
@@ -135,7 +186,11 @@ export default class TabSettingsModal {
135
186
  buttons.forEach((btn, index) => {
136
187
  if ((tabName === "request" && index === 0) ||
137
188
  (tabName === "prefix" && index === 1) ||
138
- (tabName === "endpoints" && index === 2)) {
189
+ (tabName === "editor" && index === 2) ||
190
+ (tabName === "endpoints" && index === 3) ||
191
+ (tabName === "importexport" && index === 4) ||
192
+ (tabName === "shortcuts" && index === 5) ||
193
+ (tabName === "about" && index === 6)) {
139
194
  addClass(btn, "active");
140
195
  }
141
196
  else {
@@ -145,6 +200,10 @@ export default class TabSettingsModal {
145
200
  contents.forEach((content) => {
146
201
  if (content.id === `${tabName}-content`) {
147
202
  addClass(content, "active");
203
+ if (tabName === "editor" && content.innerHTML.indexOf("not yet initialized") > -1) {
204
+ content.innerHTML = "";
205
+ this.drawEditorSettings(content);
206
+ }
148
207
  }
149
208
  else {
150
209
  removeClass(content, "active");
@@ -181,6 +240,104 @@ export default class TabSettingsModal {
181
240
  section.appendChild(checkboxContainer);
182
241
  container.appendChild(section);
183
242
  }
243
+ drawEditorSettings(container) {
244
+ var _a, _b, _c;
245
+ const yasqe = this.tab.getYasqe();
246
+ if (!yasqe) {
247
+ const notice = document.createElement("div");
248
+ notice.textContent = "Query editor is not yet initialized.";
249
+ addClass(notice, "settingsHelp");
250
+ container.appendChild(notice);
251
+ return;
252
+ }
253
+ const formatterSection = document.createElement("div");
254
+ addClass(formatterSection, "settingsSection");
255
+ const formatterLabel = document.createElement("label");
256
+ formatterLabel.textContent = "Query Formatter";
257
+ addClass(formatterLabel, "settingsLabel");
258
+ const formatterHelp = document.createElement("div");
259
+ formatterHelp.textContent = "Choose which formatter to use when formatting SPARQL queries (Shift+Ctrl+F).";
260
+ addClass(formatterHelp, "settingsHelp");
261
+ const formatterSelect = document.createElement("select");
262
+ formatterSelect.id = "formatterTypeSelect";
263
+ addClass(formatterSelect, "settingsSelect");
264
+ const sparqlFormatterOption = document.createElement("option");
265
+ sparqlFormatterOption.value = "sparql-formatter";
266
+ sparqlFormatterOption.textContent = "SPARQL Formatter (external library)";
267
+ formatterSelect.appendChild(sparqlFormatterOption);
268
+ const legacyOption = document.createElement("option");
269
+ legacyOption.value = "legacy";
270
+ legacyOption.textContent = "Legacy Formatter (built-in)";
271
+ formatterSelect.appendChild(legacyOption);
272
+ const currentFormatter = ((_a = yasqe.persistentConfig) === null || _a === void 0 ? void 0 : _a.formatterType) || "sparql-formatter";
273
+ formatterSelect.value = currentFormatter;
274
+ formatterSection.appendChild(formatterLabel);
275
+ formatterSection.appendChild(formatterHelp);
276
+ formatterSection.appendChild(formatterSelect);
277
+ container.appendChild(formatterSection);
278
+ const autoformatSection = document.createElement("div");
279
+ addClass(autoformatSection, "settingsSection");
280
+ const autoformatCheckboxContainer = document.createElement("div");
281
+ addClass(autoformatCheckboxContainer, "checkboxContainer");
282
+ const autoformatCheckbox = document.createElement("input");
283
+ autoformatCheckbox.type = "checkbox";
284
+ autoformatCheckbox.id = "autoformatOnQuery";
285
+ autoformatCheckbox.checked = ((_b = yasqe.persistentConfig) === null || _b === void 0 ? void 0 : _b.autoformatOnQuery) || true;
286
+ const autoformatLabel = document.createElement("label");
287
+ autoformatLabel.htmlFor = "autoformatOnQuery";
288
+ autoformatLabel.textContent = "Auto-format query before execution";
289
+ const autoformatHelp = document.createElement("div");
290
+ autoformatHelp.textContent = "Automatically format the query using the selected formatter before executing it.";
291
+ addClass(autoformatHelp, "settingsHelp");
292
+ autoformatHelp.style.marginTop = "5px";
293
+ autoformatCheckboxContainer.appendChild(autoformatCheckbox);
294
+ autoformatCheckboxContainer.appendChild(autoformatLabel);
295
+ autoformatSection.appendChild(autoformatCheckboxContainer);
296
+ autoformatSection.appendChild(autoformatHelp);
297
+ container.appendChild(autoformatSection);
298
+ const constructValidationSection = document.createElement("div");
299
+ addClass(constructValidationSection, "settingsSection");
300
+ const constructValidationCheckboxContainer = document.createElement("div");
301
+ addClass(constructValidationCheckboxContainer, "checkboxContainer");
302
+ const constructValidationCheckbox = document.createElement("input");
303
+ constructValidationCheckbox.type = "checkbox";
304
+ constructValidationCheckbox.id = "checkConstructVariables";
305
+ constructValidationCheckbox.checked = (_c = yasqe.config.checkConstructVariables) !== null && _c !== void 0 ? _c : true;
306
+ const constructValidationLabel = document.createElement("label");
307
+ constructValidationLabel.htmlFor = "checkConstructVariables";
308
+ constructValidationLabel.textContent = "Validate CONSTRUCT query variables";
309
+ const constructValidationHelp = document.createElement("div");
310
+ constructValidationHelp.textContent =
311
+ "Show warnings for variables used in CONSTRUCT template but not defined in WHERE clause.";
312
+ addClass(constructValidationHelp, "settingsHelp");
313
+ constructValidationHelp.style.marginTop = "5px";
314
+ constructValidationCheckboxContainer.appendChild(constructValidationCheckbox);
315
+ constructValidationCheckboxContainer.appendChild(constructValidationLabel);
316
+ constructValidationSection.appendChild(constructValidationCheckboxContainer);
317
+ constructValidationSection.appendChild(constructValidationHelp);
318
+ container.appendChild(constructValidationSection);
319
+ const snippetsBarSection = document.createElement("div");
320
+ addClass(snippetsBarSection, "settingsSection");
321
+ const snippetsBarCheckboxContainer = document.createElement("div");
322
+ addClass(snippetsBarCheckboxContainer, "checkboxContainer");
323
+ const snippetsBarCheckbox = document.createElement("input");
324
+ snippetsBarCheckbox.type = "checkbox";
325
+ snippetsBarCheckbox.id = "showSnippetsBar";
326
+ snippetsBarCheckbox.checked = yasqe.getSnippetsBarVisible();
327
+ const snippetsBarLabel = document.createElement("label");
328
+ snippetsBarLabel.htmlFor = "showSnippetsBar";
329
+ snippetsBarLabel.textContent = "Show code snippets bar";
330
+ const snippetsBarHelp = document.createElement("div");
331
+ snippetsBarHelp.textContent =
332
+ "Display the code snippets bar above the editor for quick insertion of common SPARQL patterns.";
333
+ addClass(snippetsBarHelp, "settingsHelp");
334
+ snippetsBarHelp.style.marginTop = "5px";
335
+ snippetsBarCheckboxContainer.appendChild(snippetsBarCheckbox);
336
+ snippetsBarCheckboxContainer.appendChild(snippetsBarLabel);
337
+ snippetsBarSection.appendChild(snippetsBarCheckboxContainer);
338
+ snippetsBarSection.appendChild(snippetsBarHelp);
339
+ container.appendChild(snippetsBarSection);
340
+ }
184
341
  drawRequestSettings(container) {
185
342
  const reqConfig = this.tab.getRequestConfig();
186
343
  const methodSection = this.createSection("Request Method");
@@ -236,6 +393,10 @@ export default class TabSettingsModal {
236
393
  }
237
394
  open() {
238
395
  this.loadSettings();
396
+ const editorContent = this.modalContent.querySelector("#editor-content");
397
+ if (editorContent && editorContent.innerHTML === "") {
398
+ this.drawEditorSettings(editorContent);
399
+ }
239
400
  addClass(this.modalOverlay, "open");
240
401
  }
241
402
  close() {
@@ -257,6 +418,26 @@ export default class TabSettingsModal {
257
418
  const deduplicated = this.deduplicatePrefixes(prefixText);
258
419
  this.tab.yasgui.persistentConfig.setPrefixes(deduplicated);
259
420
  this.tab.yasgui.persistentConfig.setAutoCaptureEnabled(autoCapture);
421
+ const yasqe = this.tab.getYasqe();
422
+ if (yasqe && yasqe.persistentConfig) {
423
+ const formatterSelect = document.getElementById("formatterTypeSelect");
424
+ const autoformatCheckbox = document.getElementById("autoformatOnQuery");
425
+ const constructValidationCheckbox = document.getElementById("checkConstructVariables");
426
+ if (formatterSelect) {
427
+ yasqe.persistentConfig.formatterType = formatterSelect.value;
428
+ }
429
+ if (autoformatCheckbox) {
430
+ yasqe.persistentConfig.autoformatOnQuery = autoformatCheckbox.checked;
431
+ }
432
+ if (constructValidationCheckbox) {
433
+ yasqe.setCheckConstructVariables(constructValidationCheckbox.checked);
434
+ }
435
+ const snippetsBarCheckbox = document.getElementById("showSnippetsBar");
436
+ if (snippetsBarCheckbox) {
437
+ yasqe.setSnippetsBarVisible(snippetsBarCheckbox.checked);
438
+ }
439
+ yasqe.saveQuery();
440
+ }
260
441
  const requestContent = this.modalContent.querySelector("#request-content");
261
442
  if (requestContent) {
262
443
  const selects = requestContent.querySelectorAll("select[data-config]");
@@ -430,6 +611,328 @@ export default class TabSettingsModal {
430
611
  const currentTheme = this.tab.yasgui.getTheme();
431
612
  return currentTheme === "dark" ? MOON_ICON : SUN_ICON;
432
613
  }
614
+ drawImportExportSettings(container) {
615
+ const exportSection = document.createElement("div");
616
+ addClass(exportSection, "settingsSection");
617
+ const exportLabel = document.createElement("label");
618
+ exportLabel.textContent = "Export Configuration";
619
+ addClass(exportLabel, "settingsLabel");
620
+ const exportHelp = document.createElement("div");
621
+ exportHelp.textContent =
622
+ "Export your YASGUI configuration in RDF Turtle format. This includes tabs, queries, endpoints, and preferences.";
623
+ addClass(exportHelp, "settingsHelp");
624
+ const exportButtonsContainer = document.createElement("div");
625
+ addClass(exportButtonsContainer, "exportButtons");
626
+ const copyButton = document.createElement("button");
627
+ copyButton.textContent = "📋 Copy to Clipboard";
628
+ copyButton.type = "button";
629
+ addClass(copyButton, "secondaryButton");
630
+ copyButton.onclick = () => __awaiter(this, void 0, void 0, function* () {
631
+ try {
632
+ const config = this.tab.yasgui.persistentConfig.getPersistedConfig();
633
+ yield ConfigExportImport.copyConfigToClipboard(config);
634
+ this.showNotification("Configuration copied to clipboard!", "success");
635
+ }
636
+ catch (error) {
637
+ this.showNotification("Failed to copy to clipboard: " + error.message, "error");
638
+ }
639
+ });
640
+ const downloadButton = document.createElement("button");
641
+ downloadButton.textContent = "💾 Download as File";
642
+ downloadButton.type = "button";
643
+ addClass(downloadButton, "primaryButton");
644
+ downloadButton.onclick = () => {
645
+ try {
646
+ const config = this.tab.yasgui.persistentConfig.getPersistedConfig();
647
+ ConfigExportImport.downloadConfigAsFile(config);
648
+ this.showNotification("Configuration downloaded!", "success");
649
+ }
650
+ catch (error) {
651
+ this.showNotification("Failed to download: " + error.message, "error");
652
+ }
653
+ };
654
+ exportButtonsContainer.appendChild(copyButton);
655
+ exportButtonsContainer.appendChild(downloadButton);
656
+ exportSection.appendChild(exportLabel);
657
+ exportSection.appendChild(exportHelp);
658
+ exportSection.appendChild(exportButtonsContainer);
659
+ container.appendChild(exportSection);
660
+ const importSection = document.createElement("div");
661
+ addClass(importSection, "settingsSection");
662
+ const importLabel = document.createElement("label");
663
+ importLabel.textContent = "Import Configuration";
664
+ addClass(importLabel, "settingsLabel");
665
+ const importHelp = document.createElement("div");
666
+ importHelp.textContent = "Import a previously exported configuration in RDF Turtle format.";
667
+ addClass(importHelp, "settingsHelp");
668
+ const dropZone = document.createElement("div");
669
+ addClass(dropZone, "dropZone");
670
+ dropZone.innerHTML = `
671
+ <div class="dropZoneContent">
672
+ <div class="dropZoneIcon">📁</div>
673
+ <div class="dropZoneText">Drag & drop a .ttl file here</div>
674
+ <div class="dropZoneOr">or</div>
675
+ </div>
676
+ `;
677
+ const fileInput = document.createElement("input");
678
+ fileInput.type = "file";
679
+ fileInput.accept = ".ttl,.turtle,text/turtle";
680
+ fileInput.style.display = "none";
681
+ fileInput.id = "config-file-input";
682
+ const browseButton = document.createElement("button");
683
+ browseButton.textContent = "📂 Browse Files";
684
+ browseButton.type = "button";
685
+ addClass(browseButton, "secondaryButton");
686
+ browseButton.onclick = () => fileInput.click();
687
+ const pasteButton = document.createElement("button");
688
+ pasteButton.textContent = "📋 Paste from Clipboard";
689
+ pasteButton.type = "button";
690
+ addClass(pasteButton, "secondaryButton");
691
+ pasteButton.onclick = () => __awaiter(this, void 0, void 0, function* () {
692
+ try {
693
+ const content = yield ConfigExportImport.readConfigFromClipboard();
694
+ yield this.importConfiguration(content);
695
+ }
696
+ catch (error) {
697
+ this.showNotification("Failed to read from clipboard: " + error.message, "error");
698
+ }
699
+ });
700
+ fileInput.onchange = (e) => __awaiter(this, void 0, void 0, function* () {
701
+ var _a;
702
+ const file = (_a = e.target.files) === null || _a === void 0 ? void 0 : _a[0];
703
+ if (file) {
704
+ try {
705
+ const content = yield ConfigExportImport.readConfigFromFile(file);
706
+ yield this.importConfiguration(content);
707
+ }
708
+ catch (error) {
709
+ this.showNotification("Failed to read file: " + error.message, "error");
710
+ }
711
+ }
712
+ });
713
+ dropZone.ondragover = (e) => {
714
+ e.preventDefault();
715
+ addClass(dropZone, "dragover");
716
+ };
717
+ dropZone.ondragleave = () => {
718
+ removeClass(dropZone, "dragover");
719
+ };
720
+ dropZone.ondrop = (e) => __awaiter(this, void 0, void 0, function* () {
721
+ var _a, _b;
722
+ e.preventDefault();
723
+ removeClass(dropZone, "dragover");
724
+ const file = (_b = (_a = e.dataTransfer) === null || _a === void 0 ? void 0 : _a.files) === null || _b === void 0 ? void 0 : _b[0];
725
+ if (file) {
726
+ try {
727
+ const content = yield ConfigExportImport.readConfigFromFile(file);
728
+ yield this.importConfiguration(content);
729
+ }
730
+ catch (error) {
731
+ this.showNotification("Failed to read file: " + error.message, "error");
732
+ }
733
+ }
734
+ });
735
+ const importButtonsContainer = document.createElement("div");
736
+ addClass(importButtonsContainer, "importButtons");
737
+ importButtonsContainer.appendChild(browseButton);
738
+ importButtonsContainer.appendChild(pasteButton);
739
+ dropZone.appendChild(importButtonsContainer);
740
+ importSection.appendChild(importLabel);
741
+ importSection.appendChild(importHelp);
742
+ importSection.appendChild(dropZone);
743
+ importSection.appendChild(fileInput);
744
+ container.appendChild(importSection);
745
+ }
746
+ drawKeyboardShortcuts(container) {
747
+ const shortcutsData = [
748
+ {
749
+ category: "Query Editor (YASQE)",
750
+ shortcuts: [
751
+ { keys: ["Ctrl+Enter", "Cmd+Enter"], description: "Execute query" },
752
+ { keys: ["Ctrl+Space", "Cmd+Space"], description: "Trigger autocomplete" },
753
+ { keys: ["Ctrl+S", "Cmd+S"], description: "Save query to local storage" },
754
+ { keys: ["Ctrl+Shift+F", "Cmd+Shift+F"], description: "Format query" },
755
+ { keys: ["Ctrl+/", "Cmd+/"], description: "Toggle comment on selected lines" },
756
+ { keys: ["Ctrl+Shift+D", "Cmd+Shift+D"], description: "Duplicate current line" },
757
+ { keys: ["Ctrl+Shift+K", "Cmd+Shift+K"], description: "Delete current line" },
758
+ { keys: ["Esc"], description: "Remove focus from editor" },
759
+ { keys: ["Ctrl+Click"], description: "Explore URI connections (on URI)" },
760
+ ],
761
+ },
762
+ {
763
+ category: "Fullscreen",
764
+ shortcuts: [
765
+ { keys: ["F11"], description: "Toggle YASQE (editor) fullscreen" },
766
+ { keys: ["F10"], description: "Toggle YASR (results) fullscreen" },
767
+ { keys: ["F9"], description: "Switch between YASQE and YASR fullscreen" },
768
+ { keys: ["Esc"], description: "Exit fullscreen mode" },
769
+ ],
770
+ },
771
+ ];
772
+ shortcutsData.forEach((section) => {
773
+ const sectionEl = document.createElement("div");
774
+ addClass(sectionEl, "shortcutsSection");
775
+ const categoryLabel = document.createElement("h3");
776
+ categoryLabel.textContent = section.category;
777
+ addClass(categoryLabel, "shortcutsCategory");
778
+ sectionEl.appendChild(categoryLabel);
779
+ const table = document.createElement("table");
780
+ addClass(table, "shortcutsTable");
781
+ table.setAttribute("role", "table");
782
+ table.setAttribute("aria-label", `${section.category} keyboard shortcuts`);
783
+ const caption = document.createElement("caption");
784
+ caption.textContent = `${section.category} keyboard shortcuts`;
785
+ caption.style.position = "absolute";
786
+ caption.style.left = "-10000px";
787
+ caption.style.width = "1px";
788
+ caption.style.height = "1px";
789
+ caption.style.overflow = "hidden";
790
+ table.appendChild(caption);
791
+ const thead = document.createElement("thead");
792
+ const headerRow = document.createElement("tr");
793
+ const keysHeader = document.createElement("th");
794
+ keysHeader.textContent = "Keys";
795
+ keysHeader.setAttribute("scope", "col");
796
+ addClass(keysHeader, "shortcutsKeysHeader");
797
+ headerRow.appendChild(keysHeader);
798
+ const descHeader = document.createElement("th");
799
+ descHeader.textContent = "Description";
800
+ descHeader.setAttribute("scope", "col");
801
+ addClass(descHeader, "shortcutsDescHeader");
802
+ headerRow.appendChild(descHeader);
803
+ thead.appendChild(headerRow);
804
+ table.appendChild(thead);
805
+ const tbody = document.createElement("tbody");
806
+ section.shortcuts.forEach((shortcut) => {
807
+ const row = document.createElement("tr");
808
+ const keysCell = document.createElement("td");
809
+ addClass(keysCell, "shortcutsKeys");
810
+ shortcut.keys.forEach((key, index) => {
811
+ if (index > 0) {
812
+ const separator = document.createElement("span");
813
+ separator.textContent = " / ";
814
+ addClass(separator, "shortcutsSeparator");
815
+ keysCell.appendChild(separator);
816
+ }
817
+ const kbd = document.createElement("kbd");
818
+ kbd.textContent = key;
819
+ keysCell.appendChild(kbd);
820
+ });
821
+ row.appendChild(keysCell);
822
+ const descCell = document.createElement("td");
823
+ addClass(descCell, "shortcutsDescription");
824
+ descCell.textContent = shortcut.description;
825
+ row.appendChild(descCell);
826
+ tbody.appendChild(row);
827
+ });
828
+ table.appendChild(tbody);
829
+ sectionEl.appendChild(table);
830
+ container.appendChild(sectionEl);
831
+ });
832
+ }
833
+ importConfiguration(turtleContent) {
834
+ return __awaiter(this, void 0, void 0, function* () {
835
+ var _a;
836
+ try {
837
+ const parsedConfig = ConfigExportImport.parseFromTurtle(turtleContent);
838
+ const confirmMsg = `This will replace your current configuration with ${((_a = parsedConfig.tabs) === null || _a === void 0 ? void 0 : _a.length) || 0} tab(s). Continue?`;
839
+ if (!confirm(confirmMsg)) {
840
+ return;
841
+ }
842
+ this.close();
843
+ if (parsedConfig.theme) {
844
+ this.tab.yasgui.themeManager.setTheme(parsedConfig.theme);
845
+ }
846
+ if (parsedConfig.orientation) {
847
+ this.tab.yasgui.config.orientation = parsedConfig.orientation;
848
+ }
849
+ const existingTabIds = [...this.tab.yasgui.persistentConfig.getTabs()];
850
+ for (const tabId of existingTabIds) {
851
+ const tab = this.tab.yasgui.getTab(tabId);
852
+ if (tab) {
853
+ tab.close();
854
+ }
855
+ }
856
+ this.tab.yasgui.persistentConfig.updatePersistedConfig(parsedConfig);
857
+ window.location.reload();
858
+ }
859
+ catch (error) {
860
+ this.showNotification("Failed to import configuration: " + error.message, "error");
861
+ }
862
+ });
863
+ }
864
+ showNotification(message, type) {
865
+ const notification = document.createElement("div");
866
+ addClass(notification, "importExportNotification", type);
867
+ notification.textContent = message;
868
+ this.modalContent.appendChild(notification);
869
+ setTimeout(() => {
870
+ if (notification.parentNode) {
871
+ notification.parentNode.removeChild(notification);
872
+ }
873
+ }, 5000);
874
+ }
875
+ drawAboutSettings(container) {
876
+ const aboutSection = document.createElement("div");
877
+ addClass(aboutSection, "settingsSection", "aboutSection");
878
+ const titleContainer = document.createElement("div");
879
+ addClass(titleContainer, "aboutTitle");
880
+ const title = document.createElement("h3");
881
+ title.textContent = "YASGUI";
882
+ addClass(title, "aboutMainTitle");
883
+ const versionBadge = document.createElement("span");
884
+ versionBadge.textContent = `v${VERSION}`;
885
+ addClass(versionBadge, "versionBadge");
886
+ titleContainer.appendChild(title);
887
+ titleContainer.appendChild(versionBadge);
888
+ aboutSection.appendChild(titleContainer);
889
+ const subtitle = document.createElement("p");
890
+ subtitle.textContent = "Yet Another SPARQL GUI";
891
+ addClass(subtitle, "aboutSubtitle");
892
+ aboutSection.appendChild(subtitle);
893
+ const linksSection = document.createElement("div");
894
+ addClass(linksSection, "aboutLinks");
895
+ const docsLink = this.createAboutLink("📚 Documentation", "https://yasgui-doc.matdata.eu/docs/", "View the complete documentation and guides");
896
+ linksSection.appendChild(docsLink);
897
+ const releasesLink = this.createAboutLink("📝 Release Notes", "https://github.com/Matdata-eu/Yasgui/releases", "See what's new in the latest releases");
898
+ linksSection.appendChild(releasesLink);
899
+ const issuesLink = this.createAboutLink("🐛 Report Issues & Get Support", "https://github.com/Matdata-eu/Yasgui/issues", "Report bugs, request features, or ask for help");
900
+ linksSection.appendChild(issuesLink);
901
+ aboutSection.appendChild(linksSection);
902
+ const footerInfo = document.createElement("div");
903
+ addClass(footerInfo, "aboutFooter");
904
+ const paragraph1 = document.createElement("p");
905
+ paragraph1.textContent = "YASGUI is an open-source project maintained by ";
906
+ const matdataLink = document.createElement("a");
907
+ matdataLink.href = "https://matdata.eu";
908
+ matdataLink.target = "_blank";
909
+ matdataLink.rel = "noopener noreferrer";
910
+ matdataLink.textContent = "Matdata";
911
+ paragraph1.appendChild(matdataLink);
912
+ paragraph1.appendChild(document.createTextNode("."));
913
+ const paragraph2 = document.createElement("p");
914
+ paragraph2.textContent = "Licensed under the MIT License.";
915
+ footerInfo.appendChild(paragraph1);
916
+ footerInfo.appendChild(paragraph2);
917
+ aboutSection.appendChild(footerInfo);
918
+ container.appendChild(aboutSection);
919
+ }
920
+ createAboutLink(label, url, description) {
921
+ const linkContainer = document.createElement("div");
922
+ addClass(linkContainer, "aboutLinkItem");
923
+ const link = document.createElement("a");
924
+ link.href = url;
925
+ link.target = "_blank";
926
+ link.rel = "noopener noreferrer";
927
+ link.textContent = label;
928
+ addClass(link, "aboutLink");
929
+ const desc = document.createElement("p");
930
+ desc.textContent = description;
931
+ addClass(desc, "aboutLinkDescription");
932
+ linkContainer.appendChild(link);
933
+ linkContainer.appendChild(desc);
934
+ return linkContainer;
935
+ }
433
936
  destroy() {
434
937
  if (this.modalOverlay && this.modalOverlay.parentNode) {
435
938
  this.modalOverlay.parentNode.removeChild(this.modalOverlay);