fix(csp): wire display sliders and accent picker without inline on*
Lint & Test / test (push) Successful in 10s

The display brightness/contrast sliders and the accent color picker
rendered dynamic HTML with inline oninput/onchange/onclick attributes,
which are blocked by the script-src 'self' CSP — so display settings
were silently un-clickable from the WebUI.

Replace the inline attributes with data-* markers, then attach proper
event listeners after innerHTML (delegated on the container for the
slider rows, direct for the accent dropdown).
This commit is contained in:
2026-05-19 01:17:47 +03:00
parent fe82836f4d
commit e1c8474271
2 changed files with 57 additions and 11 deletions
+33 -6
View File
@@ -182,8 +182,7 @@ export async function loadDisplayMonitors() {
<span class="display-slider-label" data-i18n="display.contrast">${t('display.contrast')}</span>
<input type="range" class="display-slider display-contrast-slider"
min="0" max="100" value="${contrastValue}"
oninput="onDisplayContrastInput(${monitor.id}, this.value)"
onchange="onDisplayContrastChange(${monitor.id}, this.value)">
data-display-slider="contrast" data-monitor-id="${monitor.id}">
<span class="display-slider-value" id="contrast-val-${monitor.id}">${contrastValue}%</span>
</div>`;
}
@@ -296,8 +295,7 @@ export async function loadDisplayMonitors() {
</svg>
<span class="display-slider-label" data-i18n="display.brightness">${t('display.brightness')}</span>
<input type="range" class="display-slider display-brightness-slider" min="0" max="100" value="${brightnessValue}" ${brightnessDisabled}
oninput="onDisplayBrightnessInput(${monitor.id}, this.value)"
onchange="onDisplayBrightnessChange(${monitor.id}, this.value)">
data-display-slider="brightness" data-monitor-id="${monitor.id}">
<span class="display-slider-value display-brightness-value" id="brightness-val-${monitor.id}">${brightnessValue}%</span>
</div>
${contrastRow}
@@ -306,10 +304,15 @@ export async function loadDisplayMonitors() {
container.appendChild(card);
});
// Bind a single delegated click handler for the power buttons.
// Avoids inline onclick="..." with interpolated monitor data.
// Bind a single delegated click handler for the power buttons,
// plus input/change handlers for the brightness & contrast sliders.
// Avoids inline on* attributes (blocked by script-src 'self' CSP).
container.removeEventListener('click', _onPowerButtonClick);
container.addEventListener('click', _onPowerButtonClick);
container.removeEventListener('input', _onDisplaySliderInput);
container.addEventListener('input', _onDisplaySliderInput);
container.removeEventListener('change', _onDisplaySliderChange);
container.addEventListener('change', _onDisplaySliderChange);
// Enhance every tuning <select> with an IconSelect now that the
// cards are in the DOM (IconSelect needs offsetParent + sibling).
@@ -456,6 +459,30 @@ function _onPowerButtonClick(event) {
if (Number.isFinite(id)) toggleDisplayPower(id);
}
function _onDisplaySliderInput(event) {
const el = event.target.closest('input[data-display-slider]');
if (!el) return;
const id = Number(el.dataset.monitorId);
if (!Number.isFinite(id)) return;
if (el.dataset.displaySlider === 'brightness') {
onDisplayBrightnessInput(id, el.value);
} else if (el.dataset.displaySlider === 'contrast') {
onDisplayContrastInput(id, el.value);
}
}
function _onDisplaySliderChange(event) {
const el = event.target.closest('input[data-display-slider]');
if (!el) return;
const id = Number(el.dataset.monitorId);
if (!Number.isFinite(id)) return;
if (el.dataset.displaySlider === 'brightness') {
onDisplayBrightnessChange(id, el.value);
} else if (el.dataset.displaySlider === 'contrast') {
onDisplayContrastChange(id, el.value);
}
}
export async function toggleDisplayPower(monitorId) {
const btn = document.getElementById(`power-btn-${monitorId}`);
const isOn = btn && btn.classList.contains('on');