mirror of
https://github.com/SoPat712/videospeed.git
synced 2026-04-26 22:23:09 -04:00
Refine site rule toggle and override UI
This commit is contained in:
+119
-16
@@ -7,6 +7,17 @@
|
||||
--text: #17191c;
|
||||
--muted: #626b76;
|
||||
--accent: #111827;
|
||||
--switch-track-off: #c1cad6;
|
||||
--switch-track-off-border: #aeb8c5;
|
||||
--switch-track-on: #111827;
|
||||
--switch-track-on-border: #111827;
|
||||
--switch-thumb-off: #ffffff;
|
||||
--switch-thumb-on: #ffffff;
|
||||
--toggle-open-fg: #111827;
|
||||
--toggle-open-bg: #eef2f6;
|
||||
--toggle-open-border: #c5ccd5;
|
||||
--toggle-open-hover-bg: #e4eaf1;
|
||||
--toggle-open-hover-border: #b5c0cc;
|
||||
--danger: #b42318;
|
||||
}
|
||||
|
||||
@@ -210,6 +221,7 @@ button:active {
|
||||
}
|
||||
|
||||
button:focus-visible,
|
||||
input[type="checkbox"]:focus-visible,
|
||||
input[type="text"]:focus,
|
||||
select:focus,
|
||||
textarea:focus {
|
||||
@@ -247,10 +259,49 @@ textarea:focus {
|
||||
}
|
||||
|
||||
input[type="checkbox"] {
|
||||
width: 16px;
|
||||
height: 16px;
|
||||
margin: 2px 0 0;
|
||||
accent-color: var(--accent);
|
||||
appearance: none;
|
||||
-webkit-appearance: none;
|
||||
position: relative;
|
||||
width: 46px;
|
||||
min-width: 46px;
|
||||
height: 28px;
|
||||
margin: 0;
|
||||
border: 1px solid var(--switch-track-off-border);
|
||||
border-radius: 999px;
|
||||
background: var(--switch-track-off);
|
||||
cursor: pointer;
|
||||
transition: background-color 120ms ease, border-color 120ms ease,
|
||||
box-shadow 120ms ease;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
input[type="checkbox"]::before {
|
||||
content: "";
|
||||
position: absolute;
|
||||
top: 3px;
|
||||
left: 3px;
|
||||
width: 20px;
|
||||
height: 20px;
|
||||
border-radius: 50%;
|
||||
background: var(--switch-thumb-off);
|
||||
box-shadow: 0 1px 2px rgba(17, 24, 39, 0.18),
|
||||
inset 0 0 0 1px rgba(17, 24, 39, 0.08);
|
||||
transition: transform 120ms ease, background-color 120ms ease;
|
||||
}
|
||||
|
||||
input[type="checkbox"]:checked {
|
||||
background: var(--switch-track-on);
|
||||
border-color: var(--switch-track-on-border);
|
||||
}
|
||||
|
||||
input[type="checkbox"]:checked::before {
|
||||
transform: translateX(18px);
|
||||
background: var(--switch-thumb-on);
|
||||
}
|
||||
|
||||
input[type="checkbox"]:disabled {
|
||||
cursor: default;
|
||||
opacity: 0.7;
|
||||
}
|
||||
|
||||
label {
|
||||
@@ -322,6 +373,39 @@ label em {
|
||||
|
||||
.toggle-site-rule {
|
||||
font-weight: 400;
|
||||
color: var(--muted);
|
||||
}
|
||||
|
||||
.toggle-site-rule:hover {
|
||||
color: var(--toggle-open-fg);
|
||||
background: var(--toggle-open-hover-bg);
|
||||
border-color: var(--toggle-open-hover-border);
|
||||
}
|
||||
|
||||
.toggle-site-rule .site-rule-toggle-icon {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
width: 18px;
|
||||
height: 18px;
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
.toggle-site-rule .site-rule-toggle-icon svg {
|
||||
width: 18px;
|
||||
height: 18px;
|
||||
}
|
||||
|
||||
.site-rule:not(.collapsed) .toggle-site-rule {
|
||||
color: var(--toggle-open-fg);
|
||||
background: var(--toggle-open-bg);
|
||||
border-color: var(--toggle-open-border);
|
||||
}
|
||||
|
||||
.site-rule:not(.collapsed) .toggle-site-rule:hover {
|
||||
color: var(--toggle-open-fg);
|
||||
background: var(--toggle-open-hover-bg);
|
||||
border-color: var(--toggle-open-hover-border);
|
||||
}
|
||||
|
||||
.row {
|
||||
@@ -339,7 +423,7 @@ label em {
|
||||
}
|
||||
|
||||
.row.row-checkbox {
|
||||
grid-template-columns: minmax(0, 1fr) 24px;
|
||||
grid-template-columns: minmax(0, 1fr) auto;
|
||||
}
|
||||
|
||||
.row.row-checkbox input[type="checkbox"] {
|
||||
@@ -403,9 +487,9 @@ label em {
|
||||
|
||||
.site-override-lead {
|
||||
display: grid;
|
||||
grid-template-columns: minmax(0, 1fr) 24px;
|
||||
grid-template-columns: minmax(0, 1fr) auto;
|
||||
gap: 16px;
|
||||
align-items: flex-start;
|
||||
align-items: center;
|
||||
font-weight: 600;
|
||||
margin-bottom: 8px;
|
||||
cursor: pointer;
|
||||
@@ -414,7 +498,6 @@ label em {
|
||||
|
||||
.site-override-lead input[type="checkbox"] {
|
||||
justify-self: end;
|
||||
margin-top: 3px;
|
||||
}
|
||||
|
||||
.site-override-lead span {
|
||||
@@ -427,10 +510,19 @@ label em {
|
||||
.site-rule-override-section .site-autohide-container,
|
||||
.site-rule-override-section .site-playback-container,
|
||||
.site-rule-override-section .site-opacity-container,
|
||||
.site-rule-override-section .site-subtitleNudge-container {
|
||||
.site-rule-override-section .site-subtitleNudge-container,
|
||||
.site-controlbar-container,
|
||||
.site-popup-controlbar-container,
|
||||
.site-shortcuts-container {
|
||||
padding-left: 4px;
|
||||
}
|
||||
|
||||
.site-override-disabled {
|
||||
opacity: 0.48;
|
||||
pointer-events: none;
|
||||
user-select: none;
|
||||
}
|
||||
|
||||
.cb-editor {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
@@ -803,7 +895,7 @@ button.lucide-result-tile.lucide-picked {
|
||||
}
|
||||
|
||||
.site-rule-option-checkbox {
|
||||
grid-template-columns: minmax(0, 1fr) 24px;
|
||||
grid-template-columns: minmax(0, 1fr) auto;
|
||||
}
|
||||
|
||||
.site-rule-option-checkbox > input[type="checkbox"] {
|
||||
@@ -833,7 +925,7 @@ button.lucide-result-tile.lucide-picked {
|
||||
|
||||
.site-rule-split-label {
|
||||
display: grid;
|
||||
grid-template-columns: minmax(0, 1fr) 24px;
|
||||
grid-template-columns: minmax(0, 1fr) auto;
|
||||
gap: 16px;
|
||||
align-items: flex-start;
|
||||
width: 100%;
|
||||
@@ -845,7 +937,7 @@ button.lucide-result-tile.lucide-picked {
|
||||
|
||||
.site-rule-split-label input[type="checkbox"] {
|
||||
justify-self: end;
|
||||
margin-top: 3px;
|
||||
margin-top: 0;
|
||||
}
|
||||
|
||||
.site-rule-option-checkbox > .site-rule-split-label {
|
||||
@@ -889,8 +981,8 @@ button.lucide-result-tile.lucide-picked {
|
||||
|
||||
.force-label {
|
||||
display: flex;
|
||||
align-items: flex-start;
|
||||
gap: 8px;
|
||||
align-items: center;
|
||||
gap: 10px;
|
||||
width: auto;
|
||||
margin: 0;
|
||||
color: var(--muted);
|
||||
@@ -898,7 +990,7 @@ button.lucide-result-tile.lucide-picked {
|
||||
}
|
||||
|
||||
.force-label input {
|
||||
margin-top: 2px;
|
||||
margin-top: 0;
|
||||
}
|
||||
|
||||
.action-row {
|
||||
@@ -956,7 +1048,7 @@ button.lucide-result-tile.lucide-picked {
|
||||
}
|
||||
|
||||
.site-override-lead {
|
||||
grid-template-columns: minmax(0, 1fr) 24px;
|
||||
grid-template-columns: minmax(0, 1fr) auto;
|
||||
}
|
||||
|
||||
.action-row button,
|
||||
@@ -1005,6 +1097,17 @@ button.lucide-result-tile.lucide-picked {
|
||||
--text: #f2f4f6;
|
||||
--muted: #a0a8b2;
|
||||
--accent: #f2f4f6;
|
||||
--switch-track-off: #374151;
|
||||
--switch-track-off-border: #4b5563;
|
||||
--switch-track-on: #aab7c6;
|
||||
--switch-track-on-border: #aab7c6;
|
||||
--switch-thumb-off: #f8fafc;
|
||||
--switch-thumb-on: #111315;
|
||||
--toggle-open-fg: #f2f4f6;
|
||||
--toggle-open-bg: #2b3138;
|
||||
--toggle-open-border: #4b5563;
|
||||
--toggle-open-hover-bg: #374151;
|
||||
--toggle-open-hover-border: #64748b;
|
||||
--danger: #ff8a80;
|
||||
}
|
||||
|
||||
|
||||
+18
-10
@@ -483,7 +483,15 @@
|
||||
<template id="siteRuleTemplate">
|
||||
<div class="site-rule">
|
||||
<div class="site-rule-header">
|
||||
<button type="button" class="toggle-site-rule" title="Expand/Collapse">+</button>
|
||||
<button
|
||||
type="button"
|
||||
class="toggle-site-rule"
|
||||
title="Expand site rule"
|
||||
aria-label="Expand site rule"
|
||||
aria-expanded="false"
|
||||
>
|
||||
<span class="site-rule-toggle-icon" aria-hidden="true">…</span>
|
||||
</button>
|
||||
<input
|
||||
type="text"
|
||||
class="site-pattern"
|
||||
@@ -504,7 +512,7 @@
|
||||
<span>Override placement for this site</span>
|
||||
<input type="checkbox" class="override-placement" />
|
||||
</label>
|
||||
<div class="site-placement-container" style="display: none">
|
||||
<div class="site-placement-container">
|
||||
<div class="site-rule-option site-rule-option-field">
|
||||
<label>Default controller location:</label>
|
||||
<select class="site-controllerLocation">
|
||||
@@ -542,7 +550,7 @@
|
||||
<span>Override hide-by-default for this site</span>
|
||||
<input type="checkbox" class="override-visibility" />
|
||||
</label>
|
||||
<div class="site-visibility-container" style="display: none">
|
||||
<div class="site-visibility-container">
|
||||
<div class="site-rule-option site-rule-option-checkbox">
|
||||
<label>Hide controller by default:</label>
|
||||
<input type="checkbox" class="site-startHidden" />
|
||||
@@ -554,7 +562,7 @@
|
||||
<span>Override auto-hide for this site</span>
|
||||
<input type="checkbox" class="override-autohide" />
|
||||
</label>
|
||||
<div class="site-autohide-container" style="display: none">
|
||||
<div class="site-autohide-container">
|
||||
<div class="site-rule-option site-rule-option-checkbox">
|
||||
<label class="site-rule-split-label">
|
||||
<span>Hide with controls (idle-based)</span>
|
||||
@@ -572,7 +580,7 @@
|
||||
<span>Override playback for this site</span>
|
||||
<input type="checkbox" class="override-playback" />
|
||||
</label>
|
||||
<div class="site-playback-container" style="display: none">
|
||||
<div class="site-playback-container">
|
||||
<div class="site-rule-option site-rule-option-checkbox">
|
||||
<label>Remember playback speed:</label>
|
||||
<input type="checkbox" class="site-rememberSpeed" />
|
||||
@@ -592,7 +600,7 @@
|
||||
<span>Override opacity for this site</span>
|
||||
<input type="checkbox" class="override-opacity" />
|
||||
</label>
|
||||
<div class="site-opacity-container" style="display: none">
|
||||
<div class="site-opacity-container">
|
||||
<div class="site-rule-option site-rule-option-field">
|
||||
<label>Controller opacity:</label>
|
||||
<input type="text" class="site-controllerOpacity" />
|
||||
@@ -604,7 +612,7 @@
|
||||
<span>Override subtitle nudge for this site</span>
|
||||
<input type="checkbox" class="override-subtitleNudge" />
|
||||
</label>
|
||||
<div class="site-subtitleNudge-container" style="display: none">
|
||||
<div class="site-subtitleNudge-container">
|
||||
<div class="site-rule-option site-rule-option-checkbox">
|
||||
<label>Enable subtitle nudge:</label>
|
||||
<input type="checkbox" class="site-enableSubtitleNudge" />
|
||||
@@ -620,7 +628,7 @@
|
||||
<span>Override in-player control bar for this site</span>
|
||||
<input type="checkbox" class="override-controlbar" />
|
||||
</label>
|
||||
<div class="site-controlbar-container" style="display: none">
|
||||
<div class="site-controlbar-container">
|
||||
<div class="cb-editor">
|
||||
<div class="cb-zone">
|
||||
<div class="cb-zone-label">Active</div>
|
||||
@@ -638,7 +646,7 @@
|
||||
<span>Override extension popup for this site</span>
|
||||
<input type="checkbox" class="override-popup-controlbar" />
|
||||
</label>
|
||||
<div class="site-popup-controlbar-container" style="display: none">
|
||||
<div class="site-popup-controlbar-container">
|
||||
<div class="site-rule-option site-rule-option-checkbox">
|
||||
<label>Show popup control bar</label>
|
||||
<input type="checkbox" class="site-showPopupControlBar" />
|
||||
@@ -660,7 +668,7 @@
|
||||
<span>Override shortcuts for this site</span>
|
||||
<input type="checkbox" class="override-shortcuts" />
|
||||
</label>
|
||||
<div class="site-shortcuts-container" style="display: none"></div>
|
||||
<div class="site-shortcuts-container"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
+172
-164
@@ -312,6 +312,71 @@ function parseFiniteNumberOrFallback(value, fallback) {
|
||||
return Number.isFinite(numericValue) ? numericValue : fallback;
|
||||
}
|
||||
|
||||
function updateSiteRuleToggleIcon(toggleButton, action) {
|
||||
if (!toggleButton) return;
|
||||
var iconEl = toggleButton.querySelector(".site-rule-toggle-icon");
|
||||
if (!iconEl) return;
|
||||
|
||||
if (typeof vscIconSvgString === "function" && typeof vscSetSvgContent === "function") {
|
||||
var svgHtml = vscIconSvgString(action, 16);
|
||||
if (svgHtml && vscSetSvgContent(iconEl, svgHtml)) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
iconEl.textContent = action === "chevronUp" ? "\u2212" : "\u2026";
|
||||
}
|
||||
|
||||
function setSiteRuleExpandedState(ruleEl, expanded) {
|
||||
if (!ruleEl) return;
|
||||
|
||||
var ruleBody = ruleEl.querySelector(".site-rule-body");
|
||||
var toggleButton = ruleEl.querySelector(".toggle-site-rule");
|
||||
if (ruleBody) {
|
||||
ruleBody.style.display = expanded ? "block" : "none";
|
||||
}
|
||||
|
||||
ruleEl.classList.toggle("collapsed", !expanded);
|
||||
|
||||
if (!toggleButton) return;
|
||||
var label = expanded ? "Collapse site rule" : "Expand site rule";
|
||||
toggleButton.title = label;
|
||||
toggleButton.setAttribute("aria-label", label);
|
||||
toggleButton.setAttribute("aria-expanded", expanded ? "true" : "false");
|
||||
updateSiteRuleToggleIcon(toggleButton, expanded ? "chevronUp" : "moreHorizontal");
|
||||
}
|
||||
|
||||
function setSiteOverrideContainerState(container, enabled) {
|
||||
if (!container) return;
|
||||
|
||||
container.classList.toggle("site-override-disabled", !enabled);
|
||||
container.setAttribute("aria-disabled", enabled ? "false" : "true");
|
||||
|
||||
Array.prototype.forEach.call(
|
||||
container.querySelectorAll("input, select, textarea, button"),
|
||||
function (control) {
|
||||
control.disabled = !enabled;
|
||||
}
|
||||
);
|
||||
|
||||
Array.prototype.forEach.call(
|
||||
container.querySelectorAll(".cb-block"),
|
||||
function (block) {
|
||||
block.draggable = enabled;
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
function applySiteRuleOverrideState(ruleEl, checkboxClass, containerClass) {
|
||||
if (!ruleEl) return;
|
||||
var checkbox = ruleEl.querySelector("." + checkboxClass);
|
||||
var container = ruleEl.querySelector("." + containerClass);
|
||||
if (!container) return;
|
||||
|
||||
container.style.display = "block";
|
||||
setSiteOverrideContainerState(container, checkbox ? checkbox.checked : false);
|
||||
}
|
||||
|
||||
function syncSiteRuleField(ruleEl, rule, key, isCheckbox) {
|
||||
var input = ruleEl.querySelector(".site-" + key);
|
||||
if (!input) return;
|
||||
@@ -894,9 +959,7 @@ function createSiteRule(rule) {
|
||||
ruleEl.querySelector(".site-pattern").value = pattern;
|
||||
|
||||
// Make the rule body collapsed by default
|
||||
var ruleBody = ruleEl.querySelector(".site-rule-body");
|
||||
ruleBody.style.display = "none";
|
||||
ruleEl.classList.add("collapsed");
|
||||
setSiteRuleExpandedState(ruleEl, false);
|
||||
|
||||
var enabledCheckbox = ruleEl.querySelector(".site-enabled");
|
||||
var contentEl = ruleEl.querySelector(".site-rule-content");
|
||||
@@ -931,114 +994,99 @@ function createSiteRule(rule) {
|
||||
];
|
||||
var hasPlacementOverride =
|
||||
rule && placementKeys.some(function (k) { return rule[k] !== undefined; });
|
||||
if (hasPlacementOverride) {
|
||||
ruleEl.querySelector(".override-placement").checked = true;
|
||||
ruleEl.querySelector(".site-placement-container").style.display = "block";
|
||||
}
|
||||
ruleEl.querySelector(".override-placement").checked = Boolean(hasPlacementOverride);
|
||||
syncSiteRuleField(ruleEl, rule, "controllerLocation", false);
|
||||
syncSiteRuleField(ruleEl, rule, "controllerMarginTop", false);
|
||||
syncSiteRuleField(ruleEl, rule, "controllerMarginBottom", false);
|
||||
applySiteRuleOverrideState(ruleEl, "override-placement", "site-placement-container");
|
||||
|
||||
if (rule && rule.startHidden !== undefined) {
|
||||
ruleEl.querySelector(".override-visibility").checked = true;
|
||||
ruleEl.querySelector(".site-visibility-container").style.display = "block";
|
||||
}
|
||||
ruleEl.querySelector(".override-visibility").checked = Boolean(
|
||||
rule && rule.startHidden !== undefined
|
||||
);
|
||||
syncSiteRuleField(ruleEl, rule, "startHidden", true);
|
||||
applySiteRuleOverrideState(ruleEl, "override-visibility", "site-visibility-container");
|
||||
|
||||
if (
|
||||
var hasAutohideOverride = Boolean(
|
||||
rule &&
|
||||
(rule.hideWithControls !== undefined ||
|
||||
rule.hideWithControlsTimer !== undefined)
|
||||
) {
|
||||
ruleEl.querySelector(".override-autohide").checked = true;
|
||||
ruleEl.querySelector(".site-autohide-container").style.display = "block";
|
||||
}
|
||||
);
|
||||
ruleEl.querySelector(".override-autohide").checked = hasAutohideOverride;
|
||||
syncSiteRuleField(ruleEl, rule, "hideWithControls", true);
|
||||
syncSiteRuleField(ruleEl, rule, "hideWithControlsTimer", false);
|
||||
applySiteRuleOverrideState(ruleEl, "override-autohide", "site-autohide-container");
|
||||
|
||||
if (
|
||||
var hasPlaybackOverride = Boolean(
|
||||
rule &&
|
||||
(rule.rememberSpeed !== undefined ||
|
||||
rule.forceLastSavedSpeed !== undefined ||
|
||||
rule.audioBoolean !== undefined)
|
||||
) {
|
||||
ruleEl.querySelector(".override-playback").checked = true;
|
||||
ruleEl.querySelector(".site-playback-container").style.display = "block";
|
||||
}
|
||||
);
|
||||
ruleEl.querySelector(".override-playback").checked = hasPlaybackOverride;
|
||||
syncSiteRuleField(ruleEl, rule, "rememberSpeed", true);
|
||||
syncSiteRuleField(ruleEl, rule, "forceLastSavedSpeed", true);
|
||||
syncSiteRuleField(ruleEl, rule, "audioBoolean", true);
|
||||
applySiteRuleOverrideState(ruleEl, "override-playback", "site-playback-container");
|
||||
|
||||
if (rule && rule.controllerOpacity !== undefined) {
|
||||
ruleEl.querySelector(".override-opacity").checked = true;
|
||||
ruleEl.querySelector(".site-opacity-container").style.display = "block";
|
||||
}
|
||||
ruleEl.querySelector(".override-opacity").checked = Boolean(
|
||||
rule && rule.controllerOpacity !== undefined
|
||||
);
|
||||
syncSiteRuleField(ruleEl, rule, "controllerOpacity", false);
|
||||
applySiteRuleOverrideState(ruleEl, "override-opacity", "site-opacity-container");
|
||||
|
||||
if (
|
||||
var hasSubtitleNudgeOverride = Boolean(
|
||||
rule &&
|
||||
(rule.enableSubtitleNudge !== undefined ||
|
||||
rule.subtitleNudgeInterval !== undefined)
|
||||
) {
|
||||
ruleEl.querySelector(".override-subtitleNudge").checked = true;
|
||||
ruleEl.querySelector(".site-subtitleNudge-container").style.display =
|
||||
"block";
|
||||
}
|
||||
);
|
||||
ruleEl.querySelector(".override-subtitleNudge").checked = hasSubtitleNudgeOverride;
|
||||
syncSiteRuleField(ruleEl, rule, "enableSubtitleNudge", true);
|
||||
syncSiteRuleField(ruleEl, rule, "subtitleNudgeInterval", false);
|
||||
applySiteRuleOverrideState(
|
||||
ruleEl,
|
||||
"override-subtitleNudge",
|
||||
"site-subtitleNudge-container"
|
||||
);
|
||||
|
||||
if (rule && Array.isArray(rule.controllerButtons)) {
|
||||
ruleEl.querySelector(".override-controlbar").checked = true;
|
||||
var cbContainer = ruleEl.querySelector(".site-controlbar-container");
|
||||
cbContainer.style.display = "block";
|
||||
populateControlBarZones(
|
||||
ruleEl.querySelector(".site-cb-active"),
|
||||
ruleEl.querySelector(".site-cb-available"),
|
||||
rule.controllerButtons
|
||||
);
|
||||
}
|
||||
var hasControlbarOverride = Boolean(rule && Array.isArray(rule.controllerButtons));
|
||||
ruleEl.querySelector(".override-controlbar").checked = hasControlbarOverride;
|
||||
populateControlBarZones(
|
||||
ruleEl.querySelector(".site-cb-active"),
|
||||
ruleEl.querySelector(".site-cb-available"),
|
||||
hasControlbarOverride ? rule.controllerButtons : getControlBarOrder()
|
||||
);
|
||||
applySiteRuleOverrideState(ruleEl, "override-controlbar", "site-controlbar-container");
|
||||
|
||||
if (
|
||||
var hasPopupControlbarOverride = Boolean(
|
||||
rule &&
|
||||
(rule.showPopupControlBar !== undefined ||
|
||||
Array.isArray(rule.popupControllerButtons))
|
||||
) {
|
||||
ruleEl.querySelector(".override-popup-controlbar").checked = true;
|
||||
var popupCbContainer = ruleEl.querySelector(".site-popup-controlbar-container");
|
||||
popupCbContainer.style.display = "block";
|
||||
var sitePopupActive = ruleEl.querySelector(".site-popup-cb-active");
|
||||
var sitePopupAvailable = ruleEl.querySelector(".site-popup-cb-available");
|
||||
if (Array.isArray(rule.popupControllerButtons)) {
|
||||
populateControlBarZones(
|
||||
sitePopupActive,
|
||||
sitePopupAvailable,
|
||||
sanitizePopupButtonOrder(rule.popupControllerButtons),
|
||||
function (id) {
|
||||
return !popupExcludedButtonIds.has(id);
|
||||
}
|
||||
);
|
||||
} else if (
|
||||
sitePopupActive &&
|
||||
sitePopupAvailable &&
|
||||
sitePopupActive.children.length === 0
|
||||
) {
|
||||
populateControlBarZones(
|
||||
sitePopupActive,
|
||||
sitePopupAvailable,
|
||||
getPopupControlBarOrder(),
|
||||
function (id) {
|
||||
return !popupExcludedButtonIds.has(id);
|
||||
}
|
||||
);
|
||||
);
|
||||
ruleEl.querySelector(".override-popup-controlbar").checked =
|
||||
hasPopupControlbarOverride;
|
||||
populateControlBarZones(
|
||||
ruleEl.querySelector(".site-popup-cb-active"),
|
||||
ruleEl.querySelector(".site-popup-cb-available"),
|
||||
hasPopupControlbarOverride && Array.isArray(rule.popupControllerButtons)
|
||||
? sanitizePopupButtonOrder(rule.popupControllerButtons)
|
||||
: getPopupControlBarOrder(),
|
||||
function (id) {
|
||||
return !popupExcludedButtonIds.has(id);
|
||||
}
|
||||
}
|
||||
);
|
||||
syncSiteRuleField(ruleEl, rule, "showPopupControlBar", true);
|
||||
applySiteRuleOverrideState(
|
||||
ruleEl,
|
||||
"override-popup-controlbar",
|
||||
"site-popup-controlbar-container"
|
||||
);
|
||||
|
||||
if (rule && Array.isArray(rule.shortcuts) && rule.shortcuts.length > 0) {
|
||||
ruleEl.querySelector(".override-shortcuts").checked = true;
|
||||
var container = ruleEl.querySelector(".site-shortcuts-container");
|
||||
container.style.display = "block";
|
||||
|
||||
var hasShortcutOverride = Boolean(
|
||||
rule && Array.isArray(rule.shortcuts) && rule.shortcuts.length > 0
|
||||
);
|
||||
ruleEl.querySelector(".override-shortcuts").checked = hasShortcutOverride;
|
||||
var container = ruleEl.querySelector(".site-shortcuts-container");
|
||||
if (hasShortcutOverride) {
|
||||
rule.shortcuts.forEach((shortcut) => {
|
||||
addSiteRuleShortcut(
|
||||
container,
|
||||
@@ -1048,13 +1096,41 @@ function createSiteRule(rule) {
|
||||
shortcut.force
|
||||
);
|
||||
});
|
||||
} else {
|
||||
populateDefaultSiteShortcuts(container);
|
||||
}
|
||||
applySiteRuleOverrideState(ruleEl, "override-shortcuts", "site-shortcuts-container");
|
||||
|
||||
document.getElementById("siteRulesContainer").appendChild(ruleEl);
|
||||
}
|
||||
|
||||
function populateDefaultSiteShortcuts(container) {
|
||||
tcDefaults.keyBindings.forEach((binding) => {
|
||||
var bindings = [];
|
||||
document.querySelectorAll("#customs .shortcut-row").forEach((row) => {
|
||||
var action = row.dataset.action;
|
||||
if (!action) return;
|
||||
|
||||
var keyInput = row.querySelector(".customKey");
|
||||
var binding = normalizeStoredBinding(keyInput && keyInput.vscBinding);
|
||||
if (!binding) return;
|
||||
|
||||
var valueInput = row.querySelector(".customValue");
|
||||
bindings.push({
|
||||
action: action,
|
||||
code: binding.code,
|
||||
disabled: binding.disabled === true,
|
||||
value: customActionsNoValues.includes(action)
|
||||
? 0
|
||||
: Number(valueInput && valueInput.value),
|
||||
force: false
|
||||
});
|
||||
});
|
||||
|
||||
if (bindings.length === 0) {
|
||||
bindings = tcDefaults.keyBindings.slice();
|
||||
}
|
||||
|
||||
bindings.forEach((binding) => {
|
||||
addSiteRuleShortcut(container, binding.action, binding, binding.value, false);
|
||||
});
|
||||
}
|
||||
@@ -1626,29 +1702,26 @@ document.addEventListener("DOMContentLoaded", function () {
|
||||
eventCaller(event, "customKey", recordKeyPress)
|
||||
);
|
||||
document.addEventListener("click", (event) => {
|
||||
if (event.target.classList.contains("removeParent")) {
|
||||
event.target.parentNode.remove();
|
||||
var target = event.target;
|
||||
var targetEl = target && target.closest ? target : target.parentElement;
|
||||
if (!targetEl) return;
|
||||
|
||||
var removeParentButton = targetEl.closest(".removeParent");
|
||||
if (removeParentButton) {
|
||||
removeParentButton.parentNode.remove();
|
||||
refreshAddShortcutSelector();
|
||||
return;
|
||||
}
|
||||
if (event.target.classList.contains("remove-site-rule")) {
|
||||
event.target.closest(".site-rule").remove();
|
||||
var removeSiteRuleButton = targetEl.closest(".remove-site-rule");
|
||||
if (removeSiteRuleButton) {
|
||||
removeSiteRuleButton.closest(".site-rule").remove();
|
||||
return;
|
||||
}
|
||||
if (event.target.classList.contains("toggle-site-rule")) {
|
||||
var ruleEl = event.target.closest(".site-rule");
|
||||
var ruleBody = ruleEl.querySelector(".site-rule-body");
|
||||
var toggleButton = targetEl.closest(".toggle-site-rule");
|
||||
if (toggleButton) {
|
||||
var ruleEl = toggleButton.closest(".site-rule");
|
||||
var isCollapsed = ruleEl.classList.contains("collapsed");
|
||||
|
||||
if (isCollapsed) {
|
||||
ruleBody.style.display = "block";
|
||||
ruleEl.classList.remove("collapsed");
|
||||
event.target.textContent = "\u2212";
|
||||
} else {
|
||||
ruleBody.style.display = "none";
|
||||
ruleEl.classList.add("collapsed");
|
||||
event.target.textContent = "\u002b";
|
||||
}
|
||||
setSiteRuleExpandedState(ruleEl, isCollapsed);
|
||||
return;
|
||||
}
|
||||
});
|
||||
@@ -1670,7 +1743,10 @@ document.addEventListener("DOMContentLoaded", function () {
|
||||
"override-autohide": "site-autohide-container",
|
||||
"override-playback": "site-playback-container",
|
||||
"override-opacity": "site-opacity-container",
|
||||
"override-subtitleNudge": "site-subtitleNudge-container"
|
||||
"override-subtitleNudge": "site-subtitleNudge-container",
|
||||
"override-controlbar": "site-controlbar-container",
|
||||
"override-popup-controlbar": "site-popup-controlbar-container",
|
||||
"override-shortcuts": "site-shortcuts-container"
|
||||
};
|
||||
for (var ocb in siteOverrideContainers) {
|
||||
if (event.target.classList.contains(ocb)) {
|
||||
@@ -1679,78 +1755,10 @@ document.addEventListener("DOMContentLoaded", function () {
|
||||
"." + siteOverrideContainers[ocb]
|
||||
);
|
||||
if (targetBox) {
|
||||
targetBox.style.display = event.target.checked ? "block" : "none";
|
||||
setSiteOverrideContainerState(targetBox, event.target.checked);
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// Handle site rule override checkboxes
|
||||
if (event.target.classList.contains("override-shortcuts")) {
|
||||
var container = event.target
|
||||
.closest(".site-rule-shortcuts")
|
||||
.querySelector(".site-shortcuts-container");
|
||||
if (event.target.checked) {
|
||||
container.style.display = "block";
|
||||
if (container.children.length === 0) {
|
||||
populateDefaultSiteShortcuts(container);
|
||||
}
|
||||
} else {
|
||||
container.style.display = "none";
|
||||
}
|
||||
}
|
||||
|
||||
if (event.target.classList.contains("override-controlbar")) {
|
||||
var cbContainer = event.target
|
||||
.closest(".site-rule-controlbar")
|
||||
.querySelector(".site-controlbar-container");
|
||||
if (event.target.checked) {
|
||||
cbContainer.style.display = "block";
|
||||
var activeZone = cbContainer.querySelector(".site-cb-active");
|
||||
var availableZone = cbContainer.querySelector(".site-cb-available");
|
||||
if (
|
||||
activeZone &&
|
||||
availableZone &&
|
||||
activeZone.children.length === 0 &&
|
||||
availableZone.children.length === 0
|
||||
) {
|
||||
populateControlBarZones(
|
||||
activeZone,
|
||||
availableZone,
|
||||
getControlBarOrder()
|
||||
);
|
||||
}
|
||||
} else {
|
||||
cbContainer.style.display = "none";
|
||||
}
|
||||
}
|
||||
|
||||
if (event.target.classList.contains("override-popup-controlbar")) {
|
||||
var popupCbContainer = event.target
|
||||
.closest(".site-rule-controlbar")
|
||||
.querySelector(".site-popup-controlbar-container");
|
||||
if (event.target.checked) {
|
||||
popupCbContainer.style.display = "block";
|
||||
var popupActiveZone = popupCbContainer.querySelector(".site-popup-cb-active");
|
||||
var popupAvailableZone = popupCbContainer.querySelector(".site-popup-cb-available");
|
||||
if (
|
||||
popupActiveZone &&
|
||||
popupAvailableZone &&
|
||||
popupActiveZone.children.length === 0 &&
|
||||
popupAvailableZone.children.length === 0
|
||||
) {
|
||||
populateControlBarZones(
|
||||
popupActiveZone,
|
||||
popupAvailableZone,
|
||||
getPopupControlBarOrder(),
|
||||
function (id) {
|
||||
return !popupExcludedButtonIds.has(id);
|
||||
}
|
||||
);
|
||||
}
|
||||
} else {
|
||||
popupCbContainer.style.display = "none";
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
@@ -73,6 +73,57 @@ describe("options page", () => {
|
||||
expect(chrome.storage.sync.set).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it("shows a more-menu trigger for collapsed site rules and a collapse trigger when open", async () => {
|
||||
await setupOptions({ sync: { siteRules: [] } });
|
||||
|
||||
globalThis.createSiteRule({ pattern: "youtube.com" });
|
||||
|
||||
const rule = document.getElementById("siteRulesContainer").lastElementChild;
|
||||
const toggle = rule.querySelector(".toggle-site-rule");
|
||||
const body = rule.querySelector(".site-rule-body");
|
||||
|
||||
expect(rule.classList.contains("collapsed")).toBe(true);
|
||||
expect(body.style.display).toBe("none");
|
||||
expect(toggle.getAttribute("aria-expanded")).toBe("false");
|
||||
expect(toggle.getAttribute("aria-label")).toBe("Expand site rule");
|
||||
expect(toggle.querySelector("svg")).not.toBeNull();
|
||||
|
||||
globalThis.setSiteRuleExpandedState(rule, true);
|
||||
|
||||
expect(rule.classList.contains("collapsed")).toBe(false);
|
||||
expect(body.style.display).toBe("block");
|
||||
expect(toggle.getAttribute("aria-expanded")).toBe("true");
|
||||
expect(toggle.getAttribute("aria-label")).toBe("Collapse site rule");
|
||||
});
|
||||
|
||||
it("keeps site override settings visible but disabled until enabled", async () => {
|
||||
await setupOptions({ sync: { siteRules: [] } });
|
||||
|
||||
globalThis.createSiteRule({ pattern: "youtube.com" });
|
||||
|
||||
const rule = document.getElementById("siteRulesContainer").lastElementChild;
|
||||
const playbackOverride = rule.querySelector(".override-playback");
|
||||
const playbackContainer = rule.querySelector(".site-playback-container");
|
||||
const rememberSpeed = rule.querySelector(".site-rememberSpeed");
|
||||
|
||||
expect(playbackContainer.classList.contains("site-override-disabled")).toBe(
|
||||
true
|
||||
);
|
||||
expect(rememberSpeed.disabled).toBe(true);
|
||||
|
||||
playbackOverride.checked = true;
|
||||
playbackOverride.dispatchEvent(
|
||||
new Event("change", {
|
||||
bubbles: true
|
||||
})
|
||||
);
|
||||
|
||||
expect(playbackContainer.classList.contains("site-override-disabled")).toBe(
|
||||
false
|
||||
);
|
||||
expect(rememberSpeed.disabled).toBe(false);
|
||||
});
|
||||
|
||||
it("saves normalized settings and sanitized popup/site-rule controls", async () => {
|
||||
const chrome = await setupOptions();
|
||||
|
||||
|
||||
@@ -16,6 +16,9 @@ var vscUiIconPaths = {
|
||||
slower: '<line x1="5" y1="12" x2="19" y2="12"/>',
|
||||
faster:
|
||||
'<line x1="12" y1="5" x2="12" y2="19"/><line x1="5" y1="12" x2="19" y2="12"/>',
|
||||
moreHorizontal:
|
||||
'<circle cx="6" cy="12" r="1.5"/><circle cx="12" cy="12" r="1.5"/><circle cx="18" cy="12" r="1.5"/>',
|
||||
chevronUp: '<path d="m18 15-6-6-6 6"/>',
|
||||
display:
|
||||
'<line x1="18" y1="6" x2="6" y2="18"/><line x1="6" y1="6" x2="18" y2="18"/>',
|
||||
fast: '<polygon points="12 2 15.09 8.26 22 9.27 17 14.14 18.18 21.02 12 17.77 5.82 21.02 7 14.14 2 9.27 8.91 8.26 12 2"/>',
|
||||
|
||||
Reference in New Issue
Block a user