Last active
March 6, 2026 21:11
-
-
Save jhauga/7d0f3aa4e78e29a8309dbfea7cfb366a to your computer and use it in GitHub Desktop.
Bookmarklet - use this bookmarklet for Getting documentation links as a markdown list, with sections applied. Ensure to copy/paste the top condensed line of the bookmarklet. Info at "https://github.com/isocialPractice/bookmarklets".
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| /// *********************************************************** /// | |
| // ****************** BROWSER BOOKMARKLET GIST ***************** // | |
| // ************************************************************* // | |
| // // | |
| // LICENSE ///////////////////////////////////////////////////// | |
| // ******* // | |
| // The code in this gist is public domain. // | |
| // Licensed as Public Domain CC0 // | |
| ////////////////////////////////////////////////////////////////// | |
| // | |
| // COPY / PAST BELOW LINE TO USE | |
| javascript:(function() { /* CONFIG VARIABLES */ var skipMenuMakeMdLinkList = true; /* do not include menu links */ var skipFooterMakeMdLinkList = true; /* do not include footer links */ var skipHeaderMakeMdLinkList = false; /* do not include list header */ /******************************************************************************* Legacy templating Key INNER_TEXT = <a> tag inner text HREF_LINK = href value of <a> tag ********************************************************************************/ var mdOutputMakeMdLinkList = /* format how markdown link is output */ "- [INNER_TEXT](HREF_LINK)"; /* GLOBAL VARIABLES */ var headingsMakeMdLinkList = /* all heading elements on the page */ document.querySelectorAll("h1, h2, h3, h4, h5, h6"); var linksMakeMdLinkList = /* all anchor tag elements on the page */ document.querySelectorAll("a"); var guessMenuMakeMdLinkList = /* array of common menu or nav identifiers */ ["menu", "nav", "header", "side-nav", "top-bar", "navbar", "page-menu", "page-nav", "top-navbar"]; var guessFooterMakeMdLinkList = /* array of common footer identifiers */ ["footer", "bottom", "site-footer", "footer-wrapper", "foot", "footer-container", "foot-container", "page-footer", "page-foot"]; /* Parallel arrays where each index is one output entry. Grouped entries (links sharing a list) are stored as nested String arrays. Ungrouped entries (lone links outside any list) are stored as flat Strings. */ var aInnerTextMakeMdLinkList = []; /* a tag inner text array (String|String[]) */ var aHrefMakeMdLinkList = []; /* a href value each link (String|String[]) */ var hasHtagMakeMdLinkList = []; /* heading metadata per entry ({text,level}) */ var mdDataMakeMdLinkList = ""; /* final accumulated markdown output string */ var trackUnestMakeMdLinkList = 1; /* label counter for ungrouped "Section N" */ /************************************* SUPPORT FUNCTIONS *************************************/ /* isInZoneMakeMdLinkList Returns true if element el has ANY ancestor element (walking from el up to document.body) whose tag name, className string, or id string contains any value from the identifiers array. Case-insensitive comparison throughout. Used to filter out links that live inside nav/menu or footer zones. */ const isInZoneMakeMdLinkList = (el, identifiers) => { var node = el; while (node && node !== document.body) { var tag = node.tagName ? node.tagName.toLowerCase() : ""; var cls = node.className && typeof node.className === "string" ? node.className.toLowerCase() : ""; var nid = node.id ? node.id.toLowerCase() : ""; for (var k = 0; k < identifiers.length; k++) { var ident = identifiers[k].toLowerCase(); if (tag === ident || cls.indexOf(ident) !== -1 || nid.indexOf(ident) !== -1) { return true; } } node = node.parentElement; } return false; }; /* nearestListMakeMdLinkList Walks up the DOM from el.parentElement and returns the first ancestor element whose tag is ul, ol, or dl. Returns null if the walk reaches document.body without finding a list element. */ const nearestListMakeMdLinkList = (el) => { var node = el.parentElement; while (node && node !== document.body) { var tag = node.tagName ? node.tagName.toLowerCase() : ""; if (tag === "ul" || tag === "ol" || tag === "dl") return node; node = node.parentElement; } return null; }; /* headingForListMakeMdLinkList Finds the nearest heading element (h1–h6) that semantically precedes listEl. Strategy: 1. Check all previous siblings of listEl for a heading tag. 2. If none found, recurse upward through listEl.parentElement to check sibling headings at the parent level. Returns the heading element, or null if none can be found before body. */ const headingForListMakeMdLinkList = (listEl) => { var sibling = listEl.previousElementSibling; while (sibling) { if (/^h[1-6]$/i.test(sibling.tagName)) return sibling; sibling = sibling.previousElementSibling; } var parent = listEl.parentElement; if (parent && parent !== document.body) { return headingForListMakeMdLinkList(parent); } return null; }; /* resolveHrefMakeMdLinkList Converts a potentially relative href string to a fully absolute URL using the page%27s baseURI so that output links remain valid outside this page. Falls back to the raw href string if URL construction throws. */ const resolveHrefMakeMdLinkList = (href) => { try { return new URL(href, document.baseURI).href; } catch(e) { return href; } }; /* Gather all links, and store in two arrays: inner text, and href value. Full processing logic: - Skip links with an empty href or empty visible text. - Skip links inside nav/menu zones when skipMenuMakeMdLinkList is true. - Skip links inside footer zones when skipFooterMakeMdLinkList is true. - Skip non-navigable hrefs (javascript: protocol). - If a link lives inside a list (ul/ol/dl): * Use that list element as a grouping container. * Avoid re-processing the same list (seenLists tracks processed lists). * Collect ONLY sibling links whose nearest list IS this container, so that links inside nested sub-lists are not duplicated here. * Resolve the nearest preceding heading for the group via headingForListMakeMdLinkList. * Push a nested String array entry for the group. - If a link is NOT inside any list, push a flat String entry. */ const linkDataMakeMdLinkList = () => { var seenListsMakeMdLinkList = []; /* list elements already processed */ for (var i = 0; i < linksMakeMdLinkList.length; i++) { var link = linksMakeMdLinkList[i]; var text = (link.innerText || link.textContent || "").trim(); var href = link.getAttribute("href") || ""; if (!text || !href) continue; /* empty — skip */ if (/^javascript:/i.test(href)) continue; /* non-navigable href skip */ if (skipMenuMakeMdLinkList && isInZoneMakeMdLinkList(link, guessMenuMakeMdLinkList)) continue; if (skipFooterMakeMdLinkList && isInZoneMakeMdLinkList(link, guessFooterMakeMdLinkList)) continue; var listEl = nearestListMakeMdLinkList(link); if (listEl) { if (seenListsMakeMdLinkList.indexOf(listEl) !== -1) continue; /* dup skip */ seenListsMakeMdLinkList.push(listEl); /* Collect links that directly belong to this list container (not deeper nested sub-lists) by verifying each candidate link%27s nearest list ancestor equals this exact listEl. */ var allInList = listEl.querySelectorAll("a"); var grpText = [], grpHref = []; for (var j = 0; j < allInList.length; j++) { var sl = allInList[j]; if (nearestListMakeMdLinkList(sl) !== listEl) continue; /* nested sub-list */ var st = (sl.innerText || sl.textContent || "").trim(); var sh = sl.getAttribute("href") || ""; if (!st || !sh) continue; if (/^javascript:/i.test(sh)) continue; if (skipMenuMakeMdLinkList && isInZoneMakeMdLinkList(sl, guessMenuMakeMdLinkList)) continue; if (skipFooterMakeMdLinkList && isInZoneMakeMdLinkList(sl, guessFooterMakeMdLinkList)) continue; grpText.push(st); grpHref.push(resolveHrefMakeMdLinkList(sh)); } if (grpText.length === 0) continue; /* nothing kept — skip group */ /* Resolve the section heading that introduces this list on the page */ var hEl = headingForListMakeMdLinkList(listEl); var hText = hEl ? (hEl.innerText || hEl.textContent || "").trim() : null; var hLevel = hEl ? parseInt(hEl.tagName.replace(/[^0-9]/g, ""), 10) : null; aInnerTextMakeMdLinkList.push(grpText); /* nested array for group */ aHrefMakeMdLinkList.push(grpHref); /* nested array for group */ hasHtagMakeMdLinkList.push({ text: hText, level: hLevel }); } else { /* Link is not nested in any list — store as an individual flat entry */ aInnerTextMakeMdLinkList.push(text); aHrefMakeMdLinkList.push(resolveHrefMakeMdLinkList(href)); hasHtagMakeMdLinkList.push(null); } } }; /* Alert and console.log result, outputting data to console if clipboard fail. */ const outDataAndResultsMakeMdLinkList = (msg, data) => { if (data == undefined) data = false; alert(msg); if (data !== false) { console.log(data); } console.log("/* " + msg + " */"); }; /* Prepare the final data to output markdown list of links. Iterates over the populated parallel arrays and builds mdDataMakeMdLinkList. If skipHeaderMakeMdLinkList is true: - Output all links as a flat list with no headers. Otherwise (skipHeaderMakeMdLinkList is false): - For each grouped entry (Array): * If a heading was resolved, output "#"-repeated heading line matching the original h-tag level (e.g. h4 → "####"). * Output each link using the mdOutputMakeMdLinkList template. - For each ungrouped entry (String): * Output a generated "### Section N" heading. * Output the single link using the mdOutputMakeMdLinkList template. */ const prepDataMakeMdLinkList = () => { for (var i = 0; i < aInnerTextMakeMdLinkList.length; i++) { var entry = aInnerTextMakeMdLinkList[i]; if (Array.isArray(entry)) { var meta = hasHtagMakeMdLinkList[i]; if (!skipHeaderMakeMdLinkList && meta && meta.text && meta.level) { var hashes = ""; for (var h = 0; h < meta.level; h++) hashes += "#"; mdDataMakeMdLinkList += hashes + " " + meta.text + "\n\n"; } for (var j = 0; j < entry.length; j++) { mdDataMakeMdLinkList += mdOutputMakeMdLinkList .replace("INNER_TEXT", entry[j]) .replace("HREF_LINK", aHrefMakeMdLinkList[i][j]) + "\n"; } if (!skipHeaderMakeMdLinkList) mdDataMakeMdLinkList += "\n"; } else { /* item was not nested in a list */ if (!skipHeaderMakeMdLinkList) { /* Add Section heading for unested items */ mdDataMakeMdLinkList += "### Section " + trackUnestMakeMdLinkList + "\n\n"; trackUnestMakeMdLinkList += 1; /* increment for next section */ } mdDataMakeMdLinkList += mdOutputMakeMdLinkList .replace("INNER_TEXT", entry) .replace("HREF_LINK", aHrefMakeMdLinkList[i]) + "\n"; if (!skipHeaderMakeMdLinkList) mdDataMakeMdLinkList += "\n"; } } }; /* copyToClipboardMakeMdLinkList Attempts to copy text to clipboard using a hidden textarea fallback. Creates a temporary textarea, sets its value, selects, and executes copy. Falls back to console output if clipboard copy fails. Cleans up the textarea after attempting the copy operation. */ const copyToClipboardMakeMdLinkList = (text) => { var textarea = document.createElement("textarea"); textarea.style.cssText = "position:fixed;top:-9999px;left:-9999px;opacity:0;"; textarea.value = text; document.body.appendChild(textarea); textarea.select(); textarea.setSelectionRange(0, text.length); /* for mobile compatibility */ var success = false; try { success = document.execCommand("copy"); } catch(e) { success = false; } document.body.removeChild(textarea); if (success) { /* alert results that clipboard is ready and log results to console */ outDataAndResultsMakeMdLinkList("Output copied to clipboard.", false); } else { /* alert results that clipboard failed and log data and results to console */ outDataAndResultsMakeMdLinkList( "Clipboard unavailable — select and copy the console output.", text); } }; /********************************************************************************************* MAIN FUNCTION *********************************************************************************************/ /* Call support functions. linkDataMakeMdLinkList runs synchronously to populate the parallel arrays. prepDataMakeMdLinkList runs after a 500ms delay to allow any lazy-rendered page content to settle before querying the DOM for list and heading data. Output is written to the browser console. A clipboard copy is attempted via a hidden textarea so copy works without DevTools open. */ function runMakeMdLinkList() { linkDataMakeMdLinkList(); setTimeout(function() { prepDataMakeMdLinkList(); copyToClipboardMakeMdLinkList(mdDataMakeMdLinkList); }, 500); } /* Call main function */ runMakeMdLinkList();})(); | |
| // MAKE ANY EDITS AS NEEDED | |
| // ************************************************************* | |
| // Use the JS Formatted Bookmarklet below to see if any changes | |
| // need to be made in accordance to the page you want to use | |
| // it for. After making needed changes ensure that the revised | |
| // bookmarklet is condensed before using it in your browser. | |
| // For more info on this bookmarklet visit: | |
| // https://github.com/isocialPractice/bookmarklets | |
| // ************************************************************* | |
| // ************************************************************* | |
| // ************************JS-FORMATTED************************* | |
| javascript:(function() { | |
| /* CONFIG VARIABLES */ | |
| var skipMenuMakeMdLinkList = true; /* do not include menu links */ | |
| var skipFooterMakeMdLinkList = true; /* do not include footer links */ | |
| var skipHeaderMakeMdLinkList = false; /* do not include list header */ | |
| /******************************************************************************* | |
| Legacy templating Key | |
| INNER_TEXT = <a> tag inner text | |
| HREF_LINK = href value of <a> tag | |
| ********************************************************************************/ | |
| var mdOutputMakeMdLinkList = /* format how markdown link is output */ | |
| "- [INNER_TEXT](HREF_LINK)"; | |
| /* GLOBAL VARIABLES */ | |
| var headingsMakeMdLinkList = /* all heading elements on the page */ | |
| document.querySelectorAll("h1, h2, h3, h4, h5, h6"); | |
| var linksMakeMdLinkList = /* all anchor tag elements on the page */ | |
| document.querySelectorAll("a"); | |
| var guessMenuMakeMdLinkList = /* array of common menu or nav identifiers */ | |
| ["menu", "nav", "header", "side-nav", "top-bar", "navbar", "page-menu", | |
| "page-nav", "top-navbar"]; | |
| var guessFooterMakeMdLinkList = /* array of common footer identifiers */ | |
| ["footer", "bottom", "site-footer", "footer-wrapper", "foot", | |
| "footer-container", "foot-container", "page-footer", "page-foot"]; | |
| /* Parallel arrays where each index is one output entry. | |
| Grouped entries (links sharing a list) are stored as nested String arrays. | |
| Ungrouped entries (lone links outside any list) are stored as flat Strings. */ | |
| var aInnerTextMakeMdLinkList = []; /* a tag inner text array (String|String[]) */ | |
| var aHrefMakeMdLinkList = []; /* a href value each link (String|String[]) */ | |
| var hasHtagMakeMdLinkList = []; /* heading metadata per entry ({text,level}) */ | |
| var mdDataMakeMdLinkList = ""; /* final accumulated markdown output string */ | |
| var trackUnestMakeMdLinkList = 1; /* label counter for ungrouped "Section N" */ | |
| /************************************* SUPPORT FUNCTIONS *************************************/ | |
| /* isInZoneMakeMdLinkList | |
| Returns true if element el has ANY ancestor element (walking from el up to | |
| document.body) whose tag name, className string, or id string contains any | |
| value from the identifiers array. Case-insensitive comparison throughout. | |
| Used to filter out links that live inside nav/menu or footer zones. */ | |
| const isInZoneMakeMdLinkList = (el, identifiers) => { | |
| var node = el; | |
| while (node && node !== document.body) { | |
| var tag = node.tagName ? node.tagName.toLowerCase() : ""; | |
| var cls = node.className && typeof node.className === "string" | |
| ? node.className.toLowerCase() : ""; | |
| var nid = node.id ? node.id.toLowerCase() : ""; | |
| for (var k = 0; k < identifiers.length; k++) { | |
| var ident = identifiers[k].toLowerCase(); | |
| if (tag === ident || cls.indexOf(ident) !== -1 || nid.indexOf(ident) !== -1) { | |
| return true; | |
| } | |
| } | |
| node = node.parentElement; | |
| } | |
| return false; | |
| }; | |
| /* nearestListMakeMdLinkList | |
| Walks up the DOM from el.parentElement and returns the first ancestor | |
| element whose tag is ul, ol, or dl. Returns null if the walk reaches | |
| document.body without finding a list element. */ | |
| const nearestListMakeMdLinkList = (el) => { | |
| var node = el.parentElement; | |
| while (node && node !== document.body) { | |
| var tag = node.tagName ? node.tagName.toLowerCase() : ""; | |
| if (tag === "ul" || tag === "ol" || tag === "dl") return node; | |
| node = node.parentElement; | |
| } | |
| return null; | |
| }; | |
| /* headingForListMakeMdLinkList | |
| Finds the nearest heading element (h1–h6) that semantically precedes listEl. | |
| Strategy: | |
| 1. Check all previous siblings of listEl for a heading tag. | |
| 2. If none found, recurse upward through listEl.parentElement to check | |
| sibling headings at the parent level. | |
| Returns the heading element, or null if none can be found before body. */ | |
| const headingForListMakeMdLinkList = (listEl) => { | |
| var sibling = listEl.previousElementSibling; | |
| while (sibling) { | |
| if (/^h[1-6]$/i.test(sibling.tagName)) return sibling; | |
| sibling = sibling.previousElementSibling; | |
| } | |
| var parent = listEl.parentElement; | |
| if (parent && parent !== document.body) { | |
| return headingForListMakeMdLinkList(parent); | |
| } | |
| return null; | |
| }; | |
| /* resolveHrefMakeMdLinkList | |
| Converts a potentially relative href string to a fully absolute URL using | |
| the page's baseURI so that output links remain valid outside this page. | |
| Falls back to the raw href string if URL construction throws. */ | |
| const resolveHrefMakeMdLinkList = (href) => { | |
| try { | |
| return new URL(href, document.baseURI).href; | |
| } catch(e) { | |
| return href; | |
| } | |
| }; | |
| /* Gather all links, and store in two arrays: inner text, and href value. | |
| Full processing logic: | |
| - Skip links with an empty href or empty visible text. | |
| - Skip links inside nav/menu zones when skipMenuMakeMdLinkList is true. | |
| - Skip links inside footer zones when skipFooterMakeMdLinkList is true. | |
| - Skip non-navigable hrefs (javascript: protocol). | |
| - If a link lives inside a list (ul/ol/dl): | |
| * Use that list element as a grouping container. | |
| * Avoid re-processing the same list (seenLists tracks processed lists). | |
| * Collect ONLY sibling links whose nearest list IS this container, | |
| so that links inside nested sub-lists are not duplicated here. | |
| * Resolve the nearest preceding heading for the group via | |
| headingForListMakeMdLinkList. | |
| * Push a nested String array entry for the group. | |
| - If a link is NOT inside any list, push a flat String entry. */ | |
| const linkDataMakeMdLinkList = () => { | |
| var seenListsMakeMdLinkList = []; /* list elements already processed */ | |
| for (var i = 0; i < linksMakeMdLinkList.length; i++) { | |
| var link = linksMakeMdLinkList[i]; | |
| var text = (link.innerText || link.textContent || "").trim(); | |
| var href = link.getAttribute("href") || ""; | |
| if (!text || !href) continue; /* empty — skip */ | |
| if (/^javascript:/i.test(href)) continue; /* non-navigable href skip */ | |
| if (skipMenuMakeMdLinkList && | |
| isInZoneMakeMdLinkList(link, guessMenuMakeMdLinkList)) continue; | |
| if (skipFooterMakeMdLinkList && | |
| isInZoneMakeMdLinkList(link, guessFooterMakeMdLinkList)) continue; | |
| var listEl = nearestListMakeMdLinkList(link); | |
| if (listEl) { | |
| if (seenListsMakeMdLinkList.indexOf(listEl) !== -1) continue; /* dup skip */ | |
| seenListsMakeMdLinkList.push(listEl); | |
| /* Collect links that directly belong to this list container (not deeper | |
| nested sub-lists) by verifying each candidate link's nearest list | |
| ancestor equals this exact listEl. */ | |
| var allInList = listEl.querySelectorAll("a"); | |
| var grpText = [], grpHref = []; | |
| for (var j = 0; j < allInList.length; j++) { | |
| var sl = allInList[j]; | |
| if (nearestListMakeMdLinkList(sl) !== listEl) continue; /* nested sub-list */ | |
| var st = (sl.innerText || sl.textContent || "").trim(); | |
| var sh = sl.getAttribute("href") || ""; | |
| if (!st || !sh) continue; | |
| if (/^javascript:/i.test(sh)) continue; | |
| if (skipMenuMakeMdLinkList && | |
| isInZoneMakeMdLinkList(sl, guessMenuMakeMdLinkList)) continue; | |
| if (skipFooterMakeMdLinkList && | |
| isInZoneMakeMdLinkList(sl, guessFooterMakeMdLinkList)) continue; | |
| grpText.push(st); | |
| grpHref.push(resolveHrefMakeMdLinkList(sh)); | |
| } | |
| if (grpText.length === 0) continue; /* nothing kept — skip group */ | |
| /* Resolve the section heading that introduces this list on the page */ | |
| var hEl = headingForListMakeMdLinkList(listEl); | |
| var hText = hEl ? (hEl.innerText || hEl.textContent || "").trim() : null; | |
| var hLevel = hEl ? parseInt(hEl.tagName.replace(/[^0-9]/g, ""), 10) : null; | |
| aInnerTextMakeMdLinkList.push(grpText); /* nested array for group */ | |
| aHrefMakeMdLinkList.push(grpHref); /* nested array for group */ | |
| hasHtagMakeMdLinkList.push({ text: hText, level: hLevel }); | |
| } else { | |
| /* Link is not nested in any list — store as an individual flat entry */ | |
| aInnerTextMakeMdLinkList.push(text); | |
| aHrefMakeMdLinkList.push(resolveHrefMakeMdLinkList(href)); | |
| hasHtagMakeMdLinkList.push(null); | |
| } | |
| } | |
| }; | |
| /* Alert and console.log result, outputting data to console if clipboard fail. */ | |
| const outDataAndResultsMakeMdLinkList = (msg, data) => { | |
| if (data == undefined) data = false; | |
| alert(msg); | |
| if (data !== false) { | |
| console.log(data); | |
| } | |
| console.log("/* " + msg + " */"); | |
| }; | |
| /* Prepare the final data to output markdown list of links. | |
| Iterates over the populated parallel arrays and builds mdDataMakeMdLinkList. | |
| If skipHeaderMakeMdLinkList is true: | |
| - Output all links as a flat list with no headers. | |
| Otherwise (skipHeaderMakeMdLinkList is false): | |
| - For each grouped entry (Array): | |
| * If a heading was resolved, output "#"-repeated heading line matching | |
| the original h-tag level (e.g. h4 → "####"). | |
| * Output each link using the mdOutputMakeMdLinkList template. | |
| - For each ungrouped entry (String): | |
| * Output a generated "### Section N" heading. | |
| * Output the single link using the mdOutputMakeMdLinkList template. */ | |
| const prepDataMakeMdLinkList = () => { | |
| for (var i = 0; i < aInnerTextMakeMdLinkList.length; i++) { | |
| var entry = aInnerTextMakeMdLinkList[i]; | |
| if (Array.isArray(entry)) { | |
| var meta = hasHtagMakeMdLinkList[i]; | |
| if (!skipHeaderMakeMdLinkList && meta && meta.text && meta.level) { | |
| var hashes = ""; | |
| for (var h = 0; h < meta.level; h++) hashes += "#"; | |
| mdDataMakeMdLinkList += hashes + " " + meta.text + "\n\n"; | |
| } | |
| for (var j = 0; j < entry.length; j++) { | |
| mdDataMakeMdLinkList += mdOutputMakeMdLinkList | |
| .replace("INNER_TEXT", entry[j]) | |
| .replace("HREF_LINK", aHrefMakeMdLinkList[i][j]) + "\n"; | |
| } | |
| if (!skipHeaderMakeMdLinkList) mdDataMakeMdLinkList += "\n"; | |
| } else { /* item was not nested in a list */ | |
| if (!skipHeaderMakeMdLinkList) { | |
| /* Add Section heading for unested items */ | |
| mdDataMakeMdLinkList += "### Section " + trackUnestMakeMdLinkList + "\n\n"; | |
| trackUnestMakeMdLinkList += 1; /* increment for next section */ | |
| } | |
| mdDataMakeMdLinkList += mdOutputMakeMdLinkList | |
| .replace("INNER_TEXT", entry) | |
| .replace("HREF_LINK", aHrefMakeMdLinkList[i]) + "\n"; | |
| if (!skipHeaderMakeMdLinkList) mdDataMakeMdLinkList += "\n"; | |
| } | |
| } | |
| }; | |
| /* copyToClipboardMakeMdLinkList | |
| Attempts to copy text to clipboard using a hidden textarea fallback. | |
| Creates a temporary textarea, sets its value, selects, and executes copy. | |
| Falls back to console output if clipboard copy fails. | |
| Cleans up the textarea after attempting the copy operation. */ | |
| const copyToClipboardMakeMdLinkList = (text) => { | |
| var textarea = document.createElement("textarea"); | |
| textarea.style.cssText = "position:fixed;top:-9999px;left:-9999px;opacity:0;"; | |
| textarea.value = text; | |
| document.body.appendChild(textarea); | |
| textarea.select(); | |
| textarea.setSelectionRange(0, text.length); /* for mobile compatibility */ | |
| var success = false; | |
| try { | |
| success = document.execCommand("copy"); | |
| } catch(e) { | |
| success = false; | |
| } | |
| document.body.removeChild(textarea); | |
| if (success) { | |
| /* alert results that clipboard is ready and log results to console */ | |
| outDataAndResultsMakeMdLinkList("Output copied to clipboard.", false); | |
| } else { | |
| /* alert results that clipboard failed and log data and results to console */ | |
| outDataAndResultsMakeMdLinkList( | |
| "Clipboard unavailable — select and copy the console output.", text); | |
| } | |
| }; | |
| /********************************************************************************************* | |
| MAIN FUNCTION | |
| *********************************************************************************************/ | |
| /* Call support functions. | |
| linkDataMakeMdLinkList runs synchronously to populate the parallel arrays. | |
| prepDataMakeMdLinkList runs after a 500ms delay to allow any lazy-rendered | |
| page content to settle before querying the DOM for list and heading data. | |
| Output is written to the browser console. A clipboard copy is attempted | |
| via a hidden textarea so copy works without DevTools open. */ | |
| function runMakeMdLinkList() { | |
| linkDataMakeMdLinkList(); | |
| setTimeout(function() { | |
| prepDataMakeMdLinkList(); | |
| copyToClipboardMakeMdLinkList(mdDataMakeMdLinkList); | |
| }, 500); | |
| } | |
| /* Call main function */ | |
| runMakeMdLinkList(); | |
| })(); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment