Skip to content

Commit f10e034

Browse files
committed
templates
1 parent 3536f9d commit f10e034

File tree

2 files changed

+241
-73
lines changed

2 files changed

+241
-73
lines changed

examples/GUI/gui.js

Lines changed: 174 additions & 73 deletions
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,20 @@ function error(e) {
4646
// Clear loading spinner in the current tab when an error occurs
4747
const tabOutputElm = document.querySelector(`#${currentTabId} .results-content`);
4848
if (tabOutputElm) {
49-
tabOutputElm.innerHTML = `<div class="no-results error-result">Query failed: ${e.message}</div>`;
49+
tabOutputElm.innerHTML = '';
50+
51+
// Use error template
52+
const errorTemplate = document.getElementById('error-template');
53+
const errorClone = errorTemplate.content.cloneNode(true);
54+
const errorDiv = errorClone.querySelector('.error-result');
55+
56+
// Set error message
57+
const errorMessage = document.createElement('span');
58+
errorMessage.slot = 'error-message';
59+
errorMessage.textContent = `Query failed: ${e.message}`;
60+
errorDiv.appendChild(errorMessage);
61+
62+
tabOutputElm.appendChild(errorDiv);
5063
}
5164

5265
setTimeout(() => {
@@ -64,19 +77,38 @@ function noerror() {
6477

6578
// Status updates
6679
function updateStatus(type, message) {
80+
const createStatusSpan = (className, text) => {
81+
const span = document.createElement('span');
82+
span.className = className;
83+
span.textContent = text;
84+
return span;
85+
};
86+
6787
switch(type) {
6888
case 'executing':
69-
editorStatusElm.innerHTML = `<span class="status-info">Executing query...</span>`;
70-
resultsStatusElm.innerHTML = `<span class="status-info">Executing query...</span>`;
89+
editorStatusElm.innerHTML = '';
90+
editorStatusElm.appendChild(createStatusSpan('status-info', 'Executing query...'));
91+
92+
resultsStatusElm.innerHTML = '';
93+
resultsStatusElm.appendChild(createStatusSpan('status-info', 'Executing query...'));
7194
break;
95+
7296
case 'success':
73-
editorStatusElm.innerHTML = `<span class="status-success">Query executed successfully</span>`;
74-
resultsStatusElm.innerHTML = `<span class="status-success">${message}</span>`;
97+
editorStatusElm.innerHTML = '';
98+
editorStatusElm.appendChild(createStatusSpan('status-success', 'Query executed successfully'));
99+
100+
resultsStatusElm.innerHTML = '';
101+
resultsStatusElm.appendChild(createStatusSpan('status-success', message));
75102
break;
103+
76104
case 'error':
77-
editorStatusElm.innerHTML = `<span class="status-error">Query failed</span>`;
78-
resultsStatusElm.innerHTML = `<span class="status-error">${message}</span>`;
105+
editorStatusElm.innerHTML = '';
106+
editorStatusElm.appendChild(createStatusSpan('status-error', 'Query failed'));
107+
108+
resultsStatusElm.innerHTML = '';
109+
resultsStatusElm.appendChild(createStatusSpan('status-error', message));
79110
break;
111+
80112
default:
81113
editorStatusElm.textContent = message;
82114
break;
@@ -93,12 +125,27 @@ function execute(commands, tabId = currentTabId) {
93125
tic();
94126
updateStatus('executing');
95127

128+
// Check if we need to create a new tab
129+
// If the current tab is the initial tab and it hasn't been used yet, use it
130+
// Otherwise, create a new tab
131+
const currentTabPanel = document.getElementById(currentTabId);
132+
const isInitialUnusedTab = currentTabId === 'tab1' &&
133+
currentTabPanel &&
134+
currentTabPanel.querySelector('.results-content').innerHTML.includes('Results will be displayed here');
135+
136+
if (!isInitialUnusedTab) {
137+
tabId = createNewTab();
138+
}
139+
96140
// Get the output element for the current tab
97141
const tabOutputElm = document.querySelector(`#${tabId} .results-content`);
98142
if (!tabOutputElm) return;
99143

100-
// Show loading indicator
101-
tabOutputElm.innerHTML = '<div class="loading"><div class="spinner"></div><span>Executing query...</span></div>';
144+
// Show loading indicator using template
145+
tabOutputElm.innerHTML = '';
146+
const loadingTemplate = document.getElementById('loading-template');
147+
const loadingClone = loadingTemplate.content.cloneNode(true);
148+
tabOutputElm.appendChild(loadingClone);
102149

103150
// Add to query history
104151
addToHistory(commands);
@@ -116,7 +163,10 @@ function execute(commands, tabId = currentTabId) {
116163
tabOutputElm.innerHTML = "";
117164

118165
if (results.length === 0) {
119-
tabOutputElm.innerHTML = '<div class="no-results">Query executed successfully. No results to display.</div>';
166+
const noResultsDiv = document.createElement('div');
167+
noResultsDiv.className = 'no-results';
168+
noResultsDiv.textContent = 'Query executed successfully. No results to display.';
169+
tabOutputElm.appendChild(noResultsDiv);
120170
updateStatus('success', 'Query executed with no results');
121171
return;
122172
}
@@ -140,36 +190,50 @@ function execute(commands, tabId = currentTabId) {
140190

141191
// Create an HTML table
142192
var tableCreate = function () {
143-
function valconcat(vals, tagName) {
144-
if (vals.length === 0) return '';
145-
var open = '<' + tagName + '>', close = '</' + tagName + '>';
146-
return open + vals.join(close + open) + close;
147-
}
148193
return function (columns, values) {
149-
var tbl = document.createElement('table');
150-
var html = '<thead>' + valconcat(columns, 'th') + '</thead>';
194+
// Use the table template
195+
const tableTemplate = document.getElementById('table-template');
196+
const tableClone = tableTemplate.content.cloneNode(true);
197+
const wrapper = tableClone.querySelector('.table-wrapper');
198+
const table = tableClone.querySelector('table');
199+
200+
// Set row and column counts
201+
wrapper.querySelector('.row-count').textContent = `${values.length} row${values.length !== 1 ? 's' : ''}`;
202+
wrapper.querySelector('.column-count').textContent = `${columns.length} column${columns.length !== 1 ? 's' : ''}`;
203+
204+
// Create header cells
205+
const thead = table.querySelector('thead tr');
206+
thead.innerHTML = ''; // Clear the slot
207+
columns.forEach(column => {
208+
const th = document.createElement('th');
209+
th.textContent = column;
210+
thead.appendChild(th);
211+
});
212+
213+
// Create data rows
214+
const tbody = table.querySelector('tbody');
215+
tbody.innerHTML = ''; // Clear the slot
151216

152217
if (values.length === 0) {
153-
html += '<tbody><tr><td colspan="' + columns.length + '" class="no-results">No results</td></tr></tbody>';
218+
const emptyRow = document.createElement('tr');
219+
const emptyCell = document.createElement('td');
220+
emptyCell.className = 'no-results';
221+
emptyCell.textContent = 'No results';
222+
emptyCell.colSpan = columns.length;
223+
emptyRow.appendChild(emptyCell);
224+
tbody.appendChild(emptyRow);
154225
} else {
155-
var rows = values.map(function (v) { return valconcat(v, 'td'); });
156-
html += '<tbody>' + valconcat(rows, 'tr') + '</tbody>';
226+
values.forEach(rowData => {
227+
const row = document.createElement('tr');
228+
rowData.forEach(cellData => {
229+
const cell = document.createElement('td');
230+
cell.textContent = cellData;
231+
row.appendChild(cell);
232+
});
233+
tbody.appendChild(row);
234+
});
157235
}
158236

159-
tbl.innerHTML = html;
160-
161-
// Add a wrapper with a caption showing the number of rows
162-
var wrapper = document.createElement('div');
163-
wrapper.className = 'table-wrapper';
164-
var caption = document.createElement('div');
165-
caption.className = 'table-caption';
166-
caption.innerHTML = `
167-
<span>${values.length} row${values.length !== 1 ? 's' : ''}</span>
168-
<span>${columns.length} column${columns.length !== 1 ? 's' : ''}</span>
169-
`;
170-
wrapper.appendChild(caption);
171-
wrapper.appendChild(tbl);
172-
173237
return wrapper;
174238
}
175239
}();
@@ -178,11 +242,7 @@ var tableCreate = function () {
178242
function execEditorContents() {
179243
noerror();
180244

181-
// Create a new tab if needed
182-
if (document.querySelectorAll('.results-tabs .tab').length <= 2) { // Only the first tab and + button
183-
createNewTab();
184-
}
185-
245+
// Use the current tab if it exists, otherwise create a new one
186246
try {
187247
execute(editor.getValue() + ';');
188248
} catch (e) {
@@ -237,8 +297,7 @@ dbFileElm.onchange = function () {
237297
// Show the schema of the loaded database
238298
editor.setValue("SELECT `name`, `sql`\n FROM `sqlite_master`\n WHERE type='table';");
239299

240-
// Create a new tab for the results
241-
createNewTab();
300+
// Execute the query (this will create a new tab if needed)
242301
execEditorContents();
243302

244303
// Show success notification
@@ -300,8 +359,11 @@ function showNotification(message) {
300359
document.body.appendChild(notification);
301360
}
302361

303-
// Set message and show
362+
// Clear existing content and set new message
363+
notification.textContent = '';
304364
notification.textContent = message;
365+
366+
// Show notification
305367
notification.classList.add('show');
306368

307369
// Hide after 3 seconds
@@ -397,6 +459,18 @@ function initTabs() {
397459
// Initialize the first tab
398460
const firstTab = document.querySelector('.tab[data-tab="tab1"]');
399461
if (firstTab) {
462+
// Clear the first tab's content
463+
firstTab.innerHTML = '';
464+
465+
// Add the tab text directly
466+
firstTab.textContent = `Result ${tabCounter}`;
467+
468+
// Add close button
469+
const closeBtn = document.createElement('span');
470+
closeBtn.className = 'tab-close';
471+
closeBtn.textContent = '×';
472+
firstTab.appendChild(closeBtn);
473+
400474
setActiveTab('tab1');
401475
}
402476
}
@@ -406,26 +480,33 @@ function createNewTab() {
406480
tabCounter++;
407481
const tabId = `tab${tabCounter}`;
408482

409-
// Create tab button
410-
const tab = document.createElement('button');
411-
tab.className = 'tab';
483+
// Create tab button using template
484+
const tabTemplate = document.getElementById('tab-template');
485+
const tabClone = tabTemplate.content.cloneNode(true);
486+
const tab = tabClone.querySelector('.tab');
412487
tab.dataset.tab = tabId;
413-
tab.innerHTML = `Result ${tabCounter} <span class="tab-close">×</span>`;
488+
489+
// Clear any existing content in the tab
490+
tab.innerHTML = '';
491+
492+
// Add the tab text directly (no slots)
493+
tab.textContent = `Result ${tabCounter}`;
494+
495+
// Add close button
496+
const closeBtn = document.createElement('span');
497+
closeBtn.className = 'tab-close';
498+
closeBtn.textContent = '×';
499+
tab.appendChild(closeBtn);
414500

415501
// Insert before the + button
416502
resultsTabs.insertBefore(tab, newTabBtn);
417503

418-
// Create tab panel
419-
const tabPanel = document.createElement('div');
420-
tabPanel.className = 'tab-panel';
504+
// Create tab panel using template
505+
const panelTemplate = document.getElementById('tab-panel-template');
506+
const panelClone = panelTemplate.content.cloneNode(true);
507+
const tabPanel = panelClone.querySelector('.tab-panel');
421508
tabPanel.id = tabId;
422509

423-
// Create results content container
424-
const resultsContent = document.createElement('div');
425-
resultsContent.className = 'results-content';
426-
resultsContent.textContent = 'Execute a query to see results';
427-
428-
tabPanel.appendChild(resultsContent);
429510
document.querySelector('.results-panel .panel-content').appendChild(tabPanel);
430511

431512
// Set as active
@@ -506,9 +587,11 @@ function addToHistory(query) {
506587
function updateHistoryUI() {
507588
queryHistoryElm.innerHTML = '';
508589

509-
queryHistory.forEach((item, index) => {
510-
const historyItem = document.createElement('div');
511-
historyItem.className = 'history-item';
590+
queryHistory.forEach((item) => {
591+
// Use history item template
592+
const historyTemplate = document.getElementById('history-item-template');
593+
const historyClone = historyTemplate.content.cloneNode(true);
594+
const historyItem = historyClone.querySelector('.history-item');
512595

513596
// Format timestamp
514597
const timestamp = item.timestamp;
@@ -519,10 +602,18 @@ function updateHistoryUI() {
519602
item.query.substring(0, 60) + '...' :
520603
item.query;
521604

522-
historyItem.innerHTML = `
523-
<div class="history-query" title="${item.query}">${queryPreview}</div>
524-
<div class="history-time">${timeString}</div>
525-
`;
605+
// Set query preview
606+
const queryPreviewEl = document.createElement('span');
607+
queryPreviewEl.slot = 'query-preview';
608+
queryPreviewEl.textContent = queryPreview;
609+
historyItem.querySelector('.history-query').appendChild(queryPreviewEl);
610+
historyItem.querySelector('.history-query').title = item.query;
611+
612+
// Set query time
613+
const queryTimeEl = document.createElement('span');
614+
queryTimeEl.slot = 'query-time';
615+
queryTimeEl.textContent = timeString;
616+
historyItem.querySelector('.history-time').appendChild(queryTimeEl);
526617

527618
// Add click handler to load query
528619
historyItem.addEventListener('click', () => {
@@ -572,17 +663,27 @@ document.addEventListener('DOMContentLoaded', function() {
572663
if (editorHeader) {
573664
const shortcuts = document.createElement('div');
574665
shortcuts.className = 'shortcuts';
575-
shortcuts.innerHTML = `
576-
<span title="Execute: Ctrl/Cmd+Enter">
577-
<span class="shortcut-key">Ctrl+Enter</span>
578-
</span>
579-
<span title="Save DB: Ctrl/Cmd+S">
580-
<span class="shortcut-key">Ctrl+S</span>
581-
</span>
582-
<span title="Toggle History: Ctrl+Space">
583-
<span class="shortcut-key">Ctrl+Space</span>
584-
</span>
585-
`;
666+
667+
// Create shortcut elements using template
668+
const addShortcut = (title, keyText) => {
669+
const shortcutTemplate = document.getElementById('shortcut-template');
670+
const shortcutClone = shortcutTemplate.content.cloneNode(true);
671+
const shortcut = shortcutClone.querySelector('span');
672+
shortcut.title = title;
673+
674+
const keySlot = document.createElement('span');
675+
keySlot.slot = 'key';
676+
keySlot.textContent = keyText;
677+
shortcut.appendChild(keySlot);
678+
679+
shortcuts.appendChild(shortcut);
680+
};
681+
682+
// Add all shortcuts
683+
addShortcut('Execute: Ctrl/Cmd+Enter', 'Ctrl+Enter');
684+
addShortcut('Save DB: Ctrl/Cmd+S', 'Ctrl+S');
685+
addShortcut('Toggle History: Ctrl+Space', 'Ctrl+Space');
686+
586687
editorHeader.appendChild(shortcuts);
587688
}
588689
});

0 commit comments

Comments
 (0)