Blog Read

Blog Refreshed Part One

Well I have refreshed the theme on my blog. I wanted to switch to blogCFC because the tinyMCE was messing up my posts when I had code in a post. So I attempted to install blogCFC on the server where my site is hosted and I just could not get it to work. The problem that I had was with the SQL server scripts. I am on an older version on SQL server and it looks like the scripts were exported/written for SQL Server 2008, I did not want to change the scripts because if there was an update later for blogCFC, most likely I would not remember that I modified the SQL script. So I decided that I would figure out how to make Mango Blog work better for me starting with the tinyMCE and then on to the actual formatting of the rendered code.


So how did I do this? Well in Mango Blog they have this really cool feature called plugins that listen for events. I decided I would write a simple plugin that removes the tinyMCE if the event sees a URL variable called “noEditor” and the events that I am listening on are ( "beforeAdminPostContentEnd", "beforeAdminHeaderEnd" ). The first thing that you need to do is create a plugin.xml file, here is what mine looks like.

view plain print about
1<?xml version="1.0" encoding="UTF-8"?>
2<plugin id="com.asfusion.mango.plugins.thinklab" name="thinklab" version="0.1" provider-name="thinklab" class="thinklab.Handler">
3<description><![CDATA[
4    This plugin is fixes some of the admin UI bugs for me.
5    Bug 1 in Google Chrome the left fieldset which, is the blog post content is to big and gets pushed to the bottom of the page.
6
7    Bug 2 I wanted to be able to turn off the tinyMCE with a URL variable.
8
9]]>

10</description>
11
12 <requiresVersion match="greaterOrEqual">1.5</requiresVersion>
13 <listens>
14     <event name="beforeAdminPostContentEnd" type="synch" priority="1" />
15 </listens>
16</plugin>

The next step is to create a handler.cfc file this is where you add you CFML. I am not going to go into what all the functions do because you can find the Mango Blog documentation http://www.mangoblog.org/docs/documentation/extending-mango/creating-a-plugin. The function that I am using is the function that is for "Synchronous event handling" processEvent. Here is my function.

view plain print about
1<cffunction name="processEvent" hint="Synchronous event handling" access="public" output="false" returntype="any">
2        <cfargument name="event" type="any" required="true" />
3
4        <cfset var eventName     = arguments.event.getName() />
5        <cfset var externaldata = arguments.event.getrequestData().externaldata />
6        <cfset var _scriptHead     = "" />
7        <cfset var data         = arguments.event.getdata() />
8        
9        
10        <cfif eventName EQ "beforeAdminPostContentEnd">
11            
12            <cfsavecontent variable="_scriptHead">
13                <cfoutput>
14                <cfif isStruct( externaldata ) and structKeyExists( externaldata, 'noEditor')>
15                <script type="text/javascript" language="JavaScript">
16                    $(function()
17                    {    
18                        $("textarea##contentField").removeClass('htmlEditor');
19                    });
20                </script>
21                </cfif>
22                <style type="text/css">
23                    .widget{
24                        width:75%;
25                    }
26                    ##contentField{
27                        width:80%;
28                    }
29                </style>
30                </cfoutput>
31            </cfsavecontent>
32            <cfhtmlhead text="#_scriptHead#">
33            
34        <cfelseif eventName EQ "beforeAdminHeaderEnd">
35            
36            <cfif isStruct( externaldata ) AND structKeyExists( externaldata, 'raw') AND isArray( externaldata.raw ) >
37                <cfset arr_index = (externaldata.raw.indexOf('posts.cfm')) + 1 />
38                
39                <cfif val( arr_index )>
40                    <cfsavecontent variable="_scriptHead">
41                        <cfoutput>
42                        
43                        <script type="text/javascript" language="JavaScript">
44                            $(function()
45                            {    
46                                
47                                $('tr td.buttonColumn a.editButton').each(function(index) {
48                                 if( $(this).text().toLowerCase() == 'edit')
49                                    {
50                                        var new_button = $(this).clone();
51                                        new_button.attr('href', new_button.attr('href') + '&noEditor=true' ).text('Edit No Editor');
52                                        $(this).parent().append( new_button );
53                                    }
54                                    
55                                 });
56                            });
57                        </script>
58                        
59                        </cfoutput>
60                    </cfsavecontent>
61                    <cfhtmlhead text="#_scriptHead#">
62                </cfif>
63                
64            </cfif>
65            
66        </cfif>        
67        
68        <cfreturn arguments.event />        
69    </cffunction>

Ok lets break down the code above. The first thing that I am doing is setting my variables.

view plain print about
1<cfset var eventName     = arguments.event.getName() />
2    <cfset var externaldata = arguments.event.getrequestData().externaldata />
3    <cfset var _scriptHead     = "" />

The first variable ("eventName") is the name of the event being executed, the second variable ("externaldata") is for all of the external data like form and url variables, and the last variable will be used for storing the output for the html head.

Next is my if statement which really only needs to be in there if you're listening for multiple events, in this case I am listening for two events ( "beforeAdminPostContentEnd", "beforeAdminHeaderEnd" ).

view plain print about
1<cfsavecontent variable="_scriptHead">
2    <cfoutput>
3    <cfif isStruct( externaldata ) and structKeyExists( externaldata, 'noEditor')>
4    <script type="text/javascript" language="JavaScript">
5        $(function()
6        {    
7            $("textarea##contentField").removeClass('htmlEditor');
8        });
9    </script>
10    </cfif>
11    <style type="text/css">
12        .widget{
13            width:75%;
14        }
15        ##contentField{
16            width:80%;
17        }
18    </style>
19    </cfoutput>
20</cfsavecontent>
21<cfhtmlhead text="#_scriptHead#">

In the code above I am listening for the event "beforeAdminPostContentEnd" and then I overide the admin css and I added so jQuery to remove the "htmlEditor" class form the textarea with the id "contentField", if I find the struct key "noEditor". The next part I am taking the script and style output and putting it in the html head.


view plain print about
1<cfif isStruct( externaldata ) AND structKeyExists( externaldata, 'raw') AND isArray( externaldata.raw ) >
2    <cfset arr_index = (externaldata.raw.indexOf('posts.cfm')) + 1 />
3    
4    <cfif val( arr_index )>
5        <cfsavecontent variable="_scriptHead">
6            <cfoutput>
7            
8            <script type="text/javascript" language="JavaScript">
9                $(function()
10                {    
11                    
12                    $('tr td.buttonColumn a.editButton').each(function(index) {
13                     if( $(this).text().toLowerCase() == 'edit')
14                        {
15                            var new_button = $(this).clone();
16                            new_button.attr('href', new_button.attr('href') + '&noEditor=true' ).text('Edit No Editor');
17                            $(this).parent().append( new_button );
18                        }
19                        
20                     });
21                     $('p.buttonBar a.editButton').each(function(index) {
22                            if( $(this).text().toLowerCase() == 'create new post')
23                            {
24                                var new_button = $(this).clone();
25                                new_button.attr('href', new_button.attr('href') + '&noEditor=true' ).text('Create New Post No Editor');
26                                $(this).parent().append( new_button );
27                            }
28                        });
29                });
30            </script>
31            
32            </cfoutput>
33        </cfsavecontent>
34        <cfhtmlhead text="#_scriptHead#">
35    </cfif>
36    
37</cfif>

Next in the elseif statement I am listening for the event "beforeAdminHeaderEnd". Here we're going to look through the attribute raw element which is an array and stores the name of the file name, the file name that we're looking for is posts.cfm. Once I find the file name I add some more jQuery that will look through the DOM for "tr td.buttonColumn a.editButton" and "p.buttonBar a.editButton" then I add two new buttons, one that will allow me to edit a post without the editor and one that will allow me to create a new post without an editor.

The only problem that I have found with all of this, is that once I save my blog post the page redirects back to the post.cfm file but no "noEditor" url var so I still need to work on that. If you want the plugin here is the download link.

blog comments powered by Disqus