Ensure unique selectors for loaded extension files
| @@ -4,7 +4,7 @@ import { eventSource, event_types, saveSettings, saveSettingsDebounced, getReque | ||
| 4 | 4 | import { showLoader } from './loader.js'; |
| 5 | 5 | import { POPUP_RESULT, POPUP_TYPE, Popup, callGenericPopup } from './popup.js'; |
| 6 | 6 | import { renderTemplate, renderTemplateAsync } from './templates.js'; |
| 7 | 7 | import { delay, isSubsetOf, sanitizeSelector, setValueByPath } from './utils.js'; |
| 8 | 8 | import { getContext } from './st-context.js'; |
| 9 | 9 | import { isAdmin } from './user.js'; |
| 10 | 10 | import { t } from './i18n.js'; |
| @@ -509,10 +509,11 @@ function addExtensionStyle(name, manifest) { | ||
| 509 | 509 | |
| 510 | 510 | return new Promise((resolve, reject) => { |
| 511 | 511 | const url = `/scripts/extensions/${name}/${manifest.css}`; |
| 512 | + const id = sanitizeSelector(`${name}-css`); | |
| 512 | 513 | |
| 513 | 514 | if ($(`link[id="${nameid}"]`).length === 0) { |
| 514 | 515 | const link = document.createElement('link'); |
| 515 | 516 | link.id = nameid; |
| 516 | 517 | link.rel = 'stylesheet'; |
| 517 | 518 | link.type = 'text/css'; |
| 518 | 519 | link.href = url; |
| @@ -540,11 +541,12 @@ function addExtensionScript(name, manifest) { | ||
| 540 | 541 | |
| 541 | 542 | return new Promise((resolve, reject) => { |
| 542 | 543 | const url = `/scripts/extensions/${name}/${manifest.js}`; |
| 544 | + const id = sanitizeSelector(`${name}-js`); | |
| 543 | 545 | let ready = false; |
| 544 | 546 | |
| 545 | 547 | if ($(`script[id="${nameid}"]`).length === 0) { |
| 546 | 548 | const script = document.createElement('script'); |
| 547 | 549 | script.id = nameid; |
| 548 | 550 | script.type = 'module'; |
| 549 | 551 | script.src = url; |
| 550 | 552 | script.async = true; |
| @@ -67,6 +67,16 @@ export function escapeHtml(str) { | ||
| 67 | 67 | return String(str).replace(/&/g, '&').replace(/</g, '<').replace(/>/g, '>').replace(/"/g, '"'); |
| 68 | 68 | } |
| 69 | 69 | |
| 70 | +/** | |
| 71 | + * Make string safe for use as a CSS selector. | |
| 72 | + * @param {string} str String to sanitize | |
| 73 | + * @param {string} replacement Replacement for invalid characters | |
| 74 | + * @returns {string} Sanitized string | |
| 75 | + */ | |
| 76 | +export function sanitizeSelector(str, replacement = '_') { | |
| 77 | + return String(str).replace(/[^a-z0-9_-]/ig, replacement); | |
| 78 | +} | |
| 79 | + | |
| 70 | 80 | export function isValidUrl(value) { |
| 71 | 81 | try { |
| 72 | 82 | new URL(value); |