Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
33 changes: 25 additions & 8 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,10 @@
# Markdown Preview

A [Brackets](https://github.com/adobe/brackets) extension that provides a live preview of markdown documents.
Forked from <https://github.com/gruehle/MarkdownPreview>
Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This line should be removed.


For new features, see the changelog below.

A [Brackets](https://github.com/adobe/brackets) extension that provides a live preview of markdown documents.

![Alt text](./screenshots/markdown-preview.png?raw=true "Markdown Preview")

Expand All @@ -11,8 +15,8 @@ A [Brackets](https://github.com/adobe/brackets) extension that provides a live p
* Click the **Install** button

### How To Use
When a markdown document (with extension ".md" or ".markdown") is open, a markdown icon is shown in the
toolbar at the top of the Brackets window. Click this icon to open the preview panel. The panel can be
When a markdown document (with extension ".md" or ".markdown") is open, a markdown icon is shown in the
toolbar at the top of the Brackets window. Click this icon to open the preview panel. The panel can be
resized vertically.

The preview is updated as you edit the document. You can hover over links to see the href in a tooltip,
Expand All @@ -23,19 +27,21 @@ Hover over the preview area to show the settings "gear" icon. Click this icon to
### Settings

#### Format
By default, the document is rendered as standard Markdown. Change the dropdown to "GitHub-Flavored (GFM)"
By default, the document is rendered as standard Markdown. Change the dropdown to "GitHub-Flavored (GFM)"
to see the Markdown as it would appear in a GitHub issue, pull request, or comment.

#### Theme
There are three themes available:
There are five themes available:

* Light - Black text on a light background, similar to GitHub wiki pages.
* Dark - Light text on a dark background.
* Classic - Black text with a serif font on a light background
* Classic - Black text with a serif font on a light background.
* GitHub - The look and feel of a GitHub README.
* Custom - Adds the option to add a custom stylesheet.

#### Sync scroll position
When checked, scrolling in the editor scrolls the preview to roughly the same location.
The scroll position of the preview is based on the scroll position of the source document, so the
When checked, scrolling in the editor scrolls the preview to roughly the same location.
The scroll position of the preview is based on the scroll position of the source document, so the
position may be out of sync if you have really long lines in your source file. Scroll synchronization
works best when the preview and code view are the same height.

Expand All @@ -45,3 +51,14 @@ This extension uses the following open source components:
* [Marked](https://github.com/chjj/marked) - A markdown parser written in JavaScript
* [markdown-css-themes](https://github.com/jasonm23/markdown-css-themes) - The themes are based on the "Swiss" theme
* [markdown-mark](https://github.com/dcurtis/markdown-mark) - The icon used in the toolbar
* [github-markdown-css](https://github.com/sindresorhus/github-markdown-css) - The GitHub stylesheet


***

## Changelog

- Add support for setting a custom theme.
- Add "github" theme.
- GitHub CSS complements of <https://github.com/sindresorhus/github-markdown-css>
- Fix issue where the parsed file gets loaded twice.
150 changes: 139 additions & 11 deletions main.js
Original file line number Diff line number Diff line change
Expand Up @@ -18,10 +18,13 @@
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*
* Contributions:
* Leandro Silva | Grafluxe, 2016
*/

/*jslint vars: true, plusplus: true, devel: true, nomen: true, regexp: true, indent: 4, maxerr: 50 */
/*global define, brackets, $, window, _hideSettings */
/*global define, brackets, $, _hideSettings, _confirmFile, setCustomTheme */

define(function (require, exports, module) {
"use strict";
Expand All @@ -39,7 +42,9 @@ define(function (require, exports, module) {
WorkspaceManager = brackets.getModule("view/WorkspaceManager"),
CommandManager = brackets.getModule("command/CommandManager"),
Menus = brackets.getModule("command/Menus"),
_ = brackets.getModule("thirdparty/lodash");
_ = brackets.getModule("thirdparty/lodash"),
Dialogs = brackets.getModule("widgets/Dialogs"),
FileSystem = brackets.getModule("filesystem/FileSystem");

// Templates
var panelHTML = require("text!templates/panel.html"),
Expand All @@ -63,13 +68,15 @@ define(function (require, exports, module) {
viewMenu,
toggleCmd,
visible = false,
realVisibility = false;
realVisibility = false,
docLoading = false;

// Prefs
var _prefs = PreferencesManager.getExtensionPrefs("markdown-preview");
_prefs.definePreference("useGFM", "boolean", false);
_prefs.definePreference("theme", "string", "clean");
_prefs.definePreference("syncScroll", "boolean", true);
_prefs.definePreference("customTheme", "string", "");

// (based on code in brackets.js)
function _handleLinkClick(e) {
Expand All @@ -92,9 +99,13 @@ define(function (require, exports, module) {
}

function _calcScrollPos() {
var scrollInfo = currentEditor._codeMirror.getScrollInfo();
var scrollPercentage = scrollInfo.top / (scrollInfo.height - scrollInfo.clientHeight);
var scrollTop = ($iframe[0].contentDocument.body.scrollHeight - $iframe[0].clientHeight) * scrollPercentage;
var scrollInfo = currentEditor._codeMirror.getScrollInfo(),
scrollPercentage = scrollInfo.top / (scrollInfo.height - scrollInfo.clientHeight),
scrollTop;

if ($iframe[0].contentDocument.body) {
scrollTop = ($iframe[0].contentDocument.body.scrollHeight - $iframe[0].clientHeight) * scrollPercentage;
}

return Math.round(scrollTop);
}
Expand Down Expand Up @@ -139,12 +150,27 @@ define(function (require, exports, module) {
$iframe[0].contentDocument.body.innerHTML = bodyText;
} else {
// Make <base> tag for relative URLS
var baseUrl = window.location.protocol + "//" + FileUtils.getDirectoryPath(doc.file.fullPath);
var baseUrl = window.location.protocol + "//" + FileUtils.getDirectoryPath(doc.file.fullPath),
themeURI;

if (docLoading) {
return;
}

docLoading = true;

if (_prefs.get("theme") === "custom") {
themeURI = require.toUrl(_prefs.get("customTheme"));

_confirmFile(themeURI);
} else {
themeURI = require.toUrl("./themes/" + _prefs.get("theme") + ".css");
}

// Assemble the HTML source
var htmlSource = _.template(previewHTML)({
baseUrl : baseUrl,
themeUrl : require.toUrl("./themes/" + _prefs.get("theme") + ".css"),
themeUrl : themeURI,
scrollTop : scrollPos,
bodyText : bodyText
});
Expand All @@ -164,6 +190,7 @@ define(function (require, exports, module) {

// Make sure iframe is showing
$iframe.show();
docLoading = false;
});
}
}
Expand Down Expand Up @@ -208,7 +235,7 @@ define(function (require, exports, module) {
}
}

function _showSettings(e) {
function _showSettings() {
_hideSettings();

$settings = $(settingsHTML)
Expand All @@ -228,8 +255,12 @@ define(function (require, exports, module) {
$settings.find("#markdown-preview-theme")
.val(_prefs.get("theme"))
.change(function (e) {
_prefs.set("theme", e.target.value);
_updateSettings();
if (e.target.value === "custom" && !_prefs.get("customTheme")) {
setCustomTheme();
} else {
_prefs.set("theme", e.target.value);
_updateSettings();
}
});

var $syncScroll = $settings.find("#markdown-preview-sync-scroll");
Expand Down Expand Up @@ -324,6 +355,103 @@ define(function (require, exports, module) {
toggleCmd.setChecked(visible);
}

// Support custom theme
function _onSelectCSS(err, fi) {
if (err) {
console.error(err);
Dialogs.showModalDialog(
"",
"Markdown Preview",
"There was an error with your selection."
);
return;
}

if (fi.length === 1) {
_prefs.set("theme", "custom");
Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Once a custom theme is set, there is no way to change it to a different theme (short of renaming the file to force a reset). There should be a way to switch to a different CSS file.

Here is one possible suggestion: keep the Custom menu item, but add a new menu item whenever a custom CSS file is selected. This way the theme menu is populated with all of the built-in themes, and all themes selected by the user. If you do this, the Custom menu item should have an ellipses at the end.

_prefs.set("customTheme", fi[0]);
_updateSettings();
} else {
_showSettings();
}
}

function _onSelectModule(id) {
if (id === "cancel") {
_showSettings();
return;
}

FileSystem.showOpenDialog(
false,
false,
"Select a CSS file",
brackets.app.getUserDocumentsDirectory(),
["css"],
_onSelectCSS
);
}

function setCustomTheme() {
_hideSettings();

Dialogs.showModalDialog(
Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This dialog is not necessary. Selecting the 'Custom' theme should go directly to the file system open dialog.

"",
"Markdown Preview",
"Select a CSS file to style your theme with.",
[
{
id: "select",
text: "Select A File"
},
{
id: "cancel",
text: "Cancel"
}
]
).done(_onSelectModule);
}

function _resetCustomTheme() {
_prefs.set("customTheme", "");
_prefs.set("theme", "clean");

docLoading = false;
window.requestAnimationFrame(_updateSettings);
}

function _confirmFile(fi) {
var resetMsg = "<br><br>Please reset your custom theme path by reselecting \"custom\" from the theme dropdown.";

_hideSettings();

if (fi.slice(-4) !== ".css") {
Dialogs.showModalDialog(
"",
"Markdown Preview",
"Your file must be of type CSS. " + resetMsg
);

_resetCustomTheme();

return;
}

FileSystem.resolve(fi, function (err) {
if (err) {
console.error(err);

Dialogs.showModalDialog(
"",
"Markdown Preview",
"There was an error loading your file. " + resetMsg
);

_resetCustomTheme();
}
});
}

// Debounce event callback to avoid excess overhead
// Update preview 300 ms ofter document change
// Sync scroll 1ms after document scroll (just enough to ensure
Expand Down
3 changes: 2 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -8,5 +8,6 @@
"license": "MIT",
"engines": {
"brackets": ">=1.1"
}
},
"contributors": ["Leandro Silva (http://grafluxe.com)"]
}
1 change: 1 addition & 0 deletions styles/MarkdownPreview.css
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@

#panel-markdown-preview-frame {
border: none;
background-color: #fff;
}

#markdown-settings-toggle {
Expand Down
4 changes: 2 additions & 2 deletions templates/preview.html
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,12 @@
<base href="<%= baseUrl %>">
<link rel="stylesheet" href = "<%= themeUrl %>">
</head>
<body onload="document.body.scrollTop = <%= scrollTop %>">
<body onload="document.body.scrollTop = <%= scrollTop %>" class="markdown-body">
<%= bodyText %>
<script>
// Set scrollTop as soon as the body is parsed. This help with flicker when
// the onload event is delayed until images are loaded.
document.body.scrollTop = <%= scrollTop %>;
</script>
</body>
</html>
</html>
2 changes: 2 additions & 0 deletions templates/settings.html
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@
<option value="clean">Light</option>
<option value="dark">Dark</option>
<option value="serif">Classic</option>
<option value="github">GitHub</option>
<option value="custom">Custom</option>
</select>
</div>
<div>
Expand Down
Loading