CircleBase 晴天艦
サンプル作品A

FANZA

サンプル作品A

発売日
2026-05-01
形式
CG集
内容
CG40枚
¥1,320
FANZAで購入

※FANZA・DLsiteの購入リンクはアフィリエイトリンクです

晴天艦の作品

注入を構造的に無害化(URL出所に防御を依存させない) const SAMPLES = ["https:\/\/pics.dmm.co.jp\/digital\/doujin\/abc001\/abc001jp-1.jpg"]; const TOTAL = SAMPLES.length; // CTAスライドは TOTAL 番目(0-indexed: 0 ~ TOTAL-1 が画像, TOTAL が CTA) const PAGES = TOTAL + 1; // 画像枚数 + CTAスライド let current = 0; const overlay = document.getElementById('js-reader-overlay'); const imgWrap = document.getElementById('js-reader-img-wrap'); const imgEl = document.getElementById('js-reader-img'); const spinner = document.getElementById('js-reader-spinner'); const ctaEl = document.getElementById('js-reader-cta'); const prevBtn = document.getElementById('js-reader-prev'); const nextBtn = document.getElementById('js-reader-next'); const closeBtn = document.getElementById('js-reader-close'); const counter = document.getElementById('js-reader-counter'); const openBtn = document.getElementById('js-reader-open'); function showSpinner() { spinner.style.display = 'block'; imgEl.classList.remove('is-loaded'); } function hideSpinner() { spinner.style.display = 'none'; imgEl.classList.add('is-loaded'); } function render(index) { current = Math.max(0, Math.min(PAGES - 1, index)); if (current < TOTAL) { // フェードアウト → 画像差し替え → フェードイン imgEl.classList.remove('reader-img-visible'); imgEl.hidden = false; ctaEl.hidden = true; showSpinner(); imgEl.alt = (current + 1) + ' / ' + TOTAL + ' ページ'; const newSrc = SAMPLES[current]; imgEl.onload = () => { hideSpinner(); imgEl.classList.add('reader-img-visible'); }; imgEl.onerror = () => { hideSpinner(); imgEl.classList.add('reader-img-visible'); }; imgEl.src = newSrc; // 次ページの先読み(存在時のみ。Image()のsrc代入のみで保存しない) if (current + 1 < TOTAL) { new Image().src = SAMPLES[current + 1]; } } else { imgEl.hidden = true; ctaEl.hidden = false; } if (current < TOTAL) { counter.textContent = (current + 1) + ' / ' + TOTAL; } else { counter.textContent = '試し読み終了'; } prevBtn.disabled = (current === 0); nextBtn.disabled = (current === PAGES - 1); } const mainEl = document.querySelector('main'); function open(startIndex) { render(startIndex || 0); overlay.classList.add('is-open'); document.body.style.overflow = 'hidden'; // aria-modal の契約: 背景をフォーカス・読み上げ対象から外す(簡易フォーカストラップ) if (mainEl) mainEl.setAttribute('inert', ''); closeBtn.focus(); } function close() { overlay.classList.remove('is-open'); document.body.style.overflow = ''; if (mainEl) mainEl.removeAttribute('inert'); if (openBtn) openBtn.focus(); } // ボタン操作 if (openBtn) openBtn.addEventListener('click', () => open(0)); closeBtn.addEventListener('click', close); prevBtn.addEventListener('click', () => render(current - 1)); nextBtn.addEventListener('click', () => render(current + 1)); // 画像クリックで次へ imgEl.addEventListener('click', () => render(current + 1)); // キーボード操作 document.addEventListener('keydown', (e) => { if (!overlay.classList.contains('is-open')) return; if (e.key === 'ArrowRight' || e.key === 'ArrowDown') { e.preventDefault(); render(current + 1); } else if (e.key === 'ArrowLeft' || e.key === 'ArrowUp') { e.preventDefault(); render(current - 1); } else if (e.key === 'Escape') close(); }); // オーバーレイ背景クリックで閉じる overlay.addEventListener('click', (e) => { if (e.target === overlay) close(); }); // ?read=1 の場合はリーダーを自動起動 })();