copy into ai mdbook extention
Copy Into AI mdBook Extension
Section titled “Copy Into AI mdBook Extension”Best mobile-friendly “copy into ChatGPT” setup. See mdBook Renderers
Answer
Section titled “Answer”Use a tiny additional-js script that adds a “Copy page as Markdown” button and calls navigator.clipboard.writeText() on the main article content. This works on mobile (including iOS Safari) as long as you serve over HTTPS and trigger it from a user tap. Fall back to “select all” if the Clipboard API is unavailable or permission is denied.
References:
Why this beats alternatives
Section titled “Why this beats alternatives”- Built-in copy buttons only handle code blocks, not entire pages. See mdBook Reading
- Enabling the Markdown backend gives you a raw
.mdfile, but it still requires manual select-all on mobile. See mdBook Renderers - Print single-page is fine for long copies, but heavier and less precise for prompts. See mdBook Renderers
Minimal config
Section titled “Minimal config”[output.html]additional-js = ["copy-page.js"]
[output.markdown] # optional "View raw" link in your theme
[output.html.print] # optional one-page viewenable = truepage-break = trueSee mdBook Renderers
copy-page.js (drop next to book.toml)
Section titled “copy-page.js (drop next to book.toml)”(() => { // Prefer the main content container used by mdBook themes const root = document.getElementById("content") || document.querySelector("main, .content, article, .page"); if (!root) return;
const btn = document.createElement("button"); btn.textContent = "Copy page as Markdown"; btn.style.position = "fixed"; btn.style.right = "0.75rem"; btn.style.bottom = "0.75rem"; btn.style.zIndex = "2147483647"; btn.style.padding = "0.6rem 0.8rem";
async function copyText(text) { try { if (navigator.clipboard && navigator.clipboard.writeText) { await navigator.clipboard.writeText(text); // requires HTTPS + user tap btn.textContent = "Copied!"; setTimeout(() => (btn.textContent = "Copy page as Markdown"), 1200); } else { // Fallback: select + execCommand const ta = document.createElement("textarea"); ta.value = text; ta.style.position = "fixed"; ta.style.opacity = "0"; document.body.appendChild(ta); ta.focus(); ta.select(); document.execCommand("copy"); document.body.removeChild(ta); btn.textContent = "Copied!"; setTimeout(() => (btn.textContent = "Copy page as Markdown"), 1200); } } catch { // As a last resort, highlight content so the user can copy manually const range = document.createRange(); range.selectNodeContents(root); const sel = window.getSelection(); sel.removeAllRanges(); sel.addRange(range); alert("Tap Copy to finish"); } }
function toMarkdownish(node) { // Lightweight HTML→Markdown pass that preserves headings, lists, code, links. // Keeps it simple for robust mobile paste into ChatGPT. const clone = node.cloneNode(true);
// Strip nav/search, prev/next, footer clone.querySelectorAll("nav, header, .sidebar, .menu-title, .menu, .left, .right, footer").forEach(e => e.remove());
// Strip "$ " prompts from code to be AI-ready clone.querySelectorAll("code, pre").forEach(block => { block.innerHTML = block.innerHTML.replace(/(^|\n)\$[ ]/g, "$1"); });
// Convert common elements to Markdown-friendly text // Headings for (let i = 6; i >= 1; i--) { clone.querySelectorAll("h" + i).forEach(h => h.outerHTML = "\n" + "#".repeat(i) + " " + h.textContent + "\n"); } // Links clone.querySelectorAll("a").forEach(a => a.outerHTML = `[${a.textContent}](${a.href})`); // Code blocks clone.querySelectorAll("pre code").forEach(c => c.parentElement.outerHTML = "\n```\n" + c.textContent + "\n```\n"); // Inline code clone.querySelectorAll("code").forEach(c => c.outerHTML = "`" + c.textContent + "`"); // Lists clone.querySelectorAll("ul li").forEach(li => li.outerHTML = "- " + li.textContent + "\n"); clone.querySelectorAll("ol").forEach(ol => { Array.from(ol.children).forEach((li, idx) => li.outerHTML = (idx + 1) + ". " + li.textContent + "\n"); ol.outerHTML = ol.textContent; }); // Paragraphs clone.querySelectorAll("p").forEach(p => p.outerHTML = p.textContent + "\n\n");
return clone.textContent.replace(/\n{3,}/g, "\n\n").trim(); }
btn.addEventListener("click", () => copyText(toMarkdownish(root))); document.body.appendChild(btn);})();Nice-to-haves
Section titled “Nice-to-haves”- Keep built-in code copy buttons on (
[output.html.playground].copyable = true) for snippet-level workflows. See mdBook Renderers - Add a “View raw Markdown” link using the Markdown backend for power users. See mdBook Renderers
- If you use a page ToC preprocessor, pair it with the button so mobile users can jump to a section then copy. See mdbook-pagetoc