This is a "fact finding" question to see how difficult it would be to create a ColdFusion UDF to parse markdown on the server using the showdown.js parser. There is already a java implementation that utilizes showdown.js (see code at the end of this post) and I want to see how to go about implementing it for ColdFusion. I have no experience in Java and I would not particularly call myself "a programmer," but I don't want this to stop me from trying.
Summary
I would like to run Shadown.js server-side in order to convert markdown to HTML.
Why?
Saving two versions of a user entry, one in markdown format and another in HTML, allows us to display the raw markdown version to the end user in case they wanted to edit their entry.
Why not use a server-side parser?
For two reasons:
As of now there are no ColdFusion markdown parsers for this specific purpose
Using Showdown.js on the client-side, and then a different parser on the server-side will result in inconsistent markup between the preview displayed to the client and the version stored in the database. Given that markdown is loosely defined, most parser implementations will have subtle differences.
There is a very good blog entry that discusses the issue.
Why not do all the parsing on the client-side and post both versions?
This does not strike me as a secure solution. I also think users would potentially be able to post markdown with HTML that does not match.
Are there any existing implementations?
There is one implementation called CFShowdown, but it's not for this specific purpose. Rather, it's for handling output on a page. The comments section of the aforementioned blog features 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]";
}
Objective
Create a java class that would allow us to use this implementation with a ColdFusion UDF or a custom tag inside a component, something along the lines of <cfset html = getMarkdown(string)>
Since I have no experience with Java, I want to get some advice and input from users on where and how to start going about this task. I created a
Have files showdown.js and a file markdown.txt (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 a version that takes Adam Presley's work in Java and does it all in a CFC. Note I took that little bit of magic he added at the end of showdown.js and put it into a CFC function whose return value is appended (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>
Usage
<cfset showdown = createObject("component", "Showdown").init()>
<cfset markdownString = fileRead("#getDirectoryFromPath(getCurrentTemplatePath())#/markdown.txt")>
<cfoutput>#showdown.toHTML(markdownString)#</cfoutput>
You can run server-side javascript in CF by using CFGroovy - which basically allows you to run any JSR-223 scripting language inline with CFML.
Ben Nadel has an example of running server-side javascript using CFGroovy and Rhino
The example has everything you need - assuming you have the javascript code already put together.
Actually, I've already wrapped up Showdown in a Java library that can be used in ColdFusion. The example I provide, in what I admit is poor documentation, uses a custom tag, but you can use the Java component just as easily like so.
<cfset obj = createObject('java', 'com.adampresley.cfshowdown.Showdown').init() />
<cfset parsedText = obj.toHTML(trim(someMarkdownContent)) />
Perhaps that helps? Either way, long live Markdown! :)
Given that Markdown is not a regular language, and a majority of implementations are a series of regular expressions, there are bound to be differences between them, as you noted. There is almost no avoiding it.
If your objective is just to:
Provide a client-side markdown editor with live-preview (like the Stack Overflow question/answer editor), and
Store an identically-processed copy of the generated html for end-user display
Then I see only two real options:
Do all markdown processing server-side, and accomplish your preview using AJAX to submit the markdown and get the updated preview html (using the same library that you'll ultimately use to generate the stored html), or
Do all markdown processing client-side, and submit both the raw markdown and the generated HTML as parts of your content composition form and store 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.
Related
I am working with the Tika Java library. I'm using Lucee (a sub part of ColdFusion) and when I use an online example to retrieve text from a PDF I get an empty string.
What is the setup?
I've installed Lucee locally and have access to an empty index.cfm page. I've added the Tika jar file to the project and I see it's loaded correctly in the Lucee admin.
What is the code?
The following part is the most simple code I could find to convert a PDF to text:
handler = createObject("java", "org.apache.tika.sax.BodyContentHandler");
metadata = createObject("java", "org.apache.tika.metadata.Metadata");
inputstream = createObject("java", "java.io.FileInputStream").init(createObject("java", "java.io.File").init('C:\lucee\tomcat\webapps\ROOT\test\dummy.pdf'));
pcontext = createObject("java", "org.apache.tika.parser.ParseContext");
pdfparser = createObject("java", "org.apache.tika.parser.AutoDetectParser");
pdfparser.parse(inputstream, handler, metadata, pcontext);
writeDump(handler.toString());
so when I run this I get an empty string and I expect the text inside the PDF. Also all the metadata is empty.
Conclusion
I think that the library is perhaps not loaded correctly. But what can I do to see where this is going wrong? I don't get any error, just empty values. Tried different PDFs and even different files. Tried the autoparser and different kind of codes. Is this maybe a Lucee problem? Or a Java problem?
How can i insert javascript in java file. If i am inserting html tags it works fine but if i insert following js code it doesn't show any errors but it will not show the chart also.
i'am using chart.js
out.write(""<h1>Graph</h1>\n"");
out.write("<canvas id='canvas' height='450' width='600'></canvas>\n");
out.write("<script>\n");
out.write("var barChartData = \n");
out.write("{labels : ['Pass','Fail'],\n");
out.write("datasets : {\n");
out.write("[fillColor : 'rgba(220,220,220,0.5)',\n");
out.write("strokeColor : 'rgba(220,220,220,1)',\n");
out.write("data : [65,0]},{\n");
out.write("fillColor : 'rgba(151,187,205,0.5)',\n");
out.write("data : [0,47]}]}\n");
out.write("var myLine = new Chart(document.getElementById('canvas').getContext('2d')).Bar(barChartData);\n");
out.write("</script>\n");
Is this is the correct way using out.write ?
According to the HTML 4 specification, a <script> element requires either a type or lang attribute, unless you have specified the default scripting language.
A document that doesn't conform to this is erroneous, and the browser is free to ignore the script.
Another possibility is that your script contains errors. Use your browser's web developer support to check for javascript errors.
If you are writing to a file on Windows, use \r\n instead, because windows filesystem doesn't understands \ns as newlines. Else, you must provide more info. It could also be because you missed declarating the script type.
I want to use javascript libraries to make visualizations like D3 and many other cool ones. But my main application that generates the data is written in java. Is there a way to write a javascript in a java component and then display the visualization from java? Of course I need to pass the data from java to javascript in order to make the visualization.
Since Java 1.6 you can include JavaScript in Java using the ScriptEngine class. You can call functions from java, pass arguments and read results.
http://docs.oracle.com/javase/6/docs/technotes/guides/scripting/programmer_guide/
Short example of loading a javascript and calling a function:
ScriptEngineManager manager = new ScriptEngineManager();
ScriptEngine engine = manager.getEngineByName("js");
InputStreamReader reader = new InputStreamReader(this.getClass().getResourceAsStream("somejavascriptinthesamepackage.js"));
engine.eval(reader);
reader.close();
String result = (String) engine.eval("someFunction(" + <insert argement> + "));");
You should give more data about how the user is viewing the data, is it a web application, is the user viewing the data from a web browser and so on...
However, you can generate your data in java and then pass a JSON string to the js code. And the js code will take care of the display.
A good JSON lib is: Jackson.
I am not sure if this is possible, but I'm trying to find a front-end solution to this situation:
I am setting a JavaScript variable to a dynamic tag, populated by backend Java code:
var myString = '#myDynamicContent#';
However, there are some situations, in which the content from the output contains a carriage return; which breaks the code:
var mystring = '<div>
Carriage Return happened above and below.
</div>';
Is there anyway I can resolve this problem on the front-end? Or is it too late in the script to do something about it, because the dynamic tag will run before any JavaScript runs (thus the script is broken by that point)?
I'm sure my JS could be cleaned up (just thought this was a fun problem), but you could search out the comment in the JS.
Lets say your JS looks like this (noticed I added a tag to the comment so we know we're going after the correct one, and there is a div to just for testing):
<script id="testScript">
/*<captureMe><div>
Carriage Return happened above and below.
</div>
*/
var foo = 'bar';
</script>
<div id='test'>What do I see:</div>
Just use this to grab the comment:
var something = $("#testScript").html();
var newSomething = '';
newSomething = something.substr(something.indexOf("/*<captureMe>")+13);
newSomething = newSomething.substr(0, newSomething.indexOf("*/"));
$('#test').append('<br>'+newSomething); // just proving we captured the output, will not render returns or newline as expected by HTML
Technically, it works :), scripting-scripting...
Charbs
JavaScript supports strings that can span multiple lines by putting a backslash (\) at the end of the line, for example:
var myString = 'foo\
bar';
So you should be able to do a Java replace when you write in your server-side variable:
var myString = '#myDynamicContent.replaceAll("\\n", "\\\\n")#';
Replace the \n and/or \r with \\n and/or \\r respectively ... but it has to be done in the server-side language (in your case Java); it can't be done in JavaScript.
Building off of #Charbs' answer, you could avoid the JavaScript comments if you give your script tag a different mime type, so the browser won't try to evaluate it as JavaScript:
<script id="testScript" type="text/notjs" style="display:none">#myDynamicContent#</script>
And then just grab it like this (using jQuery):
var myString = $('#testScript').text();
To me it looks like you're doing token replacement instead of using a template engine. If you like token replacement you might Snippetory too, as it creates similar code. However it has a number of additional features. Using
var myString = '{v:myDynamicContent enc="string"}'
would create
var mystring = '<div>\r\n Carriage Return happened above and below.\r\n </div>'
And thus solve your problem. But you would have to change your code behind, too.
I am using Rhino as part of an Ant build process to bundle and minify JavaScript. In addition to that, I would also like pre-compile client-side templates, i.e. compile them from markup to JavaScript. At a glance, I thought Rhino's serialize() method would do it but that does not seem to be the case.
// Load templating engine
load( "engine.js" );
// Read template file
var template = readFile( "foo.template" ),
// Compile template
compiled = engine.compile( template );
// Write compiled template to file
serialize( compiled, "compiledFoo.js" );
This results in a binary file being written. What I want is a text file which contains the compiled template.
If using serialize() is not the answer, then what is? Since it's Rhino, it would be possible to import Java classes as well. Offhand, I can't figure out a way to do it.
I know this can be done in Node but I'm not in a position to migrate the build process from Ant-Rhino to Grunt-Node right now.
In my search for an answer I came across the fact that SpiderMonkey, Rhino's C/C++ sister, has an uneval() function, which as you can guess does the opposite of JavaScript's eval() function. One more Google search later, I found that Rhino implemented uneval() in 1.5R5. This may be the only documentation that mentions Rhino has this feature (or not).
That being said, here is the solution:
// Load the templating engine
load( "engine.js" );
// Read the template file
var template = readFile( "foo.template" ),
// Compile the template markup to JavaScript
compiled = engine.compile( template ),
// Un-evaluate the compiled template to text
code = uneval( compiled ),
// Create the file for the code
out = new java.io.FileWriter( "foo.js" );
// Write the code to the file
out.write( code, 0, code.length );
out.flush();
out.close();
quit();
Write a function in the javascript that you can call from Java that returns the value that you need as a string.