1/** 2 * KomeKaigi 2026 ã¹ãã¼ã«ã¼è¡¨ç¤º 3 * data/speakers.json ãèªã¿è¾¼ã¿ #speakers ã»ã¯ã·ã§ã³ã«æç»ããã 4 * ãã¼ã¿ãç¡ãã»åå¾ã«å¤±æããå ´åã¯ã»ã¯ã·ã§ã³ã¨ã¡ãã¥ã¼é ç®ãé表示ã®ã¾ã¾ã«ããã 5 */ 6(function () { 7 'use strict'; 8 9 const DATA_URL = 'data/speakers.json'; 10 11 const section = document.getElementById('speakers'); 12 const list = section && section.querySelector('.speaker-list'); 13 const menuItem = document.querySelector('[data-speakers-menu]'); 14 15 if (!section || !list) { 16 return; 17 } 18 19 const el = (tag, className, text) => { 20 const node = document.createElement(tag); 21 if (className) node.className = className; 22 if (text != null) node.textContent = text; 23 return node; 24 }; 25 26 // BudouX ã® <budoux-ja> ã§å ã¿ãæç¯ã®éä¸ã§æ¹è¡ãããªãããã«ããã 27 // BudouX ãèªã¿è¾¼ããªãã£ãå ´åãé常ã®ããã¹ãã¨ãã¦è¡¨ç¤ºãããã 28 const phrase = (text) => el('budoux-ja', null, text); 29 30 const createSpeaker = (speaker, session) => { 31 const article = el('article', 'speaker'); 32 33 const photo = el('div', 'speaker-photo'); 34 const img = el('img'); 35 if (speaker.image) img.src = speaker.image; 36 img.alt = speaker.name || ''; 37 img.width = 180; 38 img.height = 180; 39 img.loading = 'lazy'; 40 photo.appendChild(img); 41 42 const body = el('div', 'speaker-body'); 43 44 const type = el('p', 'speaker-type'); 45 if (session.typeEn) type.appendChild(el('span', 'speaker-type-en', session.typeEn)); 46 if (session.type) type.appendChild(el('span', 'speaker-type-ja', session.type)); 47 body.appendChild(type); 48 49 // nameSub(èªã¿ä»®åããã³ãã«ãã¼ã )ã¯æ°åã®æ¨ªã«å°ããæ·»ããæãè¿ãã¨ãã¯ã¾ã¨ãã¦æ¬¡ã®è¡ã¸éã 50 const name = el('h3', 'speaker-name'); 51 name.appendChild(el('span', 'speaker-name-main', speaker.name)); 52 if (speaker.nameSub) name.appendChild(el('span', 'speaker-name-sub', speaker.nameSub)); 53 body.appendChild(name); 54 55 if (speaker.role) { 56 const role = el('p', 'speaker-role'); 57 role.appendChild(phrase(speaker.role)); 58 body.appendChild(role); 59 } 60 61 // description ã¯æ®µè½ãã¨ã®é å(æåå1ã¤ã§ãå¯) 62 const paragraphs = [].concat(speaker.description || []).filter(Boolean); 63 if (paragraphs.length > 0) { 64 const profile = el('div', 'speaker-profile'); 65 paragraphs.forEach((text) => { 66 const p = el('p'); 67 p.appendChild(phrase(text)); 68 profile.appendChild(p); 69 }); 70 body.appendChild(profile); 71 } 72 73 article.append(photo, body); 74 return article; 75 }; 76 77 const render = (sessions) => { 78 const items = sessions.flatMap((session) => 79 (session.speakers || []).map((speaker) => createSpeaker(speaker, session)) 80 ); 81 82 if (items.length === 0) { 83 return; 84 } 85 86 list.replaceChildren(...items); 87 section.hidden = false; 88 if (menuItem) menuItem.hidden = false; 89 }; 90 91 fetch(DATA_URL) 92 .then((response) => { 93 if (!response.ok) { 94 throw new Error(`HTTP error! status: ${response.status}`); 95 } 96 return response.json(); 97 }) 98 .then((data) => render(data.sessions || [])) 99 .catch((error) => { 100 console.error('ã¹ãã¼ã«ã¼ãã¼ã¿ã®åå¾ã¨ã©ã¼:', error); 101 }); 102})();
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.