Zum Inhalt

REDAXO Artikel im Frontend editieren mit dem CKEditor

Eine Beschreibung wie man mit Hilfe des CKEditor-Addon’s für REDAXO, Artikel-Blöcke auch direkt im Frontend bearbeiten kann. Die User-Erkennung erfolgt über das Backend-Login und ermöglicht im Frontend einen Bearbeitungs-Modus aufzurufen. Somit werden entsprechend vorbereitete Blöcke des Artikels direkt Editierbar. Für mich war das einfach mal ein Versuch, in Produktiv-Systemen sollte es erst nach gründlichen Tests eingesetzt werden!

Hier verwendete Systeme

  • CKEditor 4.3.2 Standard
  • CKEditor Addon 2.1
  • REDAXO 4.5.1

CKEditor Inline-editing

Mit Hilfe des HTML5 Attribut’s contenteditable=”true” kann jeder Bereich einer Webseite editierbar gemacht werden. Der CKEditor kann diese Bereiche automatisch erkennen und stellt eine Toolbar zur Verfügung. Dies ist aber nur Sinnvoll wenn alle Bereiche als ein einziges Dokument gespeichert werden. In diesem Beispiel erzeugen wir dynamisch für jedes markierte Element eine separate Instanz des Editors, um anschliessend die einzelnen Blöcke (Slices) speichern zu können.

Das REDAXO Template

Als erstes brauchen wir ein Template welches es uns ermöglicht in den Editier-Modus zu schalten, und zugleich die Konfiguration für den CKEditor beinhaltet.

Beispiel Template:

<?php
if ($REX['LOGIN']->login_status === 1) {
    //wenn im Backend angemeldet
    if (rex_request('status_info', 'string') === 'on') {
        $_SESSION['CKE_EDIT'] = true;
    } elseif (rex_request('status_info', 'string') === 'off') {
        $_SESSION['CKE_EDIT'] = false;
    }
    if ($_SESSION['CKE_EDIT'] === true) {
        // im editiermodus
        $button_text = 'Editier-Modus ausschalten';
        $status_info = 'off';
        ?>
        <!-- ckeditor -->
        <script type="text/javascript" src="/files/addons/ckeditor/vendor/ckeditor.js"></script>
        <script type="text/javascript" src="/files/addons/ckeditor/redaxo.js"></script>
        <script type="text/javascript">
            $(document).ready(function() {
                CKEDITOR.disableAutoInline = true;
                CKEDITOR.plugins.addExternal('inlinesave', '/_data/cke/plugins/inlinesave/');
                CKEDITOR.plugins.addExternal('inlinecancel', '/_data/cke/plugins/inlinecancel/');
                CKEDITOR.plugins.addExternal('image', '/_data/cke/plugins/image/');
                CKEDITOR.stylesSet.add('my_styles', [
                    {name: 'Info Box', element: 'p', attributes: {'class': 'info'}},
                    {name: 'Box rechts', element: 'aside'},
                    {name: 'Code Colored', element: 'pre', attributes: {'class': 'prettyprint'}},
                    {name: 'Code Black', element: 'pre'},
                    {name: 'upperCase', element: 'span', attributes: {'class': 'upper'}}
                ]);
                $('*[contenteditable="true"]').each(function(index) {

                    var content_id = $(this).attr('id');
                    $(this).attr('name', content_id);

                    CKEDITOR.inline(content_id, {
                        customConfig: '/_data/cke/myConfig.js',
                        removePlugins: 'image2,widget', //http://cksource.com/temp/widget/samples/plugins/widget/widget.html
                        extraPlugins: 'inlinesave,inlinecancel,image',
                        format_tags: 'p;h1;h2;h3;h4;h5;h6;pre',
                        stylesSet: 'my_styles',
                        //toolbar: 'small',
                        toolbar: [
                            ['Inlinesave', 'Inlinecancel'],
                            ['Undo', 'Redo'],
                            ['Cut', 'Copy', 'Paste', 'PasteText', 'PasteFromWord'],
                            ['Find', 'Replace', '-', 'SpellChecker', 'wsc', 'Scayt', '-', 'SelectAll'],
                            ['Bold', 'Italic', 'Underline', 'Strike', 'Subscript', 'Superscript', '-', 'RemoveFormat'],
                            ['NumberedList', 'BulletedList', '-', 'Outdent', 'Indent', '-', 'JustifyLeft', 'JustifyCenter', 'JustifyRight', 'JustifyBlock', '-', 'BidiLtr', 'BidiRtl', 'Language'],
                            ['Styles', 'Format'],
                            ['Link', 'Unlink', '-', 'Anchor', '-', 'Image'],
                            ['ShowBlocks']
                        ]
                    });
                });
            });
        </script>
        <?php
    } else {
        $button_text = 'Editier-Modus einschalten';
        $status_info = 'on';
    }
    // Button ausgeben
    ?>
    <form method="post" style="position:fixed;bottom:0;right:0;z-index:10000;">
        <input type="hidden" name="status_info" value="<?php echo $status_info; ?>">
        <button id="EDIT"><?php echo $button_text; ?></button>
    </form>
    <?php
}//endif - login
?>

Zuerst wird geprüft ob der Nutzer im Backend angemeldet ist, sonst erfolgt keine Ausgabe. Den aktuellen Modus speichern wir in der Session. Danach binden wir den CKEditor ein und schreiben die Konfiguration. Wir starten für jeden mit contenteditable=”true” markierten Block eine Instanz des Editors.

Problem:

Das Plugin Widget musste ich deaktivieren und somit auch das davon abhängige Plugin Image2. Es sollte jedoch möglich sein diese zu nutzen, wahrscheindlich müsste man den Editor aber anders einbinden, so wie hier zu sehen http://cksource.com/temp/widget/samples/plugins/widget/widget.html

Das REDAXO Modul

Um das Editieren im Frontend zu ermöglichen müssen wir die Modulausgaben entsprechend bearbeiten.

Beispiel Modul-Ausgabe:

<?php

$attributes = '';
if ($_SESSION['CKE_EDIT'] === true && $REX['LOGIN']->login_status === 1)
    $attributes = ' contenteditable="true" id="REX_SLICE_ID_1"'; // _1 = value1

?>
<section<?php echo $attributes; ?>>
    REX_VALUE[2]
</section>

Zuerst prüfen wir ob der Editiermodus aktiviert wurde. Wenn ja dann geben wir die nötigen Attribute aus. Das Attribut ID enthält die Slice-Id gefolgt von einem Unterstrich und einer 1 die für “value1” steht.

Im Template wird damit erkannt, dass der Block editierbar ist und kann anhand der ID später dem entsprechenden Slice zugeordnet werden.

Das CKEditor Plugin

Um das Speichern der Blöcke zu ermöglichen benötigen wir noch ein Plugin welches uns diese Funktion im Editor bereitstellt. Daher das Plugin InlineSave und Inline Cancel downloaden. Die Einbindung erfolgt im Template (Pfade anpassen).

Danach die plugin.js von Inline Save öffnen und folgenden Inhalt einfügen.

Beispiel plugin.js

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

        editor.addCommand('inlinesave', {
            exec: function(editor) {

                addData();

                function addData() {

                    var data = editor.getData();

                    var contend_id = editor.name;

                    jQuery.ajax({
                        type: "POST",
                        /* url zur Seite wo das php-script liegt */
                        url: "/pages/ckedump.php",
                        data: {
                            html: data, // enthält den Inhalt des Editors
                            id: contend_id // enthält Slice-ID und Value-Nummer
                        }

                    }).done(function(data, textStatus, jqXHR) {

                        alert("Erfolgreich gespeichert! " + jqXHR.responseText);

                    }).fail(function(jqXHR, textStatus, errorThrown) {

                        alert("ACHTUNG! - Fehler beim speichern! " + jqXHR.responseText);
                    });
                }
            }
        });

        editor.ui.addButton('Inlinesave', {
            label: 'Save',
            command: 'inlinesave',
            icon: this.path + 'images/inlinesave.png'
        });
    }
});

Hiermit empfangen wir die Daten des Editors um sie mittels ajax zu speichern. Der Pfad zur Seite mit dem PHP-Script muss angepasst werden.

Der PHP teil

Dazu irgendwo in Redaxo einen offline-Artikel erstellen und nachfolgenden Code einfügen. Geht in einem Modul, Template oder direkt im Artikel.

<?php

$html = rex_request('html', 'string');
$content_id = rex_request('id', 'string');

$ids = explode("_", $content_id);
$slice_id = intval($ids[0]);
$value_id = $ids[1];

if ($REX['LOGIN']->login_status === 1 && $_SESSION['CKE_EDIT'] === true && $html !== '' && $value_id !== '' && $slice_id !== 0) {
    //wenn im Backend angemeldet, frontend-edit an ist und daten gesendet werden

    $sql = rex_sql::factory();
    //$sql->debugsql = 1; 
    $sql->setTable($REX['TABLE_PREFIX'] . 'article_slice');
    $sql->setWhere('id = ' . $slice_id);
    $sql->setValue('value' . $value_id, $html);

    if ($sql->update()) {
        echo 'Value'.$value_id.' von Slice mit der ID ' . $slice_id . ' erfolgreich aktuallisiert.';
        rex_generateAll(); //redaxo cache erneuern - sollte besser gelöst werden
    } else {
        echo '<b>Speichern fehlgeschlagen</b> - ';
    }
} else {
    echo '<b>Speichern nicht möglich</b>';
}

?>

Darin empfangen wir die Daten welche das Plugin übermittelte und speichern diese direkt in die Datenbank.

Achtung

Das Ganze ist experimentell in REDAXO, daher bitte mit Vorsicht einsetzen. Ausserdem müssen noch die Probleme mit der Kompatibilität der Widgets beseitigt werden.

Zu beachten ist noch, dass bei diesem Vorgehen das Container-Element im Modul stehen muss und nur das REX_VALUE vom Editor beinhalten darf. Alles andere würde dann bei jedem speichern erneut hinzugefügt werden.

Veröffentlicht inLösungenProjekte

Neueste Beiträge

Themen: