Code 'n' Stuff - An occasional series of handy bits of code and techniques that I've found useful in ASP.NET, VB.NET, C#, PHP, Javascript, and many, many more!

Using TinyMCE in a Flex/AIR application : Part 1 (03/11/2009)

I've recently started using Adobe Flex to develop multi-platform apps and I am very impressed with it. It allows the very fast development of powerful UI software without having to worry about OS-specific stuff.

Because of Flex's object-oriented nature, it's also quite straightforward to extend beyond the controls supplied. This came in very handy when I had to address a recent requirement - namely the inclusion of an XHTML aware full text editor into an application. There are a number of options available out in the big wide world, but my favourite for web-based editing is definitely TinyMCE.

Given Flex's ability to handle web pages and Javascript within HTML containers it seemed an obvious step to use TinyMCE in this way. However, after trawling the web for examples it quickly  became very clear that it wasn't going to be possible to simply drop it in and have it work straight away.

The most useful post I found was on the TinyMCE forum (http://tinymce.moxiecode.com/punbb/viewtopic.php?id=14078). Unfortunately the referenced blog entry that shows how to set things up seems no longer to be available, so I will outline the steps I have taken to set up TinyMCE in an AIR app, showing the problems encountered and the solutions I have used. The finished app will be a standalone window containing a TinyMCE instance, along with a means of inserting and reading HTML from it.

The version of TinyMCE that was initially used for these tests was 3.2.1, however later versions, including the current (v3.2.7 as of Nov '09) have a bug in some relative url code that causes a failure when run under AIR. See towards the end of the article for more information. 

This article assumes a working knowledge of both Flex and TinyMCE.

1. Set up the TinyMCE/Air app in Flex.

Do this in the normal way by creating an AIR application with no special settings. Then include the TinyMCE source into the app by using the 'Import -> File System' function. Place the contents in a folder called 'tiny_mce' under the src folder. (see figure, left). This means it will be copied into the same relative path under the resulting app, thus avoiding any problems with include paths.

Obviously, if you need to have a common TinyMCE installation serving several apps, the approach will be different.  

 

2. Create an HTML container for the TinyMCE editor

What we need to do is create a container that will hold the HTML page that the TinyMCE editor instance will run in. The component for this is the HTML component under 'Adobe AIR' in the Flex component chooser. Add one of these to the form and make it a reasonable size.

Next, add an <mx:string> component to the source of the form. This will contain the HTML and javascript that initialises the TinyMCE editor and its initial content. We shall use the simplest TinyMCE example here, so if you need more complex functionality amend this javascript accordingly:

<mx:String id="MCEeditorCode">
    <![CDATA[
        <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
        <html xmlns="http://www.w3.org/1999/xhtml">
	    <head>
            <script type="text/javascript" src= "tiny_mce/tiny_mce_src.js"></script>
            <script type="text/javascript">
               tinyMCE.init({
                             mode : "textareas",
                             theme : "simple"
                            });
            </script>
          </head>
          <body>
            <textarea id="content" name="content" style="width:90%;">
              <p>This is the initial content</p>
            </textarea>
          </body>
        </html>
     ]]>
</mx:String>

3. Create an event handler that initialises the TinyMCE instance

To ensure that the TinyMCE instance can execute and is initialised correctly, we add an event handler to the form to handle the 'creationcomplete' event.

<mx:Script>
  <![CDATA[
    private function init() {
htmlContainer.htmlLoader.placeLoadStringContentInApplicationSandbox =true;
      htmlContainer.htmlText = MCEeditorCode;
    }
  ]]>
</mx:Script>

4. Add functionality to insert/read HTML

Because AIR is capable of calling javascript within an HTML container, it is very simple to add functions that add to and read from the TinyMCE instance. To do this, we create a couple of helper functions in the javascript section within the MCEeditorCode string object.

// Helper function to insert supplied HTML to TinyMCE instance
function insertHTML(txt) {
tinyMCE.execInstanceCommand('content', 'mceInsertRawHTML', false, txt);
}
 
// Helper function to extract HTML content from TinyMCE instance
function getHTML() {
return tinyMCE.activeEditor.getContent();
}

Next, add a couple of event handlers to the AIR script section that will call these javascript functions:

private function showHTML(e:Event): void {
   Alert.show(htmlContainer.htmlLoader.window.getHTML());
}
private function insertHTML(e:Event): void {
   htmlContainer.htmlLoader.window.insertHTML(txtTest.text);
}    

Next, add a couple of buttons and a text input box to the form and attach these to the above event handlers:

<mx:Button label="Show HTML" click="showHTML(event);"/> 
<mx:TextInput
id="txtTest"/>
<mx:Button
label="Insert" click="insertHTML(event);"/>

If you run this application now, you should see a form with an instance of TinyMCE, initally populated with the content, and you can use the buttons to read or change the HTML directly. If the TinyMCE fails to initialise and you are using a version of TinyMCE later than v3.2.1, see below for instructions on amending the source to make it work.

A Flex archive of the simple example is available here.

 

Further articles will cover the issues encountered when attempting to use the advanced functionality of TinyMCE, particularly working with dialog boxes and external CSS styles.

Footnote: How To 'Fix' TinyMCE 3.2.7 to work correctly with Flex

When I was initially testing using TinyMCE v3.2.1 I found that this example worked straight away, however with the latest version (3.2.7) there appears to be a bug that prevents things from working correctly. After several days of testing and debugging the TinyMCE source I found that some code that attempts to determine relative URLs fails when called from within AIR. Since I hadn't the time to try to debug this, I simply copied the relevant code from the 3.2.1 source to the 3.2.7 source. The code in question is in tiny_mce_src.js, as follows

v3.2.7
509   // Relative path http:// or protocol relative //path
510   if (!/^\w*:?\/\//.test(u))
511    u = (s.base_uri.protocol || 'http') + '://mce_host' + t.toAbsPath(s.base_uri.path, u);

Replace this with the equivalent code from v3.2.1 

514   // Relative path
515 if (u.indexOf(':/') === -1 && u.indexOf('//') !== 0)
516 u = (s.base_uri.protocol || 'http') + '://mce_host' + t.toAbsPath(s.base_uri.path, u);

A bug was raised on SourceForge for this
(http://sourceforge.net/tracker/?func=detail&atid=635682&aid=2891260&group_id=103281) , but as yet, there has been no response. 

 
  | +44 (0)8456 430 187 | ccinfo@coderscollective.com | 
All site content
© coderscollective.pz 2008