在服务器端为 ColdFusion 实现 Showdown.js markdown 解析器

发布于 2024-10-10 06:06:11 字数 2258 浏览 6 评论 0原文

这是一个“事实调查”问题,旨在了解使用 创建 ColdFusion UDF 来解析服务器上的 markdown 有多困难showdown.js 解析器。 已经有一个利用 showdown.js 的 java 实现(请参阅本文末尾的代码),我想了解如何为 ColdFusion 实现它。我没有 Java 经验,我不会特别称自己为“程序员”,但我不希望这阻止我尝试。

摘要

我想在服务器端运行 Shadown.js 以转换 markdown到 HTML。

为什么?

保存用户条目的两个版本,一个是 Markdown 格式,另一个是 HTML 格式,这样我们就可以向最终用户显示原始 Markdown 版本,以防他们想要编辑其条目。

为什么不使用服务器端解析器?

有两个原因:

  1. 到目前为止,还没有用于此特定目的的 ColdFusion markdown 解析器
  2. 在客户端使用 Showdown.js,然后在客户端使用不同的解析器服务器端将导致向客户端显示的预览与数据库中存储的版本之间的标记不一致。鉴于 markdown 的定义很松散,大多数解析器实现都会有细微的差异。

一个非常好的博客条目讨论这个问题。

为什么不在客户端进行所有解析并发布两个版本?

我认为这不是一个安全的解决方案。我还认为用户可能会发布带有不匹配 HTML 的 Markdown。

是否有任何现有的实现?

一个名为 CFShowdown 的实现,但它不是用于此特定目的。相反,它用于处理页面上的输出。 上述博客的评论部分具有由名为 David 的用户编写的纯 Java 实现:

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]";
}

目标

创建一个 java 类,该类允许我们将此实现与 ColdFusion UDF 或组件内的自定义标记一起使用,类似于 < code>

由于我没有 Java 经验,因此我希望从用户那里获得一些关于从何处以及如何开始执行此任务的建议和意见。我创建了一个

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:

  1. As of now there are no ColdFusion markdown parsers for this specific purpose
  2. 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

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

方圜几里 2024-10-17 06:06:11

将文件 showdown.js 和文件 markdown.txt (下面的示例)放在同一目录。

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>

ma​​rkdown.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"

更新

这是一个采用Adam Presley 在 Java 中的工作 并在 CFC 中完成这一切。请注意,我采用了他在 showdown.js 末尾添加的一点点魔法,并将其放入附加了返回值的 CFC 函数中(即 showdownAdapterJS())。

氟氯化碳

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

的使用

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

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>
浅听莫相离 2024-10-17 06:06:11

您可以使用 CFGroovy 在 CF 中运行服务器端 javascript - 它基本上允许您运行与 CFML 内联的任何 JSR-223 脚本语言。

Ben Nadel 有一个运行示例使用 CFGroovy 和 Rhino 的服务器端 javascript

该示例包含您需要的一切 - 假设您已经将 javascript 代码放在一起。

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.

眼趣 2024-10-17 06:06:11

事实上,我已经将 Showdown 封装在一个可以在 ColdFusion 中使用的 Java 库中。我提供的示例(我承认文档很差)使用了自定义标记,但您可以像这样轻松地使用 Java 组件。

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

也许这有帮助?不管怎样,Markdown 万岁! :)

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! :)

红颜悴 2024-10-17 06:06:11

鉴于 Markdown 不是一种常规语言,并且大多数实现都是一系列正则表达式,因此它们之间必然存在差异,正如您所指出的。几乎无法避免它。

如果您的目标只是:

  1. 提供具有实时预览功能的客户端 Markdown 编辑器(如 Stack Overflow 问题/答案编辑器),并
  2. 存储生成的 html 的相同处理副本以供最终用户显示

那么我只看到两个实际选项:

  1. 在服务器端执行所有 Markdown 处理,并使用 AJAX 提交 Markdown 并获取更新的预览 html 完成预览(使用最终用于生成存储的 html 的同一库),或者
  2. 执行所有 Markdown 处理客户端,并提交两者原始 Markdown 和生成的 HTML 作为内容合成表单的一部分并存储两者;这样您就可以显示原始 Markdown 进行编辑,并显示生成的 HTML 进行显示。

就我个人而言,我会选择选项 2。

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:

  1. Provide a client-side markdown editor with live-preview (like the Stack Overflow question/answer editor), and
  2. Store an identically-processed copy of the generated html for end-user display

Then I see only two real options:

  1. 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
  2. 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.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文