Einleitung:
Dieses Tutorial soll eine Möglichkeit zeigen, wie man mit Flash und PHP einen einfachen Html-Editor realisieren kann. Es sind ausschließlich Kenntnisse in Flash MX 2004 und AS 2 erforderlich. Die php-Datei ist ziemlich klein, aber dennoch sehr wichtig. Ich habe versucht den php-Code so ausführlich wie möglich zu erklären, damit dieser auch ohne Vorkenntnisse verständlich ist.
Vorschau
Die Klasse <HtmlEditor>:
Die Klasse HtmlEditor bietet lediglich eine Methode zum hinzufügen von Tags in ein Textfeld ein.
PHP-Code:
class ped.nazari.htmleditor.HtmlEditor
{
public function HtmlEditor ()
{
}
public static function addHtmlTag (_gui : Object, tag : String, more : String) : Void
{
var s : Number = _gui.startIndex;
var e : Number = _gui.endIndex;
var tf : TextField = _gui.content_txt;
if(more == undefined)
more = "";
var str : String = "<" + tag + " " + more + ">" + tf.text.substr(s, e - s) + "";
Selection.setFocus(tf);
Selection.setSelection(s, e);
tf.replaceSel(str);
}
}
Die Methode akzeptiert drei Parameter:
_gui
Ein Objekt, meistens GUI - Objekt, welches bestimmte Voraussetzungen mit sich bringen muss:
1. Es muss die Attribute startIndex und endIndex als public deklariert haben.
2. Es muss eine Eigenschaft content_txt haben, welche auf ein TextField veweist.
tag
Ein String, welches das Html-Tag ohne <>-enthält. zB "b" für bold (<b>).
more
Werden für ein Tag mehrere Attribute benötigt, wie z.B. für <font>, können diese hier eingegeben werden, z.B. addHtmlTag(gui, "font", "color='#FF0000'");
Zum Parameter _gui sei gesagt, dass damit leicht Fehler passieren können, da das Objekt welches übergeben wird nicht unbedingt die Voraussetzungen erfüllen muss. Leider können keine Schnittstellen erstellt werden, welche Klassen, die diese implementieren, "zwingen" bestimmte Attribute zu deklarieren. Daher ist hier Vorsicht geboten! Eine Überlegung wäre auch einen vierten Parameter hinzuzufügen, um das Textfeld zu übergeben, an welchem die Änderungen vorgenommen werden. So könnte man darauf verzichten, dass alle Objekte das Attribut content_txt enthalten, welches auf ein Textfeld verweist. Das bleibt euch überlassen.

In den ersten beiden Zeilen speichern wir jeweils die Anfangs- und die Endposition der Textmarkierung in Variablen: var s : Number = _gui.startIndex;
var e : Number = _gui.endIndex;
Wie das genau funktioniert, erfahren wir später im Abschnitt Klasse: HtmlEditorGUI.
Im nächsten Schritt wird einfach eine Referenz auf das Textfeld in einer Variablen gespeichert, um Tipparbeit zu reduzieren:
var tf : TextField = _gui.content_txt;
Nicht jedes Html-Tag benötigt zusätzliche Attribute, somit sollte dann der Parameter more mit dem leeren String versehen werden. Wurde ein Wert übergeben, so bleibt dieser unberührt:
if(more == undefined)
more = "";
Der wichtigste Teil dieser Methode ist der Folgende:
PHP-Code:
var str : String = "<" + tag + " " + more + ">" + tf.text.substr(s, e - s) + "";
Selection.setFocus(tf);
Selection.setSelection(s, e);
tf.replaceSel(str);
Ein Beispiel zur Veranschaulichung:
Angenommen unser Textfeld enthält den Text "Dieter ist ein guter Junger." Nun möchten wir, dass beim Klick auf ein Button ein markiertes Wort fettgedruckt wird. Dazu markieren wir z.B. das Wort "guter". Unser Button enthält u.a. den Code HtmlEditor.addHtmlTag(gui, "b");. Drücken wir nun unser Button, ändert sich der obige Text in "Dieter ist ein <b>guter</b> Junge!". Das Wort wird jetzt von Tags umgeben. Wie das alles genau funktioniert, erfahren wir später.
Unsere erste Klasse ist fertig. Jetzt könnte die Frage aufkommen, warum wir wegen einer einzigen Methode direkt eine Klasse erstellen, anstatt diese Methode in der Klasse zu deklarieren, in der sie gebraucht wird.
Dies hat vielerlei Gründe:
1. In dem wir die Methode in einer separaten Klasse "deponieren", können wir sie für weitere Projekte immer wieder verwenden, in dem wir sie z.B. unserer Standard-Bibliothek hinzufügen.
2. Dieses Tutorial zeigt, wie man einen einfachen Editor erstellt. Möchte man jedoch den Editor um weitere Funktionen erweitern, muss lediglich die Klasse HtmlEditor bearbeitet werden. Alle zuvor "simplen" Editore können durch einige kleinere Anpassungen dann um diese Funktionen erweitert werden. Public Methoden sollten nur mit größter Vorsicht geändert werden.
Die Klasse <Configuration>:
"Globale" Einstellungen werden von der Klasse Configuration geregelt. Dazu gehören z.B. die Anzahl der zulässigen Änderungen pro Tag, Sound an/aus u.v.m. In unserem Fall besteht die Klasse lediglich aus zwei Attributen, mit den Namen von zwei Dateien.
PHP-Code:
class ped.nazari.htmleditor.Configuration
{
public static var phpFile : String = "htmleditor_func.php";
public static var txtFile : String = "projects.txt";
}
txtFile enthält den Pfad zur txt-Datei als String. Diese Datei enthält den Text, der zuvor in content_txt geschrieben und anschließend hochgeladen wurde.
Für diese zwei Attribute macht es natürlich keinen Sinn eine extra Klasse zu erstellen. Aber wie auch bei der Klasse HtmlEditor erleichtert es das spätere Erweitern des Editors.
Das war kurz und schmerzlos. Sehen wir uns nun die Klasse an, welche das Laden und Senden von Daten regelt.
Die Klasse <FileManager>:
Damit der Text, den wir in unserem Editor eingeben, gespeichert und später wieder geladen werden kann, muss ein Datentransfer stattfinden. Dafür sorgt die Klasse FileManager. Da jedes FileManager-Objekt exakt das selbe macht - Daten senden bzw speichern - ist es ausreichend nur eins zu erstellen. Um dies zu erzwingen, wenden wir das Singleton-Muster an. Wie das genau funktioniert, werden wir jetzt sehen. Erst einmal der Code:
PHP-Code:
class ped.nazari.htmleditor.FileManager
{
private static var instance : FileManager;
private function FileManager ()
{
}
public function transfer (file : String, _lis : Object, mode : String) : Void
{
if (file == undefined)
{
trace("Error: the file argument is undefined!");
return;
}
var lv : LoadVars = new LoadVars();
lv._lis = _lis;
lv.fm = this;
if ( (mode == 's') || (mode == 'sl') )
{
copyStringData(_lis, lv);
}
if(mode == 's')
{
lv.send(file);
return;
}
else if (mode == 'sl')
{
var r : Number = Math.floor(Math.random() * 9999999);
lv.sendAndLoad(file + "?nocache=" + r, lv, "POST");
}
else // if (mode == 'l')
{
var r : Number = Math.floor(Math.random() * 9999999);
lv.load(file + "?nocache=" + r);
}
lv.onLoad = function (ok : Boolean)
{
var fm : FileManager = this.fm;
var dataObj : Object = {};
fm.copyStringData(this, dataObj);
this._lis.onLoad(ok, dataObj);
};
}
public function copyStringData (dataOrg : Object, dataCopy : Object) : Void
{
for (var data : String in dataOrg)
{
if(typeof dataOrg[data] == "string")
{
dataCopy[data] = dataOrg[data];
}
}
}
public static function getInstance () : FileManager
{
if (instance == undefined)
instance = new FileManager();
return instance;
}
}
Die Methode copyStringData() kopiert alle Attribute eines Objektes, welche einen String als Wert besitzen, in ein anderes Objekt. Die Parameter dazu sind:
dataOrg
Das Objekt, welche die Daten enthält.
dataCopy
Das Objekt, welche die Daten kopiert.
Die Funktion, die die Klasse FileManager zu dem macht, was sie ist, heißt transfer(). Die Funktion besitzt drei Parameter:
file
Ein Pfad zur Datei, an der Daten gesendet bzw. von der Daten geladen werden soll.
_lis
Das Objekt, welches bei send bzw. sendAndLoad die Daten enthält, welche gesendet werden soll und benachrichtigt wird soll, wenn die Daten geladen wurden. Da jedes Objekt als Argument eingegeben werden kann, ist es wichtig darauf zu achten, dass das Objekt eine onLoad()-Methode besitzt. I.d.R. handelt es sich aber um ein LoadVars-Objekt.
mode
Hier wird bestimmt um welche Art von Transfer es sich handelt. Es gibt drei Möglichkeiten:
's' für send
'sl' für sendAndLoad (Hinweis: nicht die Zahl eins, sondern ein kleines 'L')
'l' für load (Hinweis: nicht die Zahl eins, sondern ein kleines 'L')
Jede andere Angabe wird als 'l' behandelt, d.h. es werden Daten geladen.
Anfangs wird überprüft, ob das Argument file leer ist. Ist dies der Fall macht es keinen Sinn weiterzumachen, und die Funktion wird mit return beendet.
PHP-Code:
if (file == undefined)
{
trace("Error: the file argument is undefined!");
return;
}
var lv : LoadVars = new LoadVars();
lv._lis = _lis;
lv.fm = this; Sollen Daten gesendet werden - dies ist der Fall, wenn das Attribut mode den Wert 's' oder 'sl' besitzt - werden diese mit Hilfe von copyStringData() von _lis nach lv kopiert.
PHP-Code:
if ( (mode == 's') || (mode == 'sl') )
{
copyStringData(_lis, lv);
}
PHP-Code:
if(mode == 's')
{
lv.send(file);
return;
}
PHP-Code:
else if (mode == 'sl')
{
var r : Number = Math.floor(Math.random() * 9999999);
lv.sendAndLoad(file + "?nocache=" + r, lv, "POST");
}
Ist mode gleich 'l' oder irgendein anderer Wert außer 's' oder 'sl', werden lediglich Daten von der Datei geladen. Auch hier wird wie bei 'sl' verhindert, dass immer die aktuelle Datei geladen wird.
PHP-Code:
else // if (mode == 'l')
{
var r : Number = Math.floor(Math.random() * 9999999);
lv.load(file + "?nocache=" + r);
}
Die Zeile var fm : FileManager = this.fm; dient nur dazu, dem Compiler die Typkontrolle zu ermöglichen. Anschließend wird ein lokales Objekt dataObj erstellt, welche die geladenen Daten von lv mit Hilfe von copyStringData() kopiert. Als letztes wird die onLoad-Methode von _lis aufgerufen und als Argumente werden ok und dataObj übergeben. Hätten wir nicht zuvor _lis unda das FileManager-Objekt in lv gespeichert, wäre es nicht einfach, vielleicht sogar unmöglich, auf diese Objekte zuzugreifen.
Hinweis: Die FileManager.as-Datei, die Ihr von dieser Seite runterladen könnt, enthält mehr Code als hier beschrieben. Darüber werden wir bei weitere Features einbauen reden.
Ich muss zugeben, dass ein Klassenname wie FileTransferManager mehr Sinn machen würde. Da es mir erst aufgefallen ist, als ich das Programm fast fertig hatte, habe ich es einfach so gelassen.
Ok, jetzt wo wir wissen wie wir unsere Daten senden und laden können, bringen wir ein bischen Farbe ins Spiel.
Die Klasse <ColorSet>:
Die Klasse ColorSet enthält die Eigenschaften und Methoden unserer Farbpalette, wie z.B. die Anzahl der Farben pro Spalte, die Standardfarben etc...
PHP-Code:
class ped.nazari.htmleditor.ColorSet
{
private var col_arr : Array;
private var defaultColors_arr : Array = ["FF0000", "000000"];
public var col_mc : MovieClip;
private var cols : Number = 3;
public function ColorSet (target : MovieClip, depth : Number,
overwrite : Boolean, colors : Array)
{
if ( depth == undefined )
depth = target.getNextHighestDepth();
target.createEmptyMovieClip("colorSet_mc"+depth, depth);
col_mc = target["colorSet_mc"+depth];
if( overwrite && (colors != undefined) )
col_arr = colors.concat();
else
{
col_arr = defaultColors();
for (var i:Number = 0; i < colors.length; i++)
{
col_arr.push(colors[i]);
}
}
init();
}
public function defaultColors() : Array
{
return defaultColors_arr.concat();
}
public function setCols (cols : Number) : Void
{
this.cols = cols;
}
public function getCols () : Number
{
return cols;
}
private function init () : Void
{
var c : Number = 0;
var y : Number = 0;
for (var i:Number = 0; i < col_arr.length; i++)
{
col_mc.attachMovie("colorRect_mc", "rect"+i, i);
var rect : MovieClip = col_mc["rect"+i];
rect.colObj = new Color(rect);
rect.color = col_arr[i];
rect._x = c * rect._width;
rect._y = y * rect._height,
rect.colObj.setRGB("0x"+rect.color);
c++;
if ( c == cols )
{
c = 0;
y++;
}
}
}
}
Der Konstruktor erwartet vier Parameter:
target
Das MovieClip, welches das Paletten-Mc enthalten soll (parent-mc von col_mc).
depth
Die Tiefe des Paletten-Mcs.
overwrite
Wenn true, wird die Standardpalette vom vierten Argument colors überschrieben und wird somit nicht mehr angezeigt. Ansonsten werden die Farben in colors zusätzlich zu den Standardfarben (defaultColors_arr) angezeigt.
colors
Ein Array mit den Farben der Farbpalette.
Die ersten beiden Zeilen im Rumpf des Konstruktors stellen sicher, dass falsche depth-Angaben abgefangen werden. Dies ist nicht zwingend notwendig und funktioniert nur ab Flash MX 2004 und höher.
PHP-Code:
if ( depth == undefined )
depth = target.getNextHighestDepth();
PHP-Code:
target.createEmptyMovieClip("colorSet_mc"+depth, depth);
col_mc = target["colorSet_mc"+depth];
PHP-Code:
if( overwrite && (colors != undefined) )
col_arr = colors.concat();
PHP-Code:
else
{
col_arr = defaultColors();
for (var i:Number = 0; i < colors.length; i++)
{
col_arr.push(colors[i]);
}
}
Als letztes wird im Konstruktor die Methode init() aufgerufen. Diese ist als private deklariert, was nicht unbedingt sein muss. Es ist kein Problem sie später als public zu deklarieren und sie somit für andere Klassen zugänglich zu machen. Der umgekehrte Fall, könnte jedoch unerwartete Folgen haben. Die Methode init() sorgt ausschließlich für die Initialisierung der Optik der Farbpalette. Für die Funktionalität sorgt die Klasse: HtmlEditorGUI. Mehr dazu im nächsten Kapitel.
In einer for-Schleife werden MovieClips mit dem Verknüpfungsnamen colorRect_mc in col_mc attached. Da es sich hierbei um Quadrate handelt, hätte man es auch dynamisch lösen können. Das bleibt jedem selbst überlassen.
PHP-Code:
col_mc.attachMovie("colorRect_mc", "rect"+i, i);
var rect : MovieClip = col_mc["rect"+i];
colorObj
Das Color-Objekt, welches für die Einfärbung sorgt..
color
Die Farbe mit der die MovieClips eingefärbt werden. (Die Farbe erhalten wir aus dem Array col_arr)
Anschließend werden die Farben positioniert
rect._x = c * rect._width;
rect._y = y * rect._height;
und eingefärbt rect.colObj.setRGB("0x"+rect.color);
c steht für Spalte (column) und y für die y-Position. Ist die maximale Spaltenanzahl erreicht wird c wieder auf 0 gesetzt und y um eins inkrementiert, also es wird in die nächste Zeile gerutscht, beginnend bei der ersten Spalte.
PHP-Code:
c++;
if ( c == cols )
{
c = 0;
y++;
}
Unsere Farbpalette ist nun fertig. Da wir sie von den restlichen Klassen getrennt haben, können wir sie jeder Zeit in einem anderen Programm wiederverwenden. Mit Hilfe der Standardfarben ist es uns m öglich, in allen Programmen, wo wir ColorSet benutzen, einheitliche Farben zu benutzen. Die Funktionalität habe ich bewusst nicht in der Klasse selbst eingebaut, da dadurch die Wiederverwendbarkeit eingeschränkt werden würde. In unserem Fall möchten wir Text einfärben. Aber wenn die Farbpalette dazu benutzt werden soll MovieClips einzufärben, benötigen wir andere Funktionen. Deshalb überlassen wir diese Arbeit anderen Klassen. In diesem Fall der Klasse: HtmlEditorGUI, die letzte und umfangreichste Klasse unseres Programms.
Die Klasse <HtmlEditorGUI>:
Kommen wir nun zu der Klasse, die für die graphische Oberfläche (GUI = Graphical User Interface) verantwortlich ist. Da es sich hierbei um eine relativ große Klasse handelt und das meiste ziemlich einfach zu verstehen ist, besprechen wir nur die wichtigsten Funktionen.
Um Html-Tags im Editor einfügen zu können, benötigen wir eine Methode, die es uns ermöglicht. Die Klasse HtmlEditor bietet schon eine sehr nützliche Methode: addHtmlTag(). Davon machen wir gebrauch, um spezielle Tags einzufügen, z.B. <b>-Tags:
PHP-Code:
public function bold () : Void
{
HtmlEditor.addHtmlTag(this, "B");
}
Bei der Methode color() wird zusätzlich ein drittes Argument übergeben, um die Farbe festzulegen.
PHP-Code:
public function color (col : String) : Void
{
HtmlEditor.addHtmlTag(this, "font", "color=" + col);
}
Auf diese Weise können beliebig viele Tags hinzugefügt werden. Flash unterstützt z.Zt. leider nur relativ wenige.
Um die txt-Datei zu laden, verwenden wir die Methode loadTxt().
PHP-Code:
public function loadTxt () : Void
{
makeStatusNormal("loading projects...");
var fm : FileManager = FileManager.getInstance();
fm.transfer(Configuration.txtFile, lv, "l");
lv.onLoad = function (ok:Boolean, dataObj : Object)
{
var gui : HtmlEditorGUI = this._gui;
if (ok)
{
gui.statusSucceed("Projects loaded! :)");
if(dataObj.content != "")
{
gui.content_txt.text = dataObj.content;
gui.textBuffer = gui.content_txt.text;
// refreshes the preview
if ( gui.isPreviewOn() )
{
gui.activatePreview();
}
}
else
gui.content_txt.text = "Zur Zeit sind keine Projekte in Planung.";
}
else
{
gui.statusFail(Configuration.txtFile + " could not be loaded!");
gui.content_txt.text = "Fehler beim laden der Projekte aufgetreten.\n\n" +
"BitteWebmaster melden.";
}
};
}
ok
wenn true, ist alles gut gelaufen, ansonsten ist ein Fehler aufgetaucht.
dataObj
ein Objekt, welches die geladenen Daten enthält.
Mit Hilfe von ok kann man Fehlermeldungen bzw. Bestätigungen, dass alles glatt gelaufen ist, ausgeben.
Für das Hochladen der Daten ist die Methode upload() zuständig:
PHP-Code:
public function upload () : Void
{
...
// Verhindert direkt aufruf der php-Datei
lv.submitted = true;
var fm : FileManager = FileManager.getInstance();
fm.transfer(Configuration.phpFile, lv, "sl");
lv.onLoad = function(ok : Boolean, dataObj : Object)
{
var gui : HtmlEditorGUI = this._gui;
if (ok)
{
if(dataObj.status == 1)
gui.statusSucceed("Data uploaded! :-)");
else
gui.statusFail("Failed uploading data!");
}
else
gui.statusFail(Configuration.phpFile + " could not be loaded!");
lv.submitted = false;
};
}
Wir haben hier nur einen kleinen Teil der Klasse HtmlEditorGUI besprochen. Wenn ihr irgendwelche Fragen zu der Klasse (oder auch andere) habt, schreibt mir eine Email oder postet eure Frage im Forum.
Jetzt haben wir alle Klassen durch. Gehen wir nun über zur php-Datei. Mal schauen was uns da erwartet.
Die php-Datei <htmleditor_func>:
Php ermöglicht es uns Dateien auf dem Server zu speichern bzw. zu entfernen. Ohne php wären die Änderungen die wir im Editor vornehmen nur temporär, was unseren Editor nutzlos machen würde. Es sind nur ein paar Zeilen Code, die dennoch viel bewirken:
PHP-Code:
<?php
if($submitted)
{
unlink($txtFile);
$fp = fopen($txtFile, "w");
flock($fp, 2);
fwrite($fp, "content=" . stripslashes($content));
flock($fp, 3);
fclose($fp);
echo "status=1";
}
else
echo "Bitte keine Direktaufrufe!!";
?>
Nun wird eine neue Datei mit dem gleichen Namen angelegt und zum bearbeiten freigegeben: $fp = fopen($txtFile, "w"); Damit nicht mehrere Zugriffe auf der Datei gleichzeitig durchgeführt werden können, was die Datei beschädigen könnte, wird die Datei für andere gesperrt: flock($fp, 2); Anschließend wird der neue Inhalt des Editors in die Textdatei geschrieben. fwrite($fp, "content=" . stripslashes($content)); Auch hier wird die Variable $content von Flash gesendet: lv.content = textBuffer; (s. HtmlEditorGUI). "content=" am Anfang der Textdatei ermöglicht es den Text wieder in Flash zu laden, als Variable mit dem Namen content. Anschließend wird die Datei wieder freigegeben und geschlossen:
flock($fp, 3); fclose($fp)
Als letztes senden wir mit Hilfe von echo direkt an Flash die Meldung "status=1". status wird von Flash als Variable aufgefasst, mit dem Wert eins. Wurde der Code bis dahin ausgeführt und status somit den Wert eins besitzt, ist alles fehlerfrei abgelaufen. Ist vorher ein Fehler aufgetreten und die Ausführung der php-Datei abgebrochen, erhält status nicht den Wert 1 und wir wissen, es muss ein Fehler aufgetreten sein.
Mehr Informationen zu den einzelnen Methoden und php im Allgemeinen, findet ihr bei unter php.net.
Das war´s! Unser Editor ist nun fertig. Die Dateien könnt ihr unter download runterladen. Ich hoffe ich konnte alles verständlich erklären.

___________________________________________________________
Hi,
es gibt jetzt eine neue datenbankbasierte Version. Neuheiten:
- - mehrere Einträge können geschrieben werden
- - Verwaltung von mehreren Benutzern mit unterschiedlichen Rechten
- - Löschen und Editieren von Einträgen
Vorschau
Download



Kommentar schreiben

Bereiche
Kategorien
Forum - Webmaster & Internet





Artikel bewerten