course.js 2.8 KB

1234567891011121314151617181920
  1. /* Offline course interactions: file:// search, copy, and keyboard chapter toggles. */
  2. (()=>{
  3. const script=[...document.scripts].find(s=>s.src.endsWith('/graph_assets/course.js'));
  4. const base=script?new URL('../',script.src):new URL('.',location.href);
  5. document.querySelectorAll('.highlight').forEach((box)=>{
  6. if(box.querySelector('.course-copy'))return;
  7. const code=box.querySelector('code')||box.querySelector('pre');if(!code)return;
  8. const btn=document.createElement('button');btn.type='button';btn.className='course-copy';btn.textContent='复制';btn.setAttribute('aria-label','复制代码');
  9. btn.addEventListener('click',async()=>{const t=code.innerText;try{await navigator.clipboard.writeText(t)}catch(e){const a=document.createElement('textarea');a.value=t;document.body.appendChild(a);a.select();document.execCommand('copy');a.remove()}btn.textContent='已复制';setTimeout(()=>btn.textContent='复制',1200)});box.appendChild(btn);
  10. });
  11. document.querySelectorAll('label.md-nav__link[for]').forEach(label=>label.addEventListener('keydown',e=>{if(e.key==='Enter'||e.key===' '){e.preventDefault();label.click()}}));
  12. const old=document.querySelector('[data-md-component="search-query"]');
  13. if(!old)return;
  14. // Clone the input to avoid duplicate worker-driven handlers under file://.
  15. const input=old.cloneNode(true);old.replaceWith(input);
  16. const area=document.querySelector('[data-md-component="search-result"]');
  17. if(!area)return;
  18. function render(){const q=input.value.trim().toLocaleLowerCase();area.replaceChildren();const title=document.createElement('div');title.className='md-search-result__meta';area.appendChild(title);if(!q){title.textContent='输入关键字搜索全部课程(离线可用)';return}const words=q.split(/\s+/);const results=(window.COURSE_SEARCH_DOCS||[]).map(d=>({d,score:words.reduce((n,w)=>n+(d.title.toLocaleLowerCase().includes(w)?10:0)+(d.text.toLocaleLowerCase().includes(w)?1:0),0)})).filter(x=>words.every(w=>(x.d.title+' '+x.d.text).toLocaleLowerCase().includes(w))).sort((a,b)=>b.score-a.score).slice(0,30);title.textContent=`找到 ${results.length} 个结果`;for(const {d}of results){const row=document.createElement('div');row.className='course-result';const a=document.createElement('a');a.href=new URL(d.location,base).href;a.textContent=d.title;row.appendChild(a);const p=document.createElement('p');const pos=d.text.toLocaleLowerCase().indexOf(words[0]);p.textContent=(pos>30?'…':'')+d.text.slice(Math.max(0,pos-30),Math.max(0,pos-30)+160)+'…';row.appendChild(p);area.appendChild(row)}}
  19. input.addEventListener('input',render);document.querySelector('.md-search__form')?.addEventListener('submit',e=>e.preventDefault());document.querySelector('.md-search__form')?.addEventListener('reset',()=>setTimeout(render,0));render();
  20. })();