Building a Rich Text Editor: Day 3
Following up on the previous post… I had been thinking of the middle ground between strict coupling and completely loose coupling through event emitters.
Throughout the day, I developed designs and always ended up with hundreds of events. In order to set data in a block, I tried passing data from DOM to document, to the page, and block. The moment I transition from DOM→Doc level to Page→Block level or even in reverse flow, I triggered a series of useless events that were never going to be used. The problem was that there are going to be numerous blocks and so few pages relatively.
If I choose to do strict coupling, I’ll lose my leverage of having multiple models interacting in a space. So, I just gave up and started writing down the events that each block is going to subscribe to. This was simple by watching the DOM events:
That’s it. All combinations of these events can trigger any of the following events:
That is it. These 6 events were enough to cause the ripple effect and let each model handle the behavior independently. This is where I saw that events: 2–5 will interact with the parent page only. The caretUpdate and selection will interact with Doc directly. So, what if there were 2 applications so other blocks will never receive the events meant for this page. Similarly, a page will never broadcast to blocks of other pages as the room has been restricted.
This is where I could develop the model design completely. Today, I’ll be setting up a few guidelines as I had set up on Day 1 for development.
How to Design Events
Every model will subscribe and publish to events that it is directly interacting with visually. If other models are getting affected indirectly, it is the responsibility of the receiving model to pass on the events to the required locations.
For instance, typing will trigger keydown event. This keydown event should be handled by the specific block. The models that are directly interacting with this block are its parent Page and Caret.
Caret is a model that is going to interact with multiple blocks across different pages. However, it is always a part of Doc. In this case, it will be assumed that caret is part of Doc model so it will become easy to locate and communicate with it.
So, here are the rules:
- Every attribute will be private or public readonly. The attribute will be accessible by getter/setter methods only.
- Every setter method will update the value and trigger any events that are necessary.
- Each event that is triggered through a model should reach the models that are directly interacting with it in the DOM.
- A model will only subscribe to events that are directly interacting with.
- A model will have to pass the events to other models that it is interacting with if it does not handle it. The aim of an event can also be considered to stop the propagation of the event.
I’ve already designed the model for Block. Its going to take sometime to completely design the events for all models. Tomorrow, I’ll share the complete design of this document that should help anyone develop an editor.