1async function initForthcoming(articleList) { 2 const container = document.querySelector('.forthcoming .content-row'); 3 if (!container || !articleList) return; 4 5 // 1. Skeleton UI 미리 ìì± (리ì¤í¸ ê°ìë§í¼) 6 articleList.forEach((item, index) => { 7 if (item.articleType) { 8 const subHeadingHtml = `<h6 class="AOPSubheading">${item.articleType}</h6>`; 9 container.insertAdjacentHTML('beforeend', subHeadingHtml); 10 } else { 11 const skeletonHtml = ` 12 <div class="articleBox card border-0" id="article-slot-${index}"> 13 <div class="row gx-3 gy-3"> 14 <div class="col-md-12"> 15 <div class="skeleton skeleton-img"></div> 16 </div> 17 <div class="col-md-12"> 18 <div class="content"> 19 <div class="skeleton skeleton-text" style="width:30%"></div> 20 <div class="skeleton skeleton-title"></div> 21 <div class="skeleton skeleton-text"></div> 22 <div class="skeleton skeleton-text" style="width:50%"></div> 23 </div> 24 </div> 25 </div> 26 </div> 27 `; 28 container.insertAdjacentHTML('beforeend', skeletonHtml); 29 } 30 }); 31 32 // ì ë ¬ì© ë¹ ë°ì¤ 미리 ì½ì (2ê°) 33 const preEmptyHtml = ` 34 <div class="articleBox card border-0 empty-box" style="visibility:hidden; height:0; margin:0!important; padding:0;"></div> 35 <div class="articleBox card border-0 empty-box" style="visibility:hidden; height:0; margin:0!important; padding:0;"></div>`; 36 container.insertAdjacentHTML('beforeend', preEmptyHtml); 37 38 39 // 2. ì¤í ì ëµ ë¶í 40 const PRIORITY_COUNT = 3; // 먼ì ì²ë¦¬í ê°ì 41 const priorityItems = articleList.slice(0, PRIORITY_COUNT); 42 const backgroundItems = articleList.slice(PRIORITY_COUNT); 43 44 /** 45 * A. ìì 3í¸: ë³ë ¬ ì²ë¦¬ (ì¦ì ë ëë§) 46 */ 47 const priorityPromises = priorityItems.map(async (item, index) => { 48 if (!item.doi) return null; 49 try { 50 const data = await fetchForthcomingArticleData(item.doi, item.im, item.sub); 51 updateArticleSlot(index, data); // ìë£ëë ëë¡ ì¦ì íë©´ ì ë°ì´í¸ 52 } catch (err) { 53 updateArticleSlot(index, { error: true, doi: item.doi }); 54 } 55 }); 56 57 58 // ì°ì ìì ìì ì´ ëª¨ë ììë¨ (ìë£ë¥¼ 기ë¤ë¦¬ì§ ìê³ ë°±ê·¸ë¼ì´ë 루í ìì½ ê°ë¥) 59 // íì§ë§ ì´ê¸° íë©´ì ìì ì±ì ìí´ ì°ì ìì ìë£ë¥¼ 기ë¤ë¦° í ë머ì§ë¥¼ ë리ë ê²ì´ ì¢ìµëë¤. 60 await Promise.all(priorityPromises); 61 62 /** 63 * B. ë머ì§: ìì°¨ ì²ë¦¬ (íëì© ì°¨ë¡ëë¡) 64 * for...of 문ì ì¬ì©íë©´ awaitê° ê±¸ë¦´ ëë§ë¤ ë¤ì 루íë¡ ëì´ê°ê¸° ì ì ë기í©ëë¤. 65 */ 66 for (let i = 0; i < backgroundItems.length; i++) { 67 const item = backgroundItems[i]; 68 const originalIndex = i + PRIORITY_COUNT; // ì ì²´ 리ì¤í¸ììì ì¸ë±ì¤ ê³ì° 69 70 if (!item.doi) continue; 71 72 try { 73 // ì´ì ìì²ì´ ëëì¼ ë¤ì ìì²ì´ ììë¨ (ìë² ë¶í ë°©ì§ ë° ìì ë³´ì¥) 74 const data = await fetchForthcomingArticleData(item.doi, item.im, item.sub); 75 updateArticleSlot(originalIndex, data); 76 } catch (err) { 77 updateArticleSlot(originalIndex, { error: true, doi: item.doi }); 78 } 79 } 80 81} 82 83// ë°ì´í°ë§ ê°ì ¸ì¤ë ìì íì± í¨ì (UI ì¡°ì ì ì¸) 84async function fetchForthcomingArticleData(doi, imInput, subsubject) { 85 const journalID = '0161NRP'; 86 const journalAcron = 'nrp' 87 88 const urlsToTry = [ 89 `https://e-nrp.org/DOIx.php?id=${doi}`, 90 `https://www.e-nrp.org/DOIx.php?id=${doi}` 91 ]; 92 93 let response; 94 let finalUrl = ""; 95 96 // 2. ì±ê³µí ëê¹ì§ ìì°¨ì ì¼ë¡ ìëí©ëë¤. 97 for (const url of urlsToTry) { 98 try { 99 const res = await fetch(url); 100 if (res.ok) { 101 response = res; 102 finalUrl = url; 103 break; // ì±ê³µíë©´ 루í ì¢ ë£ 104 } 105 } catch (err) { 106 console.warn(`${url} ì ì ì¤í¨, ë¤ì 주ì ìë ì¤...`); 107 } 108 } 109 110 if (!response) { 111 console.error("모ë URL ì ìì ì¤í¨íìµëë¤."); 112 return; 113 } 114 115 try { 116 const htmlText = await response.text(); 117 const parser = new DOMParser(); 118 const doc = parser.parseFromString(htmlText, "text/html"); 119 120 // 기본 ë°ì´í° í ë¹ 121 let frontMeta = doc.querySelector("#article-front-meta-left")?.innerText || ""; 122 let vol = "", page = "", epub = ""; 123 124 if (frontMeta.includes('.')) { 125 vol = frontMeta.split('.')[1].trim().split(';')[1].split(':')[0]; 126 page = frontMeta.split('.')[1].trim().split(':')[1].split('-')[0]; 127 epub = frontMeta.split('.')[4].trim() 128 } 129 130 let im = imInput;
131 let imgDisplay = ""; 132 if (!im) { 133 // 1. Graphical Abstract ì²´í¬ 134 const headers = Array.from(doc.querySelectorAll('.article-section-header h2')); 135 const hasGraphicalAbstract = headers.some(h => h.innerText.toLowerCase().includes('graphical abstract')); 136 137 if (hasGraphicalAbstract) { 138 im = "abf001"; 139 } else { 140 // 2. Figures ì²´í¬ 141 const portletHeaders = Array.from(doc.querySelectorAll('.porlet h5')); 142 const hasFigures = portletHeaders.some(h => h.innerText.toLowerCase().includes('figures')); 143 const hasTables = portletHeaders.some(h => h.innerText.toLowerCase().includes('tables')); 144 145 if (hasFigures) { 146 im = "g001-l"; 147 } else if (hasTables) { 148 im = "i001-l"; 149 } else { 150 // ë ë¤ ìì ê²½ì° 151 im = "xxxx"; 152 imgDisplay = " d-none"; // ë¶í¸ì¤í¸ë© í´ëì¤ ëë CSS í´ëì¤ 153 } 154 } 155 } 156 157 const citeButton = doc.querySelector('.CiteDialog'); 158 let author = ""; 159 const metaJournal = doc.querySelector('meta[name="citation_journal_title"]')?.getAttribute('content')?.trim(); 160 161 162 // 1. data ìì±ìì ìí¸íë í ì¤í¸ ê°ì ¸ì¤ê¸° 163 const encodedCitation = citeButton.getAttribute('data-article-citation'); 164 165 if (encodedCitation) { 166 try { 167 // 2. Base64 ëì½ë© (atob í¨ì ì¬ì©) 168 // ì¸ì½ë©ë 문ìì´ ë´ë¶ì HTML íê·¸ë í¹ì문ìê° ìì¬ ìì ì ìì¼ë¯ë¡ ì²ë¦¬ 169 const decodedText = decodeURIComponent(escape(window.atob(encodedCitation))); 170
171 // 3. ëì½ë©ë í ì¤í¸ìì 첫 ë²ì§¸ ë§ì¹¨í(.)ê¹ì§ ì르기 172 author = decodedText.split('.')[0].trim() + "."; 173 174 // 4. ì¶ì¶ë í ì¤í¸ ìì íì ì§ëª ì´ í¬í¨ëì´ ìë¤ë©´ ì´í¤ë¦ì²´ë¡ ì¹í 175 if (author.includes(metaJournal)) { 176 // í´ë¹ íì ì§ëª ë¶ë¶ë§ <i>íê·¸ë¡ ê°ì¸ê¸° 177 author = author.replace(metaJournal, `<i>${metaJournal}</i>`); 178 } 179 180 } catch (e) { 181 console.error("Base64 ëì½ë© ì¤í¨:", e); 182 // ëì½ë© ì¤í¨ ì ëìì¼ë¡ ë©íë°ì´í° ì¬ì© 183 const metaAuthor = doc.querySelector('meta[name="citation_author"]')?.content; 184 author = metaAuthor ? metaAuthor + "." : "Author Unknown."; 185 } 186 } 187 188 let subject = doc.querySelector('.article-type')?.innerText; 189 190 // 1. íì´ì§ ë´ ëª¨ë <script> í그를 ê²ì¬ 191 const scripts = Array.from(doc.querySelectorAll('script')); 192 const typeScript = scripts.find(s => s.textContent.includes('document.getElementsByClassName("article-type")[0].innerHTML')); 193 194 if (typeScript) { 195 // ì ê·ííìì¼ë¡ "Research Article" ë¶ë¶ë§ ì¶ì¶ 196 // .innerHTML = "..." ëë .innerHTML = '...' íí를 모ë ì°¾ì 197 const match = typeScript.textContent.match(/\.innerHTML\s*=\s*["'](.+?)["']/); 198 if (match && match[1]) { 199 subject = match[1]; 200 } 201 } 202 203 // 본문 ííì ë°ë¼ absë§ ì°ê²°í ë ¼ë¬¸ì¸ì§ íì¸ 204 const bodyElement = doc.querySelector('#article-level-0-body'); 205 let isAbsOnly = false; 206 207 if (!bodyElement) { 208 isAbsOnly = true; 209 } else { 210 const children = bodyElement.children; 211 const hasOnlySupplementary = (children.length === 1 && children[0].id === 'supplementary-material'); 212 213 const textContent = bodyElement.innerText.trim(); 214 if (hasOnlySupplementary || textContent.length < 50) { 215 isAbsOnly = true; 216 } 217 } 218 219 let displayLink = `https://doi.org/${doi}`; 220 let displayText = displayLink; 221 222 if (isAbsOnly) { 223 epub = epub.replace('Published ', 'Posted '); 224 displayLink = finalUrl; 225 displayText = 'Abstract'; 226 } 227 228 229 // ììì© ë°ì´í° ê°ì²´ ë°í 230 return { 231 imgDisplay: imgDisplay, 232 imgSrc: `../ArticleImage/${journalID}/${journalAcron}-${vol}-${page}-${im}.jpg` || '', 233 subject: subject, 234 subsubject: subsubject, 235 title: doc.querySelector('.article-title .content-title')?.innerHTML || '', 236 author: author, 237 history: doc.querySelector('.article-received-accepted-date')?.innerText || '', 238 epub: epub, 239 link: finalUrl, 240 doi: doi, 241 page: page, 242 displayLink: displayLink, 243 displayText: displayText 244 }; 245 } catch (e) { 246 return { title: "Error loading data", doi: doi }; 247 } 248} 249 250function updateArticleSlot(index, data) { 251 const slot = document.getElementById(`article-slot-${index}`); 252 if (!slot) return; 253 254 let articleHtml = ""; 255 256 if (data.error) { 257 // [ë¡ë ì¤í¨ ì UI] 258 articleHtml = ` 259 <div class="row gx-3 gy-3 error-box"> 260 <div class="col-12 text-center py-4"> 261 <div class="error-icon" style="font-size: 24px;">â ï¸</div> 262 <div class="error-text" style="color: #888; font-size: 13px; margin-top: 10px;"> 263 Failed to load data.<br> 264 <small><a href="https://doi.org/${data.doi}" target="_blank">${data.doi}</a></small> 265 </div> 266 </div> 267 </div> 268 `; 269 } else { 270 // [ì ì ë¡ë ì UI] 271 articleHtml = ` 272 <div class="row gx-3 gy-3"> 273 <div class="col-md-12${data.imgDisplay}"> 274 <div class="thumbnail"><img class="img-fluid myImg" src="${data.imgSrc}"/></div> 275 </div> 276 <div class="col-md-12"> 277 <div class="content"> 278 <div class="d-flex justify-content-between"> 279 <div class="subject">${data.subject}</div> 280 <div class="sub_articleType">Forthcoming</div> 281 </div> 282 <div class="articleType"></div> 283 <div class="card-text title"><a href="${data.link}">${data.title}</a></div> 284 <div class="card-text author">${data.author}</div> 285 <div class="card-text disc"> 286 <div class="history">${data.history}</div> 287 <div class="epub">${data.epub}</div> 288 <div class="doi"><a href="${data.link}">Abstract + Full Text</a></div> 289 </div> 290 </div> 291 </div> 292 </div> 293 `; 294 } 295 296 slot.innerHTML = articleHtml; 297 slot.classList.add('loaded'); 298}
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.