ckeditor / ckeditor5

Powerful rich text editor framework with a modular architecture, modern integrations, and features like collaborative editing.
https://ckeditor.com/ckeditor-5
Other
8.71k stars 3.63k forks source link

What are the differences between Groups of Dispatchers? #5748

Closed loagit closed 4 years ago

loagit commented 4 years ago

Hi. I am trying to properly understand how the conversion process between the CKEditor 5 MVC architecture layers happens. In particular, it is a little difficult to know exactly the differences between One-Way Converters and Two-Way Converters.

By reading more about the Editing Engine, you can understand that there are two tree data structures present in CKEditor 5. One represents the "master" data, referred to as Model. This type of structure is organized in a special way (unlike the standard DOM structure) to allow its manipulation to be easier, more viable.

There are two “pipelines”: the editing pipeline (also called the “editing view”) and the data pipeline (the “data view”). Treat them as two separate views of one model. The editing pipeline renders and handles the DOM that the user sees and can edit. The data pipeline is used when you call editor.getData(), editor.setData() or paste content into the editor.

Source

The other tree structure represents the content present in the CKEditor 5 editor, and closely resembles (is) much the familiar DOM. It is in the view layer, and can be called Editing View.

Still according to the documentation (and here I start to get a little lost, probably), there is a third model called Data View. I imagine there is no such model, but a way to represent the data structure present in Editing View as HTML, Markdown, JSON, and so on, and vice versa.

I know that when we are creating new elements for the editor (a custom plugin, for example), we need to perform an upcasting and downcasting process between Model and Editing View. As I understand it, this must be done through the Conversion utility class. In the documentation, two approaches are presented for performing conversions:

Using Two-Way Converters, the conversion process between Model and Editing View is quite simple. With One-Way Converters, on the other hand, it is defined that the conversion must happen through the use of something called Groups of Dispatcher, which can be:

The for method documentation demonstrates the use of only two of the Groups of Dispatcher, and only feature the upcast and downcast process.

That's exactly where I start to get confused, and I know the problem is that I just still don't fully understand how the thing works. What are the differences between Groups of Dispatchers? I say, clearly, simply and practically. In the documentation it is said that they represent conversion directions. Shouldn't there be a conversion only between upcast and downcast? What does dataDowncast mean? And editingDowncast?

I believe upcast is from Editing View to Model, and editingDowncast is from Model to Editing View, the editor's content. dataDowncast... What?

For example, why are 3 converters declared for each of the 3 elements in Implementing a block widget:

...
// <simpleBox> converters
conversion.for( 'upcast' ).elementToElement( {
     model: 'simpleBox',
     view: {
         name: 'section',
         classes: 'simple-box'
     }
} );
conversion.for( 'dataDowncast' ).elementToElement( {
     model: 'simpleBox',
     view: {
         name: 'section',
         classes: 'simple-box'
    }
} );
conversion.for( 'editingDowncast' ).elementToElement( {
     model: 'simpleBox',
     view: ( modelElement, viewWriter ) => {
         const section = viewWriter.createContainerElement( 'section', { class: 'simple-box' } );
         return toWidget( section, viewWriter, { label: 'simple box widget' } );
     }
} );
...

Where is the downcast process? Are there two? Something similar can be seen on Implementing a inline widget.

If this kind of information is present somewhere, I apologize, I probably haven't found it yet, I'm new to CKEditor 5. Can anyone help me to better understand all this, please? :(

jodator commented 4 years ago

Hey, @loagit - thanks for that detailed explanation of why our docs are confusing to you. We know that the conversion process is probably the hardest to understand (and to explain) in the CKEditor 5 architecture. We know that writing converters are very tricky and that we need to update the docs.

Below are my thoughts on those things, so if you ask somebody else from the team you might get slightly different answer ;)

From my perspective you can think about that whole process as below:

  1. The Model represents the content in a way that is easier to process, implement collaboration features, etc. It also detaches the structure of the document from the DOM/HTML. All the changes in the document are done on the Model.

  2. The View is the part that is used to present the Model and is also used to interact with it.

  3. The EditingView is used in the editing area of the editor. It is used to render the model to the view (during the editingDowncast) and to reflect user interaction with the content (inside the DOM contenteditable area) back to the model.

  4. The DataView is used when you set (most commonly editor.setData( '<p>foo</p>' ) ) or get data from the editor (ie, when editor.getData() to store the editor content in a DB).

  5. The conversion process happens when you transform Model representation to the View or vice versa. Taking the above you can have:

    5a. The upcast conversion which happens when you transform your data (View) (ie HTML but can be XML if using different data processor) to Model structure

    5b. The editingDowncast conversion is done to represent Model structure in the editingView

    5c. The dataDonwcast conversion happens when you want to take the Model structure for your application (most commonly you want to get HTML but you can also want Markdown)

    5d. If your feature content (Model) is represented the same way in the data (the content used in your application) and in the editing area you don't have to define separate conversion utilities for them and you can use downcast alias for both.

  6. Two-way vs One-way: One way is either Model to View or View to Model while Two way is a single definition used for both Model to View and View to Model (mostly used for straight forward representations):

    // Two-way converter:
    conversion.elementToElement( { model: 'paragraph', view: 'p' } );
    
    // is the same as:
    conversion.for( 'downcast' ).elementToElement( { model: 'paragraph', view: 'p' } );
    conversion.for( 'upcast' ).elementToElement( { model: 'paragraph', view: 'p' } );
    
    // and is also the same as:
    conversion.for( 'editingDowncast' ).elementToElement( { model: 'paragraph', view: 'p' } );
    conversion.for( 'dataDowncast' ).elementToElement( { model: 'paragraph', view: 'p' } );
    conversion.for( 'upcast' ).elementToElement( { model: 'paragraph', view: 'p' } );
  7. Why there's different editingDowncast and dataDowncast - because we know from previous projects that you might need to represent some editing feature (like Widget) a bit different in the editing area - where the user interacts it while creating the content - and a bit different in the data you get from the editor. Most commonly we add some additional markup for widgets in the editing area used to style the wiget (all these fancy borders) which aren't need in the data you get from the editor.

@loagit As a bottom line - I'm curious if those remarks are helpful? Do you have a better/worse understanding of what happens there? Can you write how do you see those aspects? Also, did you see various conversion examples?

I'm asking because maybe we could learn something to improve the docs and help others better understand the whole idea behind it.

loagit commented 4 years ago

Hi @jodator. Glad to see you!

[...] We know that the conversion process is probably the hardest to understand (and to explain) in the CKEditor 5 architecture. We know that writing converters are very tricky and that we need to update the docs.

[...] @loagit As a bottom line - I'm curious if those remarks are helpful? Do you have a better/worse understanding of what happens there? Can you write how do you see those aspects? Also, did you see various conversion examples?

I'm asking because maybe we could learn something to improve the docs and help others better understand the whole idea behind it.

I have already posted some issues here, and I am very happy again to see how you guys seek to give support. But not only that. I am also happy to see how open-minded you are, and willing to improve. The name of this is entrepreneurship. Keep up the good work. :)

Regarding of what was pointed out, I would like to comment on them here, ok?

  1. The Model represents the content in a way that is easier to process, implement collaboration features, etc. It also detaches the structure of the document from the DOM/HTML. All the changes in the document are done on the Model.

  2. The View is the part that is used to present the Model and is also used to interact with it.

That was pretty much what I understood too.

  1. The EditingView is used in the editing area of the editor. It is used to render the model to the view (during the editingDowncast) and to reflect user interaction with the content (inside the DOM contenteditable area) back to the model.

"during the editingDowncast"? I just looked at the documentation again. I saw that there are 3 types of conversions. So this would be a conversion from Model To Editing View, from the Model tree to the editor tree. According to the presented table in documentation, I can imagine the following case:

table

  1. The DataView is used [used? As a... utility tool? Or as a third stored structure?] when you set (most commonly editor.setData('<p>foo</p>')) or get data from the editor (ie, when editor.getData() to store the editor content in a DB).

From what I thought, DataView is just the name of the result of a conversion, not something that is stored (as a value, a variable, a data or a model of something), such as Editing View and Model. It makes little sense to keep and to update information that will only be used in the process of saving or retrieving database content.

But... For God's sake correct me if I'm wrong please, because I might be... By the way you spoke, and according to the ckeditor 5 mvc architecture image (note a root drawing), it makes me think there is a third data structure stored in CKEditor 5. Counting, we have 3:

If Data View represents a data structure, which is saved (in memory, like the other 2) by CKEditor 5, what is the reason for its existence? Isn't there a CKEditor 5-ready data model of its own, and another one for user editing in the editor? Is this right? I'm asking because I don't know. I would like this to be confirmed if possible. Also...

  1. Why there's different editingDowncast and dataDowncast - because we know from previous projects that you might need to represent some editing feature (like Widget) a bit different in the editing area - where the user interacts it while creating the content - and a bit different in the data [a conversion to and from data? The text representation?] you get from the editor. Most commonly we add some additional markup for widgets in the editing area used to style the wiget (all these fancy borders) which aren't need in the data you get from the editor.

"[...] and a bit different in the data. [...]": I'm starting to think Conversion is doing DataProcessor work. editingDowncast is Conversion work, ok, because you are converting from Model to Editing View. But shouldn't dataDowncast be DataProcessor's job? Would it not be considered good practice to leave each part of a program solely responsible for its own? If I put conversion logic inside (or using) Conversion (like, inside simpleboxediting or placeholderediting), wouldn't I have to repeat the same code in DataProcessor? For me, Conversion should be just converting Model to Editing View and vice versa only.

Still talking about the MVC architecture diagram, I believe that DataProcessor should be between Model and DataView, existing in the Controller layer, replacing the two converter squares:

dataprocessor

Note: The conversion between Model and Editing View has been omitted in the image.

It seems to me that there are types of conversion, or occasions of conversion. One thing is to prepare Editing View and Model to work with different components (such as simpleBox and placeholder). Another one is to develop a process for extracting these components as some text, following a specific format or representation (HTML, Markdown, JSON, etc.).

You can very well use the editor with custom plugins and features, without necessarily getting data through getData. Of course, under these conditions, it does not mean that you will get and define the content of CKEditor, but it does mean that it will be able to (it will know how to) perform a representation of its own content. This means a concern, or obligation for an occasion. To get a representation and define content based on one, this is another occasion / concern.

In Implementing a block widget and Implementing a inline widget, it is easy to see that there is a occasion of conversion where editor elements (Editing View) need to be transformed into model elements, and vice versa, because:

But there is another occasion of conversion when it is desired to obtain content in another format. This process involves other participants (no longer Editing View and Model together), and I am referring to Data and Model.

  1. The conversion process happens when you transform Model representation to the View or vice versa. Taking the above you can have: 5a. The upcast conversion which happens when you transform your data (View) (ie HTML but can be XML if using different data processor) to Model structure [...] 5c. The dataDonwcast conversion happens when you want to take the Model structure for your application (most commonly you want to get HTML but you can also want Markdown)

If, and only if, the following code snippet is transforming from Model to Data (text, HTML, Markdown, JSON, etc.):

conversion.for( 'dataDowncast' ).elementToElement( { model: 'paragraph', view: 'p' } );

Why do I need to set this in Conversion instead of setting up a DataProcessor? By the way, do you need to use DataProcessor then? I'm thinking about DataProcessor, because this tool is already there to be used, can be plugged and unplugged, replaced, and it is even possible to define a custom DataProcessor.

And note the name of the Group of Dispatcher: dataDowncast. Now look at the second property name of the ConverterDefinition object: view. View? What? Shouldn't it be data then? Wouldn't this be from Model to Data?

Actually, I'm not asking for anything in CKEditor 5 source code to be changed, I just want to understand the following (in summary):

  1. Conversion and DataProcessor are responsible for converting what?
  2. Is there conversion repetition in Conversion compared to DataProcessor?
  3. Is Data View a result of a procedure, or does it represent a stored data set such as Editing View and Model? If so, what is its purpose, since I can later convert it to something else? And how is your data structured? Is it a list, a set, a queue, a tree, etc? The MVC architecture diagram shown shows a tree structure.
  4. What does each of the Groups of Dispatchers mentioned in conversion represent? What do they convert to what? Model to Editing View? Data View to Model? Data View to Editing View? What?

@jodator maybe I'm overcomplicating things, I don't know, really. I don't want it to look like I'm downplaying CKEditor. I'm not! CKEditor 5 is an amazing tool, no wonder I chose it. The problem is that I can't quite understand the documentation. Using pure CKEditor 5 without any change is the easiest thing. But the problem begins when something needs to be altered or created, for that requires gaining deeper knowledge of this utility.

scofalik commented 4 years ago

Thanks @jodator for clarifying this subject.

Hi @loagit! Thanks for sharing your concerns. Actually, you got it almost right in your second post. Also, nice pictures ;). I'd like to clarify your doubts.

As @jodator already stated, there is the model tree structure that is abstract and represents data stored in the editor. There is also the view tree structure which can be understood as "Virtual DOM". In short, we call them simply "model" and "view".

I confirm that we use two separate view tree structures. One is the "editing view", the other is the "data view". As @jodator explained: for some features, there is a need to represent those features differently in the editing view and in the data input/output. Hence, we generate two structures.

As for the naming for "conversion directions (ways)", we have:

Given that we have two views, we differentiate between "editingDowncast" (model -> editing view) and "dataDowncast" (model -> data view). Different converters for the same model element may produce a different "virtual dom structure", according to the feature's needs. There is also just "downcast" which means both "editingDowncast" and "dataDowncast" for those features, for which editing and data view structures are the same. These are the simple features, like paragraph or bold. "Upcasting" takes place only for loading the data, so there's no need for "editingUpcast".

We also have something that we call "pipelines". Pipeline is a name for conversion in both ways (up/down) + tools, utilities and structures that are needed for handling the conversion process. So, we say that we have the editing pipeline and the data pipeline and they are represented by controller.EditingController and controller.DataController classes.

I wanted to clarify this before I jump into your doubts so you are assured that you understood those concepts correctly (and the diagram makes me believe you did).

From what I thought, DataView is just the name of the result of a conversion, not something that is stored (as a value, a variable, a data or a model of something), such as Editing View and Model.

The data view is a tree structure. Just like the editing view. The structures use the same elements and tools from view directory, like view.Element or view.TreeWalker.

The difference is that for the editing pipeline, we maintain that structure all the time. In the data pipeline this structure is only temporary, created for the time of editor.getData() and editor.setData() execution. I guess this is why you might get confused. In the editor pipeline, we use View class, while in the data pipeline we don't (we just use view.DocumentFragment as the "root" of the view structure and as I said, it exists only during getData() and setData()).

So, to sum up, whenever we talk about the data view or converting to the data view, we think about the same process that happens for the editing view.

I'm starting to think Conversion is doing DataProcessor work.

Still talking about the MVC architecture diagram, I believe that DataProcessor should be between Model and DataView, existing in the Controller layer, replacing the two converter squares:

I understand why you think this way. This is actually something that was brought up by the community on a few occasions but named differently. Some community members were calling it "getting data straight from the model" and it was usually connected with having to obtain, for example, JSON data instead of HTML and those users wanted to do that straight from the model.

As much as this would be possible, I'd like to explain why this is a bad idea. It is all connected with the nature of CKE5 and with our desire to make the framework pluggable.

We want to create the virtual DOM structure (and real DOM too). Why?

HTML (and thus DOM) is a closed set* of available elements. They are well defined and described. There are a lot of available tools that operate on them. Since the set rarely changes, there is rarely a need to change something in an existing tool. It is not something that can be changed by an editor plugin or through editor configuration.

* - We could argue that you can introduce custom tags for your own needs (this is what we actually do) but those can be "translated" on a 1:1 basis (so <myElement> in virtual DOM becomes <myElement> in real DOM). This is not always true for the model elements though, which are a bigger abstraction over virtual/real DOM.

On the contrary, the model is an open set of available elements. Since we support pluggable architecture and encourage our users to create their plugins, basically everyone can create a new model element name with its own "meaning". The set of available model element names heavily depends on editor configuration and is outside of our control. This means that it is impossible to write a data processor, that gets HTML straight from the model, because it would be impossible to always have it up-to-date (with the available model element names and their meaning).

I hope that, at this point, you understand the need of having an intermediate step of translating the model to something that is better defined and more stable. And DOM (or virtual DOM) is perfect for that.

Since we already have a process for generating the (virtual) DOM (which is the conversion process), why should we introduce another tool for that? If we did, we'd introduce more complexity for custom plugin creators (more things to learn).

I am trying to comprehend the part where you talk about "conversion occasions". I think that, in general, we talk about the same thing but using slightly different words. I see that your main concern is using the same "tool" (conversion) to deal with both types of occasions. If I haven't convinced you, or If I understood you incorrectly, I'd like to read more about your point of view.

If, and only if, the following code snippet is transforming from Model to Data (text, HTML, Markdown, JSON, etc.):

conversion.for( 'dataDowncast' ).elementToElement( { model: 'paragraph', view: 'p' } );

Why do I need to set this in Conversion instead of setting up a DataProcessor?

This is hard to discuss without knowing what do you mean by "setting up a DataProcessor"? I'll try to answer, although I am not sure if I will address your concerns.

As I already stated, there can be a lot of custom model elements provided by third parties, so there's no way of implementing a tool that would know how to handle those custom model elements (for example, that myCustomElement should become <div class="myCustomElement"><span></span></div> in the data output). So you will have to define "translation" rules somewhere in the end. My question again: why introduce a new mechanism for that?

As far as the data format is concerned. I already mentioned that we'd like to use the tools that are already available (for generating HTML/XML/Markdown/other possible formats). Since DOM/HTML is de facto "the language of the web", those tools usually have DOM/HTML <-> format conversion utilities. This is why we choose to use DOM as our intermediate step in the data pipeline.

Again, we already have mechanisms for creating DOM (for the editing pipeline purposes), so why not use them?

And note the name of the Group of Dispatcher: dataDowncast. Now look at the second property name of the ConverterDefinition object: view. View? What? Shouldn't it be data then? Wouldn't this be from Model to Data?

I hope that my clarifications up to this point already covered that. Maybe, there's a way to further clarify this but I hope that after you learn that editing view and data view are both "virtual dom" tree structures then it makes sense.

However, maybe, there's a room for improvement for two-way converters, to let specify different conversion configuration for editingDowncast and dataDowncast.

editor.conversion.elementToElement( {
    model: 'myElement',
    editing(View): () => { // Something custom and complex here...  },
    data(View): 'myElement'
} );

So, summary time!

Conversion and DataProcessor are responsible for converting what?

Conversion is a process of generation virtual DOM (called a view in CKE5) from the model. We have the editing view and the data view that may be different for the same model.

DataProcessor is responsible for taking DOM and outputting actual data in the specified format. Since there are multiple formats and all of them have to/from DOM conversion, this is convenient in extensible, pluggable architecture.

Is there conversion repetition in Conversion compared to DataProcessor?

I don't think so. I hope that the above answer also answers this question.

Is Data View a result of a procedure, or does it represent a stored data set such as Editing View and Model? If so, what is its purpose, since I can later convert it to something else?

The data view is a structure like the editing view but it is temporary, an intermediate step in the data pipeline. DataProcessor generates data from it. DataProcessor converts data to it.

Using pure CKEditor 5 without any change is the easiest thing. But the problem begins when something needs to be altered or created, for that requires gaining deeper knowledge of this utility.

We are aware of this problem :(. Creating documentation / tutorials is not easy for a platform like CKE5, which is both extensible and powerful and needs to be easily configurable in the most common, basic scenarios.

On one hand, we need to provide "quick start" tutorials for "basic users" (who just configure the editor). Then, we need to cater to "intermediate users" (basic plugins creators, like a button that inserts a timestamp). But we cannot go way too deep in the engine, because that might be too discouraging ("I don't need to know all the details!). Finally, there are "super users", who'd like to know it all and create sophisticated plugins and integrations. So, there are multiple levels of needs for the architecture knowledge, hence we would need multiple tutorial series, which is very time consuming :(.

loagit commented 4 years ago

@scofalik Hey! Nice to see you too. :)

I understand why you think this way. This is actually something that was brought up by the community on a few occasions but named differently. Some community members were calling it "getting data straight from the model" and it was usually connected with having to obtain, for example, JSON data instead of HTML and those users wanted to do that straight from the model.

As much as this would be possible, I'd like to explain why this is a bad idea. It is all connected with the nature of CKE5 and with our desire to make the framework pluggable.

We want to create the virtual DOM structure (and real DOM too). Why?

HTML (and thus DOM) is a closed set* of available elements. They are well defined and described. There are a lot of available tools that operate on them. Since the set rarely changes, there is rarely a need to change something in an existing tool. It is not something that can be changed by an editor plugin or through editor configuration.

[...]

On the contrary, the model is an open set of available elements. Since we support pluggable architecture and encourage our users to create their plugins, basically everyone can create a new model element name with its own "meaning". The set of available model element names heavily depends on editor configuration and is outside of our control. This means that it is impossible to write a data processor, that gets HTML straight from the model, because it would be impossible to always have it up-to-date (with the available model element names and their meaning).

From what I understand in relation to what you said it is possible to define different, custom elements within Model, like simpleBox, right? And because of this, it is difficult to define a translator (DataProcessor) capable of transforming Model into Data (such as Markdown, JSON, and so on). I'm saying this trying to keep up with you.

I hope that, at this point, you understand the need of having an intermediate step of translating the model to something that is better defined and more stable. And DOM (or virtual DOM) is perfect for that.

Since we already have a process for generating the (virtual) DOM (which is the conversion process), why should we introduce another tool for that? If we did, we'd introduce more complexity for custom plugin creators (more things to learn).

So, to get a desired representation from Model, you first need to turn it into something like DOM, correct? I'm still following what you said. Notice you mentioned "or virtual DOM" here. From what you demonstrate, it is preferable to generate a DOM first. Also, it makes me understand that it's even possible to use third-party tools (ready-made) to transform the generated DOM into other types of representations, like Markdown, JSON etc (to get the desired result).

I am trying to comprehend the part where you talk about "conversion occasions". I think that, in general, we talk about the same thing but using slightly different words. I see that your main concern is using the same "tool" (conversion) to deal with both types of occasions. If I haven't convinced you, or If I understood you incorrectly, I'd like to read more about your point of view.

I was wrong because I thought Data View was not a data structure but just a result. It was making me think that there was a direct conversion from Model to data (text, like HTML, XML, Markdown, JSON, etc...). Like so:

conversion.for( 'dataDowncast' ).elementToElement( { model: 'paragraph', view: 'p' } );

And that the same thing was done in DataProcessor. That's also why I questioned the name of the view property. Now that I know Data View is a data structure (even if it's temporary), and it's a virtual DOM, like Editing View...

Conversion is a process of generation virtual DOM (called a view in CKE5) from the model. We have the editing view and the data view that may be different for the same model.

If Data View and Editing View are virtual DOM structures generated from a Model conversion, for what reasons or in what situations would they be different? I mean, if they came from the same source, why would a developer make them different? Could you show an example?

For example, I can easily understand the case of Simple Box:

// Model
<simpleBox>
    <simpleBoxTitle></simpleBoxTitle>
    <simpleBoxDescription></simpleBoxDescription>
</simpleBox>

// View (Editing View and Data View)
<section class="simple-box">
    <h1 class="simple-box-title"></h1>
    <div class="simple-box-description"></div>
</section>

We are aware of this problem :(. Creating documentation / tutorials is not easy for a platform like CKE5, which is both extensible and powerful and needs to be easily configurable in the most common, basic scenarios.

On one hand, we need to provide "quick start" tutorials for "basic users" (who just configure the editor). Then, we need to cater to "intermediate users" (basic plugins creators, like a button that inserts a timestamp). But we cannot go way too deep in the engine, because that might be too discouraging ("I don't need to know all the details!). Finally, there are "super users", who'd like to know it all and create sophisticated plugins and integrations. So, there are multiple levels of needs for the architecture knowledge, hence we would need multiple tutorial series, which is very time consuming :(.

Can I be a little honest with you (the team)? What I see when I click on documentation is a mess. The documentation shows a top menu with a tree side menu. Do you know how many items you have in each menu, and how many more in each menu when clicked? It is scary! Not to mention a huge text to read on each clicked item. It seems like I need to read everything that is written in order to use CKEditor with some custom stuff. That's when I think: No... No way...

It is not at all welcoming, or much less attractive. The CKEditor 5 presentation page is very different from the documentation page. When I visit it, I want to read, to know and to discover. I like to visit this page. Notice there's a whole advertisement of the product (the editor):

See how flashy it is, full of images and colors, but in an organized way.? While the CKEditor introduction page attracts interested readers, when the documentation begins to be read by the user I bet many give up.

Organized and well-presented information makes the urge to read even if there is plenty of content to read. GUIDE THE USER. He doesn't know what to do, where to start. Imagine that the user is "dumb" (or is lost). I'm sorry for the word, and the way I'm saying it, but in marketing strategies you start to notice certain things when you think that way. Of course no one is dumb, this is an exaggerated but necessary point of view.

@scofalik mentioned levels of knowledge for different users. This is a great idea! Do you know what you guys could do? You could put choices to users showing what they would like to do:

ckeditor help

This way you guide the user, but he/she is the one who chooses what he/she wants or not to do. Create subsections. When you teach or present something, imagine that the user has never seen it and has no experience. This will help to put yourself in the learner's shoes.

I apologize for the drawing, but I made it quick, in a single afternoon, so I couldn't complete it. I've been kind of out of time. If you need more documentation ideas, please just ask, I will be happy to help.

I also apologize for the words that may have sounded harsh. I also don't want to downplay anyone's work, I can see how dedicated everyone is, especially getting support here. What I wanted was to make a constructive criticism, pointing out exactly where I believe that if it is improved, CKEditor users will be very happy, and will surely become fans of this tool, advertising it for you without having to spend a single coin. This can attract more users, more contributors, sponsors, and so on. I think, in the rest, there is nothing to improve. You already have a very good tool. :)

scofalik commented 4 years ago

If Data View and Editing View are virtual DOM structures generated from a Model conversion, for what reasons or in what situations would they be different? I mean, if they came from the same source, why would a developer make them different? Could you show an example?

The same editor content (model) might need to be represented differently in the editable element and in the data output. The most common case for that are widget elements (for example an image or a table) which have additional UI or more complex UX (behavior)

For example, see the table case:

The editing view:

<figure class="table ck-widget ck-widget_with-selection-handle" contenteditable="false">
    <div class="ck ck-widget__selection-handle">
        <!-- svg code cut out to make it less mess !-->
    </div>
    <table>
        <tbody>
            <tr>
                <td class="ck-editor__editable ck-editor__nested-editable" contenteditable="true"><span>Foo</span></td>
                <td class="ck-editor__editable ck-editor__nested-editable" contenteditable="true"><span>Bar</span></td>
            </tr>
            <tr>
                <td class="ck-editor__editable ck-editor__nested-editable" contenteditable="true"><span>Abc</span></td>
                <td class="ck-editor__editable ck-editor__nested-editable" contenteditable="true"><span>Xyz</span></td>
            </tr>
        </tbody>
    </table>
</figure>

Data output:

<figure class="table">
    <table>
        <tbody>
            <tr>
                <td>Foo</td>
                <td>Bar</td>
            </tr>
            <tr>
                <td>Abc</td>
                <td>Xyz</td>
            </tr>
        </tbody>
    </table>
</figure>

For the editing view, we need to:

We don't need all that mess in the output data.

Another example are markers. Markers are for now used, I think, only in collaboration features so I am not sure if you had a chance to see them in action. In short, marker is basically a live range (updates automatically) that also can be converted to both views.

To show the marker as a highlight (for comments feature) we convert it to a <span> that contains some text (that gives the text the background) or sets a class on a widget (for a yellow border). You can check the editable DOM on the linked page. Try adding a comment to the whole table.

But this representation is very inconvenient when you save and ready the data. So, for saving the data, we do it differently, we add a tag where the marker starts and where the marker ends. So you can easily find the marker boundaries. Use watchdog._editor.getData() on the linked page to see the output.

And the third reason is being flexible. We don't know what kind of features we, or our users, will come up with. I can imagine that some features are differently shown in the editing view (for example, to enhance UX) and differently in the data view. Try embedding a tweet (just paste the link into the editor) and see what's the difference between editing and data. Imagine a hypothetical "image rotator" feature. In the editing view, it doesn't need scrolling, arrows, etc. but maybe you'd like to have a grid with added photos, have it drag&droppable, etc.

I also apologize for the words that may have sounded harsh.

Don't worry, we are used to the criticism, and a lot of it is not constructive :). We rarely get this kind of constructive feedback in regards to docs, so it is much welcomed. The voice from the community will help us in shaping the docs, after all, we create them for you. The docs at this moment have their problems, yes. My personal opinion is that I agree with some of your ideas (guiding the user, feeling of overwhelming, separate paths for separate user groups).

OTOH, we need a lot of what is already there to be able to link to specific content or explanation.

Sorry for keeping my comment so short when you spent some time describing your ideas. But I cannot say when and how we will approach refreshing the docs, so I don't want to drag out the discussion (esp. since this issue is about a specific thing).

loagit commented 4 years ago

All my questions regarding conversions have been answered. Thank you all. Once again, I am pleased with everyone's support. See you later. :)