Fixing < code > blocks when using TinyMCE in BlogCFC
While working on setting up and integrating the superb BlogCFC with my own custom template, I discovered that the admin section does not utilise a richtext editor (Ray is hardcore :). However, Ray has been very helpful by splitting out the textarea HTML used on the blog entry input page which makes it very easy to plug in a suitable rich text editor.
The one I have chosen is TinyMCE. It's very nice to configure (incredibly easy - easy is good) and pretty lightweight. Nick Tong over at succor.co.uk blogged about adding TinyMCE to BlogCFC last year and it's a nice clear guide to anyone who wants to do this. Check out his blog post here.
Now, while it's a pretty trivial job to get TinyMCE working with BlogCFC there are a number of initial problems that break some functionality. These are to do with the custom tags which you can use to embed certain formatting / features into a blog post. As the tags are HTML style TinyMCE decides to nuke them from the source code view and escapes them in visual mode - not good.
The first of these is the <more/> tag which allows you to break up a blog post so that on the index page you only see a summary and then click 'more' to view the entire post. A fix to this is to modify BlogCFC to support [ more/ ] instead. Nick Tong has again blogged about making the changes here.
The second problem is in including a nicely colour coded scrolling code box which you can use to include Coldfusion code samples on your blost posts. Out of the box, the way to do this is to enclose the code sample with <code> </code> tags. As above, this is a no no with TinyMCE as it doesn't recognise the tags as valid HTML and so removes them. If you try including them in the visual mode (which is what I wanted) it escapes the characters and breaks the functionality.
I spent a couple of hours looking into this and have come up with a modification which allows the code output functionality to work in visual editing mode, but using { code } and { /code } tags instead (without the spaces - I am having to do that to avoid my mod kicking in and showing 'and' in code display :).
It's not perfect as any e-mails then get sent out will include the { code } and { /code } tags, although this could be fixed by modifying the e-mail sender function.
Anyway, here is the code. The first block shows what code you need to replace. The second block is the code you will need to copy and paste into blog.cfc. This mod is based on version 5.9 of BlogCFC though it may work in earlier versions:
File: org/camden/blog/blog.cfc - Lines 2087 - 2113:
<cfif findNoCase("<code>",arguments.string) and findNoCase("</code>",arguments.string)>
<cfset counter = findNoCase("<code>",arguments.string)>
<cfloop condition="counter gte 1">
<cfset codeblock = reFindNoCase("(?s)(.*)(<code>)(.*)(</code>)(.*)",arguments.string,1,1)>
<cfif arrayLen(codeblock.len) gte 6>
<cfset codeportion = mid(arguments.string, codeblock.pos[4], codeblock.len[4])>
<cfif len(trim(codeportion))>
<cfif arguments.printformat>
<cfset style = "codePrint">
<cfelse>
<cfset style = "code">
</cfif>
<cfset result = variables.utils.coloredcode(codeportion, style)>
<cfelse>
<cfset result = "">
</cfif>
<cfset newbody = mid(arguments.string, 1, codeblock.len[2]) & result & mid(arguments.string,codeblock.pos[6],codeblock.len[6])>
<cfset arguments.string = newbody>
<cfset counter = findNoCase("<code>",arguments.string,counter)>
<cfelse>
<!--- bad crap, maybe <code> and no ender, or maybe </code><code> --->
<cfset counter = 0>
</cfif>
</cfloop>
</cfif>
Replace the above code with the following:
<cfset var codeTags = ArrayNew(1)>
<cfset codeTags[ArrayLen(codeTags)+1] = StructNew()>
<cfset codeTags[ArrayLen(codeTags)].startTag = "<code>">
<cfset codeTags[ArrayLen(codeTags)].endTag = "</code>">
<cfset codeTags[ArrayLen(codeTags)+1] = StructNew()>
<cfset codeTags[ArrayLen(codeTags)].startTag = "{code}">
<cfset codeTags[ArrayLen(codeTags)].endTag = "{/code}">
<cfset codeTags[ArrayLen(codeTags)].richText = true>
<cfloop from="1" to="#ArrayLen(codeTags)#" index="codeTagCount">
<cfif findNoCase("#codeTags[codeTagCount].startTag#",arguments.string) and findNoCase("#codeTags[codeTagCount].endTag#",arguments.string)>
<cfset counter = findNoCase("#codeTags[codeTagCount].startTag#",arguments.string)>
<cfloop condition="counter gte 1">
<cfset codeblock = reFindNoCase("(?s)(.*)(#codeTags[codeTagCount].startTag#)(.*)(#codeTags[codeTagCount].endTag#)(.*)",arguments.string,1,1)>
<cfif arrayLen(codeblock.len) gte 6>
<cfset codeportion = mid(arguments.string, codeblock.pos[4], codeblock.len[4])>
<cfif StructKeyExists(codeTags[codeTagCount],"richText")>
<!--- Replace various elements which the rich text editor will have inserted which we don't want for code view --->
<cfset codeportion = Replace(codeportion,"<p>","#Chr(13)#","ALL")>
<cfset codeportion = Replace(codeportion,"</p>","","ALL")>
<cfset codeportion = Replace(codeportion,"<br />","#Chr(13)#","ALL")>
<cfset codeportion = Replace(codeportion,"<","<","ALL")>
<cfset codeportion = Replace(codeportion,">",">","ALL")>
<cfset codeportion = Replace(codeportion," ","[nbsp]","ALL")>
<cfset codeportion = Replace(codeportion,"&##","#","ALL")>
</cfif>
<cfif len(trim(codeportion))>
<cfif arguments.printformat>
<cfset style = "codePrint">
<cfelse>
<cfset style = "code">
</cfif>
<cfset result = variables.utils.coloredcode(codeportion, style)>
<cfelse>
<cfset result = "">
</cfif>
<cfif StructKeyExists(codeTags[codeTagCount],"richText")>
<!--- Replace the nbsp placeholder back into a real --->
<cfset result = Replace(result,"[nbsp]"," ","ALL")>
<cfset result = Replace(result,"&","&","ALL")>
</cfif>
<cfset newbody = mid(arguments.string, 1, codeblock.len[2]) & result & mid(arguments.string,codeblock.pos[6],codeblock.len[6])>
<cfset arguments.string = newbody>
<cfset counter = findNoCase("#codeTags[codeTagCount].startTag#",arguments.string,counter)>
<cfelse>
<!--- bad crap, maybe <code> and no ender, or maybe </code><code> --->
<cfset counter = 0>
</cfif>
</cfloop>
</cfif>
</cfloop>
This should work nicely and allow you to add code blocks into TinyMCE visual mode.
You can change the start and end tags recognised for code output by editing this block of code:
<cfset codeTags[ArrayLen(codeTags)+1] = StructNew()>
<cfset codeTags[ArrayLen(codeTags)].startTag = "<code>">
<cfset codeTags[ArrayLen(codeTags)].endTag = "</code>">
<cfset codeTags[ArrayLen(codeTags)+1] = StructNew()>
<cfset codeTags[ArrayLen(codeTags)].startTag = "{code}">
<cfset codeTags[ArrayLen(codeTags)].endTag = "{/code}">
<cfset codeTags[ArrayLen(codeTags)].richText = true>
The 'richText' key signifies that the start and end tags contain text from a richtext editor and thus require certain character filtering etc.
Let me know if you find any problems with this. I have a nasty suspicion there may be a few problems with certain code samples but I haven't had too much time to test this yet. Looking good so far though.
Apologies in advance if anyone comes up with a cleaner and simpler way of doing this - this was really just a quick fix to get TinyMCE working with code output - , but if you do please post in the comments.





I'm having a problem getting richtext to work with cftextarea in a cfgrid.
The cftextarea is populated when one clicks on an entry in the cfgrid which in
turn is populated by a query. When I remove the cfgrid and corresponding code
for the textarea and just leave the textarea in place the richtext editor will show
as well as in instances created using tinymce encoded.
I've even tried installing Tinymce site specific and using the various and many ways
to instantiate the editor upon the cftextarea. Nothing works.
Is this an unknown problem with the cftextarea?
Regards,
Michael
sentiant@parallelcomputersolutions.com
Thanks for your comment - much appreciated.
I'm afraid I haven't come across the problem you have with <cfgrid>, <cftextarea> and TinyMCE.
I imagine that the javascript which <cfgrid> is using is causing somethig to break in TinyMCE.
I haven't really used those tags yet though so I'm not sure how they work technically.
Sorry I couldn't be any more help but good look finding the solution.
of this issue and have yet to hear from them about it. Great article by
the way. I've used MCE on my coldfusion sites for a few years now and
really like its being lightweight and so on. It does have some issues with
handling line feeds and links but once you look at the code underlying
its pretty easy to work with. Most users of a site might not know
how to do this though.
In my last job we used SoEditor Pro by SiteObjects. That would often generate appalling code and the amount of problems it gave us when clients were let lose on it.. I ended up writing code to clean up the HTML upon form submission. To be fair though, it must have been about 4 years old and we continued to use it due to the codebase I had built around it.
I'm thinking of focusing on FCKEditor for a big project I'm working on now due to it being built into CF8. Apparentely it works really well and has some excellent ongoing development by it's author. Saying that though, I think TinyMCE really hits the nail on the head when it comes to lightweight deployment..
Did you look in the TinyMCE docs for the <a href="http://wiki.moxiecode.com/index.php/TinyMCE:Config...; width and height attributes? </a> ...