function preceding(element) { return element && (element.previousElementSibling || preceding(element.parentNode)); } function deriveFilename(element) { // TODO: Make pattern and default name configurable const match = element && element.textContent.match(/^\s*(.+[/\\])?([^/\\]+\.\w+)\s*$/); return match ? match[2] : "code.txt"; } window.addEventListener("load", () => { for (const codeElement of document.querySelectorAll("#dokuwiki__content pre.code")) { const code = codeElement.textContent; // Try to interpret the element before the
 element as file name
    const filename = deriveFilename(preceding(codeElement));
    const button = document.createElement("button");
    button.textContent = "Download";
    button.classList.add("downloadcodeblock");
    button.addEventListener("click", () => {
      // Support for browser.downloads.download isn't good yet, so use  instead
      const a = document.createElement("a");
      a.href = "data:text/plain;charset=utf-8," + encodeURIComponent(code);
      a.download = filename;
      a.click();
    }, false);
    codeElement.parentNode.insertBefore(button, codeElement);
  }
}, false);