6

If you’ve done anything in dotCMS involving the WYSIWYG field, then you are familiar with TinyMCE, the script driving that interface. Currently, we already have the ability via a plugin to modify TinyMCE’s interface in the back end. This is useful, because TinyMCE is highly customizable, meaning you can provide specifically tailored interfaces for different circumstances. However, it’s also possible to do the same for TinyMCE on the front end, when it’s output through the use of the submitContent() macro, without the need for an extra plugin.

In dotCMS 1.9, the submitContent() macro is built in by default. Prior to that, you needed the Front End Content Submission plugin. The technique here applies specifically to 1.9, but will also work if you modify the macro in the plugin for 1.7. All you need to do is replace the 1.7 macro with the one from 1.9.

1.7 submitContent() macro (from plugin)

#macro(submitContent $structureName)
	#parse('/static/plugins/org.dotcms.frontend.content.submission/content_form_macro.vtl')
#end

1.9 submitContent() macro (built in)

#macro(submitContent $structureNameAux)
   #set($structureName = $structureNameAux)
   #if ($UtilMethods.isSet($submitContentSrc))
      #dotParse($submitContentSrc)
   #else
      #parse('/static/content/content_form_macro.vtl')
   #end
#end

Hopefully the key difference is fairly obvious. Basically in 1.9 the macro checks for the $submitContentSrc variable, allowing you to override traditional output, in 1.7 it didn’t. All we need to do is leverage $submitContentSrc and we can fully control how the macro displays the TinyMCE editor for WYSIWYG fields. The other key is also exposed in the code above, and that’s the /static/content/content_form_macro.vtl file.

First, go make a copy of this file, and save it anywhere in your dotCMS website browser (remember, using $submitContentSrc does a dotParse(), not a parse(), so don’t save the new file to your server’s file structure!). For this example, we’ll save this file to /global/vtl/content_form_macro_override.vtl. The first thing you need to do is tell this file that you need it to get a new file that will control the WYSIWYG, look to lines 329-336:

...
#if($isDontShowFields && $stringsapi.MatchCommaSeparated($dontShowFields,$field.velocityVarName))
    #parse('/static/content/hidden_field_render.vtl')
#else
    #parse('/static/content/wysiwyg_field_render.vtl')
<script language="javascript">
    updateTabCounter("$currentTab");
</script>
#end
...

Let’s point line 332 somewhere else, because that’s the file that controls TinyMCE. Note, I change the parse() to a dotParse() (again, because I’ll store the new file in dotCMS).

...
#if($isDontShowFields && $stringsapi.MatchCommaSeparated($dontShowFields,$field.velocityVarName))
    #parse('/static/content/hidden_field_render.vtl')
#else
    #dotParse('/global/vtl/wysiwyg_field_render_override.vtl')
<script language="javascript">
    updateTabCounter("$currentTab");
</script>
#end
...

Save that edited file. Now, go grab the code from the original /static/content/wysiwyg_field_render.vtl file, and put it in a new one in dotCMS at /global/vtl/wysiwyg_field_render_override.vtl.

Original /static/content/wysiwyg_field_render.vtl file contents

#if(!$_contentFormWYSIWYGIncluded)
	<script src="/html/js/tinymce/jscripts/tiny_mce/tiny_mce.js" type="text/javascript"></script>
    <script type="text/javascript">
		tinyMCE.init({
       			mode : "none",
       			theme : "simple"
       		});

       	function enableWYSIWYG(textAreaId){
    		try {
    			tinyMCE.execCommand('mceAddControl', false, textAreaId);
    		}catch(e){
    			alert(e.message);
    		}
    		enabledWYSIWYG[textAreaId] = true;
      	}
    </script>
	#set($_contentFormWYSIWYGIncluded = true)
#end
<textarea dojoType="dijit.form.Textarea" name="$fieldAux.velocityVarName" id="$fieldAux.velocityVarName" class="textAreaField">$!fieldDefaultValue</textarea><span id="alert${fieldAux.velocityVarName}" class="errorMessages"></span>
<script type="text/javascript">
	enableWYSIWYG("$fieldAux.velocityVarName");
</script>

This creates the plain, simple WYSIWYG that is normally output:

Simple TinyMCE WYSIWYG

Simple TinyMCE WYSIWYG

Let’s make some changes to this so that it shows a more robust toolbar instead of the simple interface, and we’ll add the Paste From Word tool:

#if(!$_contentFormWYSIWYGIncluded)
	<script src="/html/js/tinymce/jscripts/tiny_mce/tiny_mce.js" type="text/javascript"></script>
    <script type="text/javascript">
		tinyMCE.init({
       			mode : "none",
       			theme : "advanced",
                        theme_advanced_buttons1 : "pasteword,bold,italic,underline,separator,strikethrough,justifyleft,justifycenter,justifyright, justifyfull,bullist,numlist,undo,redo,link,unlink",
                        theme_advanced_buttons2 : "",
                        theme_advanced_buttons3 : "",
                        theme_advanced_toolbar_location : "top",
                        theme_advanced_toolbar_align : "left",
                        theme_advanced_statusbar_location : "bottom",
                        plugins : 'paste,inlinepopups'
       		});

       	function enableWYSIWYG(textAreaId){
    		try {
    			tinyMCE.execCommand('mceAddControl', false, textAreaId);
    		}catch(e){
    			alert(e.message);
    		}
    		enabledWYSIWYG[textAreaId] = true;
      	}
    </script>
	#set($_contentFormWYSIWYGIncluded = true)
#end
<textarea dojoType="dijit.form.Textarea" name="$fieldAux.velocityVarName" id="$fieldAux.velocityVarName" class="textAreaField">$!fieldDefaultValue</textarea><span id="alert${fieldAux.velocityVarName}" class="errorMessages"></span>
<script type="text/javascript">
	enableWYSIWYG("$fieldAux.velocityVarName");
</script>

Now, save this file. You’ve now made all the edits to the files that you need. Keep in mind, you really have no limit with respect to what you can do to TinyMCE here, so you can make the editor as simple or complex as you like (the full, huge editor, or a simple one that only allows adding links). Here is the new, slightly more feature rich editor in this example:

Enhanced TinyMCE WYSIWYG

Enhanced TinyMCE WYSIWYG

To quickly recap, here are the changes we’ve made so far:

  1. 1.7 users updated their submitContent() macro to be a copy of the one from 1.9
  2. Created a new file based on /static/content/content_form_macro.vtl and saved it in dotCMS
  3. Edited the new version of the content_form_macro.vtl file to tell it to use a different WYSIWYG code source
  4. Created a new file based on /static/content/wysiwyg_field_render.vtl and saved it in dotCMS
  5. Edited the new version of the wysiwyg_field_render.vtl file to give it new JavaScript configuration settings for TinyMCE

So, to put this into use now, let’s say you wanted to allow front end submission of blog entries. Here’s what you’d do:

#* Set the macro source file variable to the one you created so it will override the one used by default *#
#set($submitContentSrc = "/global/vtl/content_form_macro_override.vtl")
#submitContent('Blog Entry')

Super easy, no? Obviously you could take this much further, since having the copy of the content_form_macro.vtl file gives you full access to the behavior of the macro’s output. Each field type has a corresponding .vtl file that you could copy and edit just like we did for the WYSIWYG. Or, if you used the submit content macro in different places based on various structures, you could provide individual experiences in each location. Here’s an idea:

Modifying /global/vtl/content_form_macro_override.vtl for conditions

...
#if($isDontShowFields && $stringsapi.MatchCommaSeparated($dontShowFields,$field.velocityVarName))
    #parse('/static/content/hidden_field_render.vtl')
#else
    #if($VTLSERVLET_URI == "/events/submit.dot")
        #dotParse('/global/vtl/wysiwyg_field_render_advanced-no-images.vtl')
    #elseif($VTLSERVLET_URI == "/articles/submit.dot")
        #dotParse('/global/vtl/wysiwyg_field_render_advanced-full.vtl')
    #else
        #parse(''/static/content/wysiwyg_field_render.vtl')
    #end
<script language="javascript">
    updateTabCounter("$currentTab");
</script>
#end
...

See how on lines 332-338 I apply different .vtl files based on the location of the form, and otherwise default to the normal simple WYSIWYG? You can manipulate these behaviors however you want to give yourself full control over your TinyMCE editor on front end pages to give your users exactly the experience that they need from the tool.

Image Gallery Recap

6 Responses to “Modify submitContent()’s TinyMCE Editor”

  1. Joel says:

    And so effectively, you could use the CMSUserWebAPI to create custom menus per user role then. That’s one of those smaller features I’m seeing in other wCMS platforms that’s skipped over in dotCMS at this point. But this seems like one way to accomplish that.

    • Michael Fienen says:

      Yeah, definitely. You could, for instance, give users with the Power User role a full featured editor, while user just set as CMS User get a more basic one. Just check the roles the user has, and include the appropriate setup for their highest level.

  2. Glen says:

    It seems that the upgrade to 1.9 means that the opensource community can’t do this any more. Is that correct? (At least not without hacking the 1.7 plugin to the new code base found in 1.9)

    • Michael Fienen says:

      Actually, if you look back, this should work as described in 1.9. The base macro is actually more flexible in 1.9 than 1.7 because it allows you to override the source code by setting a variable, which is why I describe the process of modifying 1.7 to work more like 1.9, allowing you to do the customization.

  3. Joshua says:

    Helped me alot tonight Fienen – totally forgot about using $submitContentSrc – I used this today to override a bug with custom field permissions

Trackbacks/Pingbacks

  1. Tweets that mention Modify submitContent()’s TinyMCE Editor | Learn dotCMS -- Topsy.com - June 17, 2010

    […] This post was mentioned on Twitter by Michael Fienen, Christopher Falzone. Christopher Falzone said: RT @fienen: Modify submitContent()'s TinyMCE Editor | Learn dotCMS http://ow.ly/1ZKjK […]

Leave a Reply