Skip to content

Commit f3cf9b0

Browse files
committed
fix: prevent non-markdown files from rendering in md viewer
Guard _loadMdviewrPreview to check that the current document is actually a markdown file before activating MarkdownSync. Fixes race where async getPreviewDetails returns stale markdown details but the editor has already switched to a binary/json file, causing its content to be rendered as markdown. Add tests verifying: binary/json files don't render in md viewer, last md preview stays visible for non-previewable files, and md preview resumes correctly when switching back to md.
1 parent 8a1d674 commit f3cf9b0

4 files changed

Lines changed: 105 additions & 1 deletion

File tree

docs/API-Reference/command/Menus.md

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -612,6 +612,13 @@ Commands, which control a MenuItem's name, enabled state, and checked state.
612612
| --- | --- | --- |
613613
| id | <code>string</code> | unique identifier for context menu. Core context menus in Brackets use a simple title as an id. Extensions should use the following format: "author.myextension.mycontextmenu name" |
614614

615+
<a name="_initHamburgerMenu"></a>
616+
617+
## \_initHamburgerMenu()
618+
Hamburger menu: when the titlebar is too narrow to fit all menu items on one row,
619+
overflow items are hidden and a hamburger button appears with a dropdown listing them.
620+
621+
**Kind**: global function
615622
<a name="event_EVENT_BEFORE_CONTEXT_MENU_OPEN"></a>
616623

617624
## "EVENT_BEFORE_CONTEXT_MENU_OPEN"

src/extensionsIntegrated/Phoenix-live-preview/main.js

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -869,6 +869,11 @@ define(function (require, exports, module) {
869869
if (!currentDoc) {
870870
return;
871871
}
872+
// Only render markdown files — skip binary, json, and other non-markdown files
873+
// (can happen when previewDetails is stale from async getPreviewDetails)
874+
if (!utils.isMarkdownFile(currentDoc.file.fullPath)) {
875+
return;
876+
}
872877

873878
const mdFileURL = encodeURI(previewDetails.URL);
874879
const baseURL = mdFileURL.substring(0, mdFileURL.lastIndexOf("/") + 1);
@@ -1179,6 +1184,7 @@ define(function (require, exports, module) {
11791184
if (_isMdviewrActive && urlPinned) {
11801185
return;
11811186
}
1187+
11821188
if(!LivePreviewSettings.isUsingCustomServer() && !LiveDevelopment.isActive()
11831189
&& (panel.isVisible() || StaticServer.hasActiveLivePreviews())) {
11841190
// we do this only once after project switch if live preview for a doc is not active.
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
{"name": "test", "value": 42}

test/spec/md-editor-edit-more-integ-test.js

Lines changed: 91 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@
1818
*
1919
*/
2020

21-
/*global describe, beforeAll, afterAll, awaitsFor, it, awaitsForDone, expect*/
21+
/*global describe, beforeAll, afterAll, awaitsFor, awaits, it, awaitsForDone, expect*/
2222

2323
define(function (require, exports, module) {
2424

@@ -447,5 +447,95 @@ define(function (require, exports, module) {
447447
execSearchTests("edit", _enterEditMode);
448448
execSearchTests("reader", _enterReaderMode);
449449
});
450+
451+
describe("Non-markdown file preview behavior", function () {
452+
453+
function _getMdPreviewH1() {
454+
const mdDoc = _getMdIFrameDoc();
455+
if (!mdDoc) { return null; }
456+
const h1 = mdDoc.querySelector("#viewer-content h1");
457+
return h1 ? h1.textContent : null;
458+
}
459+
460+
it("should not render binary/json files in md viewer when switching from md", async function () {
461+
// Open a markdown file first
462+
await awaitsForDone(SpecRunnerUtils.openProjectFiles(["doc1.md"]),
463+
"open doc1.md");
464+
await _waitForMdPreviewReady(EditorManager.getActiveEditor());
465+
466+
// Remember what the md viewer is showing
467+
const mdH1Before = _getMdPreviewH1();
468+
expect(mdH1Before).not.toBeNull();
469+
470+
// Switch to a JSON file (non-markdown, non-previewable)
471+
await awaitsForDone(SpecRunnerUtils.openProjectFiles(["test-data.json"]),
472+
"open test-data.json");
473+
// Negative assertion: wait for any async switch to settle
474+
await awaits(500);
475+
476+
// The md viewer should still show the last md file's content,
477+
// NOT the json file's content
478+
const mdH1After = _getMdPreviewH1();
479+
expect(mdH1After).toBe(mdH1Before);
480+
481+
// The md viewer content should NOT contain json data
482+
const mdDoc = _getMdIFrameDoc();
483+
const viewerText = mdDoc.getElementById("viewer-content").textContent;
484+
expect(viewerText).not.toContain('"name"');
485+
expect(viewerText).not.toContain('"value"');
486+
487+
await awaitsForDone(CommandManager.execute(Commands.FILE_CLOSE, { _forceClose: true }),
488+
"force close test-data.json");
489+
}, 15000);
490+
491+
it("should resume md preview when switching back to md from non-md file", async function () {
492+
// Open doc1.md
493+
await awaitsForDone(SpecRunnerUtils.openProjectFiles(["doc1.md"]),
494+
"open doc1.md");
495+
await _waitForMdPreviewReady(EditorManager.getActiveEditor());
496+
const doc1H1 = _getMdPreviewH1();
497+
498+
// Switch to JSON
499+
await awaitsForDone(SpecRunnerUtils.openProjectFiles(["test-data.json"]),
500+
"open test-data.json");
501+
await awaits(500);
502+
503+
// Switch to doc2.md — should show doc2 content, not doc1 or json
504+
await awaitsForDone(SpecRunnerUtils.openProjectFiles(["doc2.md"]),
505+
"open doc2.md");
506+
await _waitForMdPreviewReady(EditorManager.getActiveEditor());
507+
508+
const doc2H1 = _getMdPreviewH1();
509+
expect(doc2H1).not.toBeNull();
510+
expect(doc2H1).not.toBe(doc1H1);
511+
512+
await awaitsForDone(CommandManager.execute(Commands.FILE_CLOSE, { _forceClose: true }),
513+
"force close doc2.md");
514+
}, 15000);
515+
516+
it("should keep last md preview when switching to HTML file", async function () {
517+
// Open a markdown file
518+
await awaitsForDone(SpecRunnerUtils.openProjectFiles(["doc1.md"]),
519+
"open doc1.md");
520+
await _waitForMdPreviewReady(EditorManager.getActiveEditor());
521+
const mdH1 = _getMdPreviewH1();
522+
523+
// Switch to HTML — live preview should switch to HTML, hiding md viewer
524+
await awaitsForDone(SpecRunnerUtils.openProjectFiles(["simple.html"]),
525+
"open simple.html");
526+
await awaits(500);
527+
528+
// MD iframe should be hidden (HTML live preview takes over)
529+
const mdIFrame = _getMdPreviewIFrame();
530+
const mdHidden = !mdIFrame || mdIFrame.style.display === "none";
531+
// OR if md viewer stayed visible, its content should be the last md file
532+
if (!mdHidden) {
533+
expect(_getMdPreviewH1()).toBe(mdH1);
534+
}
535+
536+
await awaitsForDone(CommandManager.execute(Commands.FILE_CLOSE, { _forceClose: true }),
537+
"force close simple.html");
538+
}, 15000);
539+
});
450540
});
451541
});

0 commit comments

Comments
 (0)