2017-10-27 4 views
0

In CKEditor5 habe ich versucht, ein benutzerdefiniertes Element zu implementieren, um ein Modell zur Bearbeitung zu konvertieren. Dann wird das editierbare Element (@ ckeditor/ckeditor5-engine/src/view/editableelement) im Containerelement (@ ckeditor/ckeditor5-engine/src/view/containerelement) auf das übergeordnete Containerelement fokussiert und kann nicht bearbeitet werden.Kann nicht in EditableElement von CKEditor5 eingegeben werden

Zum Beispiel, wenn es durchgeführt wird wie folgt:

buildModelConverter().for(editing.modelToView) 
      .fromElement('myElement') 
      .toElement(new ContainerElement('div', {}, [new EditableElement('h4')])); 

Das Ergebnis des tatsächlichen Bearbeitung nach dom 'myElement' und keydown "abc" eingefügt wird. (Ich hoffe, die Texteingabe von "abc" zu h4 Tag aber ...)

<div>​​​​​​​ 
    abc 
    <h4> 
    <br data-cke-filler="true"> 
    </h4> 
</div> 

Ich habe auch versucht Widget mit für contenteditable Attribut angewandt wird. Text konnte jedoch nicht in h4 eingegeben werden.

<div class="ck-widget" contenteditable="false">​​​​​​​ 
    <h4 class="ck-editable" contenteditable="true"> 
    <br data-cke-filler="true"> 
    </h4> 
</div> 

Ist dieser Fehler, oder ich Fehler beim Verständnis des Containerelements gemacht?

[weitere Details]

Ich gehe davon aus einem Widget Plugin für die Rangliste zu machen.

Erstens ist die Rangliste durch <ol> und <li> Tags strukturiert, weil mehrere Elemente haben. Ich löste das, indem ich zwei Schemas wie "rankingList" und "rankingListItem", definierte, also realisierte ich dynamische Elemente, die verschachtelte Modellelemente verwenden.

const item1 = new ModelElement('rankingListItem'); 
const item2 = new ModelElement('rankingListItem'); 
const model = new ModelElement('rankingList', {}, [item1, item2]); 
// and insert 

Als nächstes hat das Element der Rangliste Link, Bild, Titel und Notiz. Daher hat die Ranglistenposition die folgenden DOM-Struktur:

<ol><!-- apply toWidget --> 
    <li> 
    <a href="link[editable]"> 
     <img src="image[editable]"> 
     <h3>title[editable]</h3> 
     <p>notes[editable]</p> 
    </a> 
    </li> 
    ... 
</ol> 

Ich erwarte, dass das View-Element ist die folgende:

const {ref, src, title, notes} = data; // how to get data? 
const view = new ContainerElement('a', {ref}, [ 
    new EmptyElement('img', {src}), 
    new EditableElement('h3', {}, new Text(title)), 
    new EditableElement('p', {}, new Text(title)), 
    ]); 
// maybe incorrect ... 

Abschließend möchte ich nicht editierbare Ansicht verwenden definiert DOM zu brechen Baum. Wie kann ich es realisieren?

+1

Hallo! Bevor ich Ihnen antworten kann, geben Sie mir bitte mehr Details darüber, was Sie erreichen möchten. 'Die Rolle von EditableElement erstellt verschachtelte editierbare Elemente, wie die Beschriftung in der Bildfunktion. Der Anwendungsfall hierfür ist, wenn ein Teil des DOM-Unterbaums nicht bearbeitet werden kann (wie das Bild selbst in der Bildfunktion), aber ein Bereich innerhalb (Bildunterschrift) sein sollte. Das zweite HTML-Beispiel ist also viel näher am Anwendungsfall für 'EditableElement'. Wenn Sie nur ein 'h4' Element wünschen, das mit' div' umhüllt ist, sollten Sie nur ein anderes 'ContainerElement' verwenden. Lass es mich wissen und dann gebe ich dir eine ausführliche Antwort. –

+0

Vielen Dank für Ihre schnelle Antwort. Ich habe die Details zum Frageteil hinzugefügt, bitte bestätigen. – inoutch

Antwort

5

Vielen Dank für die Beschreibung Ihres Falles. Für uns bedeutet es im Moment sehr viel zu wissen, wie Entwickler den Editor einsetzen und welche Erwartungen Sie haben.

Leider sieht dies wie eine sehr komplexe Funktion aus. Es sieht auch so aus, als würde es eine benutzerdefinierte UI benötigen (um link url und image src zu bearbeiten - es sei denn, sie ändern sich nicht, nachdem sie dem Editor hinzugefügt wurden). Es scheint, dass man mit zwei Problemen zu kämpfen:

  • Positionszuordnung zwischen dem Modell und der Ansicht,
  • verschachtelte editables.

Zuerst Ihre Frage zu EditableElement beantworten - es scheint sie für h3 und p Elemente als richtig zu verwenden.

Diese komplexe Funktion benötigt jedoch benutzerdefinierte Konverter.Converter-Builder (die Sie verwendet haben) sind dafür vorgesehen, in einfachen Fällen verwendet zu werden, z. B. Element-zu-Element-Konvertierung oder Attribut-zu-Attribut-Konvertierung.

Hinter der netten API, Build Converter ist eine Funktionsfabrik, die eine oder mehrere Funktionen erstellt. Diese werden dann als Rückrufe zu ModelConversionDispatcher hinzugefügt (was editor.editing.modelToView ist eine Instanz von). ModelConversionDispatcher löst während der Konvertierung eine Reihe von Ereignissen aus. Dabei wird eine Änderung des Modells in die Ansicht übersetzt.

Wie ich bereits erwähnt habe, müssten Sie diese Konvertierungsfunktionen selbst schreiben.

Da dies ein zu großes Thema für eine detaillierte und gründliche Antwort ist, werde ich Ihnen kurz vorstellen, woran Sie interessiert sein sollten. Leider gibt es noch keine Anleitungen zum Erstellen von benutzerdefinierten Konvertern von Grund auf neu. Das ist ein sehr weites Thema.

Zunächst möchte ich Ihnen erklären, woher die meisten Ihrer Probleme kommen. Wie Sie bereits wissen, hat der Editor drei Ebenen: Modell (Daten), Ansicht (DOM-ähnliche Struktur) und DOM. Das Modell wird in Ansicht konvertiert und die Ansicht wird in DOM gerendert. Umgekehrt wird beim Laden von Daten DOM in View konvertiert und View in Model konvertiert. Aus diesem Grund müssen Sie Modell-zu-Bild-Konverter und Modell-zu-Modell-Konverter für Ihre Funktion bereitstellen.

Das wichtige Teil dieses Puzzles ist engine.conversion.Mapper. Seine Aufgabe besteht darin, Elemente und Positionen von Modell zu Modell abzubilden. Wie Sie vielleicht schon gesehen haben, könnte das Modell ganz anders aussehen als die Ansicht. Korrekte Position Mapping zwischen diesen ist der Schlüssel. Wenn Sie einen Buchstaben an der Einfügemarke (in DOM) eingeben, wird diese Position dem Modell zugeordnet, und der Buchstabe wird in das Modell eingefügt und erst dann wieder in die Ansicht und das DOM konvertiert. Wenn die Konvertierung von Ansicht zu Modellposition falsch ist, können Sie an dieser Stelle nicht tippen oder wirklich nichts tun.

ist ziemlich einfach für sich. Sie müssen nur angeben, welche Ansichtselemente an welche Modellelemente gebunden sind. Zum Beispiel in dem Modell könnten Sie haben:

<listItem type="bulleted" indent="0">Foo</listItem> 
<listItem type="bulleted" indent="1">Bar</listItem> 

Während in der Ansicht haben Sie:

<ul> 
    <li> 
    Foo 
    <ul> 
     <li>Bar</li> 
    </ul> 
    </li> 
</ul> 

Wenn der Mapper weiß, dass erste listItem gebunden ist, mit ersten <li> und die zweiten listItem gebunden ist, mit Sekunde <li>, dann ist es in der Lage, Positionen richtig zu übersetzen.

Zurück zu Ihrem Fall. Jeder Konverter muss Daten für bereitstellen. Da Sie Converter Builder verwendet haben, machen die von ihm erstellten Konverter dies bereits. Aber sie sind einfach, so, wenn Sie bieten:

buildModelConverter().for(editing.modelToView) 
     .fromElement('myElement') 
     .toElement(new ContainerElement('div', {}, [new EditableElement('h4')])); 

es wird davon ausgegangen, dass myElement mit dem <div> gebunden ist. Also alles, was innerhalb dieser <div> geschrieben wird direkt auf myElement gehen und wird dann zu Beginn des myElement gemacht werden:

<div> 
    <h4></h4> 
</div> 

Unter der Annahme, dass Sie schrieb nur x an <h4>, wird diese Position myElement versetzt abgebildet werden 0 in das Modell und dann gerendert, um am Anfang von <div> anzuzeigen.

Modell:

<myElement>x</myElement> 

Ausblick:

<div>x<h4></h4></div> 

Wie Sie sehen können, in Ihrem Fall ist es <h4>, die mit myElement gebunden werden soll.

Momentan sind wir in der Refactoring-Phase. Eines der Ziele ist die Bereitstellung von Utility-Funktionen für Konverter-Builder. Eine dieser Utilities sind Konverter für Elemente, die ein Wrapper-Element haben, wie in dem obigen "div + h4" -Fall. Dies ist auch ein Fall von Bildmerkmalen. Das Bild wird durch <image> im Modell dargestellt, aber es ist <figure><img /></figure> in der Ansicht. Sie können unter ckeditor5-image sehen, wie diese Konverter jetzt aussehen. Wir wollen sie vereinfachen.

Leider ist Ihr echter Fall noch komplizierter, weil Sie mehrere Elemente darin haben. CKE5-Architektur sollte in der Lage sein, Ihren Fall zu behandeln, aber Sie müssen verstehen, dass es fast unmöglich ist, ohne geeignete Anleitungen zu schreiben.

Wenn Sie aber basteln möchten, sollten Sie Studieckeditor5-image Repo. Es wird nicht einfach sein, aber das ist der beste Weg. Image Plugin zusammen mit ImageCaption sind sehr ähnlich zu Ihrem Fall.

Modell:

<image alt="x" src="y"> 
    <caption>Foo</caption> 
</image> 

Ausblick:

<figure class="image"> 
    <img alt="x" src="y" /> 
    <figcaption>Foo</caption> 
</figure> 

Während in Ihrem Fall, ich das Modell irgendwo zwischen diesen Zeilen sehen würde:

<rankItem imageSrc="x" linkUrl="y"> 
    <rankTitle>Foo</rankTitle> 
    <rankNotes>Bar</rankNotes> 
</rankItem> 

Und ich würde machen die Ansicht etwas schwerer, aber es wird einfacher sein, Konverter zu schreiben:

<li contenteditable="false"> 
    <a href="y"> 
    <img src="x" /> 
    <span class="data"> 
     <span class="title" contenteditable="true">Foo</span> 
     <span class="notes" contenteditable="true">Bar</span> 
    </span> 
    </a> 
</li> 

Für rankTitle und rankNotes - Basis sie auf caption Element (ckeditor5-image/src/imagecaption/imagecaptionengine.js).

Für rankItem - Basis es auf image Element (ckeditor5-image/src/image/).

Noch einmal - bedenken Sie, dass wir dabei sind, all dies zu vereinfachen. Wir wollen, dass die Leute ihre eigenen Features schreiben, sogar die komplizierten wie deine. Uns ist jedoch bewusst, wie komplex es gerade ist. Aus diesem Grund gibt es im Moment keine Dokumente - wir wollen die Dinge ändern und vereinfachen.

Und schließlich - man könnte schaffen, dass Rangliste einfacher, mit Link Plugin und Elemente bauen mit Konverter Bauer:

  • rankList -><ol class="rank">,
  • rankItem -><li>,
  • rankImage -><img />,
  • rankNotes -><span class="notes">,
  • rankTitle -><span class="title">.

Es wird jedoch möglich sein, es zu vermasseln, weil die gesamte Struktur bearbeitbar sein wird.

Modell:

<rankList> 
    <rankItem> 
    <rankImage linkHref="" /> 
    <rankTitle>Foo</rankTitle> 
    <rankNotes>Bar</rankNotes> 
    </rankItem> 
    ... 
</rankList> 

Wo "Foo" und "Bar" auch linkHref Attribut gesetzt haben.

Ausblick:

<ol class="rank"> 
    <li> 
    <a href=""><img src="" /></a> 
    <span class="title"><a href="">Title</a></span> 
    <span class="notes"><a href="">Foo</a></span> 
    </li> 
    ... 
</ol> 

Etwas ähnliches, während bei weitem nicht perfekt, sollte viel einfacher sein, so lange zu schreiben, wie wir vor dem Refactoring sind und vor dem Schreiben Führer.

Natürlich müssen Sie auch View-to-Model-Konverter bereitstellen. Vielleicht möchten Sie sie selbst schreiben (werfen Sie einen Blick auf ckeditor5-list/src/converters.jsviewModelConverter() - obwohl Ihre einfacher wird, weil es flach sein wird, nicht verschachtelte Liste). Oder Sie können sie über den Converter Builder generieren.

Vielleicht wird es möglich sein, den obigen Ansatz (einfacher) zu verwenden, aber contentEditable Attribut verwenden, um die Struktur zu steuern. rankList müsste mit contentEditable="false" in <ol> konvertiert werden. Vielleicht könnten Sie beispielsweise toWidget für eine bessere Auswahlbehandlung verwenden. rankNotes und rankTitle müssten mit contentEditable="true" in Element konvertiert werden (vielleicht toWidgetEditable()).

+0

Vielen Dank für Ihre ausführlichen Antworten und Hinweise zur Implementierung. Es war sehr einfach zu verstehen, und was ich will. Ich werde versuchen, benutzerdefinierte Widget durch Modellierung eines nach dem anderen zu implementieren. – inoutch

Verwandte Themen