From 2be5e4ff7d7dca0ead8dae25c487869a72fa3856 Mon Sep 17 00:00:00 2001 From: Titus Date: Wed, 20 Jun 2012 21:35:47 -0600 Subject: [PATCH] Added documentation for authoring and testing extensions --- README.md | 72 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 72 insertions(+) diff --git a/README.md b/README.md index e897c4f..e9ac627 100644 --- a/README.md +++ b/README.md @@ -232,6 +232,78 @@ Once installed the tests can be run from the project root using: New test cases can easily be added. Create a markdown file (ending in `.md`) which contains the markdown to test. Create a `.html` file of the exact same name. It will automatically be tested when the tests are executed with `mocha`. +Creating Markdown Extensions +---------------------------- + +A showdown extension is simply a function which returns an array of extensions. Each single extension can be one of two types: + + - Language Extension -- Language extensions are ones that that add new markdown syntax to showdown. For example, say you wanted `^^youtube http://www.youtube.com/watch?v=oHg5SJYRHA0` to automatically render as an embedded YouTube video, that would be a language extension. + - Output Modifiers -- After showdown has run, and generated HTML, an output modifier would change that HTML. For example, say you wanted to change `
` to be `
`, that would be an output modifier. + +Each extension can provide two combinations of interfaces for showdown. + +#### Regex/Replace + +Regex/replace style extensions are very similar to javascripts `string.replace` function. Two properties are given, `regex` and `replace`. `regex` is a string and `replace` can be either a string or a function. If `replace` is a string, it can use the `$1` syntax for group substituation, exactly as if it were making use of `string.replace` (internally it does this actually); The value of `regex` is assumed to be a global replacement. + +#### Regex/Replace Example + +``` js +var demo = function(converter) { + return [ + // Replace escaped @ symbols + { type: 'lang', regex: '\\@', replace: '@' } + ]; +} +``` + +#### Filter + +Alternately, if you'd just like to do everything yourself, you can specify a filter which is a callback with a single input parameter, text (the current source text within the showdown engine). + +#### Filter Example + +``` js +var demo = function(converter) { + return [ + // Replace escaped @ symbols + { type: 'lang', function(text) { + return text.replace(/\\@/g, '@'); + }} + ]; +} +``` + +#### Implementation Concerns + +One bit which should be taken into account is maintaining both client-side and server-side compatibility. This can be achieved with a few lines of boilerplate code. First, to prevent polluting the global scope for client-side code, the extension definition should be wrapped in a self executing function. + +``` js +(function(){ + // Your extension here +}()); +``` + +Second, client-side extensions should add a property onto `Showdown.extensions` which matches the name of the file. As an example, a file named `demo.js` should then add `Showdown.extensions.demo`. Server-side extensions can simply export themselves. + +``` js +(function(){ + var demo = function(converter) { + // ... extension code here ... + }; + + // Client-side export + if (typeof window !== 'undefined' && window.Showdown && window.Showdown.extensions) { window.Showdown.extensions.demo = demo; } + // Server-side export + if (typeof module !== 'undefined') module.exports = demo; +}()); +``` + +#### Testing Extensions + +The showdown test runner is setup to automatically test cases for extensions. To add test cases for an extension, create a new folder under `./test/extensions` which matches the name of the `.js` file in `./src/extensions`. Place any test cases into the filder using the md/html format and they will automatically be run when tests are run. + + Credits ---------------------------