Tipitaka

/* Tripiṭaka Widget (Fallback + Enhanced) */ #trpk-widget.trpk{ –bg:#0b1020; –panel:rgba(255,255,255,.06); –panel2:rgba(255,255,255,.10); –text:rgba(255,255,255,.92); –muted:rgba(255,255,255,.70); –border:rgba(255,255,255,.14); –shadow:0 18px 60px rgba(0,0,0,.45); –focus:rgba(125,211,252,.18); –focusB:rgba(125,211,252,.70); –danger:rgba(244,63,94,.55); –dangerBg:rgba(244,63,94,.10); color:var(–text); background:var(–bg); border:1px solid var(–border); border-radius:16px; overflow:hidden; box-shadow:var(–shadow); max-width:1100px; margin:16px auto; font-family:system-ui,-apple-system,Segoe UI,Roboto,Arial,sans-serif; } #trpk-widget.trpk[data-theme=”light”]{ –bg:#f7f7fb; –panel:rgba(0,0,0,.04); –panel2:rgba(0,0,0,.06); –text:rgba(0,0,0,.88); –muted:rgba(0,0,0,.62); –border:rgba(0,0,0,.12); –shadow:0 18px 60px rgba(0,0,0,.12); –focus:rgba(3,105,161,.12); –focusB:rgba(3,105,161,.55); } #trpk-widget a{color:inherit} #trpk-widget .trpk-top{display:flex;gap:12px;align-items:center;justify-content:space-between;padding:12px;border-bottom:1px solid var(–border);background:linear-gradient(180deg,var(–panel2),transparent)} #trpk-widget .trpk-brand{display:flex;gap:10px;align-items:center;min-width:240px} #trpk-widget .trpk-logo{font-size:20px} #trpk-widget .trpk-title{font-weight:900;font-size:14px} #trpk-widget .trpk-sub{font-size:12px;color:var(–muted);margin-top:2px;line-height:1.25} #trpk-widget .trpk-actions{display:flex;gap:8px;flex-wrap:wrap;align-items:center} #trpk-widget .trpk-btn,#trpk-widget .trpk-input,#trpk-widget .trpk-select{ border:1px solid var(–border); background:var(–panel); color:var(–text); border-radius:10px; padding:9px 10px; font:inherit; } #trpk-widget .trpk-btn{cursor:pointer} #trpk-widget .trpk-btn-sm{padding:8px 9px;font-size:12px} #trpk-widget .trpk-input{width:min(260px,44vw);outline:none} #trpk-widget .trpk-input:focus{border-color:var(–focusB);box-shadow:0 0 0 3px var(–focus)} #trpk-widget .trpk-fallback{display:grid;grid-template-columns:330px 1fr;min-height:520px} #trpk-widget .trpk-fb-nav{border-right:1px solid var(–border);padding:10px;background:linear-gradient(180deg,var(–panel),transparent)} #trpk-widget .trpk-fb-hd{font-weight:900;font-size:13px;margin:4px 0 10px} #trpk-widget .trpk-fb-hd2{font-weight:900;font-size:12px;color:var(–muted);margin:14px 0 8px} #trpk-widget .trpk-link{display:block;padding:10px;border:1px solid var(–border);border-radius:12px;background:var(–panel);text-decoration:none;margin-bottom:8px} #trpk-widget .trpk-link:hover{border-color:rgba(125,211,252,.55)} #trpk-widget .trpk-fb-note{font-size:12px;color:var(–muted);line-height:1.35;margin-top:10px} #trpk-widget .trpk-fb-main{padding:10px} #trpk-widget .trpk-iframe{width:100%;height:640px;border:1px solid var(–border);border-radius:14px;background:#fff} #trpk-widget .trpk-app{display:none} #trpk-widget .trpk-body{display:grid;grid-template-columns:360px 1fr;min-height:520px} #trpk-widget .trpk-nav{border-right:1px solid var(–border);background:linear-gradient(180deg,var(–panel),transparent)} #trpk-widget .trpk-navhd{display:flex;gap:8px;align-items:center;justify-content:space-between;padding:10px;border-bottom:1px solid var(–border)} #trpk-widget .trpk-navc{padding:10px;max-height:560px;overflow:auto} #trpk-widget .trpk-leaf{width:100%;text-align:left;border:1px solid var(–border);background:var(–panel);border-radius:12px;padding:10px;margin-top:8px} #trpk-widget .trpk-leaf .t{display:block;font-weight:900;font-size:13px} #trpk-widget .trpk-leaf .m{display:block;color:var(–muted);font-size:12px;margin-top:4px;line-height:1.25} #trpk-widget .trpk-readerhd{display:flex;gap:10px;align-items:flex-start;justify-content:space-between;padding:12px;border-bottom:1px solid var(–border);background:linear-gradient(180deg,var(–panel2),transparent)} #trpk-widget .trpk-crumb{font-size:12px;color:var(–muted)} #trpk-widget .trpk-rt{font-size:14px;font-weight:900;margin-top:6px} #trpk-widget .trpk-tools{display:flex;gap:8px;flex-wrap:wrap;align-items:center} #trpk-widget .trpk-content{padding:14px 12px 20px;max-height:640px;overflow:auto} #trpk-widget .trpk-verse{display:grid;grid-template-columns:56px 1fr;gap:12px;align-items:start;padding:12px;border:1px solid var(–border);border-radius:14px;background:var(–panel);margin-bottom:12px} #trpk-widget .trpk-vn{width:46px;height:34px;border-radius:12px;border:1px solid var(–border);background:transparent;font-weight:900;color:var(–text);cursor:pointer} #trpk-widget .trpk-vt{font-size:14px;line-height:1.55;white-space:pre-wrap} #trpk-widget .trpk-err{display:none;margin:12px;padding:12px;border:1px solid var(–danger);border-radius:12px;background:var(–dangerBg)} #trpk-widget .trpk-toast{position:fixed;left:50%;bottom:22px;transform:translateX(-50%);background:rgba(0,0,0,.75);color:#fff;padding:10px 12px;border-radius:999px;font-size:12px;opacity:0;pointer-events:none;transition:opacity 160ms ease;z-index:999999} #trpk-widget .trpk-toast.on{opacity:1} #trpk-widget .trpk-modal{position:fixed;inset:0;display:none;z-index:999998} #trpk-widget .trpk-modal.on{display:block} #trpk-widget .trpk-backdrop{position:absolute;inset:0;background:rgba(0,0,0,.55)} #trpk-widget .trpk-card{position:absolute;left:50%;top:50%;transform:translate(-50%,-50%);width:min(680px,92vw);max-height:min(600px,86vh);border:1px solid var(–border);border-radius:16px;background:var(–bg);box-shadow:var(–shadow);overflow:hidden} #trpk-widget .trpk-cardhd{display:flex;align-items:center;justify-content:space-between;padding:12px;border-bottom:1px solid var(–border)} #trpk-widget .trpk-cardbd{padding:12px;max-height:520px;overflow:auto} @media (max-width:900px){ #trpk-widget .trpk-fallback{grid-template-columns:1fr} #trpk-widget .trpk-fb-nav{border-right:none;border-bottom:1px solid var(–border)} #trpk-widget .trpk-iframe{height:560px} #trpk-widget .trpk-body{grid-template-columns:1fr} #trpk-widget .trpk-nav{border-right:none;border-bottom:1px solid var(–border)} #trpk-widget .trpk-navc{max-height:260px} } (() => { const root = document.getElementById(“trpk-widget”); if (!root) return; // Theme toggle (works even if API part fails) const setTheme = (t) => root.setAttribute(“data-theme”, t); const themeKey = “trpk_theme_v1”; let theme = localStorage.getItem(themeKey) || root.getAttribute(“data-theme”) || “dark”; setTheme(theme); // UI refs const fallback = document.getElementById(“trpk-fallback”); const app = document.getElementById(“trpk-app”); const navList = document.getElementById(“trpk-navList”); const search = document.getElementById(“trpk-search”); const crumb = document.getElementById(“trpk-crumb”); const rt = document.getElementById(“trpk-rt”); const chapter = document.getElementById(“trpk-chapter”); const prevBtn = document.getElementById(“trpk-prev”); const nextBtn = document.getElementById(“trpk-next”); const copyRefBtn = document.getElementById(“trpk-copyref”); const content = document.getElementById(“trpk-content”); const err = document.getElementById(“trpk-err”); const errmsg = document.getElementById(“trpk-errmsg”); const toastEl = document.getElementById(“trpk-toast”); const modal = document.getElementById(“trpk-modal”); const modalBody = document.getElementById(“trpk-modalBody”); const API = root.dataset.wsapi || “https://en.wikisource.org/w/api.php”; const K = { cont:”trpk_cont_v1″, bms:”trpk_bms_v1″, dnCache:”trpk_dn_cache_v1″ }; const jparse=(s,f)=>{ try{ const v=JSON.parse(s); return v==null?f:v; }catch{ return f; } }; const esc=(s)=>String(s).replace(/&/g,”&”).replace(//g,”>”).replace(/”/g,”"”).replace(/’/g,”'”); const collapse=(s)=>String(s||””).replace(/\s+/g,” “).trim(); const clamp=(n,a,b)=>Math.max(a,Math.min(b,n)); const mem = new Map(); let state = jparse(localStorage.getItem(K.cont), { view:”library” }); let bookmarks = jparse(localStorage.getItem(K.bms), []); const LIBRARY = [ { type:”collection”, id:”dn”, title:”Dīgha Nikāya (Long Discourses)”, note:”List from Portal:Tipitaka/Digha_Nikaya” }, { type:”book”, id:”sbe10″, title:”Sutta Nipāta (SBE Vol. X)”, note:”Wikisource PD edition”, page:”Sacred_Books_of_the_East/Volume_10″ }, { type:”book”, id:”sbe11″, title:”Buddhist Suttas (SBE Vol. XI)”, note:”Wikisource PD edition”, page:”Sacred_Books_of_the_East/Volume_11″ }, { type:”book”, id:”sbe13″, title:”Vinaya Texts (SBE Vol. XIII)”, note:”Wikisource PD edition”, page:”Sacred_Books_of_the_East/Volume_13″ }, { type:”book”, id:”sbe17″, title:”Vinaya Texts (SBE Vol. XVII)”, note:”Wikisource PD edition”, page:”Sacred_Books_of_the_East/Volume_17″ }, { type:”book”, id:”sbe20″, title:”Vinaya Texts (SBE Vol. XX)”, note:”Wikisource PD edition”, page:”Sacred_Books_of_the_East/Volume_20″ }, { type:”book”, id:”portal”, title:”Tipiṭaka Portal (Index)”, note:”Wikisource hub page”, page:”Portal:Tipitaka” } ]; function toast(msg){ if (!toastEl) return; toastEl.textContent = msg; toastEl.classList.add(“on”); setTimeout(()=>toastEl.classList.remove(“on”), 1700); } function showErr(e){ if (err) err.style.display=”block”; if (errmsg) errmsg.textContent = (e && e.message) ? e.message : String(e); } function clearErr(){ if (err) err.style.display=”none”; if (errmsg) errmsg.textContent = “”; } function saveState(){ localStorage.setItem(K.cont, JSON.stringify(state)); } function saveBms(){ localStorage.setItem(K.bms, JSON.stringify(bookmarks)); } async function copyText(text){ try{ if(navigator.clipboard?.writeText){ await navigator.clipboard.writeText(text); return; } }catch{} const ta=document.createElement(“textarea”); ta.value=text; ta.style.position=”fixed”; ta.style.opacity=”0″; document.body.appendChild(ta); ta.select(); document.execCommand(“copy”); document.body.removeChild(ta); } async function apiParseText(page, section){ const key=`t:${page}:${String(section||”0″)}`; if(mem.has(key)) return mem.get(key); const url = API + “?action=parse&format=json&origin=*&page=” + encodeURIComponent(page) + “&prop=text&section=” + encodeURIComponent(String(section||”0″)); const r = await fetch(url, {cache:”no-cache”}); if(!r.ok) throw new Error(“Wikisource API error (“+r.status+”)”); const d = await r.json(); const html = (d?.parse?.text?.[“*”]) || “”; mem.set(key, html); return html; } async function apiParseSections(page){ const key=`s:${page}`; if(mem.has(key)) return mem.get(key); const url = API + “?action=parse&format=json&origin=*&page=” + encodeURIComponent(page) + “&prop=sections”; const r = await fetch(url, {cache:”no-cache”}); if(!r.ok) throw new Error(“Wikisource API error (“+r.status+”)”); const d = await r.json(); const raw = d?.parse?.sections || []; const secs = [{index:”0″, line:”(Full text)”}].concat(raw.map(s=>({index:String(s.index), line:String(s.line)}))); mem.set(key, secs); return secs; } function htmlToBlocks(html){ const tmp=document.createElement(“div”); tmp.innerHTML = html || “”; tmp.querySelectorAll(“sup.reference, span.mw-editsection, .mw-editsection, .reference”).forEach(n=>n.remove()); const blocks=[]; tmp.querySelectorAll(“p, li”).forEach(el=>{ const t = collapse(el.textContent || “”); if (t.length>=3) blocks.push(t); }); if(!blocks.length){ const t = collapse(tmp.textContent || “”); if(t) blocks.push(t); } return blocks; } function setChapterOptions(secs, cur){ if(!chapter) return; if(!secs || secs.length{ const idx=String(s.index), label=s.line || (“Section “+idx); return `${esc(label)}`; }).join(“”); } function currentRef(){ if(state.view!==”page”) return “Wikisource”; const sec = chapter?.selectedOptions?.[0]?.textContent || “”; const base = (state.label||state.title||”Wikisource”).replace(/_/g,” “); return (sec && sec!==”(Full text)”) ? (base+” — “+sec) : base; } function renderBlocks(blocks, refBase){ if(!content) return; if(!blocks?.length){ content.innerHTML = `
No readable text found.
`; return; } content.innerHTML = blocks.map((txt,i)=>{ const n=String(i+1), ref=`${refBase}:${i+1}`; return `
${esc(txt)}
`; }).join(“”); } function filterNav(){ if(!search || !navList) return; const q=(search.value||””).trim().toLowerCase(); const btns=[…navList.querySelectorAll(“button.trpk-leaf”)]; if(!q){ btns.forEach(b=>b.style.display=”block”); return; } btns.forEach(b=>{ b.style.display=(b.textContent||””).toLowerCase().includes(q)?”block”:”none”; }); } async function loadDnList(){ const cached=jparse(localStorage.getItem(K.dnCache),null); if(cached?.items?.length) return cached.items; const html = await apiParseText(“Portal:Tipitaka/Digha_Nikaya”,”0″); const tmp=document.createElement(“div”); tmp.innerHTML=html; const anchors=[…tmp.querySelectorAll(“a”)]; const titles=[]; for(const a of anchors){ const t=a.getAttribute(“title”)||””, href=a.getAttribute(“href”)||””; if(!href.startsWith(“/wiki/”)) continue; if(t.includes(“Portal:”)||t.includes(“Index:”)) continue; if(!t.toLowerCase().includes(“sutta”)) continue; titles.push(t); } const seen=new Set(), uniq=[]; for(const t of titles){ if(seen.has(t)) continue; seen.add(t); uniq.push(t); } const items=uniq.map((t,i)=>({title:t.replace(/ /g,”_”), label:`DN ${i+1} — ${t}`})); localStorage.setItem(K.dnCache, JSON.stringify({at:new Date().toISOString(), items})); return items; } async function openLibrary(){ clearErr(); state={view:”library”}; saveState(); if(crumb) crumb.textContent=”Wikisource”; if(rt) rt.textContent=”Library”; setChapterOptions(null,”0″); if(content) content.innerHTML = `
Select a text from the left.
`; if(navList){ navList.innerHTML = LIBRARY.map(x=>{ return ``; }).join(“”); } filterNav(); } async function openDn(){ clearErr(); state={view:”collection”, id:”dn”}; saveState(); if(crumb) crumb.textContent=”Collection”; if(rt) rt.textContent=”Dīgha Nikāya (DN)”; setChapterOptions(null,”0″); if(content) content.innerHTML = `
Pick a sutta from the left.
`; if(navList) navList.innerHTML = `
Loading DN list…
`; const items = await loadDnList(); if(navList){ navList.innerHTML = items.map(it=>{ return ``; }).join(“”); } filterNav(); } async function openPage(title,label,section){ clearErr(); if(content) content.textContent=”Loading…”; state={view:”page”, title, label:label||title, section:String(section||”0″)}; saveState(); if(crumb) crumb.textContent=”Wikisource”; if(rt) rt.textContent=(state.label||state.title).replace(/_/g,” “); const secs=await apiParseSections(title); setChapterOptions(secs, state.section); const html=await apiParseText(title, state.section); const blocks=htmlToBlocks(html); const secText=chapter?.selectedOptions?.[0]?.textContent||””; const base=(state.label||state.title).replace(/_/g,” “); const refBase=(secText && secText!==”(Full text)”) ? (base+” — “+secText) : base; renderBlocks(blocks, refBase); } function openModal(){ if(!modal) return; modal.classList.add(“on”); modal.setAttribute(“aria-hidden”,”false”); } function closeModal(){ if(!modal) return; modal.classList.remove(“on”); modal.setAttribute(“aria-hidden”,”true”); } function renderBookmarks(){ if(!modalBody) return; if(!bookmarks.length){ modalBody.innerHTML = `
No bookmarks yet. Open a text and press +.
`; return; } modalBody.innerHTML = bookmarks.map(bm=>{ const dt = new Date(bm.createdAt).toLocaleString(); return `
`; }).join(“”); } function addBookmark(){ if(state.view!==”page”){ toast(“Open a text first”); return; } const sec=chapter?.selectedOptions?.[0]?.textContent||””; const base=(state.label||state.title).replace(/_/g,” “); const label=(sec && sec!==”(Full text)”) ? (base+” — “+sec) : base; const id=”bm_”+Math.random().toString(16).slice(2)+”_”+Date.now(); bookmarks.unshift({id, createdAt:new Date().toISOString(), state:{…state}, label}); bookmarks=bookmarks.slice(0,200); saveBms(); toast(“Bookmark added”); } // Buttons (top bar) root.addEventListener(“click”, (e) => { const a = e.target.closest(“[data-trpk-action]”); if (!a) return; const act = a.getAttribute(“data-trpk-action”); if (act === “theme”) { theme = (theme === “dark”) ? “light” : “dark”; localStorage.setItem(themeKey, theme); setTheme(theme); } if (act === “bookmarks”) { renderBookmarks(); openModal(); } if (act === “addbm”) addBookmark(); if (act === “closeModal”) closeModal(); }); search?.addEventListener(“input”, filterNav); copyRefBtn?.addEventListener(“click”, () => { copyText(currentRef()).then(()=>toast(“Copied reference”)).catch(()=>toast(“Copy failed”)); }); prevBtn?.addEventListener(“click”, () => { if(state.view!==”page” || !chapter || chapter.options.length { if(state.view!==”page” || !chapter || chapter.options.length { if(state.view!==”page”) return; state.section = chapter.value; saveState(); openPage(state.title, state.label, state.section).catch(showErr); }); // Delegate clicks (nav + verse copy + bookmark modal) root.addEventListener(“click”, (e) => { const openBtn = e.target.closest(“[data-open]”); if (openBtn) { const payload = jparse(openBtn.getAttribute(“data-open”), null); if (!payload) return; if (payload.type===”collection” && payload.id===”dn”) openDn().catch(showErr); if (payload.type===”book”) { const b = LIBRARY.find(x=>x.id===payload.id && x.type===”book”); if (b) openPage(b.page, b.title, “0”).catch(showErr); } if (payload.type===”page”) openPage(payload.title, payload.label, payload.section||”0″).catch(showErr); return; } const copyBtn = e.target.closest(“[data-copy]”); if (copyBtn) { const n = copyBtn.getAttribute(“data-copy”); const verseEl = root.querySelector(`[data-verse=”${CSS.escape(n)}”]`); if (!verseEl) return; const txt = collapse(verseEl.querySelector(“.trpk-vt”)?.textContent || “”); const ref = verseEl.getAttribute(“data-ref”) || currentRef(); copyText(txt + “\n\n— ” + ref).then(()=>toast(“Copied verse + reference”)).catch(()=>toast(“Copy failed”)); return; } const bmOpen = e.target.closest(“[data-bm-open]”); if (bmOpen) { const id = bmOpen.getAttribute(“data-bm-open”); const bm = bookmarks.find(x=>x.id===id); if (bm) { closeModal(); openPage(bm.state.title, bm.state.label, bm.state.section).catch(showErr); } return; } const bmDel = e.target.closest(“[data-bm-del]”); if (bmDel) { const id = bmDel.getAttribute(“data-bm-del”); bookmarks = bookmarks.filter(x=>x.id!==id); saveBms(); renderBookmarks(); toast(“Bookmark deleted”); } }); // Try to enable enhanced mode. If it fails, fallback remains visible. (async () => { try { // Quick ping const ping = await fetch(API + “?action=query&format=json&origin=*&meta=siteinfo&siprop=general”, {cache:”no-cache”}); if (!ping.ok) throw new Error(“Cannot reach Wikisource API (” + ping.status + “)”); // Show enhanced app, hide fallback only AFTER ping success if (app) { app.style.display=”block”; app.setAttribute(“aria-hidden”,”false”); } if (fallback) fallback.style.display=”none”; // Load library await openLibrary(); // Restore last view if (state.view===”collection” && state.id===”dn”) await openDn(); if (state.view===”page” && state.title) await openPage(state.title, state.label, state.section||”0″); toast(“Reader loaded”); } catch (e) { // Keep fallback visible showErr(e); } })(); })();
Tripiṭaka Reader (English)
Source (public domain editions): Wikisource. Enhanced reader uses ONE API: Wikisource MediaWiki API.
Note: a single complete redistribution-safe public-domain English full Tipiṭaka API is not currently available; this loads what Wikisource provides.
Library (Fallback)
Tipiṭaka Portal (Index) Dīgha Nikāya (portal)
Public domain books (Wikisource)
Sutta Nipāta (SBE Vol. X) Buddhist Suttas (SBE Vol. XI) Vinaya Texts (SBE Vol. XIII) Vinaya Texts (SBE Vol. XVII) Vinaya Texts (SBE Vol. XX)
If your WordPress blocks JavaScript, this fallback still works. Copying “verse + reference” is manual here (select text on the right and copy; use the page title as reference).

Leave a Comment