'use strict'; /* Manga page: info, follow toggle and the chapter list (books are just separators). */ (async function () { const id = new URLSearchParams(location.search).get('m') || ''; let me, M; try { [me, M] = await Promise.all([api('api/me'), api('api/manga?' + qsa({ m: id }))]); } catch (e) { return showError(e); } topNav(me); document.title = M.title + ' · MangaCircus'; const meta = M.meta || {}, main = $('main'); main.textContent = ''; const TYPE = { rtl: 'Manga · right to left', ltr: 'Comic · left to right', ttb: 'Webtoon · vertical strip' }; const arr = x => (Array.isArray(x) ? x : x ? [x] : []); const follow = h('button', { class: 'btn' }, ''); const drawFollow = () => { follow.textContent = M.following ? '🔔 Notifying you' : 'Notify me about new chapters'; follow.classList.toggle('on', M.following); }; follow.onclick = async () => { M.following = (await api('api/follow', { m: M.id, on: !M.following })).following; drawFollow(); }; drawFollow(); const sources = arr(meta.sources).filter(s => s && s.name); main.append(h('section', { class: 'hero' }, M.cover ? h('img', { src: M.cover, alt: '' }) : null, h('div', { class: 'info' }, h('h1', {}, M.title), arr(meta.altTitles).length ? h('div', { class: 'muted' }, arr(meta.altTitles).join(' · ')) : null, h('div', { class: 'muted' }, [arr(meta.authors).join(', '), meta.status, meta.year, TYPE[M.direction]].filter(Boolean).join(' · ')), h('div', { class: 'chips' }, arr(meta.tags).map(t => h('span', { class: 'chip' }, t))), meta.description ? h('p', { class: 'desc' }, meta.description) : null, sources.length ? h('div', { class: 'sources small' }, h('span', { class: 'muted' }, 'Sources: '), sources.map(s => (safeHref(s.url) ? h('a', { href: safeHref(s.url), target: '_blank', rel: 'noopener noreferrer' }, s.name) : h('span', {}, s.name + ' ')))) : null, h('div', { class: 'actions' }, M.continue ? h('a', { class: 'btn primary', href: readUrl(M.id, M.continue.c, M.continue.v) }, M.continue.text) : null, follow)))); const books = {}; for (const b of M.books) books[b.key] = b; const list = h('section', { class: 'chapters' }); main.append(list); let lastBook = null; for (const ch of M.chapters) { if (ch.book !== lastBook && M.books.length > 1) { const b = books[ch.book]; list.append(h('div', { class: 'book-sep' }, b.label + (b.title ? ' · ' + b.title : ''))); } lastBook = ch.book; list.append(chapterRow(ch)); } function chapterRow(ch) { const wrap = h('div', {}); const panel = h('div', { class: 'versions', hidden: true }); function draw() { const p = ch.progress, done = p && p.done; const state = h('button', { class: 'state' + (done ? ' done' : ''), title: done ? 'Mark as unread' : 'Mark as read' }, done ? '✓ read' : p ? `page ${p.p + 1} / ${p.n}` : `${ch.versions[0].pages} p.`); state.onclick = async () => { if (done) { await api('api/unread', { m: M.id, c: ch.id }); ch.progress = null; } else { const v = ch.versions[0]; await api('api/progress', { m: M.id, c: ch.id, v: v.id, p: v.pages - 1, n: v.pages, done: true }); ch.progress = { v: v.id, p: v.pages - 1, n: v.pages, done: true }; } draw(); }; const verBtn = ch.versions.length > 1 ? h('button', { class: 'btn small', onclick: () => { panel.hidden = !panel.hidden; } }, ch.versions.length + ' versions') : null; wrap.textContent = ''; wrap.append(h('div', { class: 'ch' + (done ? ' read' : '') }, h('a', { class: 'ch-main', href: readUrl(M.id, ch.id) }, h('span', { class: 'ch-label' }, ch.label), h('span', { class: 'ch-title' }, ch.title || ''), ch.extra ? h('span', { class: 'tag' }, 'extra') : null), verBtn, state), panel); drawVersions(); } function drawVersions() { panel.textContent = ''; panel.append(h('div', { class: 'muted small', style: 'padding-top:6px' }, 'The best rated version opens by default. Vote to change that for everyone.')); ch.versions.forEach((v, i) => { const vote = async value => { ch.versions = (await api('api/vote', { m: M.id, c: ch.id, v: v.id, value: v.my === value ? 0 : value })).versions; drawVersions(); }; panel.append(h('div', { class: 'ver' }, h('div', { class: 'src' }, safeHref(v.sourceUrl) ? h('a', { href: safeHref(v.sourceUrl), target: '_blank', rel: 'noopener noreferrer' }, v.source || v.id) : h('span', {}, v.source || v.id), i === 0 ? h('span', { class: 'tag', style: 'margin-left:8px' }, 'default') : null, h('div', { class: 'muted small' }, `${v.pages} pages · added ${new Date(v.added).toLocaleDateString()}`)), h('span', { class: 'vote' }, h('button', { class: v.my > 0 ? 'on' : '', title: 'Better', onclick: () => vote(1) }, '▲'), h('b', {}, v.score), h('button', { class: v.my < 0 ? 'on' : '', title: 'Worse', onclick: () => vote(-1) }, '▼')), h('a', { class: 'btn small', href: readUrl(M.id, ch.id, v.id) }, 'Read'))); }); } draw(); return wrap; } })();