Nearly four years ago now, I “implemented” MarkDown for the comments here on my blog. At the time, Graffiti CMS (the blog engine I use) was being fairly regularly updated and I didn’t want to change my server-side code unnecessarily. I’d already run into merge issues in the past with new fixes from the CodePlex repository.
Why the air-quotes for “implemented”? Because I had decided to do this via JavaScript in the browser. Essentially if you opened a blog post, the code would find the comments already made and then convert them using the AttackLabs JavaScript library. Because of the process comments go through on the server-side, this wasn’t exactly the best idea, let alone the fact that displaying a post meant all this extra time-consuming work in the browser. As it happened, those comments that had code blocks in them tended to produce some badly laid-out results.
Over the weekend, I’d finally had enough of the whole thing. Given that Graffiti CMS is pretty much no longer being updated – the scourge of many underfunded open-source projects you might argue (the last update was May 2013) – I decided to finally fork my source code. Time for some changes!
The original code in Graffiti.Core for saving a new comment did this:
protected override void BeforeValidate()
{
base.BeforeValidate();
//By default we allow no markup
if(IsNew)
{
UniqueId = Guid.NewGuid();
Body = Util.ConvertTextToHTML(Body);
IGraffitiUser gu = GraffitiUsers.Current;
That call to Util.ConvertTextToHtml
did three things: it encoded the raw text from the text input field (the comment body) to HTML entity characters where necessary (so, things like <
for <
, &
for &
, and so on), converted any url links it found into <a>
elements, and then wrapped paragraphs into <p>
elements. Unfortunately all that made code blocks in comments look pretty bloody awful. In essence, I’d have to go in and modify them by hand.
The code now looks like this:
protected override void BeforeValidate()
{
base.BeforeValidate();
//By default we allow no markup
if(IsNew)
{
UniqueId = Guid.NewGuid();
//Comments are now written in Markdown and converted
//Body = Util.ConvertTextToHTML(Body);
var markdownProcessor = new Markdown();
Body = markdownProcessor.Transform(Body);
IGraffitiUser gu = GraffitiUsers.Current;
Woah! What’s this Markdown class? I‘m using Jeff Attwood’s MarkdownSharp library (it’s available on NuGet from within Visual Studio, or you can download it here). So, what happens now is that you or I would write MarkDown text in the comment input field, it gets sent via a callback to the server-side code, the text gets transformed to HTML via this MarkDown converter on the server, and stored like that in the Comments table in the database. When it’s shown together with the post it’s associated with, no further processing is done: it’s already in the correct HTML.
(Aside: OK, let me ’fess up here. In reality this happened in two stages as I worked my way to this better solution. My first attempt was to convert all of the comments on this site to what might be called MarkDown text. Then all that happened was the MarkDown text would be sent along with the post HTML and the JavaScript code for the page would convert it on the fly to HTML using the AttackLabs library. In essence, I wrote some batch code that reversed what Graffiti CMS had already done to the comments when saving them (the first code above). Oh boy. Remember what they say about regular expressions? You have an issue, you solve it with regex, and now you have two issues? Yep, that was me in spades – I was drowning in not-quite-right regexes. Happily, in the end, I ended up with this way cleaner and clearer version.)
(Aside, 2ième partie: Hoo, boy has it been a while since I’ve written batch update code in C#. Quite a while…)
Stay tuned as I “fix” other parts of Graffiti CMS…
1 Response
#1 Mehul Harry said...
27-Feb-15 1:00 PMThat's Cool!
I love me some MarkDown too!
-Mehul
Leave a response
Note: some MarkDown is allowed, but HTML is not. Expand to show what's available.
_emphasis_
**strong**
[text](url)
`IEnumerable`
* an item
1. an item
> Now is the time...
Preview of response