You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
This is a rough draft of an blocks api for TinyMCE to be used to manage complex block components within tinymce. The blocks can only be inserted at root level this is a difference from the current contenteditable false support we have in tinymce but it would make them easier to handle especially the more complex blocks.
Editor instance api
editor.blocks.register(id:String, config:Object)
Registers a new block type in the editor. Registered blocks will appear in the insert blocks toolbar.
editor.blocks.insert(id:String)
Inserts the block by id into the editor at caret position splitting any text block in the process.
editor.blocks.canInsert(id:String):Boolean
Returns true/false if the block by id can be inserted at caret position. For example you can't insert a block inside another block in some cases since the block can’t be split when inserting a block inside a caption part of a figure.
editor.blocks.getAll():Object
Returns an name/value object with all registered blocks.
Blocks data structure
type:String (Optional)
Can be the following types:
simple - Default type just contenteditable=false. Used for figure element etc.
shimmed - Places a shimmed mask on top of the block when it's not selected. Used for youtube etc.
unmanaged - Selection needs to be managed by the block. Undo manager would ignore changes inside the block. Events just passthrough etc. Used for codemirror etc.
title:String
This is the title that will be displayed in the insert blocks toolbar.
icon:String
This is the icon that will be displayed in the inserts blocks toolbar.
toolbar:[Object] (Optional)
This is an array of objects describing the toolbar items.
Gets called when the user wants to insert a block into the editor. This is where the user constructs the block to be inserted into the editor. The api is provided since in unmanaged mode you might want to do selection on events inside the complex block. The callback is needed if the operation is async or if you want to perform other actions after the insert has been done by tiny for example converting an element into an codemirror instance. The api methods would either be no-ops or return null until the element callback is executed.
remove(api:Api) (Optional)
Gets called when the block is about to be removed by the user on say delete/backspace. This means the api.dom() function will return the reference to the currently attached dom node things like cleanups for event unbinding can be done before it’s removed.
load(api:Api):Element (Optional)
Gets called when the block was loaded into the editor after contents was parsed and attached to the dom. Similar to insert this is where you can construct a more complex version of the block converting it from say a pre element into a codemirror instance.
save(api:Api):Element (Optional)
Gets called when the block is about to be saved before serialization.
Toolbar items structure
type:String
Optional type of what UI element to create. Defaults to “button” and would in version 1 be the only thing supported. Other things could be listbox/selectbox/menubutton etc this is yet to be determined.
icon:String
Icon to be displayed in the blocks contextual toolbar.
tooltip:String
Tooltip to be displayed when hovering the contextual toolbar items.
action(api:Api)
Callback that gets executed when the toolbar item is clicked/pressed.
Block interaction api
dom():Element
Returns the dom element created by the block.
select()
Selects the block element. Useful in unmanaged mode.
unselect(forward:Boolean)
Unselects the block and moves the selection back to the editor before/after the block.
remove()
Removes the block from the editor this will fire the remove operation but will reposition the caret into the closest valid location.
Example of contents produced by the editor on serialization
<divdata-mce-block="my-fancy-block">
My fancy block
</div>
Example of contents produced while within the editor
<divdata-mce-block="my-fancy-block" contenteditable="false" data-mce-id="guid-123">
My fancy block
</div>
Examples of operations for various user interactions
User Interaction
Block operations
Insert
insert
Delete/Backspace
remove
Cut
save, remove
Copy
save
Paste
load
Drag & Drop (internally)
save, remove, load
Drag & Drop (externally)
load
Drag & Drop (to external)
save
Load editor contents
load
Save editor contents
save
Undo
save, remove (for unmanaged blocks)
Redo
load (for unmanaged blocks)
Scenarios
Mobile
Some of the more advanced block types won’t work on mobile. There are multiple ways this can be solved by an implementor. One way is to just register a different block type with the same id but as a placeholder though load/save. The other way is to produce a simpler form of the block for example a codemirror instance could be represented as a pre element or a textarea.
Custom UI
If you want to roll your own UI and just use the block api for state management you can just register blocks without toolbars and then based on selection render your own custom toolbar. This might be how wordpress would use this api if they want to do their own react ui but still get the benefits we provide around these blocks.
React blocks
Unmanaged blocks can be rendered by anything since they are more or less just raw dom nodes. This opens up using things like react to render these blocks. It’s then up to the implementor to handle the complexity.
Insert dialogs
Since the insert operation is async you could present say a dialog for some blocks where the insert is delayed until the callback is executed.
Oembed
Since the insert operation is async a service could be queried and then the callback would insert the embed block.
Modern theme
There is no reason why the concept of these blocks can’t be represented in both the inlite and the modern theme. There just needs to be a different UI for inserting them say under the “+” toolbar button. That means all users of tiny could benefit from these blocks not just those that use inline editing.
Converting comments from/to dom
Wordpress has a concept of wrapping the blocks in comments while it’s being stored in the wp_post field and then parsing and converting those comments into blocks while editing. It’s possible to do this though a plugin in tinymce separate from this block api. We can provide Wordpress with an example of this process.
The text was updated successfully, but these errors were encountered:
With this proposal, to implement something like an image with caption, would the implementation of edit effectively be to apply a contenteditable="true" attribute to the nested figcaption element?
Yes the toolbar would be for block level things and when you have an selection within a nested contenteditable=true you get the text formatting controls. We might need to abstract away the adding/removing of contenteditable attributes though. I think this is stuff that gets more clear when we do the spike poc of this.
Editor Blocks API proposal
This is a rough draft of an blocks api for TinyMCE to be used to manage complex block components within tinymce. The blocks can only be inserted at root level this is a difference from the current contenteditable false support we have in tinymce but it would make them easier to handle especially the more complex blocks.
Editor instance api
editor.blocks.register(id:String, config:Object)
Registers a new block type in the editor. Registered blocks will appear in the insert blocks toolbar.
editor.blocks.insert(id:String)
Inserts the block by id into the editor at caret position splitting any text block in the process.
editor.blocks.canInsert(id:String):Boolean
Returns true/false if the block by id can be inserted at caret position. For example you can't insert a block inside another block in some cases since the block can’t be split when inserting a block inside a caption part of a figure.
editor.blocks.getAll():Object
Returns an name/value object with all registered blocks.
Blocks data structure
type:String (Optional)
Can be the following types:
title:String
This is the title that will be displayed in the insert blocks toolbar.
icon:String
This is the icon that will be displayed in the inserts blocks toolbar.
toolbar:[Object] (Optional)
This is an array of objects describing the toolbar items.
insert(api:Api, callback:function(element:Element))
Gets called when the user wants to insert a block into the editor. This is where the user constructs the block to be inserted into the editor. The api is provided since in unmanaged mode you might want to do selection on events inside the complex block. The callback is needed if the operation is async or if you want to perform other actions after the insert has been done by tiny for example converting an element into an codemirror instance. The api methods would either be no-ops or return null until the element callback is executed.
remove(api:Api) (Optional)
Gets called when the block is about to be removed by the user on say delete/backspace. This means the api.dom() function will return the reference to the currently attached dom node things like cleanups for event unbinding can be done before it’s removed.
load(api:Api):Element (Optional)
Gets called when the block was loaded into the editor after contents was parsed and attached to the dom. Similar to insert this is where you can construct a more complex version of the block converting it from say a pre element into a codemirror instance.
save(api:Api):Element (Optional)
Gets called when the block is about to be saved before serialization.
Toolbar items structure
type:String
Optional type of what UI element to create. Defaults to “button” and would in version 1 be the only thing supported. Other things could be listbox/selectbox/menubutton etc this is yet to be determined.
icon:String
Icon to be displayed in the blocks contextual toolbar.
tooltip:String
Tooltip to be displayed when hovering the contextual toolbar items.
action(api:Api)
Callback that gets executed when the toolbar item is clicked/pressed.
Block interaction api
dom():Element
Returns the dom element created by the block.
select()
Selects the block element. Useful in unmanaged mode.
unselect(forward:Boolean)
Unselects the block and moves the selection back to the editor before/after the block.
remove()
Removes the block from the editor this will fire the remove operation but will reposition the caret into the closest valid location.
Example of usage
Example of contents produced by the editor on serialization
Example of contents produced while within the editor
Examples of operations for various user interactions
Scenarios
Mobile
Some of the more advanced block types won’t work on mobile. There are multiple ways this can be solved by an implementor. One way is to just register a different block type with the same id but as a placeholder though load/save. The other way is to produce a simpler form of the block for example a codemirror instance could be represented as a pre element or a textarea.
Custom UI
If you want to roll your own UI and just use the block api for state management you can just register blocks without toolbars and then based on selection render your own custom toolbar. This might be how wordpress would use this api if they want to do their own react ui but still get the benefits we provide around these blocks.
React blocks
Unmanaged blocks can be rendered by anything since they are more or less just raw dom nodes. This opens up using things like react to render these blocks. It’s then up to the implementor to handle the complexity.
Insert dialogs
Since the insert operation is async you could present say a dialog for some blocks where the insert is delayed until the callback is executed.
Oembed
Since the insert operation is async a service could be queried and then the callback would insert the embed block.
Modern theme
There is no reason why the concept of these blocks can’t be represented in both the inlite and the modern theme. There just needs to be a different UI for inserting them say under the “+” toolbar button. That means all users of tiny could benefit from these blocks not just those that use inline editing.
Converting comments from/to dom
Wordpress has a concept of wrapping the blocks in comments while it’s being stored in the wp_post field and then parsing and converting those comments into blocks while editing. It’s possible to do this though a plugin in tinymce separate from this block api. We can provide Wordpress with an example of this process.
The text was updated successfully, but these errors were encountered: