@matdata/yasgui 5.3.0 → 5.5.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/build/ts/src/ConfigExportImport.js +1 -0
- package/build/ts/src/ConfigExportImport.js.map +1 -1
- package/build/ts/src/PersistentConfig.d.ts +7 -1
- package/build/ts/src/PersistentConfig.js +32 -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 +46 -11
- package/build/ts/src/Tab.js.map +1 -1
- package/build/ts/src/TabSettingsModal.d.ts +6 -2
- package/build/ts/src/TabSettingsModal.js +519 -114
- package/build/ts/src/TabSettingsModal.js.map +1 -1
- package/build/ts/src/index.d.ts +10 -0
- package/build/ts/src/index.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 +143 -122
- package/build/yasgui.min.js.map +4 -4
- package/package.json +1 -1
- package/src/ConfigExportImport.ts +1 -0
- package/src/PersistentConfig.ts +44 -2
- package/src/Tab.ts +76 -18
- package/src/TabSettingsModal.scss +565 -14
- package/src/TabSettingsModal.ts +676 -143
- package/src/index.ts +11 -0
- package/src/tab.scss +3 -4
- package/src/themes.scss +1 -1
- package/src/version.ts +3 -0
|
@@ -10,6 +10,7 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
|
|
|
10
10
|
import { addClass, removeClass } from "@matdata/yasgui-utils";
|
|
11
11
|
import "./TabSettingsModal.scss";
|
|
12
12
|
import * as ConfigExportImport from "./ConfigExportImport";
|
|
13
|
+
import { VERSION } from "./version";
|
|
13
14
|
const MOON_ICON = `<svg viewBox="0 0 24 24" fill="currentColor">
|
|
14
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"/>
|
|
15
16
|
</svg>`;
|
|
@@ -89,38 +90,55 @@ export default class TabSettingsModal {
|
|
|
89
90
|
this.modalContent.appendChild(header);
|
|
90
91
|
const body = document.createElement("div");
|
|
91
92
|
addClass(body, "modalBody");
|
|
92
|
-
const
|
|
93
|
-
addClass(
|
|
93
|
+
const sidebar = document.createElement("div");
|
|
94
|
+
addClass(sidebar, "modalSidebar");
|
|
94
95
|
const requestTab = document.createElement("button");
|
|
95
96
|
requestTab.textContent = "Request";
|
|
96
|
-
addClass(requestTab, "
|
|
97
|
+
addClass(requestTab, "modalNavButton", "active");
|
|
97
98
|
requestTab.onclick = () => this.switchTab("request");
|
|
99
|
+
const endpointsTab = document.createElement("button");
|
|
100
|
+
endpointsTab.textContent = "SPARQL Endpoints";
|
|
101
|
+
addClass(endpointsTab, "modalNavButton");
|
|
102
|
+
endpointsTab.onclick = () => this.switchTab("endpoints");
|
|
98
103
|
const prefixTab = document.createElement("button");
|
|
99
104
|
prefixTab.textContent = "Prefixes";
|
|
100
|
-
addClass(prefixTab, "
|
|
105
|
+
addClass(prefixTab, "modalNavButton");
|
|
101
106
|
prefixTab.onclick = () => this.switchTab("prefix");
|
|
102
107
|
const editorTab = document.createElement("button");
|
|
103
108
|
editorTab.textContent = "Editor";
|
|
104
|
-
addClass(editorTab, "
|
|
109
|
+
addClass(editorTab, "modalNavButton");
|
|
105
110
|
editorTab.onclick = () => this.switchTab("editor");
|
|
106
|
-
const endpointsTab = document.createElement("button");
|
|
107
|
-
endpointsTab.textContent = "Endpoint Buttons";
|
|
108
|
-
addClass(endpointsTab, "modalTabButton");
|
|
109
|
-
endpointsTab.onclick = () => this.switchTab("endpoints");
|
|
110
111
|
const importExportTab = document.createElement("button");
|
|
111
112
|
importExportTab.textContent = "Import/Export";
|
|
112
|
-
addClass(importExportTab, "
|
|
113
|
+
addClass(importExportTab, "modalNavButton");
|
|
113
114
|
importExportTab.onclick = () => this.switchTab("importexport");
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
115
|
+
const shortcutsTab = document.createElement("button");
|
|
116
|
+
shortcutsTab.textContent = "Keyboard Shortcuts";
|
|
117
|
+
addClass(shortcutsTab, "modalNavButton");
|
|
118
|
+
shortcutsTab.onclick = () => this.switchTab("shortcuts");
|
|
119
|
+
const aboutTab = document.createElement("button");
|
|
120
|
+
aboutTab.textContent = "About";
|
|
121
|
+
addClass(aboutTab, "modalNavButton");
|
|
122
|
+
aboutTab.onclick = () => this.switchTab("about");
|
|
123
|
+
sidebar.appendChild(requestTab);
|
|
124
|
+
sidebar.appendChild(endpointsTab);
|
|
125
|
+
sidebar.appendChild(prefixTab);
|
|
126
|
+
sidebar.appendChild(editorTab);
|
|
127
|
+
sidebar.appendChild(importExportTab);
|
|
128
|
+
sidebar.appendChild(shortcutsTab);
|
|
129
|
+
sidebar.appendChild(aboutTab);
|
|
130
|
+
const contentArea = document.createElement("div");
|
|
131
|
+
addClass(contentArea, "modalContentArea");
|
|
132
|
+
body.appendChild(sidebar);
|
|
133
|
+
body.appendChild(contentArea);
|
|
120
134
|
const requestContent = document.createElement("div");
|
|
121
135
|
addClass(requestContent, "modalTabContent", "active");
|
|
122
136
|
requestContent.id = "request-content";
|
|
123
137
|
this.drawRequestSettings(requestContent);
|
|
138
|
+
const endpointsContent = document.createElement("div");
|
|
139
|
+
addClass(endpointsContent, "modalTabContent");
|
|
140
|
+
endpointsContent.id = "endpoints-content";
|
|
141
|
+
this.drawEndpointsSettings(endpointsContent);
|
|
124
142
|
const prefixContent = document.createElement("div");
|
|
125
143
|
addClass(prefixContent, "modalTabContent");
|
|
126
144
|
prefixContent.id = "prefix-content";
|
|
@@ -129,19 +147,25 @@ export default class TabSettingsModal {
|
|
|
129
147
|
addClass(editorContent, "modalTabContent");
|
|
130
148
|
editorContent.id = "editor-content";
|
|
131
149
|
this.drawEditorSettings(editorContent);
|
|
132
|
-
const endpointsContent = document.createElement("div");
|
|
133
|
-
addClass(endpointsContent, "modalTabContent");
|
|
134
|
-
endpointsContent.id = "endpoints-content";
|
|
135
|
-
this.drawEndpointButtonsSettings(endpointsContent);
|
|
136
150
|
const importExportContent = document.createElement("div");
|
|
137
151
|
addClass(importExportContent, "modalTabContent");
|
|
138
152
|
importExportContent.id = "importexport-content";
|
|
139
153
|
this.drawImportExportSettings(importExportContent);
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
154
|
+
const shortcutsContent = document.createElement("div");
|
|
155
|
+
addClass(shortcutsContent, "modalTabContent");
|
|
156
|
+
shortcutsContent.id = "shortcuts-content";
|
|
157
|
+
this.drawKeyboardShortcuts(shortcutsContent);
|
|
158
|
+
const aboutContent = document.createElement("div");
|
|
159
|
+
addClass(aboutContent, "modalTabContent");
|
|
160
|
+
aboutContent.id = "about-content";
|
|
161
|
+
this.drawAboutSettings(aboutContent);
|
|
162
|
+
contentArea.appendChild(requestContent);
|
|
163
|
+
contentArea.appendChild(endpointsContent);
|
|
164
|
+
contentArea.appendChild(prefixContent);
|
|
165
|
+
contentArea.appendChild(editorContent);
|
|
166
|
+
contentArea.appendChild(importExportContent);
|
|
167
|
+
contentArea.appendChild(shortcutsContent);
|
|
168
|
+
contentArea.appendChild(aboutContent);
|
|
145
169
|
this.modalContent.appendChild(body);
|
|
146
170
|
const footer = document.createElement("div");
|
|
147
171
|
addClass(footer, "modalFooter");
|
|
@@ -160,14 +184,16 @@ export default class TabSettingsModal {
|
|
|
160
184
|
document.body.appendChild(this.modalOverlay);
|
|
161
185
|
}
|
|
162
186
|
switchTab(tabName) {
|
|
163
|
-
const buttons = this.modalContent.querySelectorAll(".
|
|
187
|
+
const buttons = this.modalContent.querySelectorAll(".modalNavButton");
|
|
164
188
|
const contents = this.modalContent.querySelectorAll(".modalTabContent");
|
|
165
189
|
buttons.forEach((btn, index) => {
|
|
166
190
|
if ((tabName === "request" && index === 0) ||
|
|
167
|
-
(tabName === "
|
|
168
|
-
(tabName === "
|
|
169
|
-
(tabName === "
|
|
170
|
-
(tabName === "importexport" && index === 4)
|
|
191
|
+
(tabName === "endpoints" && index === 1) ||
|
|
192
|
+
(tabName === "prefix" && index === 2) ||
|
|
193
|
+
(tabName === "editor" && index === 3) ||
|
|
194
|
+
(tabName === "importexport" && index === 4) ||
|
|
195
|
+
(tabName === "shortcuts" && index === 5) ||
|
|
196
|
+
(tabName === "about" && index === 6)) {
|
|
171
197
|
addClass(btn, "active");
|
|
172
198
|
}
|
|
173
199
|
else {
|
|
@@ -293,6 +319,317 @@ export default class TabSettingsModal {
|
|
|
293
319
|
constructValidationSection.appendChild(constructValidationCheckboxContainer);
|
|
294
320
|
constructValidationSection.appendChild(constructValidationHelp);
|
|
295
321
|
container.appendChild(constructValidationSection);
|
|
322
|
+
const snippetsBarSection = document.createElement("div");
|
|
323
|
+
addClass(snippetsBarSection, "settingsSection");
|
|
324
|
+
const snippetsBarCheckboxContainer = document.createElement("div");
|
|
325
|
+
addClass(snippetsBarCheckboxContainer, "checkboxContainer");
|
|
326
|
+
const snippetsBarCheckbox = document.createElement("input");
|
|
327
|
+
snippetsBarCheckbox.type = "checkbox";
|
|
328
|
+
snippetsBarCheckbox.id = "showSnippetsBar";
|
|
329
|
+
snippetsBarCheckbox.checked = yasqe.getSnippetsBarVisible();
|
|
330
|
+
const snippetsBarLabel = document.createElement("label");
|
|
331
|
+
snippetsBarLabel.htmlFor = "showSnippetsBar";
|
|
332
|
+
snippetsBarLabel.textContent = "Show code snippets bar";
|
|
333
|
+
const snippetsBarHelp = document.createElement("div");
|
|
334
|
+
snippetsBarHelp.textContent =
|
|
335
|
+
"Display the code snippets bar above the editor for quick insertion of common SPARQL patterns.";
|
|
336
|
+
addClass(snippetsBarHelp, "settingsHelp");
|
|
337
|
+
snippetsBarHelp.style.marginTop = "5px";
|
|
338
|
+
snippetsBarCheckboxContainer.appendChild(snippetsBarCheckbox);
|
|
339
|
+
snippetsBarCheckboxContainer.appendChild(snippetsBarLabel);
|
|
340
|
+
snippetsBarSection.appendChild(snippetsBarCheckboxContainer);
|
|
341
|
+
snippetsBarSection.appendChild(snippetsBarHelp);
|
|
342
|
+
container.appendChild(snippetsBarSection);
|
|
343
|
+
}
|
|
344
|
+
drawEndpointsSettings(container) {
|
|
345
|
+
const section = document.createElement("div");
|
|
346
|
+
addClass(section, "settingsSection");
|
|
347
|
+
const label = document.createElement("label");
|
|
348
|
+
label.textContent = "SPARQL Endpoints";
|
|
349
|
+
addClass(label, "settingsLabel");
|
|
350
|
+
const help = document.createElement("div");
|
|
351
|
+
help.textContent =
|
|
352
|
+
"Manage your SPARQL endpoints. Each endpoint can have its own authentication and be displayed as a quick-switch button.";
|
|
353
|
+
addClass(help, "settingsHelp");
|
|
354
|
+
section.appendChild(label);
|
|
355
|
+
section.appendChild(help);
|
|
356
|
+
const endpointsList = document.createElement("div");
|
|
357
|
+
addClass(endpointsList, "endpointsTable");
|
|
358
|
+
this.renderEndpointsList(endpointsList);
|
|
359
|
+
section.appendChild(endpointsList);
|
|
360
|
+
container.appendChild(section);
|
|
361
|
+
}
|
|
362
|
+
renderEndpointsList(container) {
|
|
363
|
+
container.innerHTML = "";
|
|
364
|
+
const configs = this.tab.yasgui.persistentConfig.getEndpointConfigs();
|
|
365
|
+
const table = document.createElement("table");
|
|
366
|
+
addClass(table, "endpointsTableElement");
|
|
367
|
+
const thead = document.createElement("thead");
|
|
368
|
+
const headerRow = document.createElement("tr");
|
|
369
|
+
const headers = ["Endpoint", "Label", "Button", "Authentication", "Actions"];
|
|
370
|
+
headers.forEach((h) => {
|
|
371
|
+
const th = document.createElement("th");
|
|
372
|
+
th.textContent = h;
|
|
373
|
+
headerRow.appendChild(th);
|
|
374
|
+
});
|
|
375
|
+
thead.appendChild(headerRow);
|
|
376
|
+
table.appendChild(thead);
|
|
377
|
+
const tbody = document.createElement("tbody");
|
|
378
|
+
if (configs.length === 0) {
|
|
379
|
+
const emptyRow = document.createElement("tr");
|
|
380
|
+
const emptyCell = document.createElement("td");
|
|
381
|
+
emptyCell.colSpan = 5;
|
|
382
|
+
emptyCell.textContent = "No endpoints yet. Add one below or access an endpoint to have it automatically tracked.";
|
|
383
|
+
addClass(emptyCell, "emptyMessage");
|
|
384
|
+
emptyCell.style.textAlign = "center";
|
|
385
|
+
emptyCell.style.padding = "20px";
|
|
386
|
+
emptyRow.appendChild(emptyCell);
|
|
387
|
+
tbody.appendChild(emptyRow);
|
|
388
|
+
}
|
|
389
|
+
configs.forEach((config, index) => {
|
|
390
|
+
const row = document.createElement("tr");
|
|
391
|
+
const endpointCell = document.createElement("td");
|
|
392
|
+
endpointCell.textContent = config.endpoint;
|
|
393
|
+
endpointCell.title = config.endpoint;
|
|
394
|
+
addClass(endpointCell, "endpointCell");
|
|
395
|
+
row.appendChild(endpointCell);
|
|
396
|
+
const labelCell = document.createElement("td");
|
|
397
|
+
const labelInput = document.createElement("input");
|
|
398
|
+
labelInput.type = "text";
|
|
399
|
+
labelInput.value = config.label || "";
|
|
400
|
+
labelInput.placeholder = "Optional label";
|
|
401
|
+
addClass(labelInput, "endpointLabelInput");
|
|
402
|
+
labelInput.onchange = () => {
|
|
403
|
+
this.tab.yasgui.persistentConfig.addOrUpdateEndpoint(config.endpoint, {
|
|
404
|
+
label: labelInput.value.trim() || undefined,
|
|
405
|
+
});
|
|
406
|
+
this.renderEndpointsList(container);
|
|
407
|
+
this.tab.refreshEndpointButtons();
|
|
408
|
+
};
|
|
409
|
+
labelCell.appendChild(labelInput);
|
|
410
|
+
row.appendChild(labelCell);
|
|
411
|
+
const buttonCell = document.createElement("td");
|
|
412
|
+
const buttonCheckbox = document.createElement("input");
|
|
413
|
+
buttonCheckbox.type = "checkbox";
|
|
414
|
+
buttonCheckbox.checked = !!config.showAsButton;
|
|
415
|
+
buttonCheckbox.disabled = !config.label;
|
|
416
|
+
buttonCheckbox.setAttribute("aria-label", config.label ? "Show this endpoint as a quick-switch button" : "Add a label first to enable button");
|
|
417
|
+
buttonCheckbox.title = config.label
|
|
418
|
+
? "Show this endpoint as a quick-switch button"
|
|
419
|
+
: "Add a label first to enable button";
|
|
420
|
+
buttonCheckbox.onchange = () => {
|
|
421
|
+
this.tab.yasgui.persistentConfig.addOrUpdateEndpoint(config.endpoint, {
|
|
422
|
+
showAsButton: buttonCheckbox.checked,
|
|
423
|
+
});
|
|
424
|
+
this.tab.refreshEndpointButtons();
|
|
425
|
+
};
|
|
426
|
+
buttonCell.appendChild(buttonCheckbox);
|
|
427
|
+
addClass(buttonCell, "centerCell");
|
|
428
|
+
row.appendChild(buttonCell);
|
|
429
|
+
const authCell = document.createElement("td");
|
|
430
|
+
const authButton = document.createElement("button");
|
|
431
|
+
authButton.type = "button";
|
|
432
|
+
addClass(authButton, "configureAuthButton");
|
|
433
|
+
if (config.authentication) {
|
|
434
|
+
authButton.textContent = "✓ Configured";
|
|
435
|
+
addClass(authButton, "authenticated");
|
|
436
|
+
}
|
|
437
|
+
else {
|
|
438
|
+
authButton.textContent = "Configure";
|
|
439
|
+
}
|
|
440
|
+
authButton.onclick = () => this.showAuthenticationModal(config.endpoint);
|
|
441
|
+
authCell.appendChild(authButton);
|
|
442
|
+
addClass(authCell, "centerCell");
|
|
443
|
+
row.appendChild(authCell);
|
|
444
|
+
const actionsCell = document.createElement("td");
|
|
445
|
+
const deleteButton = document.createElement("button");
|
|
446
|
+
deleteButton.type = "button";
|
|
447
|
+
deleteButton.textContent = "Delete";
|
|
448
|
+
addClass(deleteButton, "deleteEndpointButton");
|
|
449
|
+
deleteButton.onclick = () => {
|
|
450
|
+
if (confirm(`Delete endpoint "${config.endpoint}"?`)) {
|
|
451
|
+
this.tab.yasgui.persistentConfig.deleteEndpointConfig(config.endpoint);
|
|
452
|
+
this.renderEndpointsList(container);
|
|
453
|
+
this.tab.refreshEndpointButtons();
|
|
454
|
+
}
|
|
455
|
+
};
|
|
456
|
+
actionsCell.appendChild(deleteButton);
|
|
457
|
+
addClass(actionsCell, "centerCell");
|
|
458
|
+
row.appendChild(actionsCell);
|
|
459
|
+
tbody.appendChild(row);
|
|
460
|
+
});
|
|
461
|
+
table.appendChild(tbody);
|
|
462
|
+
container.appendChild(table);
|
|
463
|
+
const addForm = document.createElement("div");
|
|
464
|
+
addClass(addForm, "addEndpointForm");
|
|
465
|
+
const addFormTitle = document.createElement("div");
|
|
466
|
+
addFormTitle.textContent = "Add New Endpoint";
|
|
467
|
+
addClass(addFormTitle, "addFormTitle");
|
|
468
|
+
addForm.appendChild(addFormTitle);
|
|
469
|
+
const formInputs = document.createElement("div");
|
|
470
|
+
addClass(formInputs, "addFormInputs");
|
|
471
|
+
const endpointInput = document.createElement("input");
|
|
472
|
+
endpointInput.type = "url";
|
|
473
|
+
endpointInput.placeholder = "Endpoint URL (e.g., https://dbpedia.org/sparql)";
|
|
474
|
+
addClass(endpointInput, "addEndpointInput");
|
|
475
|
+
formInputs.appendChild(endpointInput);
|
|
476
|
+
const addButton = document.createElement("button");
|
|
477
|
+
addButton.type = "button";
|
|
478
|
+
addButton.textContent = "+ Add Endpoint";
|
|
479
|
+
addClass(addButton, "addEndpointButton");
|
|
480
|
+
addButton.onclick = () => {
|
|
481
|
+
const endpoint = endpointInput.value.trim();
|
|
482
|
+
if (!endpoint) {
|
|
483
|
+
alert("Please enter an endpoint URL.");
|
|
484
|
+
return;
|
|
485
|
+
}
|
|
486
|
+
if (!/^https?:\/\//i.test(endpoint)) {
|
|
487
|
+
alert("Endpoint URL must start with http:// or https://");
|
|
488
|
+
return;
|
|
489
|
+
}
|
|
490
|
+
try {
|
|
491
|
+
new URL(endpoint);
|
|
492
|
+
}
|
|
493
|
+
catch (e) {
|
|
494
|
+
alert(e instanceof Error && e.message ? "Malformed URL: " + e.message : "Please enter a valid URL.");
|
|
495
|
+
return;
|
|
496
|
+
}
|
|
497
|
+
const existing = this.tab.yasgui.persistentConfig.getEndpointConfig(endpoint);
|
|
498
|
+
if (existing) {
|
|
499
|
+
alert("This endpoint is already in the list.");
|
|
500
|
+
return;
|
|
501
|
+
}
|
|
502
|
+
this.tab.yasgui.persistentConfig.addOrUpdateEndpoint(endpoint, {});
|
|
503
|
+
endpointInput.value = "";
|
|
504
|
+
this.renderEndpointsList(container);
|
|
505
|
+
this.tab.refreshEndpointButtons();
|
|
506
|
+
};
|
|
507
|
+
formInputs.appendChild(addButton);
|
|
508
|
+
addForm.appendChild(formInputs);
|
|
509
|
+
container.appendChild(addForm);
|
|
510
|
+
}
|
|
511
|
+
showAuthenticationModal(endpoint) {
|
|
512
|
+
const config = this.tab.yasgui.persistentConfig.getEndpointConfig(endpoint);
|
|
513
|
+
const existingAuth = config === null || config === void 0 ? void 0 : config.authentication;
|
|
514
|
+
const authModalOverlay = document.createElement("div");
|
|
515
|
+
addClass(authModalOverlay, "authModalOverlay");
|
|
516
|
+
authModalOverlay.onclick = () => authModalOverlay.remove();
|
|
517
|
+
const authModal = document.createElement("div");
|
|
518
|
+
addClass(authModal, "authModal");
|
|
519
|
+
authModal.onclick = (e) => e.stopPropagation();
|
|
520
|
+
const header = document.createElement("div");
|
|
521
|
+
addClass(header, "authModalHeader");
|
|
522
|
+
const title = document.createElement("h3");
|
|
523
|
+
title.textContent = "Configure Authentication";
|
|
524
|
+
const subtitle = document.createElement("div");
|
|
525
|
+
subtitle.textContent = endpoint;
|
|
526
|
+
addClass(subtitle, "authModalSubtitle");
|
|
527
|
+
header.appendChild(title);
|
|
528
|
+
header.appendChild(subtitle);
|
|
529
|
+
authModal.appendChild(header);
|
|
530
|
+
const body = document.createElement("div");
|
|
531
|
+
addClass(body, "authModalBody");
|
|
532
|
+
const typeSection = document.createElement("div");
|
|
533
|
+
addClass(typeSection, "authModalSection");
|
|
534
|
+
const typeLabel = document.createElement("label");
|
|
535
|
+
typeLabel.textContent = "Authentication Type";
|
|
536
|
+
const typeSelect = document.createElement("select");
|
|
537
|
+
const basicOption = document.createElement("option");
|
|
538
|
+
basicOption.value = "basic";
|
|
539
|
+
basicOption.textContent = "HTTP Basic Authentication";
|
|
540
|
+
typeSelect.appendChild(basicOption);
|
|
541
|
+
typeSection.appendChild(typeLabel);
|
|
542
|
+
typeSection.appendChild(typeSelect);
|
|
543
|
+
body.appendChild(typeSection);
|
|
544
|
+
const usernameSection = document.createElement("div");
|
|
545
|
+
addClass(usernameSection, "authModalSection");
|
|
546
|
+
const usernameLabel = document.createElement("label");
|
|
547
|
+
usernameLabel.textContent = "Username";
|
|
548
|
+
const usernameInput = document.createElement("input");
|
|
549
|
+
usernameInput.type = "text";
|
|
550
|
+
usernameInput.placeholder = "Enter username";
|
|
551
|
+
usernameInput.value = (existingAuth === null || existingAuth === void 0 ? void 0 : existingAuth.username) || "";
|
|
552
|
+
usernameInput.autocomplete = "username";
|
|
553
|
+
usernameSection.appendChild(usernameLabel);
|
|
554
|
+
usernameSection.appendChild(usernameInput);
|
|
555
|
+
body.appendChild(usernameSection);
|
|
556
|
+
const passwordSection = document.createElement("div");
|
|
557
|
+
addClass(passwordSection, "authModalSection");
|
|
558
|
+
const passwordLabel = document.createElement("label");
|
|
559
|
+
passwordLabel.textContent = "Password";
|
|
560
|
+
const passwordInput = document.createElement("input");
|
|
561
|
+
passwordInput.type = "password";
|
|
562
|
+
passwordInput.placeholder = "Enter password";
|
|
563
|
+
passwordInput.value = (existingAuth === null || existingAuth === void 0 ? void 0 : existingAuth.password) || "";
|
|
564
|
+
passwordInput.autocomplete = "current-password";
|
|
565
|
+
passwordSection.appendChild(passwordLabel);
|
|
566
|
+
passwordSection.appendChild(passwordInput);
|
|
567
|
+
body.appendChild(passwordSection);
|
|
568
|
+
const securityNotice = document.createElement("div");
|
|
569
|
+
addClass(securityNotice, "authSecurityNotice");
|
|
570
|
+
securityNotice.innerHTML = `
|
|
571
|
+
<strong>⚠️ Security Notice:</strong>
|
|
572
|
+
<ul>
|
|
573
|
+
<li>Credentials are stored in browser localStorage</li>
|
|
574
|
+
<li>Only use with HTTPS endpoints</li>
|
|
575
|
+
<li>Be cautious when using on shared computers</li>
|
|
576
|
+
</ul>
|
|
577
|
+
`;
|
|
578
|
+
body.appendChild(securityNotice);
|
|
579
|
+
authModal.appendChild(body);
|
|
580
|
+
const footer = document.createElement("div");
|
|
581
|
+
addClass(footer, "authModalFooter");
|
|
582
|
+
const removeButton = document.createElement("button");
|
|
583
|
+
removeButton.textContent = "Remove Authentication";
|
|
584
|
+
removeButton.type = "button";
|
|
585
|
+
addClass(removeButton, "authRemoveButton");
|
|
586
|
+
removeButton.onclick = () => {
|
|
587
|
+
this.tab.yasgui.persistentConfig.addOrUpdateEndpoint(endpoint, {
|
|
588
|
+
authentication: undefined,
|
|
589
|
+
});
|
|
590
|
+
authModalOverlay.remove();
|
|
591
|
+
const endpointsList = this.modalContent.querySelector(".endpointsTable");
|
|
592
|
+
if (endpointsList)
|
|
593
|
+
this.renderEndpointsList(endpointsList);
|
|
594
|
+
};
|
|
595
|
+
if (!existingAuth) {
|
|
596
|
+
removeButton.disabled = true;
|
|
597
|
+
}
|
|
598
|
+
const cancelButton = document.createElement("button");
|
|
599
|
+
cancelButton.textContent = "Cancel";
|
|
600
|
+
cancelButton.type = "button";
|
|
601
|
+
addClass(cancelButton, "authCancelButton");
|
|
602
|
+
cancelButton.onclick = () => authModalOverlay.remove();
|
|
603
|
+
const saveButton = document.createElement("button");
|
|
604
|
+
saveButton.textContent = "Save";
|
|
605
|
+
saveButton.type = "button";
|
|
606
|
+
addClass(saveButton, "authSaveButton");
|
|
607
|
+
saveButton.onclick = () => {
|
|
608
|
+
const username = usernameInput.value.trim();
|
|
609
|
+
const password = passwordInput.value;
|
|
610
|
+
if (username && password) {
|
|
611
|
+
this.tab.yasgui.persistentConfig.addOrUpdateEndpoint(endpoint, {
|
|
612
|
+
authentication: {
|
|
613
|
+
type: "basic",
|
|
614
|
+
username,
|
|
615
|
+
password,
|
|
616
|
+
},
|
|
617
|
+
});
|
|
618
|
+
authModalOverlay.remove();
|
|
619
|
+
const endpointsList = this.modalContent.querySelector(".endpointsTable");
|
|
620
|
+
if (endpointsList)
|
|
621
|
+
this.renderEndpointsList(endpointsList);
|
|
622
|
+
}
|
|
623
|
+
else {
|
|
624
|
+
alert("Please enter both username and password.");
|
|
625
|
+
}
|
|
626
|
+
};
|
|
627
|
+
footer.appendChild(removeButton);
|
|
628
|
+
footer.appendChild(cancelButton);
|
|
629
|
+
footer.appendChild(saveButton);
|
|
630
|
+
authModal.appendChild(footer);
|
|
631
|
+
authModalOverlay.appendChild(authModal);
|
|
632
|
+
document.body.appendChild(authModalOverlay);
|
|
296
633
|
}
|
|
297
634
|
drawRequestSettings(container) {
|
|
298
635
|
const reqConfig = this.tab.getRequestConfig();
|
|
@@ -388,6 +725,10 @@ export default class TabSettingsModal {
|
|
|
388
725
|
if (constructValidationCheckbox) {
|
|
389
726
|
yasqe.setCheckConstructVariables(constructValidationCheckbox.checked);
|
|
390
727
|
}
|
|
728
|
+
const snippetsBarCheckbox = document.getElementById("showSnippetsBar");
|
|
729
|
+
if (snippetsBarCheckbox) {
|
|
730
|
+
yasqe.setSnippetsBarVisible(snippetsBarCheckbox.checked);
|
|
731
|
+
}
|
|
391
732
|
yasqe.saveQuery();
|
|
392
733
|
}
|
|
393
734
|
const requestContent = this.modalContent.querySelector("#request-content");
|
|
@@ -475,90 +816,6 @@ export default class TabSettingsModal {
|
|
|
475
816
|
const deduplicated = this.deduplicatePrefixes(combined);
|
|
476
817
|
this.tab.yasgui.persistentConfig.setPrefixes(deduplicated);
|
|
477
818
|
}
|
|
478
|
-
drawEndpointButtonsSettings(container) {
|
|
479
|
-
const section = document.createElement("div");
|
|
480
|
-
addClass(section, "settingsSection");
|
|
481
|
-
const label = document.createElement("label");
|
|
482
|
-
label.textContent = "Custom Endpoint Buttons";
|
|
483
|
-
addClass(label, "settingsLabel");
|
|
484
|
-
const help = document.createElement("div");
|
|
485
|
-
help.textContent = "Add custom endpoint buttons that will appear next to the endpoint textbox.";
|
|
486
|
-
addClass(help, "settingsHelp");
|
|
487
|
-
section.appendChild(label);
|
|
488
|
-
section.appendChild(help);
|
|
489
|
-
const buttonsList = document.createElement("div");
|
|
490
|
-
addClass(buttonsList, "endpointButtonsList");
|
|
491
|
-
this.renderEndpointButtonsList(buttonsList);
|
|
492
|
-
section.appendChild(buttonsList);
|
|
493
|
-
const addForm = document.createElement("div");
|
|
494
|
-
addClass(addForm, "addEndpointButtonForm");
|
|
495
|
-
const labelInput = document.createElement("input");
|
|
496
|
-
labelInput.type = "text";
|
|
497
|
-
labelInput.placeholder = "Button label (e.g., DBpedia)";
|
|
498
|
-
addClass(labelInput, "endpointButtonLabelInput");
|
|
499
|
-
const endpointInput = document.createElement("input");
|
|
500
|
-
endpointInput.type = "url";
|
|
501
|
-
endpointInput.placeholder = "Endpoint URL (e.g., https://dbpedia.org/sparql)";
|
|
502
|
-
addClass(endpointInput, "endpointButtonEndpointInput");
|
|
503
|
-
const addButton = document.createElement("button");
|
|
504
|
-
addButton.textContent = "+ Add Button";
|
|
505
|
-
addClass(addButton, "addEndpointButton");
|
|
506
|
-
addButton.type = "button";
|
|
507
|
-
addButton.onclick = () => {
|
|
508
|
-
const labelValue = labelInput.value.trim();
|
|
509
|
-
const endpointValue = endpointInput.value.trim();
|
|
510
|
-
if (!labelValue || !endpointValue) {
|
|
511
|
-
alert("Please enter both a label and an endpoint URL.");
|
|
512
|
-
return;
|
|
513
|
-
}
|
|
514
|
-
const currentButtons = this.tab.yasgui.persistentConfig.getCustomEndpointButtons();
|
|
515
|
-
currentButtons.push({ label: labelValue, endpoint: endpointValue });
|
|
516
|
-
this.tab.yasgui.persistentConfig.setCustomEndpointButtons(currentButtons);
|
|
517
|
-
labelInput.value = "";
|
|
518
|
-
endpointInput.value = "";
|
|
519
|
-
this.renderEndpointButtonsList(buttonsList);
|
|
520
|
-
};
|
|
521
|
-
addForm.appendChild(labelInput);
|
|
522
|
-
addForm.appendChild(endpointInput);
|
|
523
|
-
addForm.appendChild(addButton);
|
|
524
|
-
section.appendChild(addForm);
|
|
525
|
-
container.appendChild(section);
|
|
526
|
-
}
|
|
527
|
-
renderEndpointButtonsList(container) {
|
|
528
|
-
container.innerHTML = "";
|
|
529
|
-
const customButtons = this.tab.yasgui.persistentConfig.getCustomEndpointButtons();
|
|
530
|
-
if (customButtons.length === 0) {
|
|
531
|
-
const emptyMsg = document.createElement("div");
|
|
532
|
-
emptyMsg.textContent = "No custom buttons yet. Add one below.";
|
|
533
|
-
addClass(emptyMsg, "emptyMessage");
|
|
534
|
-
container.appendChild(emptyMsg);
|
|
535
|
-
return;
|
|
536
|
-
}
|
|
537
|
-
customButtons.forEach((btn, index) => {
|
|
538
|
-
const item = document.createElement("div");
|
|
539
|
-
addClass(item, "endpointButtonItem");
|
|
540
|
-
const labelSpan = document.createElement("span");
|
|
541
|
-
labelSpan.textContent = `${btn.label}`;
|
|
542
|
-
addClass(labelSpan, "buttonLabel");
|
|
543
|
-
const endpointSpan = document.createElement("span");
|
|
544
|
-
endpointSpan.textContent = btn.endpoint;
|
|
545
|
-
addClass(endpointSpan, "buttonEndpoint");
|
|
546
|
-
const removeBtn = document.createElement("button");
|
|
547
|
-
removeBtn.textContent = "×";
|
|
548
|
-
addClass(removeBtn, "removeButton");
|
|
549
|
-
removeBtn.type = "button";
|
|
550
|
-
removeBtn.onclick = () => {
|
|
551
|
-
const currentButtons = this.tab.yasgui.persistentConfig.getCustomEndpointButtons();
|
|
552
|
-
currentButtons.splice(index, 1);
|
|
553
|
-
this.tab.yasgui.persistentConfig.setCustomEndpointButtons(currentButtons);
|
|
554
|
-
this.renderEndpointButtonsList(container);
|
|
555
|
-
};
|
|
556
|
-
item.appendChild(labelSpan);
|
|
557
|
-
item.appendChild(endpointSpan);
|
|
558
|
-
item.appendChild(removeBtn);
|
|
559
|
-
container.appendChild(item);
|
|
560
|
-
});
|
|
561
|
-
}
|
|
562
819
|
getThemeToggleIcon() {
|
|
563
820
|
const currentTheme = this.tab.yasgui.getTheme();
|
|
564
821
|
return currentTheme === "dark" ? MOON_ICON : SUN_ICON;
|
|
@@ -695,6 +952,93 @@ export default class TabSettingsModal {
|
|
|
695
952
|
importSection.appendChild(fileInput);
|
|
696
953
|
container.appendChild(importSection);
|
|
697
954
|
}
|
|
955
|
+
drawKeyboardShortcuts(container) {
|
|
956
|
+
const shortcutsData = [
|
|
957
|
+
{
|
|
958
|
+
category: "Query Editor (YASQE)",
|
|
959
|
+
shortcuts: [
|
|
960
|
+
{ keys: ["Ctrl+Enter", "Cmd+Enter"], description: "Execute query" },
|
|
961
|
+
{ keys: ["Ctrl+Space", "Cmd+Space"], description: "Trigger autocomplete" },
|
|
962
|
+
{ keys: ["Ctrl+S", "Cmd+S"], description: "Save query to local storage" },
|
|
963
|
+
{ keys: ["Ctrl+Shift+F", "Cmd+Shift+F"], description: "Format query" },
|
|
964
|
+
{ keys: ["Ctrl+/", "Cmd+/"], description: "Toggle comment on selected lines" },
|
|
965
|
+
{ keys: ["Ctrl+Shift+D", "Cmd+Shift+D"], description: "Duplicate current line" },
|
|
966
|
+
{ keys: ["Ctrl+Shift+K", "Cmd+Shift+K"], description: "Delete current line" },
|
|
967
|
+
{ keys: ["Esc"], description: "Remove focus from editor" },
|
|
968
|
+
{ keys: ["Ctrl+Click"], description: "Explore URI connections (on URI)" },
|
|
969
|
+
],
|
|
970
|
+
},
|
|
971
|
+
{
|
|
972
|
+
category: "Fullscreen",
|
|
973
|
+
shortcuts: [
|
|
974
|
+
{ keys: ["F11"], description: "Toggle YASQE (editor) fullscreen" },
|
|
975
|
+
{ keys: ["F10"], description: "Toggle YASR (results) fullscreen" },
|
|
976
|
+
{ keys: ["F9"], description: "Switch between YASQE and YASR fullscreen" },
|
|
977
|
+
{ keys: ["Esc"], description: "Exit fullscreen mode" },
|
|
978
|
+
],
|
|
979
|
+
},
|
|
980
|
+
];
|
|
981
|
+
shortcutsData.forEach((section) => {
|
|
982
|
+
const sectionEl = document.createElement("div");
|
|
983
|
+
addClass(sectionEl, "shortcutsSection");
|
|
984
|
+
const categoryLabel = document.createElement("h3");
|
|
985
|
+
categoryLabel.textContent = section.category;
|
|
986
|
+
addClass(categoryLabel, "shortcutsCategory");
|
|
987
|
+
sectionEl.appendChild(categoryLabel);
|
|
988
|
+
const table = document.createElement("table");
|
|
989
|
+
addClass(table, "shortcutsTable");
|
|
990
|
+
table.setAttribute("role", "table");
|
|
991
|
+
table.setAttribute("aria-label", `${section.category} keyboard shortcuts`);
|
|
992
|
+
const caption = document.createElement("caption");
|
|
993
|
+
caption.textContent = `${section.category} keyboard shortcuts`;
|
|
994
|
+
caption.style.position = "absolute";
|
|
995
|
+
caption.style.left = "-10000px";
|
|
996
|
+
caption.style.width = "1px";
|
|
997
|
+
caption.style.height = "1px";
|
|
998
|
+
caption.style.overflow = "hidden";
|
|
999
|
+
table.appendChild(caption);
|
|
1000
|
+
const thead = document.createElement("thead");
|
|
1001
|
+
const headerRow = document.createElement("tr");
|
|
1002
|
+
const keysHeader = document.createElement("th");
|
|
1003
|
+
keysHeader.textContent = "Keys";
|
|
1004
|
+
keysHeader.setAttribute("scope", "col");
|
|
1005
|
+
addClass(keysHeader, "shortcutsKeysHeader");
|
|
1006
|
+
headerRow.appendChild(keysHeader);
|
|
1007
|
+
const descHeader = document.createElement("th");
|
|
1008
|
+
descHeader.textContent = "Description";
|
|
1009
|
+
descHeader.setAttribute("scope", "col");
|
|
1010
|
+
addClass(descHeader, "shortcutsDescHeader");
|
|
1011
|
+
headerRow.appendChild(descHeader);
|
|
1012
|
+
thead.appendChild(headerRow);
|
|
1013
|
+
table.appendChild(thead);
|
|
1014
|
+
const tbody = document.createElement("tbody");
|
|
1015
|
+
section.shortcuts.forEach((shortcut) => {
|
|
1016
|
+
const row = document.createElement("tr");
|
|
1017
|
+
const keysCell = document.createElement("td");
|
|
1018
|
+
addClass(keysCell, "shortcutsKeys");
|
|
1019
|
+
shortcut.keys.forEach((key, index) => {
|
|
1020
|
+
if (index > 0) {
|
|
1021
|
+
const separator = document.createElement("span");
|
|
1022
|
+
separator.textContent = " / ";
|
|
1023
|
+
addClass(separator, "shortcutsSeparator");
|
|
1024
|
+
keysCell.appendChild(separator);
|
|
1025
|
+
}
|
|
1026
|
+
const kbd = document.createElement("kbd");
|
|
1027
|
+
kbd.textContent = key;
|
|
1028
|
+
keysCell.appendChild(kbd);
|
|
1029
|
+
});
|
|
1030
|
+
row.appendChild(keysCell);
|
|
1031
|
+
const descCell = document.createElement("td");
|
|
1032
|
+
addClass(descCell, "shortcutsDescription");
|
|
1033
|
+
descCell.textContent = shortcut.description;
|
|
1034
|
+
row.appendChild(descCell);
|
|
1035
|
+
tbody.appendChild(row);
|
|
1036
|
+
});
|
|
1037
|
+
table.appendChild(tbody);
|
|
1038
|
+
sectionEl.appendChild(table);
|
|
1039
|
+
container.appendChild(sectionEl);
|
|
1040
|
+
});
|
|
1041
|
+
}
|
|
698
1042
|
importConfiguration(turtleContent) {
|
|
699
1043
|
return __awaiter(this, void 0, void 0, function* () {
|
|
700
1044
|
var _a;
|
|
@@ -737,6 +1081,67 @@ export default class TabSettingsModal {
|
|
|
737
1081
|
}
|
|
738
1082
|
}, 5000);
|
|
739
1083
|
}
|
|
1084
|
+
drawAboutSettings(container) {
|
|
1085
|
+
const aboutSection = document.createElement("div");
|
|
1086
|
+
addClass(aboutSection, "settingsSection", "aboutSection");
|
|
1087
|
+
const titleContainer = document.createElement("div");
|
|
1088
|
+
addClass(titleContainer, "aboutTitle");
|
|
1089
|
+
const title = document.createElement("h3");
|
|
1090
|
+
title.textContent = "YASGUI";
|
|
1091
|
+
addClass(title, "aboutMainTitle");
|
|
1092
|
+
const versionBadge = document.createElement("span");
|
|
1093
|
+
versionBadge.textContent = `v${VERSION}`;
|
|
1094
|
+
addClass(versionBadge, "versionBadge");
|
|
1095
|
+
titleContainer.appendChild(title);
|
|
1096
|
+
titleContainer.appendChild(versionBadge);
|
|
1097
|
+
aboutSection.appendChild(titleContainer);
|
|
1098
|
+
const subtitle = document.createElement("p");
|
|
1099
|
+
subtitle.textContent = "Yet Another SPARQL GUI";
|
|
1100
|
+
addClass(subtitle, "aboutSubtitle");
|
|
1101
|
+
aboutSection.appendChild(subtitle);
|
|
1102
|
+
const linksSection = document.createElement("div");
|
|
1103
|
+
addClass(linksSection, "aboutLinks");
|
|
1104
|
+
const docsLink = this.createAboutLink("📚 Documentation", "https://yasgui-doc.matdata.eu/docs/", "View the complete documentation and guides");
|
|
1105
|
+
linksSection.appendChild(docsLink);
|
|
1106
|
+
const releasesLink = this.createAboutLink("📝 Release Notes", "https://github.com/Matdata-eu/Yasgui/releases", "See what's new in the latest releases");
|
|
1107
|
+
linksSection.appendChild(releasesLink);
|
|
1108
|
+
const issuesLink = this.createAboutLink("🐛 Report Issues & Get Support", "https://github.com/Matdata-eu/Yasgui/issues", "Report bugs, request features, or ask for help");
|
|
1109
|
+
linksSection.appendChild(issuesLink);
|
|
1110
|
+
aboutSection.appendChild(linksSection);
|
|
1111
|
+
const footerInfo = document.createElement("div");
|
|
1112
|
+
addClass(footerInfo, "aboutFooter");
|
|
1113
|
+
const paragraph1 = document.createElement("p");
|
|
1114
|
+
paragraph1.textContent = "YASGUI is an open-source project maintained by ";
|
|
1115
|
+
const matdataLink = document.createElement("a");
|
|
1116
|
+
matdataLink.href = "https://matdata.eu";
|
|
1117
|
+
matdataLink.target = "_blank";
|
|
1118
|
+
matdataLink.rel = "noopener noreferrer";
|
|
1119
|
+
matdataLink.textContent = "Matdata";
|
|
1120
|
+
paragraph1.appendChild(matdataLink);
|
|
1121
|
+
paragraph1.appendChild(document.createTextNode("."));
|
|
1122
|
+
const paragraph2 = document.createElement("p");
|
|
1123
|
+
paragraph2.textContent = "Licensed under the MIT License.";
|
|
1124
|
+
footerInfo.appendChild(paragraph1);
|
|
1125
|
+
footerInfo.appendChild(paragraph2);
|
|
1126
|
+
aboutSection.appendChild(footerInfo);
|
|
1127
|
+
container.appendChild(aboutSection);
|
|
1128
|
+
}
|
|
1129
|
+
createAboutLink(label, url, description) {
|
|
1130
|
+
const linkContainer = document.createElement("div");
|
|
1131
|
+
addClass(linkContainer, "aboutLinkItem");
|
|
1132
|
+
const link = document.createElement("a");
|
|
1133
|
+
link.href = url;
|
|
1134
|
+
link.target = "_blank";
|
|
1135
|
+
link.rel = "noopener noreferrer";
|
|
1136
|
+
link.textContent = label;
|
|
1137
|
+
addClass(link, "aboutLink");
|
|
1138
|
+
const desc = document.createElement("p");
|
|
1139
|
+
desc.textContent = description;
|
|
1140
|
+
addClass(desc, "aboutLinkDescription");
|
|
1141
|
+
linkContainer.appendChild(link);
|
|
1142
|
+
linkContainer.appendChild(desc);
|
|
1143
|
+
return linkContainer;
|
|
1144
|
+
}
|
|
740
1145
|
destroy() {
|
|
741
1146
|
if (this.modalOverlay && this.modalOverlay.parentNode) {
|
|
742
1147
|
this.modalOverlay.parentNode.removeChild(this.modalOverlay);
|