Skip to content

@paulirish /data-markdown.user.js
Created

Embed URL

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
*[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
  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)

// ==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;
});
}());
<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>
@danielfilho

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

@mathiasbynens

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==
@patik

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

@mathiasbynens

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

@paulirish
Owner

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

@mathiasbynens

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

@patik

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

@niczak

Brilliant.

@espadrine

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

@lancejpollard

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

@SlexAxton

document.write

more like

document dot right

@patik

@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

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
Owner

@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

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

@Digitalsabre

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

@espadrine

@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

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

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

@espadrine

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

@Digitalsabre

@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

Now we're getting somewhere:

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

@espadrine

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

@Digitalsabre

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

@espadrine

@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

@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

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

@passcod

@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

very cool!! rock on man...

@paulirish
Owner

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

and it works as is in html5slide too! excelent.

@jeromeetienne

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
Owner

sgtm. changed.

@paulirish
Owner

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

@MadcowD

Swag!

@makerimages

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

@makerimages

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

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Something went wrong with that request. Please try again.