mform icon indicating copy to clipboard operation
mform copied to clipboard

MForm8 Repeater textarea mit anderen WYSIWYG Editoren

Open anveno opened this issue 1 year ago • 28 comments

Description / Beschreibung

wenn ich dem addTextAreaField die Klasse "redactor-editor--..." hinzufügen, damit der Redactor Editor gerendert wird, werden die Werte nicht gespeichert und bestehende Einträge nicht angezeigt. Lasse ich die Klasse weg und nutze nur die "pure" Textarea, klappt alles wie gewohnt.

<?php
use FriendsOfRedaxo\MForm;
// init mform
$mform = MForm::factory()
    // text input element
    ->addTextField(1, ['label' => 'test rex value 1'])

    // repeater wrapper element level 1
    ->addRepeaterElement(2, MForm::factory()
        // set fieldset
        ->addFieldsetArea('fieldset1', MForm::factory()
            // text input element
            ->addTextField('text1', ['label' => 'Text 1'])
            ->addTextAreaField('textarea', array('label' => 'Text', 'class' => 'redactor-editor--small'))
            // add second fieldset area
            ->addFieldsetArea('fieldset2', MForm::factory()
                // radio element
                ->addRadioField('radio1', [1 => 'test-1', 2 => 'test-2'], ['label' => 'Radio 1'])
            )
        ) , true, true, ['default_count' => 3]
    );

echo $mform->show();
?>

Affected versions / Verwendete Versionen

MForm 8.0.0 redactor 2.4.2

anveno avatar May 22 '24 14:05 anveno

Wirst wahrscheinlich auf den cke5 wechseln müssen. Redactor müsste wohl angepasst werden. Ob der Tiny geht, kann ich auch noch nicht sagen.

skerbis avatar May 22 '24 14:05 skerbis

Aktuell wird CKE5 direkt im JS vom Repeater supported. Das war von mir ja so eigentlich nur ein Workaround, ich möchte das dahingehend ändern, dass der Repeater ein Event wirft auf das die Editoren zu reagieren haben auch der CKE5. Es ist einfach zu aufwändig alle Editoren zu Supporten, besser ist es wenn die Editoren den Repeater Supporten.

joachimdoerr avatar May 23 '24 19:05 joachimdoerr

Für redactor würde ich das Event integrieren, sobald möglich. Einfach Bescheid geben, wenn es implementiert ist.

AWqxKAWERbXo avatar May 25 '24 07:05 AWqxKAWERbXo

Mit Redactor in diesem Zusammenhang habe ich auch schon Erfahrung gesammelt. Das Problem das ich damals hatte war, das das Model nicht aktualisiert wurde, das wird an der Stelle allerdings benötigt. Ein Event muss von Redactor kommen, eher nicht vom Repeater. Beispiel:

$(document).on('rex:ready',function(event, container) {
    console.log('READY');
    $(container).find('[class*="redactor-editor--"]').each(function() {
        let classNames = $(this).attr('class').split(' ');
        for (let i = 0; i < classNames.length; i++) {
            let $profile = classNames[i].substring('redactor-editor--'.length);
            if ($profile !== '' && redactor_profiles[$profile]) {
                let options = redactor_profiles[$profile];
                options.lang = redactorLang;

                options['callbacks'] = {
                    'blur': (e) => {
                        console.log('BLUR');
                        $(document).trigger('redactor:change', [event]);
                    },
                };

                if (!('pasteImages' in options)) {
                    options.pasteImages = false;
                }
                $R('.redactor-editor--' + $profile, options);
            }
        }
    })
});

So könnte man z.B. auf den Blur hören und dann im Repeater updateValues triggern. Das wäre dann natürlich gebunden an Redactor. Vielleicht kann man das Event einfach mform:update oder so nennen.

EDIT: Hier mein Code zum beschriebenen: https://github.com/FriendsOfREDAXO/yform_flexible_content/blob/master/resources/js/textarea.js#L33-L46

eaCe avatar May 30 '24 06:05 eaCe

Tiny funzt übrigens auch nicht, gleiches Resultat wie bei Redactor, die Werte werden nicht gespeichert.

Die Idee mit dem Event finde ich gut, dann können die anderen Editoren reagieren wie sie möchten/können.

ynamite avatar May 30 '24 13:05 ynamite

Nutzt jemand zwischenzeitlich einen funktionierenden (temporären) Workaround für den Redactor 2 Editor?

shauste avatar Jul 16 '24 13:07 shauste

Ich nicht. redactor2 oder redactor (Version 3, aktuelle Version)?

AWqxKAWERbXo avatar Jul 16 '24 14:07 AWqxKAWERbXo

Das redactor2 Addon wird nicht mehr supported oder weiterentwickelt und ist archiviert. Hier wird nichts passieren.

skerbis avatar Jul 16 '24 19:07 skerbis

Und mit redactor (3)?

AWqxKAWERbXo avatar Jul 16 '24 19:07 AWqxKAWERbXo

Wie ich oben beschrieben habe, glaube ich das wir ein Event vom Editor brauchen. Ich werde mir das spätestens nächste Woche noch einmal ansehen

eaCe avatar Jul 16 '24 19:07 eaCe

Vielleicht habe ich eine, wenn auch eher unschöne, Möglichkeit gefunden. Werde es heute Abend mal genauer testen

eaCe avatar Jul 28 '24 05:07 eaCe

Leider funktioniert meine Idee nicht zuverlässig. Ich befürchte es muss in den Editoren angepasst werden.

eaCe avatar Jul 28 '24 17:07 eaCe

Aber was und wie? @eaCe

AWqxKAWERbXo avatar Jul 28 '24 18:07 AWqxKAWERbXo

Der Repeater müsste 3 Events werfen können mform:repeater:init, mform:repeater:prechange und mform:repeater:change

joachimdoerr avatar Jul 31 '24 14:07 joachimdoerr

fyi: Nutze derzeit einen Workaround mit setTimeout, um Redactor im Repeater funktional zu haben. Unschön, aber klappt.

$(document).on('rex:ready',function(event, container) {
    setTimeout(function() {
    $(container).find('[class*="redactor-editor--"]').each(function() {
        let classNames = $(this).attr('class').split(' ');
        for (let i = 0; i < classNames.length; i++) {
            let $profile = classNames[i].substring('redactor-editor--'.length);
            if ($profile !== '' && redactor_profiles[$profile]) {
                let options = redactor_profiles[$profile];
                options.lang = redactorLang;
                if (!('pasteImages' in options)) {
                    options.pasteImages = false;
                }
                $R('.redactor-editor--' + $profile, options);
            }
        }
    })
    }, 25);
});

shauste avatar Aug 13 '24 08:08 shauste

fyi: Nutze derzeit einen Workaround mit setTimeout, um Redactor im Repeater funktional zu haben. Unschön, aber klappt.

$(document).on('rex:ready',function(event, container) {
    setTimeout(function() {
    $(container).find('[class*="redactor-editor--"]').each(function() {
        let classNames = $(this).attr('class').split(' ');
        for (let i = 0; i < classNames.length; i++) {
            let $profile = classNames[i].substring('redactor-editor--'.length);
            if ($profile !== '' && redactor_profiles[$profile]) {
                let options = redactor_profiles[$profile];
                options.lang = redactorLang;
                if (!('pasteImages' in options)) {
                    options.pasteImages = false;
                }
                $R('.redactor-editor--' + $profile, options);
            }
        }
    })
    }, 25);
});

Das greift leider doch nicht, Werte werden am Ende nicht gespeichert.

shauste avatar Aug 13 '24 14:08 shauste

Ich habe das nicht vergessen und probiere immer wieder neue Methoden aus. Bisher noch ohne Erfolg. Das Problem ist meist beidseitig. Es braucht etwas vom Editor und vom repeater. Am Wochenende werde ich mich wieder intensiver damit auseinandersetzen.

eaCe avatar Aug 16 '24 05:08 eaCe

@eaCe aber das wäre doch kein Problem, man kann doch sowohl in mform als auch in den Editor-Addons dafür die Voraussetzungen schaffen, oder nicht?

Wenn's um ein konzeptionelles Problem geht: m.E. müsste man vor dem verschieben den Editor destroyen und danach wieder initialisieren. D.h. mit 2 Events in mform wäre es dort getan - die jeweiligen Addons könnten dann darauf mit einem Event-Listener reagieren.

AWqxKAWERbXo avatar Aug 16 '24 07:08 AWqxKAWERbXo

Ich habe das nicht vergessen und probiere immer wieder neue Methoden aus. Bisher noch ohne Erfolg. Das Problem ist meist beidseitig. Es braucht etwas vom Editor und vom repeater. Am Wochenende werde ich mich wieder intensiver damit auseinandersetzen.

Gibt es hierzu ein Update?

shauste avatar Aug 22 '24 06:08 shauste

Leider noch nicht. Die Woche komme ich auch nicht dazu. Es gibt weitere Ansätze

eaCe avatar Aug 25 '24 14:08 eaCe

Wäre es eine einfachere Lösung, wenn die Texteditoren als Web-Component ausgeliefert würden? Dann müsste doch eigentlich nur der Tag des Editors repeatet werden und nicht destroyed oder so?

skerbis avatar Sep 01 '24 09:09 skerbis

Ich habe dasselbe Problem (mit TINY). Zudem sind auch Textfelder ohne Rich-Text-Editor sobald ein Apostroph (') im Text vorkommt fehleranfällig. 👉 Ganze Inhalte sind beim erneuten bearbeiten vom Block verschwunden.

caesarvoelkin avatar Sep 13 '24 05:09 caesarvoelkin

Danke für den Hinweis. Jeder Editor macht Probleme. Außer CKE. Das normale Zeichen Probleme bereiten sollte nicht sein. Eventuell komme ich am Sonntag dazu.

eaCe avatar Sep 13 '24 05:09 eaCe

Push... Nutze oft den TinyMCE, deswegen kann ich den Repeater mit der 8er nicht nutzen :(

godsdog avatar Sep 26 '24 09:09 godsdog

Ich glaube für den Tiny habe ich ein etwas unschönen, aber scheinbar funktionierenden workaround gefunden. Werde das noch mal überarbeiten und am Donnerstag zum Testen posten. Vorher komme ich nicht dazu.

eaCe avatar Sep 30 '24 05:09 eaCe

Ich habe leider mal wieder keine gute Nachricht. Meine neue Idee funktioniert auch nicht. Aber ich habe mich weiter mit tiny beschäftigt und herausgefunden das es einen inline Modus gibt. Für diesen braucht es aber eine div und keine textarea. Darauf kann man, glaube ich, aber nicht mit alpine horchen. Wyiwyg und dynamische Felder sind die Pest. Ich befürchte aktuell das wir eigene Felder für die Editoren benötigen. Redactor habe ich nicht weiter getestet, aber der scheitert schon beim initialisieren. Ich probiere weiter rum, werde anfangen den repeater umzubauen und bitte um Geduld

eaCe avatar Oct 03 '24 10:10 eaCe

@eaCe es stellt sich ernsthaft die Frage ob der aufwand lohnt, mit CKE5 haben wir ein Editor der im Repeater funktioniert, es wäre durch aus sinnvoll lieber alle bestehenden CKE5 Probleme anzugehen statt weiter Zeit an Redactor und Tiny zu verlieren.

joachimdoerr avatar Oct 08 '24 06:10 joachimdoerr

@eaCe ich denke, ich habe die Ursachen und einen möglichen Lösungsweg gefunden.

1. Redactor wird zu früh initialisiert (vor Repeater)

Das Problem lässt sich in Redactor bspw. mit einem Timeout umgehen. Danach ist der Editor korrekt geladen mit bestehenden Werten.

2. Es wird sehr oft rex:ready gefeuert.

Man kann mit stop() die Instanz des Editors vorzeitig zerstören.

3. Repeater bekommt die Änderungen an der Textarea nicht mit.

Sobald ich redactor via stop() zerstöre, habe ich reguläre Textfelder.

Wenn ich dann die Verschiebung von Repeater ausführe (ein Form nach unten / oben), sind die Werte komplett weg.

Sobald ich in die Textarea reingehe und ein Leerzeichen hinzufüge, oder stop() ausführe und reguläre Textfelder habe, funktioniert das Verschieben wieder und sogar das Speichern der Werte.

Lösungsansatz

Es muss einen Mechanismus vor Aktionen wie dem Verschieben der Inhalte oder vor Speichern die Werte aus den Eingabefeldern aktualisiert. Ich vermute mal, AlpineJS speichert die zwischen oder so.

Fazit

Die Instanzen von Redactor, TinyMCE, ... erst zu zerstören, ermöglicht, die realen Werte zu sehen und zu nutzen, und störungsfrei die Aktion auszuführen. Anschließend muss ein 2. Event dafür sorgen, dass die Editoren wieder reinitialisiert werden.

Proof of Concept für die korrekte Initialisierung bei Redactor (assets/addons/redactor/redactor.js)

$(document).on('rex:ready', function (event, container) {

    setTimeout(function () {
        
        $(container).find('[class*="redactor-editor--"]').each(function () {
            let classNames = $(this).attr('class').split(' ');
            for (let i = 0; i < classNames.length; i++) {
                let $profile = classNames[i].substring('redactor-editor--'.length);
                if ($profile !== '' && redactor_profiles[$profile]) {
                    let options = redactor_profiles[$profile];
                    options.lang = redactorLang;
                    if (!('pasteImages' in options)) {
                        options.pasteImages = false;

                        options.callbacks = options.callbacks || {};
                        options.callbacks.changed = function (e) {
                            var sourceElement = this.source.getElement().get(0);
                            if (sourceElement) {
                                $(sourceElement).val($(sourceElement).val() + ' ');
                                
                            }
                        };

                    }
                    $('.redactor-editor--' + $profile).redactor().stop();
                    $('.redactor-editor--' + $profile).redactor().start(options);
                }
            }
        });

    }, 500); // 500ms Verzögerung
});

AWqxKAWERbXo avatar Dec 15 '24 17:12 AWqxKAWERbXo