### Extension Options Configuration (JavaScript) Source: https://context7.com/deathau/markdownload/llms.txt This JavaScript code defines default options for the Markdownload extension and a function to retrieve the current options, merging them with defaults. It covers various settings for markdown conversion, templates, downloads, and formatting. The example shows how to update these options using `browser.storage.sync.set` to customize the markdown output and image handling. ```javascript // Default options in shared/default-options.js const defaultOptions = { headingStyle: "atx", // "atx" (# Header) or "setext" (Header\n======) hr: "___", // Horizontal rule: ___, ---, *** bulletListMarker: "-", // List marker: -, *, + codeBlockStyle: "fenced", // "fenced" or "indented" fence: "```", // Code fence: ``` or ~~~ emDelimiter: "_", // Italics: _ or * strongDelimiter: "**", // Bold: ** or __ linkStyle: "inlined", // "inlined", "referenced", or "stripLinks" linkReferenceStyle: "full", // "full", "collapsed", "shortcut" imageStyle: "markdown", // "markdown", "obsidian", "obsidian-nofolder", "noImage", "base64" frontmatter: "---\ncreated: {date:YYYY-MM-DDTHH:mm:ss} (UTC {date:Z})\ntags: [{keywords}]\nsource: {baseURI}\nauthor: {byline}\n---\n\n# {pageTitle}\n\n> ## Excerpt\n> {excerpt}\n\n---", backmatter: "", title: "{pageTitle}", includeTemplate: false, saveAs: false, downloadImages: false, imagePrefix: '{pageTitle}/', mdClipsFolder: null, disallowedChars: '[]#^', downloadMode: 'downloadsApi', // 'downloadsApi' or 'contentLink' turndownEscape: true, obsidianIntegration: false, obsidianVault: "", obsidianFolder: "", }; async function getOptions() { let options = defaultOptions; try { options = await browser.storage.sync.get(defaultOptions); } catch (err) { console.error(err); } if (!browser.downloads) options.downloadMode = 'contentLink'; return options; } // Example: Customize markdown output await browser.storage.sync.set({ headingStyle: "setext", bulletListMarker: "*", strongDelimiter: "__", imageStyle: "obsidian", downloadImages: true, imagePrefix: "assets/", frontmatter: "---\ntitle: {pageTitle}\nurl: {baseURI}\ndate: {date:YYYY-MM-DD}\n---\n\n", includeTemplate: true }); ``` -------------------------------- ### Obsidian Integration via Advanced URI (JavaScript) Source: https://context7.com/deathau/markdownload/llms.txt This JavaScript function handles sending clipped content directly to Obsidian using the Advanced URI plugin. It converts article content to Markdown, copies it to the clipboard, and then opens Obsidian to create a new note from the clipboard. It requires the Advanced URI plugin to be installed in Obsidian and specific options to be configured in the extension. ```javascript // Obsidian integration in background.js async function copyMarkdownFromContext(info, tab) { if(info.menuItemId == "copy-markdown-obsidian" || info.menuItemId == "copy-markdown-obsall") { const isSelection = info.menuItemId == "copy-markdown-obsidian"; const article = await getArticleFromContent(tab.id, isSelection); const title = await formatTitle(article); const options = await getOptions(); const obsidianVault = options.obsidianVault; const obsidianFolder = await formatObsidianFolder(article); // Convert without downloading images const { markdown } = await convertArticleToMarkdown(article, false); // Copy to clipboard await browser.tabs.executeScript(tab.id, { code: `copyToClipboard(${JSON.stringify(markdown)})` }); // Open Obsidian Advanced URI to create note from clipboard await browser.tabs.update({ url: "obsidian://advanced-uri?vault=" + obsidianVault + "&clipboard=true&mode=new&filepath=" + obsidianFolder + generateValidFileName(title) }); } } // Example configuration in options: // - obsidianIntegration: true // - obsidianVault: "MyVault" // - obsidianFolder: "Clippings/{date:YYYY-MM}/" // User right-clicks page, selects "Send Tab to Obsidian" // Creates: "MyVault/Clippings/2026-01/Article Title.md" with full content ``` -------------------------------- ### Markdown Character Escaping Example Source: https://github.com/deathau/markdownload/blob/main/user-guide.md Demonstrates how Markdown characters, specifically periods in this case, are escaped using a backslash to prevent them from being interpreted as Markdown syntax (e.g., a list item). This ensures literal display. ```markdown

1. Hello world

needs to be escaped to 1\. Hello world ``` -------------------------------- ### Initialize CodeMirror Editor and Handle Download Actions (JavaScript) Source: https://context7.com/deathau/markdownload/llms.txt Initializes a CodeMirror editor for markdown, handles user interactions for downloading full or selected content, and toggles template inclusion. It listens for messages to populate the editor with markdown and article details. ```javascript // Popup script in popup/popup.js const cm = CodeMirror.fromTextArea(document.getElementById("md"), { theme: window.matchMedia('(prefers-color-scheme: dark)').matches ? "xq-dark" : "xq-light", mode: "markdown", lineWrapping: true }); // Show/hide "Download Selected" button based on editor selection cm.on("cursorActivity", (cm) => { const somethingSelected = cm.somethingSelected(); var downloadSelectionBtn = document.getElementById("downloadSelection"); downloadSelectionBtn.style.display = somethingSelected ? "block" : "none"; }); // Download full markdown content document.getElementById("download").addEventListener("click", async function(e) { e.preventDefault(); await sendDownloadMessage(cm.getValue()); window.close(); }); // Download only selected portion document.getElementById("downloadSelection").addEventListener("click", async function(e) { e.preventDefault(); if (cm.somethingSelected()) { await sendDownloadMessage(cm.getSelection()); } }); // Toggle template inclusion document.getElementById("includeTemplate").addEventListener("click", async function(e) { e.preventDefault(); options.includeTemplate = !options.includeTemplate; document.querySelector("#includeTemplate").classList.toggle("checked"); await browser.storage.sync.set(options); await clipSite(); // Re-clip with new settings }); // Receive markdown from background script browser.runtime.onMessage.addListener(function(message) { if (message.type == "display.md") { cm.setValue(message.markdown); document.getElementById("title").value = message.article.title; imageList = message.imageList; mdClipsFolder = message.mdClipsFolder; document.getElementById("container").style.display = 'flex'; document.getElementById("spinner").style.display = 'none'; document.getElementById("download").focus(); cm.refresh(); } }); // Example usage: // 1. User clicks extension icon // 2. Popup opens with loading spinner // 3. Content script extracts DOM and selection // 4. Background script converts to markdown // 5. Popup displays editable markdown preview // 6. User clicks "Download" to save file ``` -------------------------------- ### Create Browser Context Menus for Download/Copy Actions (JavaScript) Source: https://context7.com/deathau/markdownload/llms.txt This script defines functions to create context menus in the browser for downloading and copying web content as Markdown. It handles different contexts like selection, link, and all elements. Dependencies include the browser extension API and user options fetched via `getOptions()`. It provides actions for downloading, copying, and toggling settings. ```javascript // Context menu creation in shared/context-menus.js async function createMenus() { const options = await getOptions(); browser.contextMenus.removeAll(); if (options.contextMenus) { // Download actions browser.contextMenus.create({ id: "download-markdown-selection", title: "Download Selection As Markdown", contexts: ["selection"] }); browser.contextMenus.create({ id: "download-markdown-all", title: "Download Tab As Markdown", contexts: ["all"] }); // Copy to clipboard actions browser.contextMenus.create({ id: "copy-markdown-selection", title: "Copy Selection As Markdown", contexts: ["selection"] }); browser.contextMenus.create({ id: "copy-markdown-link", title: "Copy Link As Markdown", contexts: ["link"] }); // Toggle options browser.contextMenus.create({ id: "toggle-includeTemplate", type: "checkbox", title: "Include front/back template", contexts: ["all"], checked: options.includeTemplate }); } } // Handle menu clicks in background.js browser.contextMenus.onClicked.addListener(function (info, tab) { if (info.menuItemId.startsWith("copy-markdown")) { copyMarkdownFromContext(info, tab); } else if (info.menuItemId.startsWith("download-markdown")) { downloadMarkdownFromContext(info, tab); } else if (info.menuItemId.startsWith("toggle-")) { toggleSetting(info.menuItemId.split('-')[1]); } }); // Example: User right-clicks selected text and chooses "Copy Selection As Markdown" // The extension extracts the selection, converts to markdown, and copies to clipboard ``` -------------------------------- ### Keyboard Shortcuts and Commands (JavaScript) Source: https://context7.com/deathau/markdownload/llms.txt This JavaScript code snippet demonstrates how to handle keyboard shortcuts defined in the extension's manifest. It listens for command events and triggers corresponding actions such as downloading or copying the current tab's content as Markdown. It relies on functions like `downloadMarkdownFromContext`, `copyMarkdownFromContext`, and `copyTabAsMarkdownLink` which are assumed to be defined elsewhere. ```javascript // Command handler in background.js browser.commands.onCommand.addListener(function (command) { const tab = browser.tabs.getCurrent(); if (command == "download_tab_as_markdown") { const info = { menuItemId: "download-markdown-all" }; downloadMarkdownFromContext(info, tab); } else if (command == "copy_tab_as_markdown") { const info = { menuItemId: "copy-markdown-all" }; copyMarkdownFromContext(info, tab); } else if (command == "copy_selection_as_markdown") { const info = { menuItemId: "copy-markdown-selection" }; copyMarkdownFromContext(info, tab); } else if (command == "copy_tab_as_markdown_link") { copyTabAsMarkdownLink(tab); } }); // Manifest.json keyboard shortcuts: // Alt+Shift+M - Open popup // Alt+Shift+D - Download tab as markdown // Alt+Shift+C - Copy tab as markdown // Alt+Shift+L - Copy tab URL as markdown link // Example: User presses Alt+Shift+D // Current page immediately downloads as markdown file ``` -------------------------------- ### Custom Text Substitution Placeholders Source: https://github.com/deathau/markdownload/blob/main/user-guide.md Lists available placeholders for dynamic text substitution in MarkDownload's configuration. These placeholders can insert article metadata, page information, dates, and keywords into various templates. ```text {title} {pageTitle} {length} {excerpt} {byline} {dir} {baseURI} {date:FORMAT} {keywords} {keywords:SEPARATOR} ``` -------------------------------- ### Convert Web Page to Markdown (JavaScript) Source: https://context7.com/deathau/markdownload/llms.txt Converts a web page's article content to markdown format using the Turndown library. It applies customizable front/back matter templates, processes image prefixes, and handles image downloading via the Downloads API. Dependencies include Readability.js (implicitly via `article` object), Turndown, and helper functions like `getOptions`, `textReplace`, `generateValidFileName`, and `preDownloadImages`. ```javascript // Main conversion function in background.js async function convertArticleToMarkdown(article, downloadImages = null) { const options = await getOptions(); if (downloadImages != null) { options.downloadImages = downloadImages; } // Apply front/back matter templates if (options.includeTemplate) { options.frontmatter = textReplace(options.frontmatter, article) + '\n'; options.backmatter = '\n' + textReplace(options.backmatter, article); } else { options.frontmatter = options.backmatter = ''; } options.imagePrefix = textReplace(options.imagePrefix, article, options.disallowedChars) .split('/').map(s=>generateValidFileName(s, options.disallowedChars)).join('/'); let result = turndown(article.content, options, article); if (options.downloadImages && options.downloadMode == 'downloadsApi') { result = await preDownloadImages(result.imageList, result.markdown); } return result; } // Example usage: Extract and convert current tab const article = await getArticleFromContent(tabId, false); const { markdown, imageList } = await convertArticleToMarkdown(article); // markdown now contains the converted content with front matter // imageList contains URLs mapped to local filenames for download ``` -------------------------------- ### Template Variable Substitution System (JavaScript) Source: https://context7.com/deathau/markdownload/llms.txt This function replaces placeholders in a string with article metadata, formatted dates, and transformed text. It supports various text transformations (lowercase, uppercase, kebab-case, etc.) and date formatting using `moment.js`. It also handles keyword replacement with a custom separator. ```javascript // Text replacement function in background.js function textReplace(string, article, disallowedChars = null) { // Replace article properties with transformations for (const key in article) { if (article.hasOwnProperty(key) && key != "content") { let s = (article[key] || '') + ''; if (s && disallowedChars) s = generateValidFileName(s, disallowedChars); string = string .replace(new RegExp('{' + key + '}', 'g'), s) .replace(new RegExp('{' + key + ':lower}', 'g'), s.toLowerCase()) .replace(new RegExp('{' + key + ':upper}', 'g'), s.toUpperCase()) .replace(new RegExp('{' + key + ':kebab}', 'g'), s.replace(/ /g, '-').toLowerCase()) .replace(new RegExp('{' + key + ':mixed-kebab}', 'g'), s.replace(/ /g, '-')) .replace(new RegExp('{' + key + ':snake}', 'g'), s.replace(/ /g, '_').toLowerCase()) .replace(new RegExp('{' + key + ':mixed_snake}', 'g'), s.replace(/ /g, '_')) .replace(new RegExp('{' + key + ':camel}', 'g'), s.replace(/ ./g, (str) => str.trim().toUpperCase()).replace(/^./, (str) => str.toLowerCase())) .replace(new RegExp('{' + key + ':pascal}', 'g'), s.replace(/ ./g, (str) => str.trim().toUpperCase()).replace(/^./, (str) => str.toUpperCase())); } } // Replace date formats using moment.js const now = new Date(); const dateRegex = /{date:(.+?)}/g; const matches = string.match(dateRegex); if (matches) { matches.forEach(match => { const format = match.substring(6, match.length - 1); const dateString = moment(now).format(format); string = string.replaceAll(match, dateString); }); } // Replace keywords with custom separator const keywordRegex = /{keywords:?(.*)?}/g; const keywordMatches = string.match(keywordRegex); if (keywordMatches) { keywordMatches.forEach(match => { let separator = match.substring(10, match.length - 1) || ','; const keywordsString = (article.keywords || []).join(separator); string = string.replace(new RegExp(match.replace(/\/g, '\\'), 'g'), keywordsString); }); } return string; } // Example: Generate filename and front matter const article = { pageTitle: "Getting Started with Node.js", byline: "John Doe", baseURI: "https://example.com/article", keywords: ["nodejs", "javascript", "tutorial"] }; const titleTemplate = "{pageTitle:kebab}"; const filename = textReplace(titleTemplate, article, "[]#^"); // Result: "getting-started-with-node-js" const frontMatter = `--- title: {pageTitle} author: {byline} date: {date:YYYY-MM-DD} tags: [{keywords: }] source: {baseURI} ---`; const output = textReplace(frontMatter, article); // Result: // --- // title: Getting Started with Node.js // author: John Doe // date: 2026-01-02 // tags: [nodejs javascript tutorial] // source: https://example.com/article // --- ``` -------------------------------- ### Markdown Emphasis Delimiters Source: https://github.com/deathau/markdownload/blob/main/user-guide.md Illustrates the different ways to apply emphasis (italics) to text in Markdown using either asterisks or underscores as delimiters. Consistency in usage is generally recommended. ```markdown _italics_ ``` ```markdown *italics* ``` -------------------------------- ### Download Markdown File with Browser Downloads API (JavaScript) Source: https://context7.com/deathau/markdownload/llms.txt This function triggers a markdown file download using the browser's native Downloads API. It supports downloading associated images and offers options for save location and format. It relies on the `browser.downloads` API and optionally `URL.createObjectURL` for creating file blobs. ```javascript // Download function in background.js async function downloadMarkdown(markdown, title, tabId, imageList = {}, mdClipsFolder = '') { const options = await getOptions(); if (options.downloadMode == 'downloadsApi' && browser.downloads) { // Create blob URL for markdown content const url = URL.createObjectURL(new Blob([markdown], { type: "text/markdown;charset=utf-8" })); if(mdClipsFolder && !mdClipsFolder.endsWith('/')) mdClipsFolder += '/'; // Download markdown file const id = await browser.downloads.download({ url: url, filename: mdClipsFolder + title + ".md", saveAs: options.saveAs }); // Clean up blob URL after download completes browser.downloads.onChanged.addListener(downloadListener(id, url)); // Download associated images if (options.downloadImages) { let destPath = mdClipsFolder + title.substring(0, title.lastIndexOf('/')); if(destPath && !destPath.endsWith('/')) destPath += '/'; Object.entries(imageList).forEach(async ([src, filename]) => { const imgId = await browser.downloads.download({ url: src, filename: destPath ? destPath + filename : filename, saveAs: false }); browser.downloads.onChanged.addListener(downloadListener(imgId, src)); }); } } } // Example: Download article with images const title = await formatTitle(article); const mdClipsFolder = await formatMdClipsFolder(article); await downloadMarkdown(markdown, title, tabId, imageList, mdClipsFolder); // Downloads "Article Title.md" and associated images to Downloads folder ``` -------------------------------- ### Code Block Styles in MarkDownload Source: https://github.com/deathau/markdownload/blob/main/src/options/options.html Demonstrates the two primary styles for formatting code blocks within MarkDownload: Indented and Fenced. Indented code blocks use four spaces for indentation, while Fenced code blocks use triple backticks or tildes. ```javascript const helloWorld = () => { console.log("Hello World"); } ``` ```javascript ``` const helloWorld = () => { console.log("Hello World"); } ``` ``` -------------------------------- ### Markdown Heading Styles Source: https://github.com/deathau/markdownload/blob/main/user-guide.md Demonstrates the two primary styles for Markdown headings: Setext style, which uses underlines, and Atx style, which uses hash symbols. Both achieve the same semantic heading level. ```markdown All About Dogs ============== ``` ```markdown # All About Dogs ``` -------------------------------- ### Extract Article Content with Readability (JavaScript) Source: https://context7.com/deathau/markdownload/llms.txt Parses an HTML DOM string to extract the main article content, metadata, and keywords using Mozilla's Readability.js. It preserves math formulas (MathJax/KaTeX) and code blocks, cleans header classes, and attaches page-specific metadata like base URI, title, and keywords. Dependencies include `DOMParser`, `Readability`, and browser APIs like `browser.tabs.executeScript`. ```javascript // Content extraction in background.js async function getArticleFromDom(domString) { const parser = new DOMParser(); const dom = parser.parseFromString(domString, "text/html"); // Preserve math formulas from MathJax/KaTeX const math = {}; dom.body.querySelectorAll('script[id^=MathJax-Element-]')?.forEach(mathSource => { const type = mathSource.attributes.type.value; const randomId = URL.createObjectURL(new Blob([])).substring(36); mathSource.id = randomId; math[randomId] = { tex: mathSource.innerText, inline: type ? !type.includes('mode=display') : false }; }); // Remove problematic classes from headers dom.body.querySelectorAll('h1, h2, h3, h4, h5, h6')?.forEach(header => { header.className = ''; }); // Parse with Readability const article = new Readability(dom).parse(); // Attach metadata article.baseURI = dom.baseURI; article.pageTitle = dom.title; article.keywords = dom.head.querySelector('meta[name="keywords"]')?.content?.split(',')?.map(s => s.trim()); article.math = math; return article; // Returns: { title, content, excerpt, byline, length, textContent, siteName, ... } } // Example: Get article from tab content await ensureScripts(tabId); const results = await browser.tabs.executeScript(tabId, { code: "getSelectionAndDom()" }); const article = await getArticleFromDom(results[0].dom); console.log(article.title, article.length, article.keywords); ``` -------------------------------- ### Markdown Strong (Bold) Delimiters Source: https://github.com/deathau/markdownload/blob/main/user-guide.md Shows the supported syntax for making text bold in Markdown, using either double asterisks or double underscores. Both methods achieve the same visual outcome. ```markdown **bold** ``` ```markdown __bold__ ``` -------------------------------- ### Markdown Image Styles Source: https://github.com/deathau/markdownload/blob/main/user-guide.md Illustrates various ways to include images in Markdown, from the 'Original Source' which embeds the URL directly, to 'Strip Images' which removes them. When downloading images, options include 'Pure Markdown' for standard image links and Obsidian-specific embed syntaxes. ```markdown Figure 1: ![](http://example.com/img/image.jpg) ``` ```markdown Figure 1: ``` ```markdown ![](folder/image.jpg) ``` ```markdown ![[folder/image.jpg]] ``` ```markdown ![[image.jpg]] ``` -------------------------------- ### Extract Content and Selection from DOM (JavaScript) Source: https://context7.com/deathau/markdownload/llms.txt This JavaScript code defines functions to extract the entire HTML of a web page and the HTML of the currently selected text. It ensures necessary elements like `` and `<base>` exist and cleans up hidden nodes before returning the HTML. It's designed to be executed as a content script within a browser tab. The output includes the full DOM and the selected content, which can be empty if no text is selected. ```javascript // Content script functions in contentScript/contentScript.js function getHTMLOfDocument() { // Ensure title element exists if (document.head.getElementsByTagName('title').length == 0) { let titleEl = document.createElement('title'); titleEl.innerText = document.title; document.head.append(titleEl); } // Ensure base element exists for relative URL resolution let baseEls = document.head.getElementsByTagName('base'); let baseEl; if (baseEls.length > 0) { baseEl = baseEls[0]; } else { baseEl = document.createElement('base'); document.head.append(baseEl); } let href = baseEl.getAttribute('href'); if (!href || !href.startsWith(window.location.origin)) { baseEl.setAttribute('href', window.location.href); } // Remove hidden elements removeHiddenNodes(document.body); return document.documentElement.outerHTML; } function getHTMLOfSelection() { if (window.getSelection) { var selection = window.getSelection(); if (selection.rangeCount > 0) { let content = ''; for (let i = 0; i < selection.rangeCount; i++) { range = selection.getRangeAt(0); var clonedSelection = range.cloneContents(); var div = document.createElement('div'); div.appendChild(clonedSelection); content += div.innerHTML; } return content; } } return ''; } function getSelectionAndDom() { return { selection: getHTMLOfSelection(), dom: getHTMLOfDocument() }; } // Example: Called from background script const results = await browser.tabs.executeScript(tabId, { code: "getSelectionAndDom()" }); console.log(results[0].dom); // Full page HTML console.log(results[0].selection); // Selected text HTML or empty string ``` -------------------------------- ### Markdown Horizontal Rule Styles Source: https://github.com/deathau/markdownload/blob/main/user-guide.md Illustrates the different character combinations that can be used to create a horizontal rule in Markdown. These are typically used to visually separate content sections. ```markdown *** ``` ```markdown --- ``` ```markdown ___ ``` -------------------------------- ### Markdown Link Reference Styles Source: https://github.com/deathau/markdownload/blob/main/user-guide.md Details the three styles for defining references in Markdown links: 'Full' includes an explicit number, 'Collapsed' uses the link text as the identifier, and 'Shortcut' is similar to collapsed but omits the brackets. ```markdown Link to [Google][1] [1]: http://google.com ``` ```markdown Link to [Google][] [Google]: http://google.com ``` ```markdown Link to [Google] [Google]: http://google.com ``` -------------------------------- ### Markdown Bullet List Markers Source: https://github.com/deathau/markdownload/blob/main/user-guide.md Shows the various characters supported by Markdown for creating bulleted lists. The choice of marker can affect the visual appearance of the list. ```markdown * ``` ```markdown - ``` ```markdown + ``` -------------------------------- ### Markdown Link Styles Source: https://github.com/deathau/markdownload/blob/main/user-guide.md Compares the different styles for creating links in Markdown: 'Inlined' links include the URL directly, 'Referenced' links use a separate definition, and 'Strip links' removes the URL entirely, leaving only the link text. ```markdown Link to [Google](http://google.com) ``` ```markdown Link to [Google] [Google]: http://google.com ``` ```markdown Link to Google ``` -------------------------------- ### Markdown Code Block Styles Source: https://github.com/deathau/markdownload/blob/main/user-guide.md Presents the two main ways to format code blocks in Markdown: indented code blocks, where each line is indented, and fenced code blocks, which use delimiters like backticks or tildes. Fenced blocks offer more flexibility, including syntax highlighting. ```markdown ····const helloWorld = () => { ········console.log("Hello World"); ····} ``` ```markdown ``` const helloWorld = () => { ····console.log("Hello World"); } ``` ``` -------------------------------- ### Markdown Code Block Fence Characters Source: https://github.com/deathau/markdownload/blob/main/user-guide.md Specifies the characters that can be used as delimiters for fenced code blocks in Markdown. This choice is relevant when the 'Fenced' code block style is selected. ```markdown ``` ``` ```markdown ~~~ ``` === COMPLETE CONTENT === This response contains all available snippets from this library. No additional content exists. Do not make further requests.