We have dynamic text areas that the end users can manage the content. The application itself is an angular 9, grapesJS (version: 0.17.27) to allow the users to manage content and replaced the default grapesJS Rich Text Editor with CKEditor4 and have it enabled via the grapesjs-plugin-ckeditor (version: 0.0.10).
We are facing an issue where we cannot seem to pin/dock the toolbar in a place that makes sense so it doesn't bounce around for the user. If you look at the picture and see the grapesJS frame, I can grab the iFrame and I can grab the bottom block as we create that) in conjunction with sharedSpaces top and bottom, see code below for full editor toolbar implementation setup
When I use these ids that bottom block is technically outside of the canvas and so none of the functions in the CKEditor will actually work as everytime you click on it, the text gets deselected, if I use the default positioning, i.e. remove sharedSpaces and toolbarLocation then everything works but there is no consistency to where it shows up, i.e. above or below the text and sometimes it bounces to a different location as you hit enter and continue expanding your text block.
Is there a good way to pin the CKEditor toolbar when using grapesjs on a text area?
GrapesJS Editor Code:
//remove unneeded buttons
let removeTbActions = [
'Source'
, 'Save'
, 'NewPage'
, 'ExportPdf'
, 'Preview'
, 'Print'
, 'Templates'
, 'Find'
, 'Replace'
, 'Scayt'
, 'Form'
, 'Checkbox'
, 'Radio'
, 'TextField'
, 'Textarea'
, 'Select'
, 'Button'
, 'ImageButton'
, 'HiddenField'
, 'Strike'
, 'Subscript'
, 'Superscript'
, 'CreateDiv'
, 'BidiLtr'
, 'BidiRtl'
, 'Language'
, 'Image'
, 'Flash'
, 'Table'
, 'HorizontalRule'
, 'Smiley'
, 'SpecialChar'
, 'PageBreak'
, 'Iframe'
, 'Maximize'
, 'ShowBlocks'
, 'SelectAll'
, 'PasteFromWord'
, 'PasteText'
, 'Anchor'
, 'Blockquote'
, 'JustifyBlock'
, 'Format'
, 'CopyFormatting'
, 'Font'
, 'FontSize'
].join(',');
this.grapesJsEditor = grapesjs.init({
container: '#gjs',
fromElement: true,
style: style,
height: '600px',
width: 'auto',
storageManager: false,
plugins: ['gjs-plugin-ckeditor'],
pluginsOpts: {
'gjs-plugin-ckeditor': {
options: {
sharedSpaces: {
top: 'gjs',
bottom: 'blocks'
},
toolbarLocation: 'top',
toolbarGroups: [
{ name: 'document', groups: ['mode', 'document', 'doctools'] },
{ name: 'basicstyles', groups: ['basicstyles', 'cleanup'] },
{ name: 'clipboard', groups: ['clipboard', 'undo'] },
{ name: 'editing', groups: ['find', 'selection', 'spellchecker', 'editing'] },
{ name: 'forms', groups: ['forms'] },
{ name: 'paragraph', groups: ['list', 'indent', 'blocks', 'align', 'bidi', 'paragraph'] },
{ name: 'links', groups: ['links'] },
/* { name: 'insert', groups: ['insert'] },*/
{ name: 'colors', groups: ['colors'] },
{ name: 'styles', groups: ['styles'] },
{ name: 'tools', groups: ['tools'] },
{ name: 'others', groups: ['others'] },
{ name: 'about', groups: ['about'] }
],
extraPlugins: 'colorbutton, colordialog, indent, indentblock, justify, list, listblock, liststyle, sharedspace',
// Remove some buttons provided by the standard plugins, which are
// not needed in the Standard(s) toolbar.
removeButtons: removeTbActions,
//remove unneeded Plugins
removePlugins: 'resize',
//make toolbar not resizable
resize_enabled: 'false',
extraAllowedContent: '*(*);*{*}',
allowedContent: true,
width: '100%'
}
}
},
panels: {
defaults: [{
id: 'layers',
el: '.panel__right',
resizable: false
},
{
id: 'panel-switcher',
el: '.panel__switcher',
buttons: [{
id: 'show-style',
active: true,
label: '<span class="fa fa-paint-brush" title="Styles"></span>',
command: 'show-styles',
togglable: false,
},
{
id: 'show-traits',
active: false,
label: '<span class="fa fa-cog" title="Properties"></span>',
command: 'show-traits',
togglable: false,
}]
}]
},
blockManager: {
appendTo: '#blocks',
blocks: blocksToAdd
},
selectorManager: {
appendTo: '.styles-container'
},
styleManager: {
appendTo: '.styles-container',
sectors: [{
name: 'Typography',
open: true,
buildProps: ['font-family', 'font-size', 'font-weight', 'color', 'text-align', 'text-decoration', 'font-style'],
properties: [
{ name: 'Font', property: 'font-family' },
{ name: 'Weight', property: 'font-weight' },
{ name: 'Font color', property: 'color' },
{
property: 'text-align',
type: 'radio',
defaults: 'left',
list: [
{ value: 'left', name: 'Left', className: 'fa fa-align-left' },
{ value: 'center', name: 'Center', className: 'fa fa-align-center' },
{ value: 'right', name: 'Right', className: 'fa fa-align-right' },
{ value: 'justify', name: 'Justify', className: 'fa fa-align-justify' }
],
}, {
property: 'text-decoration',
type: 'radio',
defaults: 'none',
list: [
{ value: 'none', name: 'None', className: 'fa fa-times' },
{ value: 'underline', name: 'underline', className: 'fa fa-underline' },
{ value: 'line-through', name: 'Line-through', className: 'fa fa-strikethrough' }
],
}, {
property: 'font-style',
type: 'radio',
defaults: 'normal',
list: [
{ value: 'normal', name: 'Normal', className: 'fa fa-font' },
{ value: 'italic', name: 'Italic', className: 'fa fa-italic' }
],
}],
}]
},
traitManager: {
appendTo: '.traits-container'
}
});
Also I have included pictures of when I use the default positioning and the IFrame itself.part of the IFrame showing default toolbar positioning for this text