Created
February 9, 2018 00:06
-
-
Save mcsf/57a4f328ff20ace2b3423bb69c2bcc53 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
diff --git a/blocks/api/raw-handling/markdown-converter.js b/blocks/api/raw-handling/markdown-converter.js | |
new file mode 100644 | |
index 00000000..a2d3fa63 | |
--- /dev/null | |
+++ b/blocks/api/raw-handling/markdown-converter.js | |
@@ -0,0 +1,77 @@ | |
+/** | |
+ * External dependencies | |
+ */ | |
+import showdown from 'showdown'; | |
+ | |
+export default class MarkdownConverter { | |
+ makeHtml( html ) { | |
+ // Oh, the horror! | |
+ this.converter = makeConverter( html ); | |
+ return this.converter.makeHtml( html ); | |
+ } | |
+} | |
+ | |
+function makeConverter( html ) { | |
+ let options = {}; | |
+ const tags = collectShortcodes( html ); | |
+ if ( tags.length ) { | |
+ const regex = tagsToRegex( collectShortcodes( html ) ); | |
+ showdown.extension( 'ignoreShortcodes', ignoreShortcodes( regex ) ); | |
+ options.extensions = [ 'ignoreShortcodes' ]; | |
+ } | |
+ const converter = new showdown.Converter( options ); | |
+ converter.setOption( 'noHeaderId', true ); | |
+ converter.setOption( 'tables', true ); | |
+ converter.setOption( 'literalMidWordUnderscores', true ); | |
+ return converter; | |
+} | |
+ | |
+function collectShortcodes( html ) { | |
+ let match; | |
+ const tags = []; | |
+ const re = /\[\/([a-z][a-z0-9_-]*)\]/g; | |
+ while ( ( match = re.exec( html ) ) !== null ) { | |
+ tags.push( match[ 1 ] ); | |
+ } | |
+ return tags; | |
+} | |
+ | |
+function tagsToRegex( tags ) { | |
+ return new RegExp( | |
+ '(' + | |
+ // TODO regex-escape tag | |
+ tags.map( tag => ( | |
+ `\\[${tag}\\](.*)\\[\\/${tag}\\]` | |
+ ) ).join( '|' ) + | |
+ ')', | |
+ 'g' | |
+ ); | |
+} | |
+ | |
+function ignoreShortcodes( regex ) { | |
+ return function() { | |
+ let matches = []; | |
+ return [ | |
+ { | |
+ type: 'lang', | |
+ regex, | |
+ replace( string ) { | |
+ matches.push( string ); | |
+ const n = matches.length - 1; | |
+ return '%PLACEHOLDER' + n + '%'; | |
+ }, | |
+ }, | |
+ { | |
+ type: 'output', | |
+ filter(text) { | |
+ for (let i=0; i< matches.length; ++i) { | |
+ const pat = '%PLACEHOLDER' + i + '% *'; | |
+ text = text.replace(new RegExp(pat, 'g'), matches[i]); | |
+ } | |
+ matches = []; | |
+ return text; | |
+ }, | |
+ } | |
+ ]; | |
+ }; | |
+} | |
diff --git a/blocks/api/raw-handling/test/markdown-converter.js b/blocks/api/raw-handling/test/markdown-converter.js | |
new file mode 100644 | |
index 00000000..23882eff | |
--- /dev/null | |
+++ b/blocks/api/raw-handling/test/markdown-converter.js | |
@@ -0,0 +1,38 @@ | |
+/** | |
+ * External dependencies | |
+ */ | |
+import { equal } from 'assert'; | |
+ | |
+/** | |
+ * Internal dependencies | |
+ */ | |
+import MarkdownConverter from '../markdown-converter'; | |
+ | |
+describe( 'MarkdownConverter', () => { | |
+ describe( 'when using shortcode extension', () => { | |
+ const converter = new MarkdownConverter(); | |
+ | |
+ it( 'should ignore formatting inside blacklisted shortcodes', () => { | |
+ const input1 = '[my_shortcode]hello, _there_.[/my_shortcode]'; | |
+ const output1 = '<p>[my_shortcode]hello, _there_.[/my_shortcode]</p>'; | |
+ equal( converter.makeHtml( input1 ), output1 ); | |
+ | |
+ const input2 = '[other_shortcode]hello, _there_.[/other_shortcode]'; | |
+ const output2 = '<p>[other_shortcode]hello, _there_.[/other_shortcode]</p>'; | |
+ equal( converter.makeHtml( input2 ), output2 ); | |
+ } ); | |
+ | |
+ it( 'should do the same for multi-occurrence strings', () => { | |
+ const input = '[my_shortcode]hello, _there_.[/my_shortcode] [other_shortcode]hello, _there_.[/other_shortcode]'; | |
+ | |
+ const output = '<p>[my_shortcode]hello, _there_.[/my_shortcode][other_shortcode]hello, _there_.[/other_shortcode]</p>'; | |
+ equal( converter.makeHtml( input ), output ); | |
+ } ); | |
+ | |
+ it( 'should ignore content around unclosed shortcode tags', () => { | |
+ const input = '**oh**, [unknown]hello, _there_.'; | |
+ const output = '<p><strong>oh</strong>, [unknown]hello, <em>there</em>.</p>'; | |
+ equal( converter.makeHtml( input ), output ); | |
+ } ); | |
+ } ); | |
+} ); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment