Implementing Server-Side Showdown.js markdown parser for ColdFusion

This is a "fact finding" question to understand how difficult it would be to create ColdFusion UDF to analyze markup on the server using the showdown.js parser . There is already a java implementation that uses showdown.js (see the code at the end of this post), and I want to see how to do this for ColdFusion. I have no experience in Java, and I would not call myself a "programmer", but I do not want this to stop me from trying.

Summary

I want to run Shadown.js on the server side to convert markdown to HTML.

Why?

Saving two versions of the user record, one in markdown format and the other in HTML, allows us to display the original version of markdown to the end user in case they want to edit their record.

Why not use a server-side parser?

For two reasons:

  • No ColdFusion parsers currently exist for this specific purpose.
  • Using Showdown.js on the client side and then another server-side parser will result in inconsistent markup between previewing the client and the version stored in the database. Given that markdowns are poorly defined, most parser implementations will have subtle differences.

There is a very good blog post discussing issues.

Why not do all client-side parsing and publish both versions?

This does not make me a safe solution. I also think that users will potentially be able to submit markdowns with HTML that does not match.

Are there any existing implementations?

There is one implementation called CFShowdown , but this is not for this specific purpose. Rather, it is designed to handle the output on a page. The comments section of the aforementioned blog contains a pure Java implementation written by a user called David:

ScriptEngineManager manager = new ScriptEngineManager(); ScriptEngine jsEngine = manager.getEngineByName("js"); try { jsEngine.eval(new InputStreamReader(getClass().getResourceAsStream("showdown.js"))); showdownConverter = jsEngine.eval("new Showdown.converter()"); } catch (Exception e) { log.error("could not create showdown converter", e); } try { return ((Invocable) jsEngine).invokeMethod( showdownConverter, "makeHtml", markdownString ) + ""; } catch (Exception e) { log.error("error while converting markdown to html", e); return "[could not convert input]"; } 

goal

Create a java class that allows us to use this implementation with ColdFusion UDF or a custom tag inside the component, something like strings <cfset html = getMarkdown(string)>

Since I have no experience with Java, I want to get some tips and information from users on where and how to get started with this task. I created

+5
source share
4 answers

Have the showdown.js files and the markdown.txt file (example below) in the same directory.

showdown.cfm

 <cfscript> manager = createObject("java", "javax.script.ScriptEngineManager").init(); jsEngine = manager.getEngineByName("js"); showdownJS = fileRead('#getDirectoryFromPath(getCurrentTemplatePath())#/showdown.js'); jsEngine.eval(showdownJS); showdownConverter = jsEngine.eval("new Showdown.converter()"); markdownString = fileRead("#getDirectoryFromPath(getCurrentTemplatePath())#/markdown.txt"); args = [markdownString]; result = jsEngine.invokeMethod( showdownConverter, "makeHtml", args ) & ""; </cfscript> 

markdown.txt

 Showdown Demo ------------- You can try out Showdown on this page: - Type some [Markdown] text on the left side. - See the corresponding HTML on the right. For a Markdown cheat-sheet, switch the right-hand window from *Preview* to *Syntax Guide*. Showdown is a JavaScript port of the original Perl version of Markdown. You can get the full [source code] by clicking on the version number at the bottom of the page. Also check out [WMD, the Wysiwym Markdown Editor][wmd]. It'll be open source soon; email me at the address below if you'd like to help me test the standalone version. **Start with a [blank page] or edit this document in the left window.** [Markdown]: http://daringfireball.net/projects/markdown/ [source code]: http://attacklab.net/showdown/showdown-v0.9.zip [wmd]: http://wmd-editor.com/ [blank page]: ?blank=1 "Clear all text" 

Update

Here's the version that Adam Presley accepts works in Java and does it all in CFC. Notice that I took that little magic that he added at the end of showdown.js and put it in a CFC function whose return value was added (i.e. showdownAdapterJS() ).

Cfc

 <cfcomponent output="false" accessors="true"> <cffunction name="init" output="false" access="public" returntype="Showdown" hint="Constructor"> <cfset variables.manager = createObject("java", "javax.script.ScriptEngineManager").init()> <cfset variables.engine = manager.getEngineByName("javascript")> <cfreturn this/> </cffunction> <cffunction name="toHTML" output="false" access="public" returntype="any" hint=""> <cfargument name="markdownText" type="string" required="true"/> <cfset var local = structNew()/> <cfset var bindings = variables.engine.createBindings()> <cfset var result = ""> <cftry> <cfset bindings.put("markdownText", arguments.markdownText)> <cfset variables.engine.setBindings(bindings, createObject("java", "javax.script.ScriptContext").ENGINE_SCOPE)> <cfset var showdownJS = fileRead('#getDirectoryFromPath(getCurrentTemplatePath())#/showdown.js')> <cfset showdownJS &= showdownAdapterJS()> <cfset result = engine.eval(showdownJS)> <cfcatch type="javax.script.ScriptException"> <cfset result = "The script had an error: " & cfcatch.Message> </cfcatch> </cftry> <cfreturn result> </cffunction> <cffunction name="showdownAdapterJS" output="false" access="private" returntype="string" hint=""> <cfset var local = structNew()/> <cfsavecontent variable="local.javascript"> <cfoutput>#chr(13)##chr(10)#var __converter = new Showdown.converter(); __converter.makeHtml(markdownText);</cfoutput> </cfsavecontent> <cfreturn local.javascript> </cffunction> </cfcomponent> 

Using

 <cfset showdown = createObject("component", "Showdown").init()> <cfset markdownString = fileRead("#getDirectoryFromPath(getCurrentTemplatePath())#/markdown.txt")> <cfoutput>#showdown.toHTML(markdownString)#</cfoutput> 
+4
source

You can run server-side javascript in CF using CFGroovy - which basically allows you to run any JSR-223 scripting language with CFML.

Ben Nadel has an example of running server-side javascript using CFGroovy and Rhino

The example has everything you need - if you already have javascript code.

+3
source

In fact, I already wrapped Showdown in a Java library that can be used in ColdFusion. The example that I provide, in that I admit, is poor documentation, uses a special tag, but you can use the Java component as easily as this.

 <cfset obj = createObject('java', 'com.adampresley.cfshowdown.Showdown').init() /> <cfset parsedText = obj.toHTML(trim(someMarkdownContent)) /> 

Maybe this helps? In any case, long live Markdown! :)

+3
source

Given that Markdown is not an ordinary language, and most implementations are a series of regular expressions, as you noted, there are differences between them. It is almost there.

If your goal is this:

  • Provide a client-side label editor with real-time preview (e.g. a question / answer editor for) and
  • Save identically processed copy of generated html to display end user

Then I see only two real options:

  • Do all the server side fingerprint processing and preview with AJAX to send markdowns and get an updated html preview (using the same library that you ultimately use to create the saved html), or
  • Perform processing of all markings on the client side and send both raw markdown and generated HTML as part of the form of your content and save both; so that you can display the original markdown for editing purposes and the generated HTML for display purposes.

Personally, I would go with option 2.

+1
source

All Articles