Content Management for Flash with Rails + TinyMCE
Posted on May 6th, 2008 in General |
A recent client of mine had a flash site that they wanted to be able to edit the content for. There are several tutorials found throughout the webverse on importing content into flash from a text file, xml, or other types of external media. You can even import HTML and use CSS to style the content which is cool but is still fairly limiting in what you can do.
One of the reasons for building a content management system is to make things easier. Well, having to work with flash’s limiting uses of HTML and needing to use a WYSIWYG editor presented some problems. The main problem was that the HTML that flash uses is still the old-school non-semantic way of doing things (b tags for bold, i tags for italics, etc) and most of the current WYSIWYG editors use the XHTML standards that are recommended for use today.
The following are the steps I took to get this all working together. My actionscript fu is fairly rusty, but it works.
So the first thing I needed to do was generate the XML for my content in rails. This was fairly simple using the newer respond_to method that was added with the REST stuff in 1.2. This should be nothing new.
def show respond_to do |format| format.html format.xml { @page = Page.find_by_permalink(params[:id]) } end end
The actual content being pulled was only for the XML so making a request to the database for an HTML request would have been pointless. Each HTML page had it’s own flash file which I had given the same name as the permalink to the requested page, so /pages/about would use the about.swf file. I also used the flashvars parameter to tell the flash file where to load the XML from: /pages/< %= params[:id] %>.xml. I stored the directory in a variable called resourcePath.
In the view I started out with something like this:
xml.instruct! xml.page do xml.name @page.name xml.content do @page.content end end
But that won’t work since @page.content has HTML in it. We will end up with bad XML and it will mess when I try to walk through the XML nodes in flash. Luckily there is a cdata! method which will escape all of that for now. So for the content I put xml.cdata! @page.content which wraps the CDATA escape tags around my HTML.
With that set up, I can focus on getting the data from the XML into flash. To get the content I used something similar to this:
var pageXML:XML = new XML(); var pageContent:XMLNode = new XMLNode(); pageXML.ignoreWhite = true; pageXML.onLoad = function(success:Boolean):Void { if (success) { pageContent = pageXML.firstChild.firstChild.nextSibling.firstChild; pContent.text = pageContent.nodeValue; } }; pageXML.load(resourcePath);
I basically setup two variables in the beginning. The first to store the entire XML document. The next variable is used to store the XML node that we want to use. Then I have flash ignore the whitespace in the XML since I am using builder in rails to generate the XML. Then I set a function on the onLoad event for the XML that finds the page content and puts it in the dynamic text field on the stage called pContent.
This sort of worked but I was having a few problems. Because the HTML was being escaped flash was taking all of the < and > and converting them to < and >. There was also a problem with newline characters: Flash sees newlines and returns as two newline characters. I was able to fix both problems in one line:
pContent.htmlText = pageContent.nodeValue.split("\r\n").join("\n");
By setting the htmlText method of the textarea I was able to fix my HTML problem and then taking out the double return and adding just one back in to fix the second problem.
It was after playing with what I had currently that I realized how limiting the HTML was in flash. strong and em tags didn’t work, and H tags looks like normal text. On top of that, you can use A tags in the HTML but there is no color difference. Well, to fix this, a newer feature in the last version or so of flash is the ability to use an external stylesheet. I created one with a few sample styles. Some of them had to redo the effects that should have worked in the first place.
h1 { font-size: 20pt; font-weight: bold; } h2 { font-size: 16pt; font-weight: bold; } h3 { font-size: 14px; font-weight: bold; } strong { font-weight: bold; display: inline; } em { font-style: italic; display: inline; } .underline { text-decoration: underline; } .blue { color: #1821F1; } .green { color: #368B15; } .red { color: #990000; }
Most of this is fairly self explanatory. I will mention that most tags that flash doesn’t recognize act like block tags, so things these tags were being put on their own line. Adding display: inline; fixed that in most cases.
Now to add the external stylesheet into the flash file. One “gotcha” for this is that the text must be loaded into the textbox after you load in your external styles, otherwise they will not show up. What I did was rearrange my code so that the onLoad event for the stylesheet was what loaded the XML content into the textfield.
var pageXML:XML = new XML(); var pageContent:XMLNode = new XMLNode(); var textStyles:TextField.StyleSheet = new TextField.StyleSheet(); textStyles.onLoad = function(success:Boolean):Void { if (success) { pContent.styleSheet = this; pContent.htmlText = pageContent.nodeValue.split("\r\n").join("\n"); } } pageXML.ignoreWhite = true; pageXML.onLoad = function(success:Boolean):Void { if (success) { var pageName:XMLNode = pageXML.firstChild.firstChild.firstChild; pageContent = pageXML.firstChild.firstChild.nextSibling.firstChild; textStyles.load('/stylesheets/cms_styles.css'); } }; pageXML.load(resourcePath);
This is what I have, altogether. Basically the XML is loaded, which triggers an event to load the external css file. Before that we’ve set an onLoad event for the Stylesheet object that will load the content into the text field but only after the styles have been set.
That’s about it for the flash side of things. Now, I have some classes in my css file but it still presents a problem. A lot of people aren’t going to be able to remember how to set classes on text. If they have to edit code, what’s the point of a WYSIWYG editor anyway?
That’s where TinyMCE comes in. If you haven’t heard of it, check it out. It’s a great free editor that has a lot of cool features and tons of plugins. One of the features of TinyMCE happens to be using an external stylesheet. I’ll leave setting up TinyMCE as an excersize for the reader, but here is my configuration that I used:
tinyMCE.init({ mode : 'textareas', plugins : "inlinepopups,advlink,safari,fullscreen", relative_urls : false, theme : 'advanced', theme_advanced_buttons1 : "styleselect,formatselect,|,bold,italic,|,image", theme_advanced_buttons2 : "undo,redo,|,link,unlink,code,fullscreen", theme_advanced_buttons3 : "", theme_advanced_path : true, theme_advanced_resize_horizontal : false, theme_advanced_resizing : true, theme_advanced_statusbar_location : 'bottom', theme_advanced_toolbar_align : 'left', theme_advanced_toolbar_location : 'top', content_css : "/stylesheets/cms_styles.css" });
Basically you need to make sure that styleselect is listed in one of the theme_advanced lines and add the line at the end for content_css with the url to your stylesheet.
And there you have it! WYSIWYG editing with flash!
