PageSourceSearch

https://7esl.com/wp-content/cache/breeze-minification/js/breeze_ca…assets-tests-2bfa4ec760bc.js?ver=1790912477

js 7esl.com collected 2026-10-02 05:08:52 UTC 41,185 bytes, 77 lines download raw bytes

1(function(){'use strict';var cfg=window.eslTests||{};var restUrl=cfg.restUrl||'/wp-json/esl/v1/';var nonce=cfg.nonce||'';function apiFetch(path,opts){return fetch(restUrl+path,Object.assign({headers:Object.assign({'X-WP-Nonce':nonce},(opts||{}).headers||{})},opts||{})).then(function(r){return r.json()})}
2function formatTime(sec){var m=Math.floor(sec/60),s=sec%60;return(m<10?'0':'')+m+':'+(s<10?'0':'')+s}
3function el(tag,cls,html){var e=document.createElement(tag);if(cls)e.className=cls;if(html)e.innerHTML=html;return e}
4var CEFR_COLORS={A1:'#888780',A2:'#1D9E75',B1:'#378ADD',B2:'#7F77DD',C1:'#BA7517',C2:'#D85A30'};function initMounts(){document.querySelectorAll('.esl-test-mount').forEach(function(mount){var testId=mount.getAttribute('data-test-id');if(!testId)return;var loggedIn=mount.getAttribute('data-logged-in')==='1';loadTest(mount,parseInt(testId,10),loggedIn)})}
5function loadTest(mount,testId,loggedIn){apiFetch('tests/'+testId).then(function(test){if(test&&test.code){mount.innerHTML='<p style="color:#dc2626;padding:20px">Could not load test.</p>';return}
6renderPlayer(mount,test,loggedIn)}).catch(function(){mount.innerHTML='<p style="color:#dc2626;padding:20px">Network error — please refresh.</p>'})}
7function renderPlayer(mount,test,loggedIn){var questions=test.questions||[];var SAVE_KEY='esl_draft_'+test.id+'_'+(cfg.userId||'guest');var savedDraft={};try{var raw=localStorage.getItem(SAVE_KEY);if(raw)savedDraft=JSON.parse(raw);}catch(e){}
8var state={current:0,answers:savedDraft,startTime:Date.now(),timeLimit:parseInt(test.time_limit||0,10),timerEl:null,timerInt:null,submitted:!1,};var wrap=el('div','esl-test-wrap');var typeLabel=(test.type||'test').replace(/_/g,' ');var header=el('div','esl-test-header');header.innerHTML='<div class="esl-test-header__meta">'+'<span class="esl-badge-type">'+escHtml(typeLabel)+'</span>'+(test.difficulty?'<span class="esl-badge-diff">'+escHtml(test.difficulty)+'</span>':'')+'</div>'+'<h2>'+escHtml(test.title)+'</h2>'+(test.description?'<p>'+escHtml(test.description)+'</p>':'');wrap.appendChild(header);if(state.timeLimit>0){var timerEl=el('div','esl-timer','<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><circle cx="12" cy="12" r="10"/><polyline points="12 6 12 12 16 14"/></svg> '+formatTime(state.timeLimit));state.timerEl=timerEl;wrap.appendChild(timerEl)}
9var body=el('div','esl-test-body');questions.forEach(function(q,i){body.appendChild(buildQuestion(q,i,state,test))});wrap.appendChild(body);var nav=el('div','esl-test-nav');var btnPrev=el('button','esl-btn esl-btn-ghost','← Back');var btnNext=el('button','esl-btn esl-btn-primary','Next →');var btnSub=el('button','esl-btn esl-btn-primary','Submit test');btnPrev.style.display='none';btnSub.style.display='none';nav.appendChild(btnPrev);nav.appendChild(btnNext);nav.appendChild(btnSub);wrap.appendChild(nav);function updateNav(){var i=state.current;var tot=questions.length;btnPrev.style.display=i===0?'none':'';btnNext.style.display=i===tot-1?'none':'';btnSub.style.display=i===tot-1?'':'none';body.querySelectorAll('.esl-question-block').forEach(function(b,idx){b.classList.toggle('esl-active',idx===i)})}
10btnPrev.addEventListener('click',function(){if(state.current>0){state.current--;updateNav()}});btnNext.addEventListener('click',function(){if(state.current<questions.length-1){state.current++;updateNav()}});btnSub.addEventListener('click',function(){if(state.submitted)return;submitTest(wrap,test,state,loggedIn,questions)});updateNav();if(state.timeLimit>0){var timerDeadline=Date.now()+state.timeLimit*1000;
10state.timerInt=setInterval(function(){var remaining=Math.max(0,Math.ceil((timerDeadline-Date.now())/1000));state.timerEl.innerHTML='<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><circle cx="12" cy="12" r="10"/><polyline points="12 6 12 12 16 14"/></svg> '+formatTime(remaining);if(remaining<=60)state.timerEl.classList.add('esl-timer--warning');if(remaining<=10)state.timerEl.classList.add('esl-timer--danger');if(window.eslSFX){if(remaining<=10)eslSFX.tick();else if(remaining<=30&&remaining%5===0)eslSFX.tick();}
11if(remaining<=0){clearInterval(state.timerInt);submitTest(wrap,test,state,loggedIn,questions)}},1000)}
12mount.innerHTML='';mount.appendChild(wrap)}
13function buildQuestion(q,i,state,test){var block=el('div','esl-question-block'+(i===0?' esl-active':''));block.setAttribute('data-qid',q.id);var numEl=el('h3','esl-question-heading','Question '+(i+1)+': '+escHtml(q.content));block.appendChild(numEl);if(q.media_url){var mediaEl=el('div','esl-question-media');if(q.media_type==='audio'){mediaEl.innerHTML='<audio controls src="'+escHtml(q.media_url)+'"></audio>'}else{mediaEl.innerHTML='<img src="'+escHtml(q.media_url)+'" alt="question image" loading="lazy">'}
14block.appendChild(mediaEl)}
15var answers=q.answers||[];var type=q.type;if(type==='mcq'||type==='true_false'||type==='mcq_multi'){var opts=el('div','esl-options');var letters=['A','B','C','D','E'];answers.forEach(function(a,ai){var opt=el('div','esl-option');opt.setAttribute('data-aid',a.id);var letter=el('span','esl-option-letter',letters[ai]||(ai+1));var text=el('span','esl-option-text',escHtml(a.content));opt.appendChild(letter);opt.appendChild(text);opt.addEventListener('click',function(){if(state.submitted)return;if(type==='mcq_multi'){opt.classList.toggle('esl-selected');var sel=Array.from(opts.querySelectorAll('.esl-option.esl-selected')).map(function(o){return o.getAttribute('data-aid')});state.answers[q.id]=sel}else{opts.querySelectorAll('.esl-option').forEach(function(o){o.classList.remove('esl-selected')});opt.classList.add('esl-selected');state.answers[q.id]=a.id}
16try{localStorage.setItem(SAVE_KEY,JSON.stringify(state.answers))}catch(e){}});opts.appendChild(opt)});block.appendChild(opts)}else if(type==='fill_blank'){var fw=el('div','esl-fill-wrap');var inp=el('input');inp.type='text';inp.className='esl-fill-input';inp.placeholder='Type your answer...';inp.autocomplete='off';inp.addEventListener('input',function(){state.answers[q.id]=inp.value;try{localStorage.setItem(SAVE_KEY,JSON.stringify(state.answers))}catch(e){}});fw.appendChild(inp);block.appendChild(fw)}else if(type==='matching'){var leftItems=answers.filter(function(a){return a.pair_side==='left'});var rightItems=answers.filter(function(a){return a.pair_side==='right'});rightItems=rightItems.slice().sort(function(){return Math.random()-0.5});var matchWrap=el('div','esl-match-wrap');var leftCol=el('div','esl-match-col esl-match-col--left');var arrowCol=el('div','esl-match-col esl-match-col--arrows');var rightCol=el('div','esl-match-col esl-match-col--right');var matchState={};var selectedLeft=null;function updateMatchAnswers(){state.answers[q.id]=Object.assign({},matchState)}
17function clearMatchSelections(){leftCol.querySelectorAll('.esl-match-item').forEach(function(i){i.classList.remove('esl-match-active')});rightCol.querySelectorAll('.esl-match-item').forEach(function(i){i.classList.remove('esl-match-active')});selectedLeft=null}
18function drawMatchLines(){arrowCol.innerHTML='';var leftEls=leftCol.querySelectorAll('.esl-match-item');var rightEls=rightCol.querySelectorAll('.esl-match-item');var wRect=matchWrap.getBoundingClientRect();Object.keys(matchState).forEach(function(lid){var rid=String(matchState[lid]);var lEl=null,rEl=null;leftEls.forEach(function(e){if(String(e.getAttribute('data-aid'))===String(lid))lEl=e});rightEls.forEach(function(e){if(String(e.getAttribute('data-aid'))===rid)rEl=e});if(!lEl||!rEl)return;var lR=lEl.getBoundingClientRect(),rR=rEl.getBoundingClientRect();var y1=lR.top-wRect.top+lR.height/2;var y2=rR.top-wRect.top+rR.height/2;var line=el('div','esl-match-line');var top=Math.min(y1,y2);var h=Math.abs(y2-y1)||2;line.style.cssText='top:'+top+'px;height:'+h+'px;';arrowCol.appendChild(line)})}
19leftItems.forEach(function(a){var item=el('div','esl-match-item');item.setAttribute('data-aid',a.id);item.textContent=a.content;item.addEventListener('click',function(){if(state.submitted)return;if(selectedLeft===String(a.id)){clearMatchSelections();return}
20clearMatchSelections();selectedLeft=String(a.id);item.classList.add('esl-match-active')});leftCol.appendChild(item)});rightItems.forEach(function(a){var item=el('div','esl-match-item');item.setAttribute('data-aid',a.id);item.textContent=a.content;item.addEventListener('click',function(){if(state.submitted||!selectedLeft)return;Object.keys(matchState).forEach(function(k){if(k===selectedLeft||String(matchState[k])===String(a.id))delete matchState[k]});matchState[selectedLeft]=a.id;updateMatchAnswers();leftCol.querySelectorAll('.esl-match-item').forEach(function(i){i.classList.toggle('esl-match-paired',!!matchState[String(i.getAttribute('data-aid'))])});var pairedRids=Object.values(matchState).map(String);rightCol.querySelectorAll('.esl-match-item').forEach(function(i){i.classList.toggle('esl-match-paired',pairedRids.indexOf(String(i.getAttribute('data-aid')))!==-1)});clearMatchSelections();setTimeout(drawMatchLines,60)});rightCol.appendChild(item)});matchWrap.appendChild(leftCol);matchWrap.appendChild(arrowCol);matchWrap.appendChild(rightCol);block.appendChild(matchWrap);block.appendChild(el('p','esl-q-hint','Click an item on the left, then click its match on the right.'))}else if(type==='ordering'){var ordItems=answers.slice().sort(function(){return Math.random()-0.5});var orderList=el('ul','esl-order-list');function rebuildOrderAnswer(){state.answers[q.id]=Array.from(orderList.querySelectorAll('.esl-order-item')).map(function(i){return i.getAttribute('data-aid')})}
21ordItems.forEach(function(a){var item=el('li','esl-order-item');item.setAttribute('data-aid',a.id);item.setAttribute('draggable','true');var handle=el('span','esl-order-handle','â ¿');var text=el('span','esl-order-text',escHtml(a.content));item.appendChild(handle);item.appendChild(text);item.addEventListener('dragstart',function(e){e.dataTransfer.effectAllowed='move';e.dataTransfer.setData('text/plain',String(a.id));setTimeout(function(){item.classList.add('esl-order-dragging')},0)});item.addEventListener('dragend',function(){item.classList.remove('esl-order-dragging');orderList.querySelectorAll('.esl-order-item').forEach(function(i){i.classList.remove('esl-order-over')});rebuildOrderAnswer()});item.addEventListener('dragover',function(e){e.preventDefault();orderList.querySelectorAll('.esl-order-item').forEach(function(i){i.classList.remove('esl-order-over')});item.classList.add('esl-order-over')});item.addEventListener('drop',function(e){e.preventDefault();var fromId=e.dataTransfer.getData('text/plain');var fromEl=orderList.querySelector('[data-aid="'+fromId+'"]');if(!fromEl||fromEl===item)return;var allItems=Array.from(orderList.children);var fi=allItems.indexOf(fromEl),ti=allItems.indexOf(item);orderList.insertBefore(fromEl,fi<ti?item.nextSibling:item);rebuildOrderAnswer()});var touchStartY=0,touchDragEl=null;item.addEventListener('touchstart',function(e){touchStartY=e.touches[0].clientY;touchDragEl=item;item.classList.add('esl-order-dragging')},{passive:!0});item.addEventListener('touchmove',function(e){e.preventDefault();var y=e.touches[0].clientY;var allSiblings=Array.from(orderList.querySelectorAll('.esl-order-item:not(.esl-order-dragging)'));allSiblings.forEach(function(i){i.classList.remove('esl-order-over')});allSiblings.forEach(function(i){var r=i.getBoundingClientRect();if(y>r.top&&y<r.bottom)i.classList.add('esl-order-over');})},{passive:!1});item.addEventListener('touchend',function(e){item.classList.remove('esl-order-dragging');var y=e.changedTouches[0].clientY;var allSiblings=Array.from(orderList.querySelectorAll('.esl-order-item'));var target=null;allSiblings.forEach(function(i){i.classList.remove('esl-order-over');var r=i.getBoundingClientRect();if(i!==item&&y>r.top&&y<r.bottom)target=i});if(target){var fi2=allSiblings.indexOf(item),ti2=allSiblings.indexOf(target);orderList.insertBefore(item,fi2<ti2?target.nextSibling:target)}
22rebuildOrderAnswer()});orderList.appendChild(item)});block.appendChild(orderList);block.appendChild(el('p','esl-q-hint','Drag items to arrange them in the correct order.'))}else if(type==='sentence_building'){var sbWrap=el('div','esl-sentence-wrap');var sbAnswer=el('div','esl-sentence-answer');var sbPlaceholder=el('span','esl-sentence-placeholder','Click words below to build the sentence');sbAnswer.appendChild(sbPlaceholder);var sbBank=el('div','esl-sentence-bank');var sbOrder=[];var sbCorrectSeq=answers.slice().sort(function(a,b){return(a.correct_position||0)-(b.correct_position||0)}).map(function(a){return String(a.id)});var sbShuffled=answers.slice().sort(function(){return Math.random()-0.5});function rebuildSbAnswer(){sbAnswer.innerHTML='';if(sbOrder.length===0){sbAnswer.appendChild(sbPlaceholder)}else{sbOrder.forEach(function(item){var chip=el('span','esl-word-chip esl-word-in-answer');chip.setAttribute('data-aid',item.aid);chip.textContent=item.content;chip.addEventListener('click',function(){if(state.submitted)return;sbOrder=sbOrder.filter(function(o){return o.aid!==item.aid});var bankChip=sbBank.querySelector('[data-aid="'+item.aid+'"]');if(bankChip)bankChip.classList.remove('esl-word-used');state.answers[q.id]=sbOrder.map(function(o){return o.aid});rebuildSbAnswer()});sbAnswer.appendChild(chip)})}
23state.answers[q.id]=sbOrder.map(function(o){return o.aid})}
24sbShuffled.forEach(function(a){var chip=el('span','esl-word-chip');chip.setAttribute('data-aid',a.id);chip.textContent=a.content;chip.addEventListener('click',function(){if(state.submitted||chip.classList.contains('esl-word-used'))return;chip.classList.add('esl-word-used');sbOrder.push({aid:String(a.id),content:a.content});rebuildSbAnswer()});sbBank.appendChild(chip)});sbWrap.appendChild(sbAnswer);sbWrap.appendChild(sbBank);block.appendChild(sbWrap);block.appendChild(el('p','esl-q-hint','Click words in the correct order to build the sentence. Click a word 
24in the answer to remove it.'))}
25if(q.explanation){var exp=el('div','esl-explanation','<strong>Explanation:</strong> '+escHtml(q.explanation));exp.setAttribute('data-explanation','1');block.appendChild(exp)}(function attachReportBtn(qObj){var repWrap=el('div','esl-report-wrap');repWrap.style.cssText='margin-top:10px;border-top:1px solid #f1f5f9;padding-top:8px';var toggleBtn=el('button','esl-report-toggle-btn');toggleBtn.type='button';toggleBtn.innerHTML='<span style="font-size:14px">🚩</span> Found a problem with this question?';toggleBtn.style.cssText='background:none;border:none;color:#94a3b8;font-size:12px;cursor:pointer;padding:2px 0;display:flex;align-items:center;gap:6px;transition:color .15s';toggleBtn.addEventListener('mouseenter',function(){this.style.color='#dc2626'});toggleBtn.addEventListener('mouseleave',function(){this.style.color='#94a3b8'});var formEl=el('div','esl-report-form-wrap');formEl.style.cssText='display:none;margin-top:10px;background:#fef9f9;border:1.5px solid #fecaca;border-radius:10px;padding:14px 16px';formEl.innerHTML=['<div style="font-size:13px;font-weight:700;color:#0f172a;margin-bottom:10px">Report an issue with this question</div>','<label style="font-size:12px;font-weight:700;color:#475569;text-transform:uppercase;letter-spacing:.04em;display:block;margin-bottom:4px">Issue type <span style="color:#dc2626">*</span></label>','<select class="esl-rep-type" style="width:100%;padding:8px 10px;border:1.5px solid #e2e8f0;border-radius:8px;font-size:13px;margin-bottom:10px;background:#fff">','<option value="">— Select issue type —</option>','<option value="wrong_answer">Wrong answer marked as correct</option>','<option value="multiple_correct">More than one correct answer</option>','<option value="unclear">Question is unclear or ambiguous</option>','<option value="grammar_spelling">Grammar / spelling issue</option>','<option value="wrong_explanation">Explanation is incorrect</option>','<option value="technical">Technical / display issue</option>','<option value="other">Other</option>','</select>','<label style="font-size:12px;font-weight:700;color:#475569;text-transform:uppercase;letter-spacing:.04em;display:block;margin-bottom:4px">Description <small style="font-weight:400">(optional)</small></label>','<textarea class="esl-rep-desc" placeholder="Briefly describe the problem…" rows="2" style="width:100%;padding:8px 10px;border:1.5px solid #e2e8f0;border-radius:8px;font-size:13px;font-family:inherit;resize:vertical;box-sizing:border-box;margin-bottom:10px"></textarea>','<label style="font-size:12px;font-weight:700;color:#475569;text-transform:uppercase;letter-spacing:.04em;display:block;margin-bottom:4px">Email <small style="font-weight:400">(optional, for reply)</small></label>','<input type="email" class="esl-rep-email" placeholder="[email protected]" style="width:100%;padding:8px 10px;border:1.5px solid #e2e8f0;border-radius:8px;font-size:13px;box-sizing:border-box;margin-bottom:12px">','<div style="display:flex;gap:8px;align-items:center">','<button type="button" class="esl-rep-submit-btn" style="padding:9px 18px;background:linear-gradient(135deg,#0f7ea4,#27a9cb);color:#fff;border:none;border-radius:8px;font-size:13px;font-weight:700;cursor:pointer">Submit Report</button>','<button type="button" class="esl-rep-cancel-btn" style="padding:9px 14px;background:#f1f5f9;color:#475569;border:none;border-radius:8px;font-size:13px;font-weight:600;cursor:pointer">Cancel</button>','</div>','<div class="esl-rep-msg" style="margin-top:8px;font-size:13px"></div>',].join('');toggleBtn.addEventListener('click',function(){var hidden=formEl.style.display==='none';formEl.style.display=hidden?'block':'none';if(hidden)formEl.querySelector('.esl-rep-type').focus();});formEl.querySelector('.esl-rep-cancel-btn').addEventListener('click',function(){formEl.style.display='none'});formEl.querySelector('.esl-rep-submit-btn').addEventListener('click',function(){var typeEl=formEl.querySelector('.esl-rep-type');var descEl=formEl.querySelector('.esl-rep-desc');var emailEl=formEl.querySelector('.esl-rep-email');var msgEl=formEl.querySelector('.esl-rep-msg');if(!typeEl.value){msgEl.innerHTML='<span style="color:#dc2626">⚠️ Please select an issue type.</span>';typeEl.style.borderColor='#dc2626';return}
26typeEl.style.borderColor='#e2e8f0';var submitBtn=this;submitBtn.disabled=!0;submitBtn.textContent='Sending…';msgEl.innerHTML='';
26var userAnsRaw=(typeof state!=='undefined'&&state.answers)?(state.answers[qObj.id]||''):'';var userAnsStr=typeof userAnsRaw==='object'?JSON.stringify(userAnsRaw):String(userAnsRaw);var correctLabel='';if(qObj.answers){qObj.answers.forEach(function(a){if(a.is_correct||a.pair_side)return});var corrAnswers=qObj.answers.filter(function(a){return a.is_correct});correctLabel=corrAnswers.map(function(a){return a.content}).join(', ')}
27var payload={report_type:typeEl.value,description:descEl.value,email:emailEl.value,user_answer:userAnsStr,correct_answer:correctLabel,page_url:window.location.href,test_type:(typeof test!=='undefined'&&test)?(test.type||''):'',test_level:(typeof test!=='undefined'&&test)?(test.difficulty||''):'',};var restBase=(typeof eslTests!=='undefined'&&eslTests.restUrl)?eslTests.restUrl:'/wp-json/esl/v1/';var restNonce=(typeof eslTests!=='undefined'&&eslTests.nonce)?eslTests.nonce:'';fetch(restBase+'questions/'+qObj.id+'/report',{method:'POST',headers:{'Content-Type':'application/json','X-WP-Nonce':restNonce,},body:JSON.stringify(payload),credentials:'include',}).then(function(r){return r.json()}).then(function(json){if(json.success){msgEl.innerHTML='<span style="color:#16a34a">✓ Thanks! We\'ll review this question soon.</span>';submitBtn.textContent='Sent ✓';submitBtn.style.background='#16a34a';typeEl.value='';descEl.value='';emailEl.value='';setTimeout(function(){formEl.style.display='none'},2800)}else{msgEl.innerHTML='<span style="color:#dc2626">⚠️ '+(json.message||'Submission failed.')+'</span>';submitBtn.disabled=!1;submitBtn.textContent='Submit Report'}}).catch(function(){msgEl.innerHTML='<span style="color:#dc2626">⚠️ Network error. Please try again.</span>';submitBtn.disabled=!1;submitBtn.textContent='Submit Report'})});repWrap.appendChild(toggleBtn);repWrap.appendChild(formEl);block.appendChild(repWrap)})(q);return block}
28function submitTest(wrap,test,state,loggedIn,questions){if(state.submitted)return;state.submitted=!0;if(state.timerInt)clearInterval(state.timerInt);var timeSpent=Math.round((Date.now()-state.startTime)/1000);if(!loggedIn){renderResultGuest(wrap,test,state,timeSpent,questions);return}
29wrap.querySelectorAll('.esl-btn').forEach(function(b){b.disabled=!0});var cleanAnswers={};Object.keys(state.answers).forEach(function(k){var v=state.answers[k];if(typeof v==='object'&&v!==null&&!Array.isArray(v)&&Object.keys(v).length===0){cleanAnswers[k]=null}else{cleanAnswers[k]=v}});apiFetch('tests/'+test.id+'/submit',{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify({answers:cleanAnswers,time_spent:timeSpent})}).then(function(result){if(result&&result.score_pct!==undefined){try{localStorage.removeItem(SAVE_KEY)}catch(e){}
30renderResult(wrap,test,result,questions,state.answers);if(result.streak_message){setTimeout(function(){showStreakToast(result.streak_message,result.streak)},1200)}
31apiFetch('user/achievements').then(function(all){if(!Array.isArray(all))return;var now=Date.now();var fresh=all.filter(function(b){if(!b.earned||!b.earned_at)return!1;var t=new Date(b.earned_at.replace(' ','T')+'Z').getTime();return(now-t)<15000});showAchievementToasts(fresh)}).catch(function(){})}else{var errMsg='Submission failed. Please try again.';if(result&&result.message)errMsg=result.message;else if(result&&result.code)errMsg='Error ['+result.code+']: '+(result.message||'');console.error('[ESL standalone] Submit error:',result);wrap.querySelectorAll('.esl-btn').forEach(function(b){b.disabled=!1});var errEl=wrap.querySelector('.esl-submit-err');if(!errEl){errEl=document.createElement('p');errEl.className='esl-submit-err';errEl.style.cssText='color:#dc2626;font-size:14px;text-align:center;padding:12px';wrap.querySelector('.esl-test-nav').appendChild(errEl)}
32errEl.textContent=errMsg}}).catch(function(err){console.error('[ESL standalone] Fetch error:',err);wrap.querySelectorAll('.esl-btn').forEach(function(b){b.disabled=!1});var errEl=wrap.querySelector('.esl-submit-err');if(!errEl){errEl=document.createElement('p');errEl.className='esl-submit-err';errEl.style.cssText='color:#dc2626;font-size:14px;text-align:center;padding:12px';wrap.querySelector('.esl-test-nav').appendChild(errEl)}
33errEl.textContent='Network error. Please check your connection and try again.'})}
34function renderResult(wrap,test,result,questions,userAnswers){var pct=result.score_pct;var passed=result.passed;if(window.eslSFX){setTimeout(function(){passed?eslSFX.pass():eslSFX.fail()},300);if(passed)setTimeout(function(){eslSFX.xp()},900);if(pct===100)setTimeout(function(){eslSFX.perfect()},400)}
35var xp=result.xp_earned;var level=result.level_result;var deg=Math.round(pct/100*360)+'deg';var screen=el('div','esl-result-screen');var circle=el('div','esl-result-score-circle');circle.style.setProperty('--pct',pct+'%');circle.innerHTML='<div class="esl-result-score-inner"><div class="esl-result-pct">'+pct+'</div><div class="esl-result-pct-label">%</div></div>';screen.appendChild(circle);var banner=el('div','esl-pass-banner esl-pass-banner--'+(passed?'pass':'fail'));banner.textContent=passed?'✓ Passed!':'✗ Not passed';screen.appendChild(banner);if(level&&CEFR_COLORS[level]){var cefrBadge=el('div','esl-cefr-result',level);cefrBadge.style.background=CEFR_COLORS[level];screen.insertBefore(cefrBadge,banner);var cefrLabel=el('p','','Your English level: <strong>'+cefrFullName(level)+'</strong>');cefrLabel.style.cssText='font-size:15px;color:#475569;margin:0 0 16px';screen.insertBefore(cefrLabel,banner);if(+cfg.is_paid===0){var up=el('div','','You are <strong>'+level+'</strong> \u2014 get your personal study plan, fix your weak areas, and practise without limits with <strong>
357ESL Pro</strong>.');up.style.cssText='background:linear-gradient(135deg,#eff6ff,#dbeafe);border:1.5px solid #bfdbfe;border-radius:14px;padding:16px 18px;margin:0 0 16px;font-size:14px;color:#1e3a5f;line-height:1.55';var upBtn=document.createElement('a');upBtn.href='/membership/?src=placement_result';upBtn.textContent='Unlock my study plan \u2192';upBtn.style.cssText='display:inline-block;margin-top:12px;background:#2563eb;color:#fff;font-weight:800;text-decoration:none;padding:10px 20px;border-radius:10px';up.appendChild(document.createElement('br'));up.appendChild(upBtn);screen.insertBefore(up,banner)}}
36screen.appendChild(el('h3','esl-result-title',passed?'Great job! 🎉':'Keep practising!'));screen.appendChild(el('p','esl-result-subtitle','You scored <strong>'+result.score_raw+'</strong> out of <strong>'+result.score_max+'</strong> points.'));var toast=el('div','esl-xp-toast','⚡ +'+xp+' XP earned!');screen.appendChild(toast);var stats=el('div','esl-result-stats');stats.appendChild(statBox(pct+'%','Score'));stats.appendChild(statBox(result.score_raw+'/'+result.score_max,'Points'));if(result.user_score){stats.appendChild(statBox(result.user_score.total_xp+' XP','Total XP'));stats.appendChild(statBox(result.user_score.level_name,'Level'))}
37screen.appendChild(stats);if(result.detail&&questions.length){var rev=el('div','esl-review-list');rev.appendChild(el('h3','','Review'));questions.forEach(function(q){var d=result.detail[q.id];if(!d)return;var item=el('div','esl-review-item esl-review-item--'+(d.correct?'correct':'wrong'));var icon=el('span','esl-review-icon',d.correct?'✓':'✗');var text=el('span','',escHtml(q.content));item.appendChild(icon);item.appendChild(text);if(q.type==='matching'&&!d.correct&&d.max>0){var partial=el('span','esl-review-partial',' ('+d.earned+'/'+d.max+' pairs correct)');partial.style.cssText='font-size:12px;color:#64748b;margin-left:6px';item.appendChild(partial)}
38rev.appendChild(item)});screen.appendChild(rev)}
39var navBtns=el('div','','');navBtns.style.cssText='display:flex;gap:12px;justify-content:center;flex-wrap:wrap';var btnRetry=el('button','esl-btn esl-btn-outline','Try again');btnRetry.addEventListener('click',function(){window.location.reload()});navBtns.appendChild(btnRetry);if(cfg.profileUrl){var btnProfile=el('a','esl-btn esl-btn-ghost','My profile');btnProfile.href=cfg.profileUrl;navBtns.appendChild(btnProfile)}
40screen.appendChild(navBtns);wrap.innerHTML='';wrap.appendChild(screen)}
41function renderResultGuest(wrap,test,state,timeSpent,questions){var answered=Object.keys(state.answers).filter(function(k){var v=state.answers[k];if(v===''||v===null||v===undefined)return!1;if(typeof v==='object'&&!Array.isArray(v)&&Object.keys(v).length===0)return!1;return!0}).length;var screen=el('div','esl-result-screen');screen.innerHTML='<div style="font-size:48px;margin-bottom:16px">📝</div>'+'<h3 class="esl-result-title">You answered '+answered+' of '+questions.length+' questions</h3>'+'<p class="esl-result-subtitle">Create a free account to save your score, earn XP, and track your progress!</p>'+'<div class="esl-guest-prompt">'+'<div class="esl-result-btns" style="margin-top:12px">'+'<a class="esl-btn esl-btn-primary" href="/signup" style="background:linear-gradient(135deg,#0f7ea4,#27a9cb)!important;color:#fff!important;text-decoration:none">Sign up free</a>'+'<a class="esl-btn esl-btn-ghost" href="/login" style="text-decoration:none">Log in</a>'+'</div>'+'</div>'+'<div style="margin-top:16px"><button class="esl-btn esl-btn-outline" onclick="location.reload()">Try again</button></div>';wrap.innerHTML='';wrap.appendChild(screen)}
42function statBox(val,label){var box=el('div','esl-result-stat');box.appendChild(el('strong','',String(val)));box.appendChild(el('span','',label));return box}
43function cefrFullName(lvl){var names={A1:'Beginner',A2:'Elementary',B1:'Intermediate',B2:'Upper-Intermediate',C1:'Advanced',C2:'Proficient'};return lvl+' — '+(names[lvl]||'')}
44function escHtml(str){return String(str||'').replace(/&/g,'&amp;').replace(/</g,'&lt;').replace(/>/g,'&gt;').replace(/"/g,'&quot;')}
45function showAchievementToasts(newBadges){if(!newBadges||!newBadges.length)return;var wrap=document.querySelector('.esl-ach-toast-wrap');if(!wrap){wrap=el('div','esl-ach-toast-wrap');document.body.appendChild(wrap)}
46newBadges.forEach(function(badge,i){setTimeout(function(){var toast=el('div','esl-ach-toast');toast.innerHTML='<span class="esl-ach-toast-icon">'+(badge.icon||'🏅')+'</span>'+'<div class="esl-ach-toast-body">'+'<span class="esl-ach-toast-label">Achievement unlocked!</span>'+'<span class="esl-ach-toast-name">'+escHtml(badge.name)+'</span>'+'<span class="esl-ach-toast-desc">'+escHtml(badge.desc)+'</span>'+'</div>';wrap.appendChild(toast);setTimeout(function(){toast.remove()},4200)},i*800)})}
47function initSSRTabPanel(panel){var blocks=Array.from(panel.querySelectorAll('.esl-question-block'));var total=blocks.length;if(!total)return;var current=0;var answers={};var startTime=Date.now();var timerInt=null;var btnPrev=panel.querySelector('#esl-tab-prev');var btnNext=panel.querySelector('#esl-tab-next');var btnSubmit=panel.querySelector('#esl-submit-btn');var progressFill=panel.querySelector('#esl-tab-progress');var progressLabel=panel.querySelector('#esl-tab-progress-label');var timerEl=panel.querySelector('#esl-tab-timer');if(!btnNext)return;panel.addEventListener('click',function(e){var opt=e.target.closest('.esl-option');if(!opt||opt.style.pointerEvents==='none')return;var qBlock=opt.closest('.esl-question-block');if(!qBlock)return;var qid=qBlock.getAttribute('data-qid');qBlock.querySelectorAll('.esl-option').forEach(function(o){o.classList.remove('esl-selected');o.setAttribute('aria-checked','false')});opt.classList.add('esl-selected');opt.setAttribute('aria-checked','true');answers[qid]=opt.getAttribute('data-aid')});panel.addEventListener('input',function(e){if(!e.target.classList.contains('esl-fill-input'))return;var qBlock=e.target.closest('.esl-question-block');if(qBlock)answers[qBlock.getAttribute('data-qid')]=e.target.value});function updateNav(){if(progressFill)progressFill.style.width=Math.round((current+1)/total*100)+'%';if(progressLabel)progressLabel.textContent=(current+1)+' / '+total;blocks.forEach(function(b,i){b.classList.toggle('esl-active',i===current)});if(btnPrev)btnPrev.style.display=current===0?'none':'';if(btnNext)btnNext.style.display=current===total-1?'none':'';if(btnSubmit)btnSubmit.style.display=current===total-1?'':'none'}
48btnNext.addEventListener('click',function(){if(current<total-1){current++;updateNav()}});if(btnPrev)btnPrev.addEventListener('click',function(){if(current>0){current--;updateNav()}});if(btnSubmit){btnSubmit.addEventListener('click',function(){if(btnSubmit.disabled)return;var timeSpent=Math.round((Date.now()-startTime)/1000);if(timerInt)clearInterval(timerInt);var loggedIn=btnSubmit.getAttribute('data-logged-in')==='1';var testId=parseInt(btnSubmit.getAttribute('data-test-id'),10);btnSubmit.disabled=!0;btnSubmit.textContent='Submitting…';if(!loggedIn){renderResultGuest(panel,total,Object.keys(answers).length);return}
49apiFetch('tests/'+testId+'/submit',{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify({answers:answers,time_spent:timeSpent})}).then(function(result){if(result&&result.score_pct!==undefined){renderSSRResult(panel,result)}else{var errMsg=(result&&result.message)?result.message:'Submission failed. Please try again.';var errEl=panel.querySelector('.esl-submit-error');if(!errEl){errEl=document.createElement('p');errEl.className='esl-submit-error';errEl.style.cssText='color:#dc2626;font-size:14px;margin-top:10px;text-align:center';btnSubmit.parentNode.insertBefore(errEl,btnSubmit.nextSibling)}
50errEl.textContent=errMsg;btnSubmit.disabled=!1;btnSubmit.textContent='Submit test'}}).catch(function(){btnSubmit.disabled=!1;btnSubmit.textContent='Submit test'})})}
51var timeLimit=parseInt(btnSubmit?btnSubmit.getAttribute('data-time-limit'):0,10);if(timerEl&&timeLimit>0){var tabDeadline=Date.now()+timeLimit*1000;timerInt=setInterval(function(){var rem=Math.max(0,Math.ceil((tabDeadline-Date.now())/1000));var m=Math.floor(rem/60),s=rem%60;timerEl.innerHTML='<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" width="16" height="16"><circle cx="12" cy="12" r="10"/><polyline points="12 6 12 12 16 14"/></svg> '+(m<10?'0':'')+m+':'+(s<10?'0':'')+s;if(rem<=60)timerEl.classList.add('esl-timer--warning');if(rem<=10)timerEl.classList.add('esl-timer--danger');if(window.eslSFX){if(rem<=10)eslSFX.tick();else if(rem<=30&&rem%5===0)eslSFX.tick();}
52if(rem<=0){clearInterval(timerInt);if(btnSubmit){btnSubmit.click()}}},1000)}
53updateNav()}
54function renderSSRResult(panel,result){var pct=result.score_pct;var passed=result.passed;var xp=result.xp_earned;var screen=document.createElement('div');screen.className='esl-result-screen';screen.innerHTML='<div class="esl-result-score-circle" style="--pct:'+pct+'%">'+'<div class="esl-result-score-inner"><div class="esl-result-pct">'+pct+'</div><div class="esl-result-pct-label">%</div></div>'+'</div>'+'<div class="esl-pass-banner esl-pass-banner--'+(passed?'pass':'fail')+'">'+(passed?'✓ Passed!':'✗ Not passed')+'</div>'+'<h3 class="esl-result-title">'+(passed?'Great job! 🎉':'Keep practising!')+'</h3>'+'<p class="esl-result-subtitle">You scored <strong>'+result.score_raw+'</strong> out of <strong>'+result.score_max+'</strong> points.</p>'+'<div class="esl-xp-toast">⚡ +'+xp+' XP earned!</div>'+'<div class="esl-gbtn-group"><button class="esl-btn esl-btn-outline" onclick="window.location.reload()">Try again</button></div>';var wrap=panel.querySelector('.esl-test-wrap');if(wrap){wrap.innerHTML='';wrap.appendChild(screen)}}
55function renderResultGuest(panel,total,answered){var screen=document.createElement('div');screen.className='esl-result-screen';screen.innerHTML='<h3 class="esl-result-title">You answered '+answered+' of '+total+' questions</h3>'+'<div class="esl-login-prompt">Log in or sign up to save your score and earn XP — <a href="/login">Log in</a> · <a href="/signup">Sign up free</a></div>'+'<div class="esl-gbtn-group"><button class="esl-btn esl-btn-outline" onclick="window.location.reload()">Try again</button></div>';var wrap=panel.querySelector('.esl-test-wrap');if(wrap){wrap.innerHTML='';wrap.appendChild(screen)}}
56function initSSRPanels(){document.querySelectorAll('#esl-panel-test[data-test-id]').forEach(function(panel){if(!panel.getAttribute('data-ssr-init')){panel.setAttribute('data-ssr-init','1');initSSRTabPanel(panel)}})}
57window.__eslRenderPlayer=renderPlayer;window.__eslInitMounts=initMounts;function showStreakToast(message,streak){var wrap=document.querySelector('.esl-ach-toast-wrap');if(!wrap){wrap=document.createElement('div');wrap.className='esl-ach-toast-wrap';document.body.appendChild(wrap)}
58var toast=document.createElement('div');toast.className='esl-ach-toast';toast.innerHTML='<span class="esl-ach-toast-icon">🔥</span>'+'<div class="esl-ach-toast-body">'+'<span class="esl-ach-toast-label">Learning streak</span>'+'<span class="esl-ach-toast-name">'+escHtml(message)+'</span>'+'<span class="esl-ach-toast-desc">Keep it up — come back tomorrow!</span>'+'</div>';wrap.appendChild(toast);setTimeout(function(){toast.remove()},4200)}
59window.eslTestsAPI={getTest:function(id){return apiFetch('tests/'+id)},getUserScore:function(){return apiFetch('user/score')},getHistory:function(){return apiFetch('user/history')},submitTest:function(id,answers,timeSpent){return apiFetch('tests/'+id+'/submit',{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify({answers:answers,time_spent:timeSpent})})}};if(document.readyState==='loading'){document.addEventListener('DOMContentLoaded',initMounts)}else{initMounts()}})();(function(){'use strict';function esc(s){return String(s==null?'':s).replace(/&/g,'&amp;').replace(/</g,'&lt;').replace(/>/g,'&gt;').replace(/"/g,'&quot;').replace(/'/g,'&#39;')}
60function ring(pct,good){var p=Math.max(0,Math.min(100,Math.round(pct||0)));var len=Math.round(p/100*314);return'<svg class="eslr-ring" width="120" height="120" viewBox="0 0 120 120" aria-hidden="true">'+'<circle cx="60" cy="60" r="50" fill="none" stroke="#EEF2F5" stroke-width="12"/>'+(len>0?'<circle cx="60" cy="60" r="50" fill="none" stroke="'+(good?'#15803D':'#F5A623')+'" stroke-width="12" stroke-linecap="round" stroke-dasharray="'+len+' 400" transform="rotate(-90 60 60)"/>':'')+'<text x="60" y="68" text-anchor="middle" font-family="Inter,Arial,sans-serif" font-weight="800" font-size="26" fill="#0B2540">'+p+'%</text></svg>'}
61function btn(kind,label,href,act){return href?'<a class="eslr-btn eslr-btn--'+kind+'" href="'+esc(href)+'">'+label+'</a>':'<button type="button" class="eslr-btn eslr-btn--'+kind+'" data-e
61slr="'+act+'">'+label+'</button>'}
62var SHARE='<svg viewBox="0 0 24 24" width="18" height="18" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M22 2L11 13"/><path d="M22 2l-7 20-4-9-9-4z"/></svg>';function lv(l){if(!l){return''}
63var k=String(l).toLowerCase(),c={kindergarten:'k','pre-a1':'pre',a1:'a1',a2:'a2',b1:'b1',b2:'b2',c1:'c1',c2:'c2'}[k];return c?'<span class="eslr-lv eslr-lv--'+c+'">'+esc(c==='k'?'K':c==='pre'?'Pre A1':l.toUpperCase())+'</span>':''}
64function eslResultHtml(o){o=o||{};var full=o.kind!=='mini',hl=o.hl||(full?'h2':'h3');var c=+o.correct||0,n=+o.total||0;var pct=(o.pct==null)?(n?Math.round(c/n*100):0):+o.pct;var passed=(o.passed==null)?null:!!o.passed;var good=passed===null?pct>=(o.passPct||60):passed;var st=!o.logged?'guest':(passed===!1?'fail':'pass');var h,sub,acts='';var cheer=pct>=100?'perfect!':(good?'nice work!':'keep going!');if(st==='guest'){h=c+' / '+n+' correct'+(full?'':' — '+cheer);sub=o.parked?'Sign up free to save this score'+(o.xp?' and your +'+(+o.xp)+' XP':'')+'.':'Sign up free to save your scores, XP and streak.';acts=btn('pri',o.parked?'Save my score — free':'Sign up free',o.signupUrl||'/signup/')+btn('sec','Try again','','retry')+(full?(o.levelUrl?btn('ghost','Find my level',o.levelUrl):''):btn('ghost','Log in',o.loginUrl||'/login/'))}else if(st==='fail'){h=c+' / '+n+' — almost there';sub='You need '+(o.passPct||60)+'% to pass. '+(o.lessonUrl?'Review the lesson and try again.':'Try again when you are ready.');acts=(o.lessonUrl?btn('pri','Review the lesson',o.lessonUrl):'')+btn(o.lessonUrl?'sec':'pri','Try again','','retry')}else{h=c+' / '+n+' correct — '+(full?(passed?'passed!':cheer):cheer);var bits=[];if(o.level){bits.push(lv(o.level))}
65if(o.xp){bits.push('+'+(+o.xp)+' XP')}
66if(o.streak>=1){bits.push(o.streak+'-day streak')}
67sub=bits.join(' · ');acts=(o.nextUrl?btn('pri',o.nextLabel||'Next test &rarr;',o.nextUrl):'')+btn(o.nextUrl?'sec':'pri','Try again','','retry')+(full?btn('ghost',SHARE+' Share','','share'):'')}
68var rev='';if(full&&o.review&&o.review.length){var li='';for(var i=0;i<o.review.length;i++){var r=o.review[i];li+='<li class="'+(r.ok?'ok':'no')+'"><span aria-hidden="true">'+(r.ok?'✓':'✗')+'</span><a href="'+esc(r.href)+'">Question '+(+r.n)+'<span class="eslr-sr">'+(r.ok?' — correct':' — wrong')+'</span></a></li>'}
69rev='<details class="eslr-rev" open><summary>Review answers</summary><ol>'+li+'</ol></details>'}
70var wrong=n-c,strip='';if(!o.paid&&o.proUrl){strip='<p class="eslr-strip"><b>Pro</b><span>'+(o.logged&&wrong>0?'Pro saves '+(wrong===1?'this mistake':'these '+wrong+' mistakes')+' to your notebook.':'Pro keeps your mistakes and builds your plan.')+'</span><a href="'+esc(o.proUrl)+'">See Pro &rarr;</a></p>'}
71var login=(st==='guest'&&full&&o.loginUrl)?'<p class="eslr-login">Already have an account? <a href="'+esc(o.loginUrl)+'">Log in</a></p>':'';if(st!=='pass'&&!full&&o.nextUrl){login+='<p class="eslr-login"><a href="'+esc(o.nextUrl)+'">'+(o.nextLabel||'Next test &rarr;')+'</a></p>'}
72var art=(full&&o.art)?'<div class="eslr-art"><img src="'+esc(o.art)+'" width="200" height="150" alt="" loading="lazy"></div>':'';return'<section class="eslr eslr--'+(full?'full':'mini')+' eslr--'+st+'" tabindex="-1" aria-label="Your result">'+art+'<div class="eslr-top">'+ring(pct,good)+'<div><'+hl+' class="eslr-h">'+h+'</'+hl+'>'+(sub?'<p class="eslr-sub">'+sub+'</p>':'')+'</div></div>'+rev+strip+'<div class="eslr-actions">'+acts+'</div>'+login+(o.extra||'')+'</section>'}
73function render(el,o){if(!el){return null}
74el.innerHTML=eslResultHtml(o);el.hidden=!1;var box=el.querySelector('.eslr');el.addEventListener('click',function(e){var b=e.target.closest?e.target.closest('[data-eslr]'):null;if(!b){return}
75var act=b.getAttribute('data-eslr');if(act==='retry'){if(o&&typeof o.onRetry==='function'){o.onRetry()}else{window.location.reload()}}
76if(act==='share'){var url=(o&&o.shareUrl)||String(location.href).split('#')[0].split('?')[0];var done=function(){b.innerHTML='Link copied'};
76if(navigator.share){navigator.share({title:document.title,url:url})['catch'](function(){})}else if(navigator.clipboard&&navigator.clipboard.writeText){navigator.clipboard.writeText(url).then(done,done)}else{done()}}});return box}
77window.eslResult={html:eslResultHtml,render:render}})()

Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.