openvibers/openvibe.live Commits
Channel jump links work: no backslash in their onclick (#680)
Changes
@@@ -368,15 +368,15 @@<div class="channel-below-fold"><div class="container"><nav class="ch-tabs ch-jump" id="ch-tabs" aria-label="Jump to a section">-- <button class="ch-tab" id="ch-tab-btn-about" data-tab="about" onclick=\"switchChannelTab('about', this, true)\" style="display:none"><i class="fa-solid fa-circle-info"></i> About<span class="ch-tab-edit" id="ch-tab-about-edit" role="button" tabindex="0" title="Edit About" onclick="event.stopPropagation(); editAboutFromTab();" style="display:none"><i class="fa-solid fa-pen"></i></span></button>-- <button class="ch-tab active" id="ch-tab-btn-videos" data-tab="videos" onclick=\"switchChannelTab('videos', this, true)\"><i class="fa-solid fa-video"></i> Videos<span class="ch-tab-badge" id="ch-tab-badge-videos" hidden></span></button>-- <button class="ch-tab" id="ch-tab-btn-agents" data-tab="agents" onclick=\"switchChannelTab('agents', this, true)\" style="display:none"><i class="fa-solid fa-robot"></i> Agents<span class="ch-tab-badge" id="ch-tab-badge-agents" hidden></span></button>-- <button class="ch-tab" id="ch-tab-btn-clips" data-tab="clips" onclick=\"switchChannelTab('clips', this, true)\"><i class="fa-solid fa-scissors"></i> Clips<span class="ch-tab-badge" id="ch-tab-badge-clips" hidden></span></button>-- <button class="ch-tab" id="ch-tab-btn-clips-taken" data-tab="clips-taken" onclick=\"switchChannelTab('clips-taken', this, true)\"><i class="fa-solid fa-film"></i> Clips Taken<span class="ch-tab-badge" id="ch-tab-badge-clips-taken" hidden></span></button>-- <button class="ch-tab" id="ch-tab-btn-pastes" data-tab="pastes" onclick=\"switchChannelTab('pastes', this, true)\"><i class="fa-solid fa-paste"></i> Pastes<span class="ch-tab-badge" id="ch-tab-badge-pastes" hidden></span></button>-- <button class="ch-tab" id="ch-tab-btn-ai-timeline" data-tab="ai-timeline" onclick=\"switchChannelTab('ai-timeline', this, true)\"><i class="fa-solid fa-brain"></i> AI Timeline<span class="ch-tab-badge" id="ch-tab-badge-ai-timeline" hidden></span></button>-- <button class="ch-tab" id="ch-tab-btn-media" data-tab="media" onclick=\"switchChannelTab('media', this, true)\" style="display:none"><i class="fa-solid fa-music"></i> Media Request</button>-- <button class="ch-tab" data-tab="analytics" onclick=\"switchChannelTab('analytics', this, true)\"><i class="fa-solid fa-chart-line"></i> Analytics</button>++ <button class="ch-tab" id="ch-tab-btn-about" data-tab="about" onclick="switchChannelTab('about', this, true)" style="display:none"><i class="fa-solid fa-circle-info"></i> About<span class="ch-tab-edit" id="ch-tab-about-edit" role="button" tabindex="0" title="Edit About" onclick="event.stopPropagation(); editAboutFromTab();" style="display:none"><i class="fa-solid fa-pen"></i></span></button>++ <button class="ch-tab active" id="ch-tab-btn-videos" data-tab="videos" onclick="switchChannelTab('videos', this, true)"><i class="fa-solid fa-video"></i> Videos<span class="ch-tab-badge" id="ch-tab-badge-videos" hidden></span></button>++ <button class="ch-tab" id="ch-tab-btn-agents" data-tab="agents" onclick="switchChannelTab('agents', this, true)" style="display:none"><i class="fa-solid fa-robot"></i> Agents<span class="ch-tab-badge" id="ch-tab-badge-agents" hidden></span></button>++ <button class="ch-tab" id="ch-tab-btn-clips" data-tab="clips" onclick="switchChannelTab('clips', this, true)"><i class="fa-solid fa-scissors"></i> Clips<span class="ch-tab-badge" id="ch-tab-badge-clips" hidden></span></button>++ <button class="ch-tab" id="ch-tab-btn-clips-taken" data-tab="clips-taken" onclick="switchChannelTab('clips-taken', this, true)"><i class="fa-solid fa-film"></i> Clips Taken<span class="ch-tab-badge" id="ch-tab-badge-clips-taken" hidden></span></button>++ <button class="ch-tab" id="ch-tab-btn-pastes" data-tab="pastes" onclick="switchChannelTab('pastes', this, true)"><i class="fa-solid fa-paste"></i> Pastes<span class="ch-tab-badge" id="ch-tab-badge-pastes" hidden></span></button>++ <button class="ch-tab" id="ch-tab-btn-ai-timeline" data-tab="ai-timeline" onclick="switchChannelTab('ai-timeline', this, true)"><i class="fa-solid fa-brain"></i> AI Timeline<span class="ch-tab-badge" id="ch-tab-badge-ai-timeline" hidden></span></button>++ <button class="ch-tab" id="ch-tab-btn-media" data-tab="media" onclick="switchChannelTab('media', this, true)" style="display:none"><i class="fa-solid fa-music"></i> Media Request</button>++ <button class="ch-tab" data-tab="analytics" onclick="switchChannelTab('analytics', this, true)"><i class="fa-solid fa-chart-line"></i> Analytics</button></nav><!-- Agents (Agent Streams S2): this channel's AI agent streams, live and past. -->@@@ -33,4 +33,9 @@ assert.match(js, /panel\.hidden = b\.style\.display === 'none';/, 'a section hidassert.match(js, /function _watchChannelSections\(\)/);assert.match(js, /new IntersectionObserver\([\s\S]{0,200}_ensureChannelSection\(e\.target\.id\.replace\('ch-panel-', ''\), true\)/, 'a section loads as it nears the screen');assert.match(js, /if \(passing && \(tab === 'analytics' \|\| tab === 'ai-timeline'\)\) return;/, 'the folds load when opened, not on the way past');--console.log('channel sections: every section on the page, a jump bar, two counted folds');++// Every inline handler in the fragment parses (11-07: a stray backslash, onclick=\"...\", broke every jump link).++assert.ok(!/onclick=\\"/.test(html), 'no backslash-escaped onclick attributes');++const handlers = [...html.matchAll(/\son(click|change|input|submit)="([^"]*)"/g)].map((m) => m[2]);++assert.ok(handlers.length > 9, 'the handlers were found');++handlers.forEach((code) => assert.doesNotThrow(() => new Function('event', code), `the handler parses: ${code.slice(0, 80)}`));++console.log('channel sections: every section on the page, a jump bar, two counted folds, every handler parses');
@@ -368,15 +368,15 @@
@@ -368,15 +368,15 @@
<div class="channel-below-fold">
<div class="channel-below-fold">
<div class="container">
<div class="container">
<nav class="ch-tabs ch-jump" id="ch-tabs" aria-label="Jump to a section">
<nav class="ch-tabs ch-jump" id="ch-tabs" aria-label="Jump to a section">
- <button class="ch-tab" id="ch-tab-btn-about" data-tab="about" onclick=\"switchChannelTab('about', this, true)\" style="display:none"><i class="fa-solid fa-circle-info"></i> About<span class="ch-tab-edit" id="ch-tab-about-edit" role="button" tabindex="0" title="Edit About" onclick="event.stopPropagation(); editAboutFromTab();" style="display:none"><i class="fa-solid fa-pen"></i></span></button>
- <button class="ch-tab active" id="ch-tab-btn-videos" data-tab="videos" onclick=\"switchChannelTab('videos', this, true)\"><i class="fa-solid fa-video"></i> Videos<span class="ch-tab-badge" id="ch-tab-badge-videos" hidden></span></button>
- <button class="ch-tab" id="ch-tab-btn-agents" data-tab="agents" onclick=\"switchChannelTab('agents', this, true)\" style="display:none"><i class="fa-solid fa-robot"></i> Agents<span class="ch-tab-badge" id="ch-tab-badge-agents" hidden></span></button>
- <button class="ch-tab" id="ch-tab-btn-clips" data-tab="clips" onclick=\"switchChannelTab('clips', this, true)\"><i class="fa-solid fa-scissors"></i> Clips<span class="ch-tab-badge" id="ch-tab-badge-clips" hidden></span></button>
- <button class="ch-tab" id="ch-tab-btn-clips-taken" data-tab="clips-taken" onclick=\"switchChannelTab('clips-taken', this, true)\"><i class="fa-solid fa-film"></i> Clips Taken<span class="ch-tab-badge" id="ch-tab-badge-clips-taken" hidden></span></button>
- <button class="ch-tab" id="ch-tab-btn-pastes" data-tab="pastes" onclick=\"switchChannelTab('pastes', this, true)\"><i class="fa-solid fa-paste"></i> Pastes<span class="ch-tab-badge" id="ch-tab-badge-pastes" hidden></span></button>
- <button class="ch-tab" id="ch-tab-btn-ai-timeline" data-tab="ai-timeline" onclick=\"switchChannelTab('ai-timeline', this, true)\"><i class="fa-solid fa-brain"></i> AI Timeline<span class="ch-tab-badge" id="ch-tab-badge-ai-timeline" hidden></span></button>
- <button class="ch-tab" id="ch-tab-btn-media" data-tab="media" onclick=\"switchChannelTab('media', this, true)\" style="display:none"><i class="fa-solid fa-music"></i> Media Request</button>
- <button class="ch-tab" data-tab="analytics" onclick=\"switchChannelTab('analytics', this, true)\"><i class="fa-solid fa-chart-line"></i> Analytics</button>
+ <button class="ch-tab" id="ch-tab-btn-about" data-tab="about" onclick="switchChannelTab('about', this, true)" style="display:none"><i class="fa-solid fa-circle-info"></i> About<span class="ch-tab-edit" id="ch-tab-about-edit" role="button" tabindex="0" title="Edit About" onclick="event.stopPropagation(); editAboutFromTab();" style="display:none"><i class="fa-solid fa-pen"></i></span></button>
+ <button class="ch-tab active" id="ch-tab-btn-videos" data-tab="videos" onclick="switchChannelTab('videos', this, true)"><i class="fa-solid fa-video"></i> Videos<span class="ch-tab-badge" id="ch-tab-badge-videos" hidden></span></button>
+ <button class="ch-tab" id="ch-tab-btn-agents" data-tab="agents" onclick="switchChannelTab('agents', this, true)" style="display:none"><i class="fa-solid fa-robot"></i> Agents<span class="ch-tab-badge" id="ch-tab-badge-agents" hidden></span></button>
+ <button class="ch-tab" id="ch-tab-btn-clips" data-tab="clips" onclick="switchChannelTab('clips', this, true)"><i class="fa-solid fa-scissors"></i> Clips<span class="ch-tab-badge" id="ch-tab-badge-clips" hidden></span></button>
+ <button class="ch-tab" id="ch-tab-btn-clips-taken" data-tab="clips-taken" onclick="switchChannelTab('clips-taken', this, true)"><i class="fa-solid fa-film"></i> Clips Taken<span class="ch-tab-badge" id="ch-tab-badge-clips-taken" hidden></span></button>
+ <button class="ch-tab" id="ch-tab-btn-pastes" data-tab="pastes" onclick="switchChannelTab('pastes', this, true)"><i class="fa-solid fa-paste"></i> Pastes<span class="ch-tab-badge" id="ch-tab-badge-pastes" hidden></span></button>
+ <button class="ch-tab" id="ch-tab-btn-ai-timeline" data-tab="ai-timeline" onclick="switchChannelTab('ai-timeline', this, true)"><i class="fa-solid fa-brain"></i> AI Timeline<span class="ch-tab-badge" id="ch-tab-badge-ai-timeline" hidden></span></button>
+ <button class="ch-tab" id="ch-tab-btn-media" data-tab="media" onclick="switchChannelTab('media', this, true)" style="display:none"><i class="fa-solid fa-music"></i> Media Request</button>
+ <button class="ch-tab" data-tab="analytics" onclick="switchChannelTab('analytics', this, true)"><i class="fa-solid fa-chart-line"></i> Analytics</button>
</nav>
</nav>
<!-- Agents (Agent Streams S2): this channel's AI agent streams, live and past. -->
<!-- Agents (Agent Streams S2): this channel's AI agent streams, live and past. -->
@@ -33,4 +33,9 @@ assert.match(js, /panel\.hidden = b\.style\.display === 'none';/, 'a section hid
@@ -33,4 +33,9 @@ assert.match(js, /panel\.hidden = b\.style\.display === 'none';/, 'a section hid
assert.match(js, /function _watchChannelSections\(\)/);
assert.match(js, /function _watchChannelSections\(\)/);
assert.match(js, /new IntersectionObserver\([\s\S]{0,200}_ensureChannelSection\(e\.target\.id\.replace\('ch-panel-', ''\), true\)/, 'a section loads as it nears the screen');
assert.match(js, /new IntersectionObserver\([\s\S]{0,200}_ensureChannelSection\(e\.target\.id\.replace\('ch-panel-', ''\), true\)/, 'a section loads as it nears the screen');
assert.match(js, /if \(passing && \(tab === 'analytics' \|\| tab === 'ai-timeline'\)\) return;/, 'the folds load when opened, not on the way past');
assert.match(js, /if \(passing && \(tab === 'analytics' \|\| tab === 'ai-timeline'\)\) return;/, 'the folds load when opened, not on the way past');
-console.log('channel sections: every section on the page, a jump bar, two counted folds');
+// Every inline handler in the fragment parses (11-07: a stray backslash, onclick=\"...\", broke every jump link).
+assert.ok(!/onclick=\\"/.test(html), 'no backslash-escaped onclick attributes');
+const handlers = [...html.matchAll(/\son(click|change|input|submit)="([^"]*)"/g)].map((m) => m[2]);
+assert.ok(handlers.length > 9, 'the handlers were found');
+handlers.forEach((code) => assert.doesNotThrow(() => new Function('event', code), `the handler parses: ${code.slice(0, 80)}`));
+console.log('channel sections: every section on the page, a jump bar, two counted folds, every handler parses');