Skip to content

Instantly share code, notes, and snippets.

@paulirish
Last active February 6, 2024 10:41
Show Gist options
  • Save paulirish/1343518 to your computer and use it in GitHub Desktop.
Save paulirish/1343518 to your computer and use it in GitHub Desktop.
*[data-markdown] - use markdown, sometimes, in your HTML

*[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
  1. 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)

// ==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://cdn.rawgit.com/showdownjs/showdown/master/src/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;
});
}());
<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>
@SlexAxton
Copy link

document.write

more like

document dot right

@patik
Copy link

patik commented Nov 8, 2011

@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).

@timmolendijk
Copy link

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.

@paulirish
Copy link
Author

@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.

@timmolendijk
Copy link

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

@Digitalsabre
Copy link

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

@espadrine
Copy link

@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).

@Digitalsabre
Copy link

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.

@Digitalsabre
Copy link

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

@espadrine
Copy link

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

@Digitalsabre
Copy link

@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.

@Digitalsabre
Copy link

Now we're getting somewhere:

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

@espadrine
Copy link

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

@Digitalsabre
Copy link

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

@espadrine
Copy link

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

@passcod
Copy link

passcod commented Nov 9, 2011

@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.

@mathiasbynens
Copy link

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

@passcod
Copy link

passcod commented Nov 9, 2011

@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.

@greenido
Copy link

greenido commented Nov 9, 2011

very cool!! rock on man...

@paulirish
Copy link
Author

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.

@jeromeetienne
Copy link

and it works as is in html5slide too! excelent.

@jeromeetienne
Copy link

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');

@paulirish
Copy link
Author

sgtm. changed.

@paulirish
Copy link
Author

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

@MadcowD
Copy link

MadcowD commented Aug 20, 2013

Swag!

@makerimages
Copy link

Does this not work when ran on a local .html page??

@makerimages
Copy link

@paulirish ? Or do we need to call boom();??

@makerimages
Copy link

@Kiodaddy
Copy link

It was working fine for you ? I tried it and zero results.

@zmwxiaoming
Copy link

how does it works

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment