Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 3 additions & 2 deletions static/css/base.css
Original file line number Diff line number Diff line change
Expand Up @@ -97,7 +97,8 @@ body { font-family: Arial, sans-serif; margin:0; }

/* Submenu (fly-out for Themes) */
.submenu { position: relative; }
.submenu > a { display: flex; justify-content: space-between; align-items: center; }
.submenu > a { display: flex; justify-content: space-between; align-items: center; padding-right: 28px !important; position: relative; }
.submenu > a::after { content: "▸"; position: absolute; right: 10px; top: 50%; transform: translateY(-50%); }
.submenu-content {
display: none;
position: absolute;
Expand All @@ -111,7 +112,7 @@ body { font-family: Arial, sans-serif; margin:0; }
}
.submenu-content li a { padding: 10px 14px; display: block; color: #eee; text-decoration: none; }
.submenu-content li a:hover { background-color: #0af; color: #fff; }
.submenu:hover .submenu-content { display: block; }
.submenu:hover > .submenu-content { display: block; }

/* Remove default list bullets and padding for all dropdowns & submenus */
.dropdown-content,
Expand Down
11 changes: 10 additions & 1 deletion static/js/auto-scroll.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
function setPref(v) { localStorage.setItem(PREF_KEY, v ? 'true' : 'false'); }

const SELECTOR_PRIORITY = ['#guideOuter', '.guide-outer', '.grid-col'];
const scrollSpeed = 1.2; // px per frame (visual)
let scrollSpeed = 1.2; // px per frame (visual)
const idleDelay = 15000; // ms initial inactivity/start delay (15s)
const waitForContentMs = 5000; // wait up to 5s for rows to be populated before cloning
const contentSampleCount = 3; // sample when checking readiness
Expand Down Expand Up @@ -436,6 +436,15 @@
window.__autoScroll.clearEnd = function(){ endReached = false; endReachedAt = 0; };
window.__autoScroll.recompute = function(){ scroller = null; };
window.__autoScroll.cloneNow = function(){ if (!scroller) scroller = findScroller(); return cloneOnce(scroller); };
window.__autoScroll.setSpeed = function(speed) {
if (typeof speed === 'number' && speed > 0) {
scrollSpeed = speed;
log('setSpeed ->', scrollSpeed);
} else {
log('setSpeed: invalid speed', speed);
}
};
window.__autoScroll.getSpeed = function(){ return scrollSpeed; };
window.__autoScroll.status = function(){ return { isScrolling, pref: prefEnabled(), loopMode, scrollerInfo: scroller ? { id: scroller.id, scrollTop: scroller.scrollTop, scrollHeight: scroller.scrollHeight, clientHeight: scroller.clientHeight, cloned: !!scroller.dataset.__autoScrollCloned, prependedHeight: scroller.dataset.__autoScrollPrependedHeight } : null, rafId: !!rafId, watchdog: !!watchdogInterval }; };
window.__autoScroll.debug = function(){ return { lastActivity, idleDelay, scrollSpeed, isScrolling, pref: prefEnabled(), loopMode, endReached, endReachedAt, autoRestart, autoRestartDelayMs, scrollerInfo: scroller ? { id: scroller.id, scrollTop: scroller.scrollTop, scrollHeight: scroller.scrollHeight, clientHeight: scroller.clientHeight, cloned: !!scroller.dataset.__autoScrollCloned, prependedHeight: scroller.dataset.__autoScrollPrependedHeight } : null, rafId, lastFrameTime, watchdogInterval }; };

Expand Down
46 changes: 44 additions & 2 deletions templates/_header.html
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,20 @@
<a href="{{ url_for('view_logs') }}">Logs</a>
<li><a href="{{ url_for('about') }}">About</a></li>
{% endif %}
<a href="#" id="toggleAutoScroll">Toggle Auto-Scroll</a>
<li class="submenu">
<a href="#">Auto-Scroll</a>
<ul class="submenu-content">
<li><a href="#" id="toggleAutoScroll">Enable/Disable Auto-Scroll</a></li>
<li class="submenu">
<a href="#">Scroll Speed</a>
<ul class="submenu-content">
<li><a href="#" data-scroll-speed="slow">Slow</a></li>
<li><a href="#" data-scroll-speed="medium">Medium</a></li>
<li><a href="#" data-scroll-speed="fast">Fast</a></li>
</ul>
</li>
</ul>
</li>
<a href="{{ url_for('change_password') }}">Change Password</a>
<li class="submenu">
<a href="#">Themes</a>
Expand Down Expand Up @@ -109,7 +122,36 @@
<li role="none"><a role="menuitem" href="{{ url_for('view_logs') }}">Logs</a></li>
<li role="none"><a role="menuitem" href="{{ url_for('about') }}">About</a></li>
{% endif %}
<li role="none"><a role="menuitem" href="#" id="mobileToggleAutoScroll">Toggle Auto-Scroll</a></li>
<li class="mobile-submenu" role="none">
<button
class="mobile-submenu-toggle"
aria-expanded="false"
aria-controls="mobileAutoScrollList"
type="button">
Auto-Scroll
<span class="mobile-submenu-caret" aria-hidden="true">▸</span>
</button>

<ul id="mobileAutoScrollList" class="mobile-submenu-list" role="menu" aria-hidden="true">
<li role="none"><a role="menuitem" href="#" id="mobileToggleAutoScroll">Enable/Disable Auto-Scroll</a></li>
<li class="mobile-submenu" role="none">
<button
class="mobile-submenu-toggle"
aria-expanded="false"
aria-controls="mobileScrollSpeedList"
type="button">
Scroll Speed
<span class="mobile-submenu-caret" aria-hidden="true">▸</span>
</button>

<ul id="mobileScrollSpeedList" class="mobile-submenu-list" role="menu" aria-hidden="true">
<li role="none"><a role="menuitem" href="#" data-scroll-speed="slow">Slow</a></li>
<li role="none"><a role="menuitem" href="#" data-scroll-speed="medium">Medium</a></li>
<li role="none"><a role="menuitem" href="#" data-scroll-speed="fast">Fast</a></li>
</ul>
</li>
</ul>
</li>
<li role="none"><a role="menuitem" href="{{ url_for('change_password') }}">Change Password</a></li>

<!-- Nested Themes submenu -->
Expand Down
67 changes: 67 additions & 0 deletions templates/guide.html
Original file line number Diff line number Diff line change
Expand Up @@ -547,6 +547,73 @@ <h3>Program Info</h3>
});
</script>

<script>
// Scroll Speed Selection Handler
document.addEventListener('DOMContentLoaded', () => {
const speedMapping = {
'slow': 0.6,
'medium': 1.2,
'fast': 2.4
};

// Apply saved speed on page load
function applySavedSpeed() {
try {
const savedSpeed = localStorage.getItem('autoScrollSpeed') || 'medium';
const speedValue = speedMapping[savedSpeed] || 1.2;
if (window.__autoScroll && typeof window.__autoScroll.setSpeed === 'function') {
window.__autoScroll.setSpeed(speedValue);
}
} catch (e) {
console.debug('Failed to retrieve or apply saved auto-scroll speed from localStorage', e);
}
}

// Handle speed selection clicks
function handleSpeedClick(e) {
e.preventDefault();
const speed = e.target.dataset.scrollSpeed;
if (speed && speedMapping[speed]) {
try {
localStorage.setItem('autoScrollSpeed', speed);
const speedValue = speedMapping[speed];
if (window.__autoScroll && typeof window.__autoScroll.setSpeed === 'function') {
window.__autoScroll.setSpeed(speedValue);
console.debug('Scroll speed set to', speed, '(' + speedValue + ' px/frame)');
}
} catch (e) {
console.error('Failed to save scroll speed preference', e);
}
}
}

// Attach event listeners to all speed selection links
document.querySelectorAll('[data-scroll-speed]').forEach(link => {
link.addEventListener('click', handleSpeedClick);
});

// Apply saved speed when auto-scroll initializes
applySavedSpeed();

// Re-apply speed when auto-scroll is loaded (in case it loads after DOMContentLoaded)
// Use a retry mechanism with maximum attempts to handle async script loading
let retryCount = 0;
const maxRetries = 5; // Max 5 attempts to find auto-scroll API
const retryInterval = 100; // 100ms between retries (total max wait: 500ms)

function retryApplySavedSpeed() {
if (window.__autoScroll && typeof window.__autoScroll.setSpeed === 'function') {
applySavedSpeed();
} else if (retryCount < maxRetries) {
retryCount++;
setTimeout(retryApplySavedSpeed, retryInterval);
}
}

setTimeout(retryApplySavedSpeed, retryInterval);
});
</script>

<!-- Mobile nav behavior (off-canvas toggle). Ensure this file contains the open/close and resize-dispatch code -->
<script src="{{ url_for('static', filename='js/mobile-nav.js') }}" defer></script>
<!-- Grid adapt script: computes scale on small screens so guide fits proportionally -->
Expand Down