@@ -6,6 +6,7 @@ import { generalSettings } from '../utils/storage-utils';
6
6
import { updateUrl } from '../utils/routing' ;
7
7
import { handleDragStart , handleDragOver , handleDrop , handleDragEnd } from '../utils/drag-and-drop' ;
8
8
import browser from '../utils/browser-polyfill' ;
9
+ import { createElementWithClass , createElementWithHTML } from '../utils/dom-utils' ;
9
10
10
11
let hasUnsavedChanges = false ;
11
12
@@ -26,15 +27,21 @@ export function updateTemplateList(loadedTemplates?: Template[]): void {
26
27
templatesToUse . forEach ( ( template , index ) => {
27
28
if ( template && template . name && template . id ) {
28
29
const li = document . createElement ( 'li' ) ;
29
- li . innerHTML = `
30
- <div class="drag-handle">
31
- <i data-lucide="grip-vertical"></i>
32
- </div>
33
- <span class="template-name">${ template . name } </span>
34
- <button type="button" class="delete-template-btn clickable-icon" aria-label="Delete template">
35
- <i data-lucide="trash-2"></i>
36
- </button>
37
- ` ;
30
+
31
+ const dragHandle = createElementWithClass ( 'div' , 'drag-handle' ) ;
32
+ dragHandle . appendChild ( createElementWithHTML ( 'i' , '' , { 'data-lucide' : 'grip-vertical' } ) ) ;
33
+ li . appendChild ( dragHandle ) ;
34
+
35
+ const templateName = createElementWithClass ( 'span' , 'template-name' ) ;
36
+ templateName . textContent = template . name ;
37
+ li . appendChild ( templateName ) ;
38
+
39
+ const deleteBtn = createElementWithClass ( 'button' , 'delete-template-btn clickable-icon' ) ;
40
+ deleteBtn . setAttribute ( 'type' , 'button' ) ;
41
+ deleteBtn . setAttribute ( 'aria-label' , 'Delete template' ) ;
42
+ deleteBtn . appendChild ( createElementWithHTML ( 'i' , '' , { 'data-lucide' : 'trash-2' } ) ) ;
43
+ li . appendChild ( deleteBtn ) ;
44
+
38
45
li . dataset . id = template . id ;
39
46
li . dataset . index = index . toString ( ) ;
40
47
li . draggable = true ;
@@ -44,13 +51,12 @@ export function updateTemplateList(loadedTemplates?: Template[]): void {
44
51
showTemplateEditor ( template ) ;
45
52
}
46
53
} ) ;
47
- const deleteBtn = li . querySelector ( '.delete-template-btn' ) ;
48
- if ( deleteBtn ) {
49
- deleteBtn . addEventListener ( 'click' , ( e ) => {
50
- e . stopPropagation ( ) ;
51
- deleteTemplate ( template . id ) ;
52
- } ) ;
53
- }
54
+
55
+ deleteBtn . addEventListener ( 'click' , ( e ) => {
56
+ e . stopPropagation ( ) ;
57
+ deleteTemplate ( template . id ) ;
58
+ } ) ;
59
+
54
60
if ( index === editingTemplateIndex ) {
55
61
li . classList . add ( 'active' ) ;
56
62
}
@@ -173,7 +179,11 @@ export function showTemplateEditor(template: Template | null): void {
173
179
174
180
const vaultSelect = document . getElementById ( 'template-vault' ) as HTMLSelectElement ;
175
181
if ( vaultSelect ) {
176
- vaultSelect . innerHTML = '<option value="">Last used</option>' ;
182
+ vaultSelect . innerHTML = '' ;
183
+ const lastUsedOption = document . createElement ( 'option' ) ;
184
+ lastUsedOption . value = '' ;
185
+ lastUsedOption . textContent = 'Last used' ;
186
+ vaultSelect . appendChild ( lastUsedOption ) ;
177
187
generalSettings . vaults . forEach ( vault => {
178
188
const option = document . createElement ( 'option' ) ;
179
189
option . value = vault ;
@@ -238,32 +248,55 @@ export function addPropertyToEditor(name: string = '', value: string = '', type:
238
248
if ( ! templateProperties ) return ;
239
249
240
250
const propertyId = id || Date . now ( ) . toString ( ) + Math . random ( ) . toString ( 36 ) . slice ( 2 , 11 ) ;
241
- const propertyDiv = document . createElement ( 'div' ) ;
242
- propertyDiv . className = 'property-editor' ;
243
- propertyDiv . innerHTML = `
244
- <div class="drag-handle">
245
- <i data-lucide="grip-vertical"></i>
246
- </div>
247
- <div class="property-select">
248
- <div class="property-selected" data-value="${ type } ">
249
- <i data-lucide="${ getPropertyTypeIcon ( type ) } "></i>
250
- </div>
251
- <select class="property-type" id="${ propertyId } -type">
252
- <option value="text">Text</option>
253
- <option value="multitext">List</option>
254
- <option value="number">Number</option>
255
- <option value="checkbox">Checkbox</option>
256
- <option value="date">Date</option>
257
- <option value="datetime">Date & time</option>
258
- </select>
259
- </div>
260
- <input type="text" class="property-name" id="${ propertyId } -name" value="${ name } " placeholder="Property name">
261
- <input type="text" class="property-value" id="${ propertyId } -value" value="${ escapeHtml ( unescapeValue ( value ) ) } " placeholder="Property value">
262
- <button type="button" class="remove-property-btn clickable-icon" aria-label="Remove property">
263
- <i data-lucide="trash-2"></i>
264
- </button>
265
- ` ;
251
+ const propertyDiv = createElementWithClass ( 'div' , 'property-editor' ) ;
266
252
propertyDiv . dataset . id = propertyId ;
253
+
254
+ const dragHandle = createElementWithClass ( 'div' , 'drag-handle' ) ;
255
+ dragHandle . appendChild ( createElementWithHTML ( 'i' , '' , { 'data-lucide' : 'grip-vertical' } ) ) ;
256
+ propertyDiv . appendChild ( dragHandle ) ;
257
+
258
+ const propertySelectDiv = createElementWithClass ( 'div' , 'property-select' ) ;
259
+ const propertySelectedDiv = createElementWithClass ( 'div' , 'property-selected' ) ;
260
+ propertySelectedDiv . dataset . value = type ;
261
+ propertySelectedDiv . appendChild ( createElementWithHTML ( 'i' , '' , { 'data-lucide' : getPropertyTypeIcon ( type ) } ) ) ;
262
+ propertySelectDiv . appendChild ( propertySelectedDiv ) ;
263
+
264
+ const select = document . createElement ( 'select' ) ;
265
+ select . className = 'property-type' ;
266
+ select . id = `${ propertyId } -type` ;
267
+ [ 'text' , 'multitext' , 'number' , 'checkbox' , 'date' , 'datetime' ] . forEach ( optionValue => {
268
+ const option = document . createElement ( 'option' ) ;
269
+ option . value = optionValue ;
270
+ option . textContent = optionValue . charAt ( 0 ) . toUpperCase ( ) + optionValue . slice ( 1 ) ;
271
+ select . appendChild ( option ) ;
272
+ } ) ;
273
+ propertySelectDiv . appendChild ( select ) ;
274
+ propertyDiv . appendChild ( propertySelectDiv ) ;
275
+
276
+ const nameInput = createElementWithHTML ( 'input' , '' , {
277
+ type : 'text' ,
278
+ class : 'property-name' ,
279
+ id : `${ propertyId } -name` ,
280
+ value : name ,
281
+ placeholder : 'Property name'
282
+ } ) ;
283
+ propertyDiv . appendChild ( nameInput ) ;
284
+
285
+ const valueInput = createElementWithHTML ( 'input' , '' , {
286
+ type : 'text' ,
287
+ class : 'property-value' ,
288
+ id : `${ propertyId } -value` ,
289
+ value : escapeHtml ( unescapeValue ( value ) ) ,
290
+ placeholder : 'Property value'
291
+ } ) ;
292
+ propertyDiv . appendChild ( valueInput ) ;
293
+
294
+ const removeBtn = createElementWithClass ( 'button' , 'remove-property-btn clickable-icon' ) ;
295
+ removeBtn . setAttribute ( 'type' , 'button' ) ;
296
+ removeBtn . setAttribute ( 'aria-label' , 'Remove property' ) ;
297
+ removeBtn . appendChild ( createElementWithHTML ( 'i' , '' , { 'data-lucide' : 'trash-2' } ) ) ;
298
+ propertyDiv . appendChild ( removeBtn ) ;
299
+
267
300
templateProperties . appendChild ( propertyDiv ) ;
268
301
269
302
propertyDiv . addEventListener ( 'mousedown' , ( event ) => {
@@ -288,23 +321,16 @@ export function addPropertyToEditor(name: string = '', value: string = '', type:
288
321
propertyDiv . addEventListener ( 'dragend' , resetDraggable ) ;
289
322
propertyDiv . addEventListener ( 'mouseup' , resetDraggable ) ;
290
323
291
- const propertySelect = propertyDiv . querySelector ( '.property-select' ) ;
292
- if ( ! propertySelect ) return ;
293
-
294
- const propertySelected = propertySelect . querySelector ( '.property-selected' ) ;
295
- const hiddenSelect = propertySelect . querySelector ( 'select' ) ;
324
+ if ( select ) {
325
+ select . value = type ;
296
326
297
- if ( hiddenSelect ) {
298
- hiddenSelect . value = type ;
299
-
300
- hiddenSelect . addEventListener ( 'change' , function ( ) {
301
- if ( propertySelected ) updateSelectedOption ( this . value , propertySelected as HTMLElement ) ;
327
+ select . addEventListener ( 'change' , function ( ) {
328
+ if ( propertySelectedDiv ) updateSelectedOption ( this . value , propertySelectedDiv ) ;
302
329
} ) ;
303
330
}
304
331
305
- const removePropertyBtn = propertyDiv . querySelector ( '.remove-property-btn' ) ;
306
- if ( removePropertyBtn ) {
307
- removePropertyBtn . addEventListener ( 'click' , ( ) => {
332
+ if ( removeBtn ) {
333
+ removeBtn . addEventListener ( 'click' , ( ) => {
308
334
templateProperties . removeChild ( propertyDiv ) ;
309
335
} ) ;
310
336
}
@@ -314,14 +340,21 @@ export function addPropertyToEditor(name: string = '', value: string = '', type:
314
340
propertyDiv . addEventListener ( 'drop' , handleDrop ) ;
315
341
propertyDiv . addEventListener ( 'dragend' , handleDragEnd ) ;
316
342
317
- if ( propertySelected ) updateSelectedOption ( type , propertySelected as HTMLElement ) ;
343
+ updateSelectedOption ( type , propertySelectedDiv ) ;
318
344
319
345
initializeIcons ( propertyDiv ) ;
320
346
}
321
347
322
348
function updateSelectedOption ( value : string , propertySelected : HTMLElement ) : void {
323
349
const iconName = getPropertyTypeIcon ( value ) ;
324
- propertySelected . innerHTML = `<i data-lucide="${ iconName } "></i>` ;
350
+
351
+ // Clear existing content
352
+ propertySelected . innerHTML = '' ;
353
+
354
+ // Create and append the new icon element
355
+ const iconElement = createElementWithHTML ( 'i' , '' , { 'data-lucide' : iconName } ) ;
356
+ propertySelected . appendChild ( iconElement ) ;
357
+
325
358
propertySelected . setAttribute ( 'data-value' , value ) ;
326
359
initializeIcons ( propertySelected ) ;
327
360
}
0 commit comments