public
Last active

*[data-markdown] - use markdown, sometimes, in your HTML

  • Download Gist
data-markdown.user.js
JavaScript
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36
// ==UserScript==
// @name Use Markdown, sometimes, in your HTML.
// @author Paul Irish <http://paulirish.com/>
// @link http://git.io/data-markdown
// @match *
// ==/UserScript==
 
 
// If you're not using this as a userscript just delete from this line up. It's cool, homey.
 
(function boom(){
if (!window.Showdown){
var scr = document.createElement('script');
scr.onload = boom;
scr.src = 'https://raw.github.com/github/github-flavored-markdown/gh-pages/scripts/showdown.js';
document.body.appendChild(scr);
return;
}
 
[].forEach.call( document.querySelectorAll('[data-markdown]'), function fn(elem){
// strip leading whitespace so it isn't evaluated as code
var text = elem.innerHTML.replace(/\n\s*\n/g,'\n'),
// set indentation level so your markdown can be indented within your HTML
leadingws = text.match(/^\n?(\s*)/)[1].length,
regex = new RegExp('\\n?\\s{' + leadingws + '}','g'),
md = text.replace(regex,'\n'),
html = (new Showdown.converter()).makeHtml(md);
 
// here, have sum HTML
elem.innerHTML = html;
 
});
 
}());
example.html
HTML
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
<div class="slide">
<section class="hbox" data-markdown>
## Who Am I?
 
* Lead developer of [Modernizr](//modernizr.com)
* Project lead of [HTML5 Boilerplate](//h5bp.com)
* I curate that [page of polyfills](//bit.ly/polyfills)
* Member of jQuery Team
* Developer Relations on Google Chrome team
</section>
</div>
 
 
 
<script src="data-markdown.user.js"></script>
readme.md
Markdown

*[data-markdown]

I just put some markdown in ur HTML

In prototypes and HTML-based slide decks, it's pleasant to write in markdown sometimes and avoid all those angle brackets.

So the idea is you're operating in an HTML environment but a few shortcuts would help so use markdown here and there.

To use:

  1. Add the following script into your HTML after the content, before other scripts
  2. Add data-markdown attributes to any tags where you're gonna use markdown within. (see example)

Userscript or script-script

This script works fine in your page and can also be used as a userscript. Just click the raw link right below to install.

(As this requires some clientside js and can trigger FOUC, this is not for production use)

Now we Can do the slides on markdown as we talked!
Rocks!

This would make a fine user script. Could you just add these lines and rename the file as data-markdown.user.js?

// ==UserScript==
// @name Use Markdown, sometimes, in your HTML.
// @author Paul Irish <http://paulirish.com/>
// @link http://git.io/data-markdown
// @match *
// ==/UserScript==

@mathiasbynens Then it would only work on your browser. The original gist will turn the page into HTML when anyone views it from any browser.

@cpatik Exactly. As @paulirish said, this is not intended for production use. But IMHO it would be great as a userscript, especially combined with something like // @match http://slides.local/.

userscriptified. also wired up a document.write dependency. hotttt

document.write is the new @require/scriptElement.onload.

@mathiasbynens Touché, it didn't occur to me that with your change the same script could be used in both ways :)

@mathiasbynens What does the UserScript comment do? Is it something you can then put in a special place in Google Chrome or something?

Nice. This one will load faster since raw is a generated file and isn't cached.

http://github.github.com/github-flavored-markdown/scripts/showdown.js

document.write

more like

document dot right

@espadrine When you click the "raw" link in the top right of this gist, in either Firefox with Greasemonkey or just plain old Chrome it will prompt you to install the script. That means it'll automatically run on any page matched by the @match line in the script (in this case, any page at all because it's an asterisk).

Did some experimenting with something similar recently. Turns out it's more complicated than what you propose.

Two problems:

HTML entities

elem.textContent will mess up HTML, but Markdown is supposed to be a superset of HTML. So you will need elem.innerHTML, but that will encode certain characters as HTML entities.

For example, the following Markdown in your document will render just fine:

you & me > the *competition*

Result:

<p>you &amp; me &gt; the <em>competition</em></p>

But imagine having something like this in your document:

Our formula: `you & me > the *competition*`

What you want the rendered result to be:

<p>Our formula: <code>you &amp; me &gt; the *competition*</code></p>

What the rendered result is instead:

<p>Our formula: <code>you &amp;amp; me &amp;gt; the *competition*</code></p>

A solution is to manually decode all HTML entities before passing the string on to the Markdown parser. I used something along the following lines (uses jQuery), but it could very well be that there are problems with this approach as well (for example; aren't we decoding a lot of entities that should not be decoded at all here?):

var md = $(elem).html().replace(/&[^;]+;/g, function(entity) {
  return $('<span>' + entity + '</span>').text();
});
var rendered = showdown.makeHtml(md);

Indentation

As soon as you want to include a monospaced block or anything that requires extra indentation, your solution of simply stripping all leading whitespace will mess things up.

@timmolendijk

it's always more complicated. :) yeah i suppose the indentation stripping i'm doing will kill nested lists. ways around that i suppose.

code blocks are already taken care of with the triple-backtick syntax.

for entities, leaving the literals there by themselves would be fine. you don't need to escape either of those.

@paulirish Leaving the literals is not an option because elem.innerHTML will encode them for you.

It's not actually doing anything in Chrome or Greasemonkey for Firefox...

@Digitalsabre actually, for my version of Google Chrome (which is pretty much the stable on), it tries to install the script, but fails with an "invalid script header" (which makes sense, in a way, I suppose).

Correction, after fixing the header (Chrome does not like @match *), the result is a page with no body content.
In Firefox, it just doesn't do anything at all.

@espadrine Try removing line 5. It should install, but then it just returns a page with no body content.

@Digitalsabre ... which is clearly not what we want ;)

@espadrine This is, admittedly, my first time working with user scripts. I really want this to work, so I hope someone comes to help us get it working.

@paulirish, @timmolendijk, @cpatik, any ideas? After forking, I've replaced // @match * with // @include *, but still GreaseMonkey does nothing. I've even added a GM_log('running...'); to the script and it doesn't appear to output that to the console. And since doing this, it will actually install in Chrome, but the result is a blank page. Check my fork for what I've done there, including fleshing out the example page.

Now we're getting somewhere:

Uncaught ReferenceError: Showdown is not defined
script.js:20

@Digitalsabre Showdown is defined in GitHub Flavored Markdown, in the document.write.

@espadrine Sure, but Chrome doesn't seem to think so.

@Digitalsabre No more of this bug with this implementation: https://gist.github.com/1349268 (but hey, still doesn't do what we want ey!

@espadrine, @Digitalsabre This works: https://gist.github.com/1349945 The trick is you have to run your code in the context of the page, not of the userscript. Bonus (untested): it should work in Firefox (Greasemonkey or Scriptish), Chrome, and Opera.

@espadrine @digitalsabre @passcod Sounds like you guys need an unsafeWindow polyfill: https://gist.github.com/1143845

@mathiasbynens No we don't, because my version runs the code directly into the page, therefore going out of the GM scope as fast as possible. A few years ago I developed this technique exactly because I was tired of playing with unsafeWindow, polyfill or not.

very cool!! rock on man...

Just updated the code. fixes:

  • Chrome wasn't treating the document.write as synchronous so now we're using a script onload. feels good man
  • indentation level of the source can be arbitrary, which lets you indent the markdown within your HTML. We compute how much indent to treat as default with the first line.

and it works as is in html5slide too! excelent.

What about using the following to get the markdown content

var text      = elem.innerHTML.replace(/\n\s*\n/g,'\n');

Instead of the following. This would give a better support for html embeded in markdown, no ?

var text      = elem.textContent.replace(/\n\s*\n/g,'\n');

This has now been implemented in the very excellent reveal.js:
https://github.com/hakimel/reveal.js#markdown

Please sign in to comment on this gist.

Something went wrong with that request. Please try again.