@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.
- package/README.md +128 -144
- package/build/ts/src/ConfigExportImport.d.ts +16 -0
- package/build/ts/src/ConfigExportImport.js +304 -0
- package/build/ts/src/ConfigExportImport.js.map +1 -0
- package/build/ts/src/PersistentConfig.d.ts +4 -0
- package/build/ts/src/PersistentConfig.js +7 -0
- package/build/ts/src/PersistentConfig.js.map +1 -1
- package/build/ts/src/Tab.d.ts +2 -1
- package/build/ts/src/Tab.js +19 -10
- package/build/ts/src/Tab.js.map +1 -1
- package/build/ts/src/TabSettingsModal.d.ts +7 -0
- package/build/ts/src/TabSettingsModal.js +504 -1
- package/build/ts/src/TabSettingsModal.js.map +1 -1
- package/build/ts/src/version.d.ts +1 -0
- package/build/ts/src/version.js +2 -0
- package/build/ts/src/version.js.map +1 -0
- package/build/yasgui.min.css +1 -1
- package/build/yasgui.min.css.map +3 -3
- package/build/yasgui.min.js +166 -106
- package/build/yasgui.min.js.map +4 -4
- package/package.json +1 -1
- package/src/ConfigExportImport.ts +391 -0
- package/src/PersistentConfig.ts +17 -0
- package/src/Tab.ts +32 -17
- package/src/TabSettingsModal.scss +262 -2
- package/src/TabSettingsModal.ts +637 -3
- package/src/sortablejs.d.ts +36 -0
- package/src/tab.scss +3 -4
- package/src/themes.scss +1 -1
- package/src/version.ts +3 -0
|
@@ -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 === "
|
|
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);
|