# end goal for the vendor/user
Have a toolbar that works:
- bold/italic/... buttons show whether they are currently active
- bold/italic/... buttons behave as expected, both on selections and on cursor position
# background: Observables vs Events
Very close to each other, a lot depends on implementation details
Conceptually it's a different beast though
## events
+ we already use events
+ more "pure", everyone is responsible for their own state
+ difference between "enterList", "leftList" vs "inList" as state
+ all logic goes to handlers
+ easy to have an api to stop event bubbling
- all logic goes to handlers
- debugging events might be harder vs observables
## observables
+ might be easier to debug
+ might be more efficient (state only calculated once)
+ state is always calculated, even if you missed an event
- maintaining state is hard, the editor already has a lot of state
- possibility for race conditions
# what can plugins do
event driven A plugin can only:
- execute commands through the editor controller (aka rawEditor).
- send events
- register event listeners
observable driven A plugin can only:
- execute commands through the editor controller (aka rawEditor).
- register observers
- update state in the statestore
# Stories
1. build a selectionchange event listener that calculates our virtual dom (experiment)
this listener is responsible for calculating the properties of the current selection and save the latest state in the editor controller.
```
{ selection: RDFABlock, attributes: { rdfaContexts: contexts, inList: unknown , bold: unknown, italic: unkown} }
```
```
<bold>foo</bold><italic>bar</italic>
```
we do this for the attributes bold, italic as an experiment and implement it as a eventListener on the DOM selectionchange event
the listener updates the richSelection field on the controller and sends out a CustomEvent editorSelectionChange
detection of italic/bold:
- for a caret, is nested within a strong or em tag
- for a selection, if the all the elements selection have the computedstyle strong/em => enabled
- for a selection, if the not all the elements selection contains more than 1 element and have the computedstyle strong/em => unknown
- for a selection, if none the elements selection contains more than 1 element and have the computedstyle strong/em => disabled
the goal is centralizing logic now spread out within the editor
RISK: what triggers the selectionchange?
3d
2. Create a makeBold & disableBold command with support for collapsed selections
This command can be registered on the editorController via a new registerCommand API.
This command can be called via the editorController via a new executeCommand API.
consider using https://developer.mozilla.org/en-US/docs/Web/API/Range/surroundContents
- The disable command removes bold from the selection
- The make bold command makes the selection bold
15d
3. Extend makeBold & disableBold command with support for non collapsed selections
The disable command removes the wrapping strong tag and maintains cursor position
The make bold command inserts a strong tag and moves the caret inside the strong tag
10d
4. Implement a component that provides a toolbar button for bold
The toolbar button shows the active state by listening to editorSelectionChange event.
If the state is enabled, the button shows as pressed. when clicked it executes the disableBold command
If the state is disabled, the button shows as unpressed. when clicked it executes the makeBold command
If the state is unknown, the button shows as unpressed. when clicked it executes the makeBold command
1d
4. Provide a statestore in the editor so plugins can register a state
The idea is that we’d have plugins that listen to certain events (such as selectionchange) and would calculate state and store that within the editor for consumption in toolbar items or other. See below for a rough example.
In this story we add a store and a mechanism for observing the store. This means being able to register an observer and having an api to api state in the store.
The store is a pojo containing observables (these are key/value pairs).
- Consider using https://rxjs.dev/guide/overview which already provides tooling for observables.
1. Provide a statePlugin that calculates basic style state
This is a piece of code that listens to basic events (such as selectionchange) and then calculates whether the current selection is bold, italic, underlined or striked through
1. Create a bold command(‘makeBold’)
```js
editor.executeCommand(‘makeSelectionBold’)
editor.executeCommand(‘enableBold’)
```
1. create a toolbar that renders components loaded from a configuration file
the components receive the editor as argument.
1. Create a basic styles (bold, italic,underline, strikethrough) toolbar item, replicating current behaviour.
1. Improve basic styles based on events offered by rawEditor
1. Create a list (ordered list, unordered list, indent, unindent) plugin
# Sample Code
```js
//the component
class BoldButton {
@tracked isActive;
editor
constructor(){
This.editor = this.args.editor;
editor.observe(‘inList’, ( { ...} ) => {
this.isActive = newState;
}
}
//per state definition of callback arguments
@action
toggleBold(){
this.editor.executeCommand(‘enableBold’)
}
}
}
```
```js
class Plugin {
constructor(editor){
this.editor = editor;
editor.register('onChange', this.fancyCalcuculator)
}
function fancyCalculator(event){
//
this.editor.setState('inList', true);
}
}
```
```js
class Editor {
//state must be mutually exclusive
stateStore: {
'inList': true
}
listeners: [] //for plugins
observers: [] // for e.g. components
registerListener(eventType, callback){
}
registerObserver(observable, callBack){
}
setState(string, bool){
//case string == inList
for(obs of observers){
obs.notify();
}
}
}
```