Tuesday, August 10, 2010

ColdMVC: Plugging in fckeditor

I am working on a CMS app and I wanted the fckeditor in my app, while using ColdMVC. Here's what I did to get it in my app.

I downloaded the fckeditor and put it in the public folder, like below...

app
>public
>>plugins
>>>fckeditor

Next, on a custom helper called "util.cfc", I added a function called editor().
1. Create a fckeditor bean.
2. Set the properties of the fckeditor. Specifically the basepath is really important. I used $.config.get('assetPath') to get to the directory where the fckeditor is located.
3. Lastly, I wrap the fckeditor in ColdMVC's field() so it looks like the other fields.

<cffunction name="editor" access="public" output="false" returntype="string">
<cfargument name="name" required="true"/>
<cfargument name="value" required="false" default=""/>
<cfargument name="width" required="false" default="100%"/>
<cfargument name="height" required="false" default="300px"/>

<cfset local.bean = application.coldmvc.beanFactory.getBean("fckeditor")/>

<cfset local.bean.basePath = "#$.config.get('assetPath')#plugins/fckeditor/"/>
<cfset local.bean.instanceName = arguments.name/>
<cfset local.bean.value = arguments.value/>
<cfset local.bean.width = arguments.width/>
<cfset local.bean.height = arguments.height/>

<cfif not StructKeyExists(arguments,"label")>
<cfset arguments.label = $.string.humanize(arguments.name)/>
</cfif>

<cfoutput>
<cfsavecontent variable="local.field">
#local.bean.create()#
</cfsavecontent>
</cfoutput>

<cfreturn $.form.field(label=arguments.label,field=trim(local.field))/>

</cffunction>


Finally on my view, I call the helper function editor() and pass in my value. The use case below is for the editing a layout record for a cms app.

<cfoutput>
<c:form action="save" bind="layout">
<c:hidden name="id" value="#layout.id()#" />
<c:input name="name" value="#layout.name()#" />

#$.util.editor(label="Layout",name="layout.layout",value=layout.layout())#

<c:submit name="save" />
</c:form>
</cfoutput>


One thing to note is that if you want to bind the fckeditor textarea to an object, so it can be used in ColdMVC's populate() for a save, you will need to prefix your instanceName in the fckeditor. I do this by wrapping the fckeditor in a helper function and use the "name" argument like this...


<--- on my view I put in "layout.layout" as the name--->
#$.util.editor(label="Layout",name="layout.layout",value=layout.layout())#

<--- inside the editor()--->
<cfset local.bean.instanceName = arguments.name/>

1 comment:

  1. Couple things:

    1. I don't think you should be creating FCKEditor as a singleton bean as you'll probably run into issues with concurrent requests. Instead, you'll want to create a new instance each request.

    2. If you have your util extend the HTMLHelper, you could have it automatically perform the binding rather than having to worry about setting the name yourself. Here's what that would look like:

    // util.cfc
    component extends="coldmvc.app.util.HTMLHelper" {

    public string function wysiwyg(height="100%", width="300px") {

    arguments.tag = "wysiwyg";
    this.bindTags = listAppend(this.bindTags, "wysiwyg");

    configure(arguments);

    var editor = new myapp.public.plugins.FCKEditor();

    editor.basePath = $.config.get("assetPath") & "plugins/fckeditor/";
    editor.instanceName = arguments.name;
    editor.value = arguments.value;
    editor.width = arguments.width;
    editor.height = arguments.height;

    arguments.field = editor.create();

    return this.field(argumentCollection=arguments);

    }

    }

    3. You could create a tag to make your view prettier. Here's what it might look like.

    // wysiwyg.cfm
    <cfif thisTag.executionMode eq "start">
    <cfset html = $.util.wysiwyg(argumentCollection=attributes) />
    <cfelse>
    <cfoutput>
    #html#
    </cfoutput>
    </cfif>

    // your view
    <cfoutput>
    <c:form action="save" bind="layout">
    <c:hidden name="id" />
    <c:input name="name" />
    <c:wysiwyg name="layout" />
    <c:submit name="save" />
    </c:form>
    </cfoutput>

    And if you didn't notice, you don't need to pass in a value for tags if the form is bound to a param. For example, if you bind the form to "foo" and your field name is "bar" and you don't pass in a value to your tag, it will try to calculate the value by calling params.foo.bar(). Just a shortcut for keeping your views even cleaner.

    PS - none of this code has been tested and hopefully my code formatting doesn't get screwed up too bad in the comment. :)

    ReplyDelete