<script>
class MangaNav {static globalArr=null ;static globalCache={};static instances=[];static prefetchedUrls={};static _hasPopstate=!1 ;constructor (e){this .config=e,this .arr=[],this .cache=MangaNav.globalCache,this .nextUrl=null ,this .prevUrl=null ,this .homeUrl=null ,this .instanceId=Math.random().toString(36 ).substr(2 ,9 ),MangaNav.instances.push(this )}run(){let e=this .config.selector;this .tag_label=document.querySelector(e.tag_label),this .tag_label&&(this .config.cat=this .tag_label.dataset.label,this .outputEls=Array.from(document.querySelectorAll(e.output)),this .outputEls.length&&(this .outputEls.forEach(e=>this .createControls(e)),MangaNav.globalArr?this .buildGlobal():this .xhr(),window.addEventListener("popstate" ,()=>{let e=location.pathname,t=MangaNav.globalArr?.find(t=>new URL(t.url).pathname===e);t&&MangaNav.instances.forEach(e=>e.loadImages(t.url))})))}createControls(e){let t=document.createElement("div" );t.innerHTML=this .config.html.nav,e.appendChild(t.firstElementChild);let r=e.querySelector(this .config.selector.select);r.addEventListener("change" ,e=>this .loadImages(e.target.value))}xhr(){let{site:e,max:t,textError:r}=this .config,a=encodeURIComponent(this .config.cat),l=`${e}/feeds/posts/summary/-/${a}?alt=json&max-results=${t}`,s=new URL(e||location.origin).origin===location.origin;(s?fetch(`${l}&start-index=1 `).then(e=>e.json()):this .jsonpRequest(`${l}&start-index=1 `)).then(e=>{let r=+e.feed.openSearch$totalResults.$t,a=Math.ceil(r/t),n=[];for (let i=0 ;i<a;i++){let h=`${l}&start-index=${i*t+1 }`;n.push(s?fetch(h).then(e=>e.json()):this .jsonpRequest(h))}return Promise.all(n)}).then(e=>{MangaNav.globalArr=e.flatMap(e=>e.feed.entry||[]).map(e=>({title:e.title.$t,date:e.published.$t,url:e.link.find(e=>"alternate" ===e.rel).href,categories:e.category?.map(e=>e.term)||[]})).sort((e,t)=>new Date(t.date)-new Date(e.date)),this .buildGlobal()}).catch (()=>this .showError(r))}jsonpRequest(e){return new Promise((t,r)=>{let a=`cb_${Date.now()}`;window[a]=e=>{t(e),delete window[a],l.remove()};let l=document.createElement("script" );l.src=`${e}&callback=${a}`,l.onerror=()=>{r(),delete window[a],l.remove()},document.body.appendChild(l)})}buildGlobal(){this .arr=MangaNav.globalArr.filter(e=>!e.categories.includes("Series" )).reverse();let e=MangaNav.globalArr.find(e=>e.categories.includes("Series" ));this .homeUrl=e?.url||MangaNav.globalArr[MangaNav.globalArr.length-1 ].url,this .processFeed()}processFeed(){let e=this .arr.map((e,t)=>{let r=e.title.match(/chapter\s*\d+(\.\d+)?/i),a=r?r[0 ].replace(/chapter/i,"Chapter" ):`Chapter ${t+1 }`;return `<option value="${e.url} " >${a}</option>`}).join("" ),t=0 ,r=this .config.selector.select;this .outputEls.forEach(a=>{let l=a.querySelector(r);l.innerHTML=e;let s=this .arr.findIndex(e=>new URL(e.url).pathname===location.pathname);t=s>-1 ?s:0 ,l.selectedIndex=t}),this .loadImages(this .arr[t].url)}renderNextPrevLinks(){[this .prevUrl,this .nextUrl].forEach(e=>{e&&!MangaNav.prefetchedUrls[e]&&(MangaNav.prefetchedUrls[e]=!0 ,this .loadImages(e,!0 ))});let e=this .prevUrl?`<a href="#" data -url="${this.prevUrl} " class ="prev-link" >Prev</a>`:"" ,t=`<a href="${this.homeUrl} " class ="home-link" >Home</a>`,r=this .nextUrl?`<a href="#" data -url="${this.nextUrl} " class ="next-link" >Next</a>`:"" ,a=`${e} ${t} ${r}`;this .outputEls.forEach(e=>{let t=e.querySelector(this .config.selector.nav_box);t.innerHTML=a,t.querySelectorAll("a[data-url]" ).forEach(e=>{e.onclick=t=>{t.preventDefault(),this .syncAll(e.dataset.url)}})})}syncAll(e){MangaNav.instances.forEach(t=>t.loadImages(e))}loadImages(e,t=!1 ){let r=document.querySelector(this .config.selector.output_chapter);if (r&&!t&&(r.innerHTML=[,,,,,].fill(this .config.html.skeleton).join("" )),this .cache[e]){t||(this .renderImages(this .cache[e]),this .updateState(e));return }fetch(`${e}`).then(e=>e.text()).then(r=>{let a=new DOMParser().parseFromString(r,"text/html" ),l=Array.from(a.querySelectorAll(this .config.selector.postbody)),s=l.map(e=>e.outerHTML);this .cache[e]=s,t||(this .renderImages(s),this .updateState(e))}).catch (()=>this .showError(this .config.textError))}prefetchImages(e){if (!e)return ;let t=document.createElement("a" );t.href=e;let r=new Image;r.src=t.href}updateState(e){history.pushState(null ,"" ,new URL(e).pathname),this .outputEls.forEach(t=>{let r=t.querySelector(this .config.selector.select);r&&(r.value=e)});let t=this .arr.findIndex(t=>new URL(t.url).pathname===new URL(e).pathname);this .nextUrl=this .arr[t+1 ]?.url||null ,this .prevUrl=this .arr[t-1 ]?.url||null ,this .prefetchImages(this .nextUrl),this .renderNextPrevLinks(),this .scrollToOutputChapter()}renderImages(e){let t=document.querySelector(this .config.selector.output_chapter);if (!t)return ;let r=document.createDocumentFragment();e.forEach(e=>{let t=document.createElement("div" );t.innerHTML=e,r.appendChild(t.firstElementChild)}),t.innerHTML="" ,t.appendChild(r)}scrollToOutputChapter(){let e=document.querySelector(this .config.selector.output_chapter);e&&e.scrollIntoView({behavior:"smooth" ,block:"start" })}showError(e){let t=document.querySelector(this .config.selector.output_chapter);t&&(t.textContent=e)}}
document.addEventListener('DOMContentLoaded' , () => {
const configNextprev = {
max: 30 ,
site: "" ,
selector: {
tag_label: '.nextJs' ,
output: '.nextJs' ,
postbody: '#output_chapter img' ,
output_chapter: '#output_chapter' ,
select: '.chapter-select' ,
nav_box: '.nextprev_ouput'
},
html: {
nav: `
<div class ="manganav" >
<div class ="nextprevJs_navigasi" >
<select class ="chapter-select" ></select>
<div class ="nextprev_ouput" ></div>
</div>
</div>
`,
skeleton: `<div class ="skeleton" ></div>`
},
textError: 'Error loading chapter'
};
new MangaNav(configNextprev).run();
});
</script>
Apa ada live demo untuk skrip ini?
karena live demo pakai proxy jadi agak lambat dibandingkan tanpa proxy.
kalau ada kabel lain seperti "project" dll
bisa ditambahkan ke dalam sini
<b:with value='["Chapter", "NovelChapter", "MangaChapter"]' var='checkLabel'>
<b:with value='["Chapter", "Sub"]' var='checkLabel'>
Jangan masukan label One Piece disitu.