Rich Text Editor (WYSIWIG) for all!

2.9
Average: 2.9 (10 votes)

This week we at Clayton State have been adding channels in preparation for our Luminis installation to go live. While doing the same menial task over and over, it struck us that there has to be a better (and easier) way for other content administrators to add new and edit existing content. Sungard caringly provided a textarea for users to input data which we found completely inadequate, so we replaced it with the powerful TinyMCE editor.

Attached are a few screenshots of what this modification looks like. For a list of TinyMCE features, check out their website here

This implementation requires us to download TinyMCE and unzip the "tiny_mce" (note the underscore) folder contained several folders inside into the "$CP_ROOT/webapps/luminis/js" directory, and then make one change to our "channel.xsl" file. The directory of "$CP_ROOT/webapps/luminis/js" should then look similar to this:

__$CP_ROOT/webapps/luminis/js
   |__tiny_mce
      |__langs
      |__license.txt
      |__plugins
      |__themes
      |__tiny_mce.js
      |__tiny_mce_popup.js
      |__tiny_mce_src.js
      |__utils

In our case, we have centralized all of our changes into the file "$CP_ROOT/webapps/luminis/WEB-INF/uPortal/org/jasig/portal/channels/cpicons/channel.xsl" since this is a location where local modification (seems to be) encouraged. This also keeps our changes outside of nested-tables.xsl which will likely be replaced when Sungard releases updates. If you do not have a "channel.xsl" file, then note the code below can go inside any ".xsl" file that is read on each page request (for example, nested-tables.xsl)

Inside of our channel.xsl file, place the following code first (Inside the context of <xsl:stylesheet ... > <xsl:template match="/">):

<!--- Made for rich text editing  -->
<xsl:call-template name="tinymce" />

This code calls a template named "tinymce" which we are about to create (below). Insert this next bit of code (Inside the context of <xsl:stylesheet ... >):

<xsl:template name="tinymce">
	<script src="js/tiny_mce/tiny_mce.js" type="text/javascript"></script>

	<script language="javascript" type="text/javascript">
		//Instantiate our TinyMCE object with the following options below. 
		//Explainations for these options can be found at 
		//http://wiki.moxiecode.com/examples/tinymce/installation_example_00.php
		tinyMCE.init({
				mode : "none",
				theme : "advanced",
				plugins : "table,advimage,advlink,emotions,preview,media,searchreplace,contextmenu,paste,fullscreen,visualchars",
				theme_advanced_buttons1 : "newdocument,preview,fullscreen,|,bold,italic,underline,strikethrough,|,justifyleft,justifycenter,justifyright,justifyfull,|,formatselect,fontselect,fontsizeselect",
				theme_advanced_buttons2 : "search,replace,|,bullist,numlist,|,outdent,indent,blockquote,|,undo,redo,|,link,unlink,anchor,image,code,|,forecolor,backcolor",
				theme_advanced_buttons3 : "tablecontrols,|,hr,sub,sup,|,charmap,emotions",
				theme_advanced_toolbar_location : "top",
				theme_advanced_toolbar_align : "left",
				theme_advanced_statusbar_location : "bottom",
				theme_advanced_resizing : true,
				invalid_elements: "!doctype,body,head,html"
		});

		window.onload = function() {
			//Gets a handle for all textarea tags
			var contents = document.getElementsByTagName('textarea');
			for(var x = 0; x &lt; contents.length; x++) {
					//Autogenerate a unique ID
					var handle = "textarea_no_" + x;
					//Set this id to each textarea
					contents[x].setAttribute('id', handle);
					//Create a new paragraph tag (to hold our "toggle" link)
					var p = document.createElement('p');
					//Append this paragrah tag after the textarea tag
					contents[x].parentNode.appendChild(p);
					//Create our link tag
					var link = document.createElement('a');
					//Make the href call our toggle_tinymce() funtion below
					link.setAttribute('href','javascript:toggle_tinymce(\'' + handle + '\')');
					//Optional highlighting via Scriptaculous to visually 
					//show which textarea will be replaced - ignored by IE6
					link.setAttribute('onmouseover','new Effect.Highlight(\'' + handle + '\')');
					//Optional class name if additional styling is wanted
					link.setAttribute('class','toggle_tinymce_link');
					//The text that the link will show
					link.innerHTML = 'Toggle advanced text editor (' + (x+1) + ')';
					//Append this inside our paragraph tag above
					contents[x].parentNode.appendChild(link);
			}
		}
		
		//Receives an id of a textarea
		function toggle_tinymce(id) {
			//Create a handle of the id received
			var elm = document.getElementById(id);
			//Code from TinyMCE's documentation to toggle 
			//the textarea passed into the TinyMCE editor with the options above
			if (tinyMCE.getInstanceById(id) == null)
					tinyMCE.execCommand('mceAddControl', false, id);
			else
					tinyMCE.execCommand('mceRemoveControl', false, id);
		}
	</script>
</xsl:template>

Save the file, and bounce your webserver. If all works according to plan, you should see the link in the screenshots that are attached below every instance of a textarea.


* Updated Tuesday, March 4 2008 to make the context in which the code snippets are placed more clear
* Updated Wednesday, February 20 2008 to include correct filename
* Updated Wednesday, February 20 2008 to show &lt; instead of < - thanks ahoward
-also included diagram of TinyMCE tree after being successfully extracted

Comments

Comment viewing options

Select your preferred way to display the comments and click "Save settings" to activate your changes.

Tiny MCE question

Are you saying put

the comment and the xsl:call

in the custom.xsl file (or channel.xsl file in your case)

and then create a file called tinymce for the rest of the code? If so, does it matter where the file is placed?

Thanks!

Clarification on placement

I should have been more specific with which context to put this code inside of. An abbreviated view of our file looks like this:

<?xml version='1.0' encoding='utf-8'?>
<xsl:stylesheet version="1.1" xmlns:cp="http://www.campuspipeline.com" ...>

...

        <!--- Made for rich text editing  -->
        <xsl:call-template name="tinymce" />

        <xsl:template name="tinymce">
        <script src="js/tiny_mce/tiny_mce.js" type="text/javascript">
        </script>

        <script language="javascript" type="text/javascript">

            tinyMCE.init({
			...
			});
            ...
	       function toggle_tinymce(id) {
	                var elm = document.getElementById(id);
	                if (tinyMCE.getInstanceById(id) == null)
	                        tinyMCE.execCommand('mceAddControl', false, id);
	                else
	                        tinyMCE.execCommand('mceRemoveControl', false, id);
	        }
        </script>

		...		

    </xsl:template>
</xsl:stylesheet>

where to put tinymce code still not clear

I'm still having trouble trying to put the code in the right spot.

I'm assuming in channel.xsl, all the tinymce code (the template call and the template itself) goes between the last closing xsl:template tag and the closing xsl:stylesheet tag.

But when I try that and restart the web server, the icons channel doesn't render. When I leave the template in channel.xsl and put the call in custom.xsl, I get a "failed to renderState" on trying to log in. I can't figure out yet what I'm doing wrong.

I'd like to get this working, because this sounds much better than modifying each file that has a textarea. Does this work just on the main portal window, or will it also work for textareas in group/course studio?

are you saying to put the

are you saying to put

the comment and the xsl call in the custom.xsl file (or channel.xsl file)

and the rest of the code in a file called tinymce? If so, does it matter where I put that file? If not correct can you please clarify?

thanks,
James

Made a change

I have changed the original documentation so that it correctly says "channel.xsl" and not "custom.xsl". I placed this code inside of "channel.xsl" because it is rendered on every page that the icons are rendered (effectively every single page). This way, any textareas inside Luminis can be transformed by clicking on the toggle link.

You are correct that all code will go inside the context <xsl:stylesheet>. This is an XSL convention that delimits that all code inside is XSL.

There are two separate pieces of code we need to create. (1) A call to a template named "tinymce". (2) The template "tinymce" itself. Both of these blocks of code are contained inside of the same file "custom.xsl".

Code block #1 calls code block #2 to be executed. The only thing external is the TinyMCE download we made to "$CP_ROOT/webapps/luminis/js" which we don't have to modify at all.

If your icon "bar" is not rendering correctly, then it sounds like you are on the right track, but might be missing a closing tag somewhere.

I added the comment and the

I added the comment and the call to my channel.xsl file and the code in my custom.xsl file. When I log into the portal I get a render error. Anybody else get this cool hack to work?

Found part of my problem

In the Javascript code, you need to replace the less-than operator (<) in the following line with &lt; otherwise the XML isn't valid:

for(var x = 0; x < contents.length; x++) {

After I did this, I ran "cptool validate file $CP_WEBINF/uPortal/org/jasig/portal/channels/cpicons/channel.xsl" and it validated successfully (I need to remember to use that command more when editing these XML files).

But after restarting the web server, the "toggle" link doesn't show up under any textarea, in fact, there's no mention of "tiny" in the HTML source for any of the pages. Is there something else I need to do to make the changes to channel.xsl known to Luminis?

got tinymce working now

I put the tinymce template into the custom.xsl for the skin we're using (xp_style) near the end of the file, and put the template call in that same file too, but within the custHeader template. It works now. But putting the tinymce javascript code in this location doesn't affect the group/course studio pages with textareas.

re: got tinymce working now

Would you be willing to let us know where you put the entries in the custom.xsl file?

I too am using xp_style and have modified the custom.xsl file, ran cptool validate file, restarted the webserver and the icons now display correctly but the link for the editor is not resident in the Targeted Content Manager page as expected..

Thanks

re: re: got tinymce working now

Here's where I put the code:

The template call:

<!-- Template for main header for all screens -->
<xsl:template name="custHeader">
<xsl:param name="schoolLogo"/>
<xsl:param name="welcomeMsg"/>
<xsl:param name="mngLinks"/>
<xsl:param name="isMainView"/>
<xsl:call-template name="tinymce" />
....

And the template itself:

<!-- Footer for all xsl based screens -->
<xsl:template name="custFooter">
<xsl:param name="copyright"/>
<xsl:param name="poweredbyimage"/>
<xsl:param name="poweredby"/>
<xsl:param name="topofpage"/>
....
</xsl:template>

<xsl:template name="tinymce">
<script src="js/tiny_mce/tiny_mce.js" type="text/javascript"></script>
....

can also use tinymce in ssb

If you put the scripts into DEFAULT info text entries for twbkwinf.P_ModifyPgInfoText, you can get this working for editing info text in SSB.

Now where should the code go?

I have tried to put the code in the channel.xsl file and the code does validate with the cptool validate command. The error I'm getting states:
XSLT.getTemplates():xsl:call-template is not allowed in this position in the stylesheet!; SystemID: jar:file:/opt/luminis/webapps/luminis/WEB-INF/lib/uPortal.jar!/org/jasig/portal/channels/cpicons/channel.xsl; Line#: 19; Column#: 37

I have tried the top of the file after the xsl:variable line and at the end before the >/stylesheet.

Thanks

Context

XSLT.getTemplates():xsl:call-template is not allowed in this position in the stylesheet means that the placement of your XSL call-template, is out of context. I have attached my channel.xsl file to this document so you can use this as a reference, if you would like. Make sure you validate your XML document with cptool before restarting your webserver.

Not to sound completely

Not to sound completely ignorant, but does this affect the targeted Announcement text area as well? Or does additional code need to be placed within ta-announcements.jsp?

Just once

That is the beauty of this method - you can place this code in once, and everything - including the textareas inside targeted announcements has a toggle link for the advanced editor.

I get the same error as

I get the same error as above:

XSLT.getTemplates():xsl:call-template is not allowed in this position in the stylesheet!; SystemID: jar:file:/u01/luminis/webapps/luminis/WEB-INF/lib/uPortal.jar!/org/jasig/portal/channels/cpicons/channel.xsl; Line#: 10; Column#: 45

The file validates. However, I had to add an extra closing tag at the end to validate properly.

And we are on v. 3.3.3.79.

Any thoughts?

Can you send your file?

Let me take a look at the file, if it doesn't contain any sensitive information, and maybe we can get this resolved fro you.

Sure thing. Thanks for the

Sure thing. Thanks for the help. I have included a link to our channel.xsl as to save room on the site.

http://www.apsu.edu/channel.xsl

This file, located on the Luminis box within uPortal.jar, validates correctly.

channel.xsl

I have reviewed your file and it appears that your xsl template named "tinymce" is in the wrong context. This should be defined outside of the <xsl match="/"> section.

Think of the <xsl match="/"> and the <xsl:template name="tinymce"> as being two functions at the same level. I have made a representation outline below:

xsl:stylesheet
|__ xsl:template match=/
   |__ xsl:call-template name=tinymce
|__ xsl:template name="tinymce"

Sorry for the confusion - I have updated the original post as well to reflect this.

Thanks for the personal

Thanks for the personal help.

Now, the file validates and the error has gone away. However, the TinyMCE editor link is nowhere to be found either in announcement admin or channel admin.

Simplify

It sounds like you now have working code inserted into your file since it validates. The "window.onload" event in Javascript signifies to execute the contained code as soon as the page finishes loading. This should be executing inside the context of "<xsl:template name="tinymce">". You can do a quick and dirty test by just inserting this javascript code just beneath the "window.onload" directive:

alert("If you see this popup, your code is being initialized");

This will cause a popup to appear everytime you click on a link inside the portal. As the code implies, if no pop-up are seen, then your code is not being called.

Do you see any Javascript error messages using either Web Developer Toolbar, or Firebug for Firefox?

Also, Luminis will not pickup changes to this file if you do not restart the webserver.

1. I have restarted the

1. I have restarted the webserver

2. The code is not being called

3. No errors in FF's Web Developer Toolbar, but lots of warnings

Thanks again.

getting this error in

getting this error in luminis 4

java.lang.NoClassDefFoundError

Thanks alot, it works. The

Thanks alot, it works.
The problem I faced is syntax error " missing closing Parentheses for the window.load function" since i copied and pasted the code from channel_5.xsl

I have did the required modification in the nested-table. i added the templete call under Header templete as follow:


and the tinymce templete under footer templete

Thanks alot for the post and comments, it helped alot