WYSIWYG Editor mit Flex

Adobe liefert Flex mit einem RichTextEditor aus. Dieser lässt sich sehr einfach einbinden und passt vom Layout her auch wunderbar zu den restlichen Flex Controls. 

Dieser Editor hat aber leider eine ziemlich begrenzte Funktionalität. Bereits beim Einfügen eines Bildes scheitern wir! Dazu kommt, dass der generierte Code nicht HTML konform ist, ein direktes verwenden in einer HTML Ausgabe ist deswegen zum Beispiel nicht möglich.

Alternative Lösungsmöglichkeit

Die einzige flash-basierte Lösung die ich finden konnte, ist diese hier: http://flashtexteditor.com/flexdemo/full Sieht auf den ersten Blick nett aus, eingefügte Bilder verhalten sich aber nicht wie gewohnt und fliessen mit dem Text mit und zudem ist dieses Control inzwischen nur noch kommerziell verfügbar. 

Wer sich mit HTML und JavaScript beschäftigt hat, wird sicherlich den einen oder anderen WYSIWYG HTML Editor gefunden haben. Um nur ein paar zu nennen:

Wäre es nicht schön, wir könnten diese Editoren in Flex verwenden? Können wir!

Flex mit Adobe AIR vs. Flex im Browser

Es gibt einen Unterschied in der Art wie wir unsere Flex Anwendung starten bzw. ausführen lassen.

Es besteht die Möglichkeit mittels NPRuntime den Browser einzubinden, der das Flash aufgerufen hat. Details dazu findet man zum Beispiel bei Adobe: http://livedocs.adobe.com/flex/gumbo/langref/flash/external/ExternalInterface.html

Auf derselben Seite findet man auch den Hinweis, dass diese Funktionalität mit Adobe AIR nicht funktioniert.

Note: Adobe AIR currently does not support the ExternalInterface class.

In diesem Artikel wird nur eine mögliche Lösung beim Einsatz von Adobe AIR präsentiert. Der Lösungsweg über ExternalInterface dürfte aber ähnlich verlaufen.

http://osflash.org/projects/wrapper

HTML Code einbinden

Bei einem AIR Projekt, haben wir ein zusätzliches Control zu Verfügung: mx:HTML. Dieses lässt sich wie jedes andere Control in Flex mit MXML verwenden.

1
<mx:HTML id="html" location="http://www.codeblog.ch"/>

Wir können damit auch lokale HTML Files einbinden. Wir installieren als erstes die aktuelle TinyMCE Version. http://tinymce.moxiecode.com/download.php

Wir kopieren anschliessend sämtliche Files in unser Flex Projekt und erhalten diese Struktur:

editor.html ist nicht Teil von TinyMCE und TinyMCE.mxml ist unser Flex Control – mehr dazu später.

Der HTML Code

Wir könnten den ganzen HTML Code für den TinyMCE Aufruf in unserem Flex Code speichern, ich hab mich jedoch entschieden den Code in einer HTML Datei abzulegen. Der Code ist fast 1:1 aus dem TinyMCE Beispiel entnommen.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title></title>
 
<style type="text/css">
html, body {
	margin: 0px;
}
</style>
 
<!-- TinyMCE -->
<script type="text/javascript" src="jscripts/tiny_mce/tiny_mce.js"></script>
<script type="text/javascript">
	tinyMCE.init({
		mode : "textareas",
		theme : "simple"
	});
</script>
<!-- /TinyMCE -->
 
</head>
<body>
	<textarea id="elm" name="elm" rows="15" cols="80" style="width: 100%;"></textarea>
</body>
</html>

Ich habe versucht den Code in ein neues MXML Control zu packen. Gleich zu Beginn der vollständige Code – sind ja nur ein paar Zeilen:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
<?xml version="1.0" encoding="utf-8"?>
<mx:HTML xmlns:mx="http://www.adobe.com/2006/mxml" location="tinymce/editor.html" initialize="init()">
	<mx:Script>
	<![CDATA[
	private var htmlComplete:Boolean = false;
	private var localHtmlCode:String = null;
 
	public function init(): void
	{
		addEventListener(Event.COMPLETE, onHTMLLoadComplete);
	}
	public function set htmlCode (value:String):void
	{
		// in case the html file hasn't been loaded yet, delay the call..
		if (htmlComplete)
			setHtml(value);
		else
			localHtmlCode = value;
	}
	public function get htmlCode():String
	{
		this.htmlLoader.window.tinyMCE.triggerSave();
		return this.htmlLoader.window.elm1.value;
	}
	private function setHtml(value:String): void
	{
		this.htmlLoader.window.tinyMCE.get('elm').setContent(value);
		this.htmlLoader.window.document.getElementById('elm').value = value;
	}
	private function onHTMLLoadComplete(e:Event):void
	{
		htmlComplete = true;
 
		if (localHtmlCode != null)
			callLater(setHtml,[localHtmlCode]);
	}
	]]>
	</mx:Script>
</mx:HTML>

Als Basis für unser Control dient mx:HTML. Wir fügen lediglich die Eigenschaft htmlCode hinzu, um den Inhalt von TinyMCE zu ändern und auslesen.

Dazu müssen wir lediglich eine Methode mit dem Zusatz “get” ausstatten und eine mit “set”.

Nun hatte ich jedoch das Problem, dass TinyMCE noch nicht komplett geladen war, als ich versucht habe die Eigenschaft htmlCode zu verändern. Ich hab deswegen, eine noch nicht vollständig getestete, Lösung versucht umzusetzen – durch das abfangen des Events “COMPLETE”, wird uns mitgeteilt wann das HTML Control geladen ist, wurde die Eigenschaft htmlCode von vorher gesetzt (htmlComplete == false), so wird nachdem das Control geladen ist, der Code mittels callLater gesetzt. callLater sollte eigentlich schon selber erst ausgeführt werden, wenn das Control fertig geladen ist. In meinem Fall hat dies jedoch nicht gereicht. (bin für jeden Hinweis dankbar).

Alles speichern und schon haben wir im Flex Builder ein neues Control in der Rubrik “Custom” zur Verfügung. Per Drag’n’Drop einfügen, Projekt starten!




4 Comments

Hinterlasse eine Antwort

Deine E-Mail-Adresse wird nicht veröffentlicht. Erforderliche Felder sind markiert *