Kunena >= 5.2 mit CKEditor

Mit Kunena 5.2 wurde der Editor durch den CKEditor ersetzt. Dieser ist um einiges moderner und bietet dem Anwender einen WYSIWYG (What you see is what you get: Was du siehst ist, was du bekommst) Editor, wie es im Rest deiner Joomla! Webseite schon fast immer der Fall ist. Der neue Editor ändert aber nichts an der Tatsache, dass Kunena BBCode basiert ist.

Ich biete schon seit einigen Jahren die Joomla! TexTools an, zu denen auch ein Editor Plugin für Kunena gehört. Der CKEditor lässt sich ebenfalls durch Plugins erweitern und es gibt auch bereits sehr viele Plugins, welche man sich installieren kann. Allerdings muss man dabei ein paar Handgriffe selbst machen, wozu der Endanwender bestimmt keine Lust hat.

Daher möchte ich euch heute hier zeigen, wie ihr selbst ein Joomla! Plugin erstellen könnt, welches den CKEditor von Kunena erweitert.

Wenn ihr jetzt nicht wisst, was Joomla! oder Kunena ist, könnte der Rest des Artikels etwas fordernd sein. Daher hier noch die Links zu den Projekten, damit ihr euch dort näher informieren könnt.

Joomla Plugin

Als Grundlage brauchen wir ein Joomla! Plugin. Ich werde nicht alle Grundlagen im Detail besprechen, daher empfehle ich euch vorher in der Doku zu Joomla! nach zu lesen, wie man ein Basis Plugin erstellt.

myJoomlaPlugin.php

Wir erstellen uns also eine PHP Datei mit dem Namen myJoomlaPlugin.php mit dem Inhalt.

class plgmyJoomlaPlugin extends CMSPlugin
{
	public function construct(&$subject, $config)
	{
		if (!(class_exists('KunenaForum') && KunenaForum::isCompatible('5.2') && KunenaForum::installed()))
		{
			return;
		}
		
		parent::construct($subject, $config);
		
		$layout = JFactory::getApplication()->input->get('layout');
		
		if (strcmp($layout, "create") == 0 || strcmp($layout, "reply") == 0 || strcmp($layout, "edit") == 0)
		{
			Factory::getDocument()->addScript("/media/plg_myJoomlaPlugin/js/myPluginCK.js");
		}
	}
}

Hier haben wir zwei Codesnippets, welche sich von einem Standard Joomla! Plugin abheben. Zuerst wollen wir sicher gehen, dass Kunena installiert, aktiv und kompatibel mit unserem folgenden Code ist.

if (!(class_exists('KunenaForum') && KunenaForum::isCompatible('5.2') && KunenaForum::installed()))
{
    return;
}

Zusätzlich wollen wir sichergehen, dass die CKEditor Plugin Dateien auch nur geladen werden, wenn Kunena auch den Editor geladen hat.

$layout = JFactory::getApplication()->input->get('layout');
if (strcmp($layout, "create") == 0 || strcmp($layout, "reply") == 0 || strcmp($layout, "edit") == 0)
{
	Factory::getDocument()
		->addScript("/media/plg_myJoomlaPlugin/js/myPluginCK.js");
}

myPluginCK.js

Als nächstes schauen wir uns die oben eingebundene JavaScript Datei an, welche wir dazu verwenden das eigentliche CKEditor Plugin aufzurufen und zu aktivieren.

Die JavaScript Datei besteht aus drei Teilen. Der erste Teil sorgt einfach nur dafür, dass der restliche Code erst ausgeführt wird, wenn die Seite und somit die CKEditor Namensräume verfügbar sind. Hier gibt es verschiedene Methoden das umzusetzen. Ich habe mich hier für die Vanilla JS Variante entschieden.

function kaTeXReady(fn) {
    if (document.attachEvent ? document.readyState === "complete" : document.readyState !== "loading") {
        fn();
    } else {
        document.addEventListener('DOMContentLoaded', fn);
    }
};

Der zweite Teil ist der Interessante an dieser Stelle. Hier haben wir zuerst eine Prüfung, dass die Editorinstanz auch vorhanden ist. Ansonsten funktionieren die folgenden Teile nur, wenn zufällig die Instanz verfügbar ist.

function katexckeditorconf() {
    CKEDITOR.on('instanceReady', function () {

Damit wir unser CKEditor Plugin integreiren können, müssen wir die Konfiguration der Instanz erweitern. Dazu holen wir uns die Konfiguration der aktuellen Editor Instanz.

editor = CKEDITOR.instances["message"];
var config = CKEDITOR.instances["message"].config;

Darauf folgend ist es ganz wichtig zuerst zu prüfen, ob wir das Plugin nicht schon hinzugefügt haben. Denn dadurch, dass wir auf das Event instanceReady hören, würden wir uns sonst eine zyklische Rekursion bauen.

if (!config.extraPlugins.includes("myckplugin")) {

Falls das Plugin noch nicht hinzugefügt wurde, können wir damit starten unser CKeditor Plugin zu positionieren. Hierzu fügen wir zuerst den Namen unseres Plugins der Liste extraPlugins hinzu.

config.extraPlugins += ",myckplugin";

Der nächste Schritt ist etwas brutal, denn wir zerstören die Editor Instanz, um sie danach dann mit der geänderten Konfiguration neu zu erzeugen.

editor.destroy();
CKEDITOR.replace('message', config);

Der verstehende Leser wird sich an der Stelle dann denken: "Wenn das Viele machen, ist das aber eine sehr unperformante Geschichte!" Da hat der verstehende Leser auch absolut recht. Entweder ihr müsst euren Kunden beibringen, was sie tun müssen, um ein Plugin hinzuzufügen. Schreibt ein Skript, welches im Backend getriggert werden kann und Kunena Dateien editiert oder ihr macht es auf diese Weise.
Ich selbst bin ja beim Kunena Projekt involviert. Wenn es nun viele Entwickler gibt, die jetzt ein Editor Plugin schreiben möchten, dann kann ich auch eine bessere Variante in Kunena einbauen. Aber im Moment gibt es wichtigere Themen als dieses und bisher war ich auch der Einzige, der ein Editor Plugin für Kunena erstellt hatte. Also, wenn ihr am Entwickeln einesn Kunena CKeditor Plugins seid, dann gebt mir bitte Bescheid, damit das dann auf Dauer verbessert werden kann.

So, jetzt haben wir die Instanz zerstört und erstellt, aber eine Sache haben wir vergessen: Wir müssen CKEditor noch zeigen, wo er jetzt das Plugin suchen soll, denn sonst würde nur in den Kunena Ordnern nach dem Plugin gesucht werden, wo es nicht zu finden ist. Dazu brauchen wir noch den folgenden Snippet, bevor wir die Instanz erneut erzeugen.

CKEDITOR.plugins.addExternal('myckplugin', '../../../plg_kunenatex/myckplugin/');

Der dritte Teil ist lediglich der Aufruf der ersten Methode mit dem Methodennamen der zweiten Methode, sodass diese erst nach vollständigem Laden der Seite ausgeführt wird.

So sieht die Datei myPluginCK.js dann im Kompletten wie folgt aus.

function kaTeXReady(fn) {
    if (document.attachEvent ? document.readyState === "complete" : document.readyState !== "loading") {
        fn();
    } else {
        document.addEventListener('DOMContentLoaded', fn);
    }
};
function katexckeditorconf() {
    CKEDITOR.on('instanceReady', function () {
        editor = CKEDITOR.instances["message"];
        var config = CKEDITOR.instances["message"].config;
        if (!config.extraPlugins.includes("myckplugin")) {
            config.extraPlugins += ",myckplugin";
            editor.destroy();
            CKEDITOR.plugins.addExternal('myckplugin', '../../../plg_kunenatex/myckplugin/');
            CKEDITOR.replace('message', config);
        }
    });
};
kaTeXReady(katexckeditorconf);

myJoomlaPlugin.xml

Zu einem Joomla! Plugin gehört auch immer eine Manifest Datei im XML Format. Ich habe euch hier ein Minimalbeispiel, auf das ich nicht näher eingehen möchte, da dies zu den Grundlagen der Joomla! Plugin Entwicklung gehört.

<?xml version="1.0" encoding="utf-8"?>
<extension version="2.5" type="plugin" group="kunena" method="upgrade">
    <name>plg_myJoomlaPlugin</name>
    <author></author>
    <creationDate></creationDate>
    <copyright></copyright>
    <license>GNU General Public License version 2 or later; see LICENSE.txt</license>
    <authorEmail></authorEmail>
    <authorUrl>www.schultschik.de</authorUrl>
    <version></version>
    <description></description>
    <files>
        <filename plugin="myJoomlaPlugin">myJoomlaPlugin.php</filename>
        <filename>index.html</filename>
    </files>
    <media folder="media/plgmyJoomlaPlugin" destination="plgmyJoomlaPlugin">
        <folder>js</folder>
        <folder>myckplugin</folder>
    </media>
</extension>

Die Datei myPluginCK.js ist demnach in dem Ordner js zu finden und muss im Installationspaket entsprechend positioniert werden oder ihr wählt euch eine eigenen Struktur.

In den nächsten Schritten gehen wir darauf ein, was in dem Ordnern myckplugin zu finden ist, beziehungsweise, was drin sein muss.

CKeditor Plugin

CKEditor setzt eine gewisse Struktur und Benamung in den Plugin Ordnern vorraus.

  • myckplugin/
    • icons/
      • myckplugin.png
    • plugin.js

Das Icon kann ein beliebiges PNG sein, welches in der Abmessung den restlichen Editoricons entspricht.

Die Javascript Datei muss den Namen plugin.js tragen, da dies der Startpunkt aller CKEditor Plugins ist. Die CKEditor Plugins können beliebig komplex werden. Für unser Beispiel benutzen wir eine sehr grundlegend schlichte Variante, um die Funktionsweise zu verdeutlichen.

Daher ist unsere plugin.js recht kurzgehalten. Was bei allen Plugins gleich ist, ist das Hinzufügen des Plugins mit dem add Befehl, dem Angeben des Icon Namens und, dass ein Plugin eine init Funktion hat.

CKEDITOR.plugins.add( 'myckplugin', {
    icons: 'myckplugin',
    init: function( editor ) {

In dieser init Funktion geschieht dann die eigentliche Magie. Zuerst fügen wir ein Kommando hinzu, sodass der Editor auch weiß, was er tun soll. In diesem Beispiel wollen wir den BBCode [myckplugin] in das Editor Feld eintragen lassen. Hierzu benötigen wir das Snippet:

editor.addCommand( 'insertmyckplugin', {
    exec: function( editor ) {
        editor.insertHtml( '[myckplugin] [/myckplugin]' );
    }
});

Was fehlt uns jetzt noch? Genau der Editorbutton auf den der Benutzer dann klicken kann, um den BBCode in den Editor einfügen zu lassen. Hierzu setzen wir direkt hinter den addCommand Befehl.

editor.ui.addButton( 'MyCkPlugin', {
    label: 'My CK Plugin',
    command: 'insertmyckplugin',
    toolbar: 'insert'
});

Das Name und das Label sind frei wählbar. Beim command sollte man darauf achten die gleiche Schreibweise, wie beim addCommand Befehl zu verwenden, sonst wird das auszuführende Kommando nicht gefunden. Bei ´´toolbar´´ habe ich ´´insert´´ gewählt, damit der Button im Bereich für einfügende Befehle aufgeführt wird. Welche Bereiche es sonst noch gibt, könnt ihr in der CKEditor Dokumentation nachlesen.

Im Kompletten sieht die plugin.js dann wie folgt aus.

CKEDITOR.plugins.add( 'myckplugin', {
    icons: 'myckplugin',
    init: function( editor ) {
        editor.addCommand( 'insertmyckplugin', {
            exec: function( editor ) {
                editor.insertHtml( '[myckplugin] [/myckplugin]' );
            }
        });
        editor.ui.addButton( 'MyCkPlugin', {
            label: 'My CK Plugin',
            command: 'insertmyckplugin',
            toolbar: 'insert'
        });
    }
});

Wer mehr Infos dazu haben möchte, kann in der CKEditor Dokumentation nachlesen.

Installation

Das Ganze packt ihr dann wie gehabt zu einem Installationspaket zusammen, mit passender Manifest Datei, und könnt es dann über den Joomla! Installationsprozess installieren. Vergesst nicht, das Plugin danach noch zu aktivieren und schon habt ihr den Editor von Kunena mit einem Joomla! Plugin erweitert.

Kompletter Sourcecode eines funktionierenden Plugins

Die veröffentlichten Versionen könnt ihr auf der Projektseite zum Kunena Plugin KaTex finden.

Der Sourcecode ist auf der GitHub Seite Joomla-Tex-Tools zu finden. Hier arbeite ich im Moment auf dem Branch 11-support-ckeditor, der sich je nach Projektfortschritt natürlich ändern kann.

Ich hoffe euch hat der Artikel und/oder das Plugin Projekt gefallen. Unterstützen könnt ihr mich gerne hier rechts oben über den PayPal Me Link oder auf GitHub über den Sponsor Button.