33import { announce } from '../utils/accessibility.js' ;
44
55let answerCallback = null ;
6+ let nextCallback = null ;
67let currentQuestion = null ;
78let uiElements = { } ;
89
@@ -110,6 +111,50 @@ export function init(container) {
110111 .quiz-meta a:hover {
111112 text-shadow: 0 0 6px var(--color-glow-secondary);
112113 }
114+ .quiz-actions {
115+ display: flex;
116+ gap: 0.5rem;
117+ margin-top: 0.75rem;
118+ flex-wrap: wrap;
119+ }
120+ .quiz-next-btn {
121+ padding: 0.5rem 1.25rem;
122+ border-radius: 8px;
123+ border: 1px solid var(--color-primary);
124+ background: var(--color-primary);
125+ color: #ffffff;
126+ font-family: var(--font-heading);
127+ font-size: 0.82rem;
128+ font-weight: 600;
129+ cursor: pointer;
130+ transition: all 0.2s ease;
131+ min-height: 36px;
132+ }
133+ .quiz-next-btn:hover {
134+ box-shadow: 0 0 12px var(--color-glow-primary);
135+ transform: translateY(-1px);
136+ }
137+ .quiz-learn-btn {
138+ padding: 0.4rem 0.75rem;
139+ border-radius: 6px;
140+ border: 1px solid var(--color-border);
141+ background: var(--color-surface-raised);
142+ color: var(--color-text-muted);
143+ font-family: var(--font-body);
144+ font-size: 0.75rem;
145+ cursor: pointer;
146+ transition: all 0.2s ease;
147+ text-decoration: none;
148+ display: inline-flex;
149+ align-items: center;
150+ gap: 0.35rem;
151+ min-height: 32px;
152+ }
153+ .quiz-learn-btn:hover {
154+ border-color: var(--color-secondary);
155+ color: var(--color-secondary);
156+ box-shadow: 0 0 8px var(--color-glow-secondary);
157+ }
113158 .katex { font-size: 1.05em; }
114159 ` ;
115160 document . head . appendChild ( style ) ;
@@ -128,6 +173,11 @@ export function init(container) {
128173 <button class="quiz-option" data-key="D" aria-label="Option D"></button>
129174 </div>
130175 <div class="quiz-feedback" aria-live="assertive"></div>
176+ <div class="quiz-actions" hidden>
177+ <button class="quiz-next-btn" aria-label="Next question">Next <i class="fa-solid fa-arrow-right" style="margin-left:0.3rem;font-size:0.75rem"></i></button>
178+ <a class="quiz-learn-btn" target="_blank" rel="noopener" data-learn="wikipedia" hidden><i class="fa-brands fa-wikipedia-w"></i> Wikipedia</a>
179+ <a class="quiz-learn-btn" target="_blank" rel="noopener" data-learn="khan" hidden><i class="fa-solid fa-graduation-cap"></i> Khan Academy</a>
180+ </div>
131181 <div class="quiz-meta"></div>
132182 </div>
133183 ` ;
@@ -138,6 +188,10 @@ export function init(container) {
138188 instruction : container . querySelector ( '.quiz-instruction' ) ,
139189 options : container . querySelectorAll ( '.quiz-option' ) ,
140190 feedback : container . querySelector ( '.quiz-feedback' ) ,
191+ actions : container . querySelector ( '.quiz-actions' ) ,
192+ nextBtn : container . querySelector ( '.quiz-next-btn' ) ,
193+ wikiBtn : container . querySelector ( '[data-learn="wikipedia"]' ) ,
194+ khanBtn : container . querySelector ( '[data-learn="khan"]' ) ,
141195 meta : container . querySelector ( '.quiz-meta' )
142196 } ;
143197
@@ -146,6 +200,12 @@ export function init(container) {
146200 btn . addEventListener ( 'click' , ( ) => handleOptionClick ( btn . dataset . key ) ) ;
147201 } ) ;
148202
203+ if ( uiElements . nextBtn ) {
204+ uiElements . nextBtn . addEventListener ( 'click' , ( ) => {
205+ if ( nextCallback ) nextCallback ( ) ;
206+ } ) ;
207+ }
208+
149209 document . addEventListener ( 'keydown' , handleKeyDown ) ;
150210
151211 const resizeHandle = container . querySelector ( '.resize-handle' ) ;
@@ -174,7 +234,15 @@ export function init(container) {
174234
175235function handleKeyDown ( e ) {
176236 if ( ! currentQuestion || ! uiElements . options ) return ;
177- if ( uiElements . options [ 0 ] . disabled ) return ;
237+
238+ // If options are disabled (already answered), Enter/N/Space advances to next
239+ if ( uiElements . options [ 0 ] . disabled ) {
240+ if ( e . key === 'Enter' || e . key === 'n' || e . key === 'N' || e . key === ' ' ) {
241+ e . preventDefault ( ) ;
242+ if ( nextCallback ) nextCallback ( ) ;
243+ }
244+ return ;
245+ }
178246
179247 const key = e . key . toUpperCase ( ) ;
180248 if ( [ '1' , 'A' ] . includes ( key ) ) handleOptionClick ( 'A' ) ;
@@ -218,7 +286,12 @@ export function showQuestion(question) {
218286 }
219287
220288 if ( uiElements . meta ) {
221- uiElements . meta . innerHTML = '' ;
289+ uiElements . meta . textContent = '' ;
290+ }
291+
292+ // Hide Next/Learn more buttons until answer is given
293+ if ( uiElements . actions ) {
294+ uiElements . actions . hidden = true ;
222295 }
223296}
224297
@@ -256,20 +329,56 @@ function handleOptionClick(selectedKey) {
256329 if ( uiElements . meta && currentQuestion . source_article ) {
257330 const article = currentQuestion . source_article ;
258331 const url = `https://en.wikipedia.org/wiki/${ encodeURIComponent ( article ) } ` ;
259- uiElements . meta . innerHTML = `Source: <a href="${ url } " target="_blank">${ article } </a>` ;
332+ uiElements . meta . textContent = '' ;
333+ const sourceLabel = document . createTextNode ( 'Source: ' ) ;
334+ const sourceLink = document . createElement ( 'a' ) ;
335+ sourceLink . href = url ;
336+ sourceLink . target = '_blank' ;
337+ sourceLink . textContent = article ;
338+ uiElements . meta . appendChild ( sourceLabel ) ;
339+ uiElements . meta . appendChild ( sourceLink ) ;
260340 }
261341
342+ // Show Next button and Learn more links instead of auto-advancing
343+ if ( uiElements . actions ) {
344+ uiElements . actions . hidden = false ;
345+
346+ // Show Wikipedia link if we have a source article
347+ if ( uiElements . wikiBtn && currentQuestion . source_article ) {
348+ const wikiUrl = `https://en.wikipedia.org/wiki/${ encodeURIComponent ( currentQuestion . source_article ) } ` ;
349+ uiElements . wikiBtn . href = wikiUrl ;
350+ uiElements . wikiBtn . hidden = false ;
351+ } else if ( uiElements . wikiBtn ) {
352+ uiElements . wikiBtn . hidden = true ;
353+ }
354+
355+ // Show Khan Academy search link based on question concepts or article
356+ if ( uiElements . khanBtn ) {
357+ const searchTerm = currentQuestion . source_article || '' ;
358+ if ( searchTerm ) {
359+ uiElements . khanBtn . href = `https://www.khanacademy.org/search?referer=%2F&page_search_query=${ encodeURIComponent ( searchTerm ) } ` ;
360+ uiElements . khanBtn . hidden = false ;
361+ } else {
362+ uiElements . khanBtn . hidden = true ;
363+ }
364+ }
365+ }
366+
367+ // Fire the answer callback immediately (records the response and updates estimator)
368+ // but do NOT auto-advance to next question — user clicks "Next" when ready
262369 if ( answerCallback ) {
263- setTimeout ( ( ) => {
264- answerCallback ( selectedKey , currentQuestion ) ;
265- } , 800 ) ;
370+ answerCallback ( selectedKey , currentQuestion ) ;
266371 }
267372}
268373
269374export function onAnswer ( callback ) {
270375 answerCallback = callback ;
271376}
272377
378+ export function onNext ( callback ) {
379+ nextCallback = callback ;
380+ }
381+
273382/**
274383 * Replaces $...$ with KaTeX rendered HTML.
275384 * Heuristic: if content between $ signs contains only numbers/punctuation, treat as currency.
0 commit comments