@matdata/yasgui 4.6.1

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.
@@ -0,0 +1,226 @@
1
+ .tabPrefixButton {
2
+ cursor: pointer;
3
+ background: transparent;
4
+ color: inherit;
5
+ border: none;
6
+ padding: 6px 12px;
7
+ font-size: 12px;
8
+ font-weight: 600;
9
+ margin-left: 10px;
10
+
11
+ &:hover {
12
+ opacity: 0.7;
13
+ }
14
+
15
+ &:active {
16
+ opacity: 0.5;
17
+ }
18
+ }
19
+
20
+ .tabSettingsModalOverlay {
21
+ display: none;
22
+ position: fixed;
23
+ top: 0;
24
+ left: 0;
25
+ right: 0;
26
+ bottom: 0;
27
+ background: rgba(0, 0, 0, 0.5);
28
+ z-index: 10000;
29
+ align-items: center;
30
+ justify-content: center;
31
+
32
+ &.open {
33
+ display: flex;
34
+ }
35
+ }
36
+
37
+ .tabSettingsModal {
38
+ background: white;
39
+ border-radius: 8px;
40
+ box-shadow: 0 4px 20px rgba(0, 0, 0, 0.3);
41
+ max-width: 800px;
42
+ width: 90%;
43
+ max-height: 90vh;
44
+ display: flex;
45
+ flex-direction: column;
46
+ overflow: hidden;
47
+ }
48
+
49
+ .modalHeader {
50
+ display: flex;
51
+ justify-content: space-between;
52
+ align-items: center;
53
+ padding: 20px;
54
+ border-bottom: 1px solid #e0e0e0;
55
+
56
+ h2 {
57
+ margin: 0;
58
+ font-size: 20px;
59
+ font-weight: 600;
60
+ }
61
+
62
+ .closeButton {
63
+ background: none;
64
+ border: none;
65
+ font-size: 32px;
66
+ line-height: 1;
67
+ cursor: pointer;
68
+ color: #666;
69
+ padding: 0;
70
+ width: 32px;
71
+ height: 32px;
72
+
73
+ &:hover {
74
+ color: #333;
75
+ }
76
+ }
77
+ }
78
+
79
+ .modalBody {
80
+ flex: 1;
81
+ overflow-y: auto;
82
+ padding: 20px;
83
+ }
84
+
85
+ .modalTabs {
86
+ display: flex;
87
+ gap: 10px;
88
+ margin-bottom: 20px;
89
+ border-bottom: 2px solid #e0e0e0;
90
+ }
91
+
92
+ .modalTabButton {
93
+ background: none;
94
+ border: none;
95
+ padding: 10px 20px;
96
+ font-size: 14px;
97
+ font-weight: 600;
98
+ cursor: pointer;
99
+ color: #666;
100
+ border-bottom: 3px solid transparent;
101
+ margin-bottom: -2px;
102
+ transition: all 0.2s;
103
+
104
+ &:hover {
105
+ color: #337ab7;
106
+ }
107
+
108
+ &.active {
109
+ color: #337ab7;
110
+ border-bottom-color: #337ab7;
111
+ }
112
+ }
113
+
114
+ .modalTabContent {
115
+ display: none;
116
+
117
+ &.active {
118
+ display: block;
119
+ }
120
+ }
121
+
122
+ .settingsSection {
123
+ margin-bottom: 20px;
124
+ }
125
+
126
+ .settingsLabel {
127
+ font-weight: 600;
128
+ margin-bottom: 8px;
129
+ font-size: 14px;
130
+ display: block;
131
+ }
132
+
133
+ .settingsHelp {
134
+ font-size: 12px;
135
+ color: #666;
136
+ margin-bottom: 10px;
137
+ font-style: italic;
138
+ }
139
+
140
+ .settingsSelect {
141
+ width: 100%;
142
+ padding: 8px;
143
+ border: 1px solid #ccc;
144
+ border-radius: 4px;
145
+ font-size: 14px;
146
+
147
+ &:focus {
148
+ outline: none;
149
+ border-color: #337ab7;
150
+ box-shadow: 0 0 0 2px rgba(51, 122, 183, 0.1);
151
+ }
152
+ }
153
+
154
+ .prefixTextarea {
155
+ width: 100%;
156
+ padding: 10px;
157
+ border: 1px solid #ccc;
158
+ border-radius: 4px;
159
+ font-family: monospace;
160
+ font-size: 13px;
161
+ resize: vertical;
162
+ box-sizing: border-box;
163
+ min-height: 200px;
164
+
165
+ &:focus {
166
+ outline: none;
167
+ border-color: #337ab7;
168
+ box-shadow: 0 0 0 2px rgba(51, 122, 183, 0.1);
169
+ }
170
+ }
171
+
172
+ .checkboxContainer {
173
+ margin-top: 15px;
174
+ display: flex;
175
+ align-items: center;
176
+ gap: 8px;
177
+
178
+ input[type="checkbox"] {
179
+ width: 18px;
180
+ height: 18px;
181
+ cursor: pointer;
182
+ }
183
+
184
+ label {
185
+ cursor: pointer;
186
+ font-size: 14px;
187
+ user-select: none;
188
+ margin: 0;
189
+ }
190
+ }
191
+
192
+ .modalFooter {
193
+ padding: 15px 20px;
194
+ border-top: 1px solid #e0e0e0;
195
+ display: flex;
196
+ justify-content: flex-end;
197
+ gap: 10px;
198
+ }
199
+
200
+ .primaryButton,
201
+ .secondaryButton {
202
+ padding: 8px 20px;
203
+ border: none;
204
+ border-radius: 4px;
205
+ font-size: 14px;
206
+ cursor: pointer;
207
+ transition: background-color 0.2s;
208
+ }
209
+
210
+ .primaryButton {
211
+ background: #337ab7;
212
+ color: white;
213
+
214
+ &:hover {
215
+ background: #286090;
216
+ }
217
+ }
218
+
219
+ .secondaryButton {
220
+ background: #e0e0e0;
221
+ color: #333;
222
+
223
+ &:hover {
224
+ background: #d0d0d0;
225
+ }
226
+ }
@@ -0,0 +1,424 @@
1
+ import { addClass, removeClass, drawSvgStringAsElement } from "@matdata/yasgui-utils";
2
+ import "./TabSettingsModal.scss";
3
+ import Tab from "./Tab";
4
+
5
+ const AcceptOptionsMap: { key: string; value: string }[] = [
6
+ { key: "JSON", value: "application/sparql-results+json" },
7
+ { key: "XML", value: "application/sparql-results+xml" },
8
+ { key: "CSV", value: "text/csv" },
9
+ { key: "TSV", value: "text/tab-separated-values" },
10
+ ];
11
+ const AcceptHeaderGraphMap: { key: string; value: string }[] = [
12
+ { key: "Turtle", value: "text/turtle" },
13
+ { key: "JSON", value: "application/rdf+json" },
14
+ { key: "RDF/XML", value: "application/rdf+xml" },
15
+ { key: "TriG", value: "application/trig" },
16
+ { key: "N-Triples", value: "application/n-triples" },
17
+ { key: "N-Quads", value: "application/n-quads" },
18
+ { key: "CSV", value: "text/csv" },
19
+ { key: "TSV", value: "text/tab-separated-values" },
20
+ ];
21
+
22
+ export default class TabSettingsModal {
23
+ private tab: Tab;
24
+ private modalOverlay!: HTMLElement;
25
+ private modalContent!: HTMLElement;
26
+ private settingsButton!: HTMLButtonElement;
27
+ private prefixButton!: HTMLButtonElement;
28
+ private prefixTextarea!: HTMLTextAreaElement;
29
+ private autoCaptureCheckbox!: HTMLInputElement;
30
+
31
+ constructor(tab: Tab, controlBarEl: HTMLElement) {
32
+ this.tab = tab;
33
+ this.init(controlBarEl);
34
+ }
35
+
36
+ private init(controlBarEl: HTMLElement) {
37
+ // Settings button
38
+ this.settingsButton = document.createElement("button");
39
+ this.settingsButton.setAttribute("aria-label", "Settings");
40
+ this.settingsButton.title = "Settings";
41
+ this.settingsButton.appendChild(
42
+ drawSvgStringAsElement(
43
+ `<svg width="100.06" height="100.05" data-name="Layer 1" version="1.1" viewBox="0 0 100.06 100.05" xmlns="http://www.w3.org/2000/svg">
44
+ <title>Settings</title>
45
+ <path d="m95.868 58.018-3-3.24a42.5 42.5 0 0 0 0-9.43l3-3.22c1.79-1.91 5-4.44 4-6.85l-4.11-10c-1-2.41-5.08-1.91-7.69-2l-4.43-0.16a43.24 43.24 0 0 0-6.64-6.66l-0.14-4.43c-0.08-2.6 0.43-6.69-2-7.69l-10-4.15c-2.4-1-4.95 2.25-6.85 4l-3.23 3a42.49 42.49 0 0 0-9.44 0l-3.21-3c-1.9-1.78-4.44-5-6.85-4l-10 4.11c-2.41 1-1.9 5.09-2 7.69l-0.16 4.42a43.24 43.24 0 0 0-6.67 6.65l-4.42 0.14c-2.6 0.08-6.69-0.43-7.69 2l-4.15 10c-1 2.4 2.25 4.94 4 6.84l3 3.23a42.49 42.49 0 0 0 0 9.44l-3 3.22c-1.78 1.9-5 4.43-4 6.84l4.11 10c1 2.41 5.09 1.91 7.7 2l4.41 0.15a43.24 43.24 0 0 0 6.66 6.68l0.13 4.41c0.08 2.6-0.43 6.7 2 7.7l10 4.15c2.4 1 4.94-2.25 6.84-4l3.24-3a42.5 42.5 0 0 0 9.42 0l3.22 3c1.91 1.79 4.43 5 6.84 4l10-4.11c2.41-1 1.91-5.08 2-7.7l0.15-4.42a43.24 43.24 0 0 0 6.68-6.65l4.42-0.14c2.6-0.08 6.7 0.43 7.7-2l4.15-10c1.04-2.36-2.22-4.9-3.99-6.82zm-45.74 15.7c-12.66 0-22.91-10.61-22.91-23.7s10.25-23.7 22.91-23.7 22.91 10.61 22.91 23.7-10.25 23.7-22.91 23.7z"/>
46
+ </svg>`,
47
+ ),
48
+ );
49
+ addClass(this.settingsButton, "tabContextButton");
50
+ controlBarEl.appendChild(this.settingsButton);
51
+ this.settingsButton.onclick = () => this.open();
52
+
53
+ // Prefix button
54
+ this.prefixButton = document.createElement("button");
55
+ this.prefixButton.setAttribute("aria-label", "Insert Prefixes");
56
+ this.prefixButton.title = "Insert saved prefixes into query";
57
+ this.prefixButton.textContent = "PREFIX";
58
+ addClass(this.prefixButton, "tabPrefixButton");
59
+ controlBarEl.appendChild(this.prefixButton);
60
+ this.prefixButton.onclick = () => this.insertPrefixesIntoQuery();
61
+
62
+ this.createModal();
63
+ }
64
+
65
+ private createModal() {
66
+ // Modal overlay
67
+ this.modalOverlay = document.createElement("div");
68
+ addClass(this.modalOverlay, "tabSettingsModalOverlay");
69
+ this.modalOverlay.onclick = () => this.close();
70
+
71
+ // Modal content
72
+ this.modalContent = document.createElement("div");
73
+ addClass(this.modalContent, "tabSettingsModal");
74
+ this.modalContent.onclick = (e) => e.stopPropagation();
75
+
76
+ // Header
77
+ const header = document.createElement("div");
78
+ addClass(header, "modalHeader");
79
+ const title = document.createElement("h2");
80
+ title.textContent = "Tab Settings";
81
+ header.appendChild(title);
82
+
83
+ const closeBtn = document.createElement("button");
84
+ closeBtn.textContent = "×";
85
+ addClass(closeBtn, "closeButton");
86
+ closeBtn.onclick = () => this.close();
87
+ header.appendChild(closeBtn);
88
+
89
+ this.modalContent.appendChild(header);
90
+
91
+ // Body with tabs
92
+ const body = document.createElement("div");
93
+ addClass(body, "modalBody");
94
+
95
+ const tabsContainer = document.createElement("div");
96
+ addClass(tabsContainer, "modalTabs");
97
+
98
+ const requestTab = document.createElement("button");
99
+ requestTab.textContent = "Request";
100
+ addClass(requestTab, "modalTabButton", "active");
101
+ requestTab.onclick = () => this.switchTab("request");
102
+
103
+ const prefixTab = document.createElement("button");
104
+ prefixTab.textContent = "Prefixes";
105
+ addClass(prefixTab, "modalTabButton");
106
+ prefixTab.onclick = () => this.switchTab("prefix");
107
+
108
+ tabsContainer.appendChild(requestTab);
109
+ tabsContainer.appendChild(prefixTab);
110
+ body.appendChild(tabsContainer);
111
+
112
+ // Tab content containers
113
+ const requestContent = document.createElement("div");
114
+ addClass(requestContent, "modalTabContent", "active");
115
+ requestContent.id = "request-content";
116
+ this.drawRequestSettings(requestContent);
117
+
118
+ const prefixContent = document.createElement("div");
119
+ addClass(prefixContent, "modalTabContent");
120
+ prefixContent.id = "prefix-content";
121
+ this.drawPrefixSettings(prefixContent);
122
+
123
+ body.appendChild(requestContent);
124
+ body.appendChild(prefixContent);
125
+
126
+ this.modalContent.appendChild(body);
127
+
128
+ // Footer
129
+ const footer = document.createElement("div");
130
+ addClass(footer, "modalFooter");
131
+
132
+ const saveBtn = document.createElement("button");
133
+ saveBtn.textContent = "Save";
134
+ addClass(saveBtn, "primaryButton");
135
+ saveBtn.onclick = () => this.save();
136
+
137
+ const cancelBtn = document.createElement("button");
138
+ cancelBtn.textContent = "Cancel";
139
+ addClass(cancelBtn, "secondaryButton");
140
+ cancelBtn.onclick = () => this.close();
141
+
142
+ footer.appendChild(cancelBtn);
143
+ footer.appendChild(saveBtn);
144
+
145
+ this.modalContent.appendChild(footer);
146
+
147
+ this.modalOverlay.appendChild(this.modalContent);
148
+ document.body.appendChild(this.modalOverlay);
149
+ }
150
+
151
+ private switchTab(tabName: string) {
152
+ const buttons = this.modalContent.querySelectorAll(".modalTabButton");
153
+ const contents = this.modalContent.querySelectorAll(".modalTabContent");
154
+
155
+ buttons.forEach((btn, index) => {
156
+ if ((tabName === "request" && index === 0) || (tabName === "prefix" && index === 1)) {
157
+ addClass(btn as HTMLElement, "active");
158
+ } else {
159
+ removeClass(btn as HTMLElement, "active");
160
+ }
161
+ });
162
+
163
+ contents.forEach((content) => {
164
+ if (content.id === `${tabName}-content`) {
165
+ addClass(content as HTMLElement, "active");
166
+ } else {
167
+ removeClass(content as HTMLElement, "active");
168
+ }
169
+ });
170
+ }
171
+
172
+ private drawPrefixSettings(container: HTMLElement) {
173
+ const section = document.createElement("div");
174
+ addClass(section, "settingsSection");
175
+
176
+ const label = document.createElement("label");
177
+ label.textContent = "Saved Prefixes";
178
+ addClass(label, "settingsLabel");
179
+
180
+ const help = document.createElement("div");
181
+ help.textContent = "Enter PREFIX declarations (one per line). These will be available for insertion into queries.";
182
+ addClass(help, "settingsHelp");
183
+
184
+ this.prefixTextarea = document.createElement("textarea");
185
+ addClass(this.prefixTextarea, "prefixTextarea");
186
+ this.prefixTextarea.placeholder =
187
+ "PREFIX rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#>\nPREFIX rdfs: <http://www.w3.org/2000/01/rdf-schema#>";
188
+ this.prefixTextarea.rows = 10;
189
+
190
+ const checkboxContainer = document.createElement("div");
191
+ addClass(checkboxContainer, "checkboxContainer");
192
+
193
+ this.autoCaptureCheckbox = document.createElement("input");
194
+ this.autoCaptureCheckbox.type = "checkbox";
195
+ this.autoCaptureCheckbox.id = "autoCapturePrefixes";
196
+
197
+ const checkboxLabel = document.createElement("label");
198
+ checkboxLabel.htmlFor = "autoCapturePrefixes";
199
+ checkboxLabel.textContent = "Automatically capture new prefixes from query editor";
200
+
201
+ checkboxContainer.appendChild(this.autoCaptureCheckbox);
202
+ checkboxContainer.appendChild(checkboxLabel);
203
+
204
+ section.appendChild(label);
205
+ section.appendChild(help);
206
+ section.appendChild(this.prefixTextarea);
207
+ section.appendChild(checkboxContainer);
208
+
209
+ container.appendChild(section);
210
+ }
211
+
212
+ private drawRequestSettings(container: HTMLElement) {
213
+ // This is a simplified version - you can expand based on TabPanel.ts
214
+ const reqConfig = this.tab.getRequestConfig();
215
+
216
+ // Request Method section
217
+ const methodSection = this.createSection("Request Method");
218
+ const methodSelect = this.createSelect(
219
+ ["GET", "POST"],
220
+ typeof reqConfig.method === "function" ? "POST" : reqConfig.method,
221
+ );
222
+ methodSelect.setAttribute("data-config", "method");
223
+ methodSection.appendChild(methodSelect);
224
+ container.appendChild(methodSection);
225
+
226
+ // Accept Header sections
227
+ const acceptSection = this.createSection("Accept Header (SELECT/ASK)");
228
+ const acceptSelect = this.createOptionsSelect(AcceptOptionsMap, <string>reqConfig.acceptHeaderSelect);
229
+ acceptSelect.setAttribute("data-config", "acceptHeaderSelect");
230
+ acceptSection.appendChild(acceptSelect);
231
+ container.appendChild(acceptSection);
232
+
233
+ const acceptGraphSection = this.createSection("Accept Header (CONSTRUCT/DESCRIBE)");
234
+ const acceptGraphSelect = this.createOptionsSelect(AcceptHeaderGraphMap, <string>reqConfig.acceptHeaderGraph);
235
+ acceptGraphSelect.setAttribute("data-config", "acceptHeaderGraph");
236
+ acceptGraphSection.appendChild(acceptGraphSelect);
237
+ container.appendChild(acceptGraphSection);
238
+ }
239
+
240
+ private createSection(title: string): HTMLElement {
241
+ const section = document.createElement("div");
242
+ addClass(section, "settingsSection");
243
+ const label = document.createElement("div");
244
+ addClass(label, "settingsLabel");
245
+ label.textContent = title;
246
+ section.appendChild(label);
247
+ return section;
248
+ }
249
+
250
+ private createSelect(options: string[], selected?: string): HTMLSelectElement {
251
+ const select = document.createElement("select");
252
+ addClass(select, "settingsSelect");
253
+ options.forEach((opt) => {
254
+ const option = document.createElement("option");
255
+ option.value = opt;
256
+ option.textContent = opt;
257
+ if (opt === selected) option.selected = true;
258
+ select.appendChild(option);
259
+ });
260
+ return select;
261
+ }
262
+
263
+ private createOptionsSelect(options: { key: string; value: string }[], selected?: string): HTMLSelectElement {
264
+ const select = document.createElement("select");
265
+ addClass(select, "settingsSelect");
266
+ options.forEach((opt) => {
267
+ const option = document.createElement("option");
268
+ option.value = opt.value;
269
+ option.textContent = opt.key;
270
+ if (opt.value === selected) option.selected = true;
271
+ select.appendChild(option);
272
+ });
273
+ return select;
274
+ }
275
+
276
+ public open() {
277
+ this.loadSettings();
278
+ addClass(this.modalOverlay, "open");
279
+ }
280
+
281
+ public close() {
282
+ removeClass(this.modalOverlay, "open");
283
+ }
284
+
285
+ private loadSettings() {
286
+ // Load prefix settings
287
+ let prefixes = this.tab.yasgui.persistentConfig.getPrefixes();
288
+ const autoCapture = this.tab.yasgui.persistentConfig.getAutoCaptureEnabled();
289
+
290
+ // Set default prefixes if none exist
291
+ if (!prefixes || prefixes.trim().length === 0) {
292
+ prefixes = `PREFIX rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#>\nPREFIX rdfs: <http://www.w3.org/2000/01/rdf-schema#>`;
293
+ this.tab.yasgui.persistentConfig.setPrefixes(prefixes);
294
+ }
295
+
296
+ this.prefixTextarea.value = prefixes;
297
+ this.autoCaptureCheckbox.checked = autoCapture;
298
+ }
299
+
300
+ private save() {
301
+ // Save prefix settings
302
+ const prefixText = this.prefixTextarea.value;
303
+ const autoCapture = this.autoCaptureCheckbox.checked;
304
+
305
+ // Parse and deduplicate prefixes
306
+ const deduplicated = this.deduplicatePrefixes(prefixText);
307
+ this.tab.yasgui.persistentConfig.setPrefixes(deduplicated);
308
+ this.tab.yasgui.persistentConfig.setAutoCaptureEnabled(autoCapture);
309
+
310
+ // Save request settings
311
+ const requestContent = this.modalContent.querySelector("#request-content");
312
+ if (requestContent) {
313
+ const selects = requestContent.querySelectorAll("select[data-config]");
314
+ const updates: any = {};
315
+ selects.forEach((select) => {
316
+ const config = (select as HTMLSelectElement).getAttribute("data-config");
317
+ if (config) {
318
+ updates[config] = (select as HTMLSelectElement).value;
319
+ }
320
+ });
321
+ this.tab.setRequestConfig(updates);
322
+ }
323
+
324
+ this.close();
325
+ }
326
+
327
+ private deduplicatePrefixes(prefixText: string): string {
328
+ const lines = prefixText.split("\n");
329
+ const seen = new Map<string, string>();
330
+ const result: string[] = [];
331
+
332
+ for (const line of lines) {
333
+ const trimmed = line.trim();
334
+ if (!trimmed) continue;
335
+
336
+ // Extract prefix label from line
337
+ const match = trimmed.match(/^\s*PREFIX\s+(\w+):\s*<(.+)>\s*$/i);
338
+ if (match) {
339
+ const label = match[1].toLowerCase();
340
+ if (!seen.has(label)) {
341
+ seen.set(label, trimmed);
342
+ result.push(trimmed);
343
+ }
344
+ } else {
345
+ // Keep non-prefix lines as-is
346
+ result.push(trimmed);
347
+ }
348
+ }
349
+
350
+ return result.join("\n");
351
+ }
352
+
353
+ private insertPrefixesIntoQuery() {
354
+ const yasqe = this.tab.getYasqe();
355
+ if (!yasqe) return;
356
+
357
+ const savedPrefixes = this.tab.yasgui.persistentConfig.getPrefixes();
358
+ if (!savedPrefixes.trim()) return;
359
+
360
+ // Get current query and find where PREFIX declarations end
361
+ const currentQuery = yasqe.getValue();
362
+ const lines = currentQuery.split("\n");
363
+
364
+ let firstNonPrefixLine = 0;
365
+ for (let i = 0; i < lines.length; i++) {
366
+ const trimmed = lines[i].trim();
367
+ // Skip empty lines and PREFIX lines
368
+ if (trimmed.length > 0 && !trimmed.toUpperCase().startsWith("PREFIX")) {
369
+ firstNonPrefixLine = i;
370
+ break;
371
+ }
372
+ }
373
+
374
+ // If we didn't find a non-PREFIX line, all lines are PREFIX or empty
375
+ if (firstNonPrefixLine === 0 && lines.length > 0) {
376
+ // Check if there's any content at all
377
+ const hasContent = lines.some((line) => line.trim().length > 0);
378
+ if (
379
+ !hasContent ||
380
+ lines.every((line) => line.trim().length === 0 || line.trim().toUpperCase().startsWith("PREFIX"))
381
+ ) {
382
+ firstNonPrefixLine = lines.length;
383
+ }
384
+ }
385
+
386
+ // Keep the rest of the query (non-PREFIX lines)
387
+ const restOfQuery = lines.slice(firstNonPrefixLine).join("\n").trim();
388
+
389
+ // Build new query with saved prefixes + rest of query
390
+ const newQuery = savedPrefixes + (restOfQuery ? "\n\n" + restOfQuery : "");
391
+ yasqe.setValue(newQuery);
392
+ yasqe.focus();
393
+ }
394
+
395
+ public capturePrefixesFromQuery() {
396
+ const autoCapture = this.tab.yasgui.persistentConfig.getAutoCaptureEnabled();
397
+ if (!autoCapture) return;
398
+
399
+ const yasqe = this.tab.getYasqe();
400
+ if (!yasqe) return;
401
+
402
+ const queryPrefixes = yasqe.getPrefixesFromQuery();
403
+ if (!queryPrefixes || Object.keys(queryPrefixes).length === 0) return;
404
+
405
+ // Convert query prefixes to text format
406
+ const newPrefixLines: string[] = [];
407
+ for (const [label, uri] of Object.entries(queryPrefixes)) {
408
+ newPrefixLines.push(`PREFIX ${label}: <${uri}>`);
409
+ }
410
+
411
+ // Merge with existing prefixes
412
+ const existingPrefixes = this.tab.yasgui.persistentConfig.getPrefixes();
413
+ const combined = existingPrefixes + "\n" + newPrefixLines.join("\n");
414
+ const deduplicated = this.deduplicatePrefixes(combined);
415
+
416
+ this.tab.yasgui.persistentConfig.setPrefixes(deduplicated);
417
+ }
418
+
419
+ public destroy() {
420
+ if (this.modalOverlay && this.modalOverlay.parentNode) {
421
+ this.modalOverlay.parentNode.removeChild(this.modalOverlay);
422
+ }
423
+ }
424
+ }
@@ -0,0 +1,64 @@
1
+ import { Config } from "./";
2
+ import Yasr from "@matdata/yasr";
3
+ import { default as Yasqe } from "@matdata/yasqe";
4
+ import { CatalogueItem } from "./endpointSelect";
5
+
6
+ export default function initialize(): Config<CatalogueItem> {
7
+ return {
8
+ autofocus: true,
9
+ endpointInfo: undefined,
10
+ persistenceId: function (yasgui) {
11
+ //Traverse parents untl we've got an id
12
+ // Get matching parent elements
13
+ var id = "";
14
+ var elem: any = yasgui.rootEl;
15
+ if ((<any>elem).id) id = (<any>elem).id;
16
+ for (; elem && elem !== <any>document; elem = elem.parentNode) {
17
+ if (elem) {
18
+ if ((<any>elem).id) id = (<any>elem).id;
19
+ break;
20
+ }
21
+ }
22
+ return "yagui_" + id;
23
+ },
24
+ tabName: "Query",
25
+ corsProxy: undefined,
26
+ persistencyExpire: 60 * 60 * 24 * 30,
27
+ persistenceLabelResponse: "response",
28
+ persistenceLabelConfig: "config",
29
+ yasqe: Yasqe.defaults,
30
+ yasr: Yasr.defaults,
31
+ endpointCatalogueOptions: {
32
+ getData: () => {
33
+ return [
34
+ {
35
+ endpoint: "https://dbpedia.org/sparql",
36
+ },
37
+ {
38
+ endpoint: "https://query.wikidata.org/bigdata/namespace/wdq/sparql",
39
+ },
40
+ ];
41
+ },
42
+ keys: [],
43
+ renderItem: (data, source) => {
44
+ const contentDiv = document.createElement("div");
45
+
46
+ contentDiv.style.display = "flex";
47
+ contentDiv.style.flexDirection = "column";
48
+ const endpointSpan = document.createElement("span");
49
+ endpointSpan.innerHTML =
50
+ data.matches.endpoint?.reduce(
51
+ (current, object) => (object.highlight ? current + object.text.bold() : current + object.text),
52
+ "",
53
+ ) || "";
54
+ contentDiv.appendChild(endpointSpan);
55
+ source.appendChild(contentDiv);
56
+ },
57
+ },
58
+ copyEndpointOnNewTab: true,
59
+ populateFromUrl: true,
60
+ autoAddOnInit: true,
61
+ requestConfig: Yasqe.defaults.requestConfig,
62
+ contextMenuContainer: undefined,
63
+ };
64
+ }