From c64a11835a50baad58b5755c8b2e51aeca19acfb Mon Sep 17 00:00:00 2001 From: Baivab Sarkar Date: Mon, 6 Jul 2026 19:07:22 +0530 Subject: [PATCH] fix(import): support multi-file markdown drops --- desktop-app/resources/index.html | 6 +- desktop-app/resources/js/script.js | 108 +++++++++++++++++++---------- index.html | 6 +- script.js | 108 +++++++++++++++++++---------- 4 files changed, 150 insertions(+), 78 deletions(-) diff --git a/desktop-app/resources/index.html b/desktop-app/resources/index.html index 2cc02c25..ccc1b1fb 100644 --- a/desktop-app/resources/index.html +++ b/desktop-app/resources/index.html @@ -83,7 +83,7 @@

Markdown Viewer

  • From GitHub
  • - + diff --git a/desktop-app/resources/js/script.js b/desktop-app/resources/js/script.js index f4b92207..531892ba 100644 --- a/desktop-app/resources/js/script.js +++ b/desktop-app/resources/js/script.js @@ -4453,31 +4453,75 @@ document.addEventListener("DOMContentLoaded", async function () { } } + function isMarkdownFile(file) { + return Boolean(file) && ( + file.type === "text/markdown" || + /\.(md|markdown)$/i.test(file.name || "") + ); + } + + function getMarkdownFileTitle(file) { + return (file && file.name ? file.name : "document.md").replace(/\.(md|markdown)$/i, ""); + } + function importMarkdownFile(file) { - if (file.size > 10 * 1024 * 1024) { - alert('File is too large (maximum 10MB supported).'); - return; - } + return new Promise(function(resolve) { + if (!file) { + resolve(false); + return; + } + + if (file.size > 10 * 1024 * 1024) { + alert('File is too large (maximum 10MB supported).'); + resolve(false); + return; + } - const reader = new FileReader(); - reader.onload = function(e) { - const text = e.target.result || ''; + const reader = new FileReader(); + reader.onload = function(e) { + const text = e.target.result || ''; - // Simple binary check: look for null bytes in the first 8KB - const checkLength = Math.min(text.length, 8000); - for (let i = 0; i < checkLength; i++) { - if (text.charCodeAt(i) === 0) { - alert('Cannot import: The selected file appears to be a binary file.'); - return; + // Simple binary check: look for null bytes in the first 8KB + const checkLength = Math.min(text.length, 8000); + for (let i = 0; i < checkLength; i++) { + if (text.charCodeAt(i) === 0) { + alert('Cannot import: The selected file appears to be a binary file.'); + resolve(false); + return; + } } + + newTab(text, getMarkdownFileTitle(file)); + resolve(true); + }; + reader.onerror = function() { + alert('Failed to read the file. Please check permissions and try again.'); + resolve(false); + }; + reader.readAsText(file); + }); + } + + async function importMarkdownFiles(fileList, options) { + const settings = options || {}; + const files = Array.from(fileList || []); + const markdownFiles = files.filter(isMarkdownFile); + + if (!markdownFiles.length) { + if (settings.showInvalidAlert !== false) { + alert("Please upload Markdown files (.md or .markdown)"); } + return 0; + } - newTab(text, file.name.replace(/\.md$/i, '')); - }; - reader.onerror = function() { - alert('Failed to read the file. Please check permissions and try again.'); - }; - reader.readAsText(file); + let importedCount = 0; + for (const file of markdownFiles) { + if (await importMarkdownFile(file)) { + importedCount++; + } + } + + return importedCount; } function isMarkdownPath(path) { @@ -9879,12 +9923,12 @@ document.addEventListener("DOMContentLoaded", async function () { }); } - fileInput.addEventListener("change", function (e) { - const file = e.target.files[0]; - if (file) { - importMarkdownFile(file); + fileInput.addEventListener("change", async function (e) { + try { + await importMarkdownFiles(e.target.files); + } finally { + this.value = ""; } - this.value = ""; }); exportMd.addEventListener("click", function () { @@ -14235,19 +14279,11 @@ document.addEventListener("DOMContentLoaded", async function () { handleDrop(e); }, false); - function handleDrop(e) { + async function handleDrop(e) { const dt = e.dataTransfer; - const files = dt.files; - if (files.length) { - const file = files[0]; - const isMarkdownFile = - file.type === "text/markdown" || - /\.(md|markdown)$/i.test(file.name || ""); - if (isMarkdownFile) { - importMarkdownFile(file); - } else { - alert("Please upload a Markdown file (.md or .markdown)"); - } + const files = dt && dt.files; + if (files && files.length) { + await importMarkdownFiles(files); } } diff --git a/index.html b/index.html index 84ca63d4..af299eb7 100644 --- a/index.html +++ b/index.html @@ -167,7 +167,7 @@

    Markdown Viewer

  • From GitHub
  • - + diff --git a/script.js b/script.js index beb0ae99..46d14b9b 100644 --- a/script.js +++ b/script.js @@ -4684,31 +4684,75 @@ ${selector} .arrowheadPath { } } + function isMarkdownFile(file) { + return Boolean(file) && ( + file.type === "text/markdown" || + /\.(md|markdown)$/i.test(file.name || "") + ); + } + + function getMarkdownFileTitle(file) { + return (file && file.name ? file.name : "document.md").replace(/\.(md|markdown)$/i, ""); + } + function importMarkdownFile(file) { - if (file.size > 10 * 1024 * 1024) { - alert('File is too large (maximum 10MB supported).'); - return; - } + return new Promise(function(resolve) { + if (!file) { + resolve(false); + return; + } + + if (file.size > 10 * 1024 * 1024) { + alert('File is too large (maximum 10MB supported).'); + resolve(false); + return; + } - const reader = new FileReader(); - reader.onload = function(e) { - const text = e.target.result || ''; + const reader = new FileReader(); + reader.onload = function(e) { + const text = e.target.result || ''; - // Simple binary check: look for null bytes in the first 8KB - const checkLength = Math.min(text.length, 8000); - for (let i = 0; i < checkLength; i++) { - if (text.charCodeAt(i) === 0) { - alert('Cannot import: The selected file appears to be a binary file.'); - return; + // Simple binary check: look for null bytes in the first 8KB + const checkLength = Math.min(text.length, 8000); + for (let i = 0; i < checkLength; i++) { + if (text.charCodeAt(i) === 0) { + alert('Cannot import: The selected file appears to be a binary file.'); + resolve(false); + return; + } } + + newTab(text, getMarkdownFileTitle(file)); + resolve(true); + }; + reader.onerror = function() { + alert('Failed to read the file. Please check permissions and try again.'); + resolve(false); + }; + reader.readAsText(file); + }); + } + + async function importMarkdownFiles(fileList, options) { + const settings = options || {}; + const files = Array.from(fileList || []); + const markdownFiles = files.filter(isMarkdownFile); + + if (!markdownFiles.length) { + if (settings.showInvalidAlert !== false) { + alert("Please upload Markdown files (.md or .markdown)"); } + return 0; + } - newTab(text, file.name.replace(/\.md$/i, '')); - }; - reader.onerror = function() { - alert('Failed to read the file. Please check permissions and try again.'); - }; - reader.readAsText(file); + let importedCount = 0; + for (const file of markdownFiles) { + if (await importMarkdownFile(file)) { + importedCount++; + } + } + + return importedCount; } function isMarkdownPath(path) { @@ -10110,12 +10154,12 @@ ${selector} .arrowheadPath { }); } - fileInput.addEventListener("change", function (e) { - const file = e.target.files[0]; - if (file) { - importMarkdownFile(file); + fileInput.addEventListener("change", async function (e) { + try { + await importMarkdownFiles(e.target.files); + } finally { + this.value = ""; } - this.value = ""; }); exportMd.addEventListener("click", function () { @@ -14466,19 +14510,11 @@ ${selector} .arrowheadPath { handleDrop(e); }, false); - function handleDrop(e) { + async function handleDrop(e) { const dt = e.dataTransfer; - const files = dt.files; - if (files.length) { - const file = files[0]; - const isMarkdownFile = - file.type === "text/markdown" || - /\.(md|markdown)$/i.test(file.name || ""); - if (isMarkdownFile) { - importMarkdownFile(file); - } else { - alert("Please upload a Markdown file (.md or .markdown)"); - } + const files = dt && dt.files; + if (files && files.length) { + await importMarkdownFiles(files); } }