diff --git a/src/rich_text_editor/model/RichTextEditor.js b/src/rich_text_editor/model/RichTextEditor.js index 35dbf97fb..5cf6234d6 100644 --- a/src/rich_text_editor/model/RichTextEditor.js +++ b/src/rich_text_editor/model/RichTextEditor.js @@ -1,6 +1,7 @@ // The initial version of this RTE was borrowed from https://github.com/jaredreich/pell // and adapted to the GrapesJS's need +import { isString } from 'underscore'; import { on, off } from 'utils/mixins'; const RTE_KEY = '_rte'; @@ -8,48 +9,45 @@ const RTE_KEY = '_rte'; const btnState = { ACTIVE: 1, INACTIVE: 0, - DISABLED: -1 + DISABLED: -1, }; const isValidAnchor = rte => { const anchor = rte.selection().anchorNode; const parentNode = anchor && anchor.parentNode; const nextSibling = anchor && anchor.nextSibling; - return ( - (parentNode && parentNode.nodeName == 'A') || - (nextSibling && nextSibling.nodeName == 'A') - ); + return (parentNode && parentNode.nodeName == 'A') || (nextSibling && nextSibling.nodeName == 'A'); }; const defActions = { bold: { name: 'bold', icon: 'B', attributes: { title: 'Bold' }, - result: rte => rte.exec('bold') + result: rte => rte.exec('bold'), }, italic: { name: 'italic', icon: 'I', attributes: { title: 'Italic' }, - result: rte => rte.exec('italic') + result: rte => rte.exec('italic'), }, underline: { name: 'underline', icon: 'U', attributes: { title: 'Underline' }, - result: rte => rte.exec('underline') + result: rte => rte.exec('underline'), }, strikethrough: { name: 'strikethrough', icon: 'S', attributes: { title: 'Strike-through' }, - result: rte => rte.exec('strikeThrough') + result: rte => rte.exec('strikeThrough'), }, link: { icon: ``, name: 'link', attributes: { style: 'font-size:1.4rem;padding:0 4px 2px;', - title: 'Link' + title: 'Link', }, state: (rte, doc) => { if (rte && rte.selection()) { @@ -64,8 +62,8 @@ const defActions = { } else { rte.insertHTML(`${rte.selection()}`); } - } - } + }, + }, }; export default class RichTextEditor { @@ -89,9 +87,7 @@ export default class RichTextEditor { } return result; }); - const actions = acts.length - ? acts - : Object.keys(defActions).map(a => defActions[a]); + const actions = acts.length ? acts : Object.keys(defActions).map(a => defActions[a]); settings.classes = { ...{ @@ -99,9 +95,9 @@ export default class RichTextEditor { button: 'action', active: 'active', disabled: 'disabled', - inactive: 'inactive' + inactive: 'inactive', }, - ...settings.classes + ...settings.classes, }; const classes = settings.classes; @@ -205,10 +201,7 @@ export default class RichTextEditor { syncActions() { this.getActions().forEach(action => { if (this.settings.actionbar) { - if ( - !action.state || - (action.state && action.state(this, this.doc) >= 0) - ) { + if (!action.state || (action.state && action.state(this, this.doc) >= 0)) { const event = action.event || 'click'; action.btn[`on${event}`] = e => { action.result(this, action); @@ -289,7 +282,6 @@ export default class RichTextEditor { * @param {string} value HTML string */ insertHTML(value) { - let lastNode; const doc = this.doc; const sel = doc.getSelection(); @@ -297,10 +289,13 @@ export default class RichTextEditor { const node = doc.createElement('div'); const range = sel.getRangeAt(0); range.deleteContents(); - node.innerHTML = value; + if (isString(value)) { + node.innerHTML = value; + } else if (value) { + node.appendChild(value); + } Array.prototype.slice.call(node.childNodes).forEach(nd => { range.insertNode(nd); - lastNode = nd; }); sel.removeAllRanges(); diff --git a/src/utils/Sorter.js b/src/utils/Sorter.js index 93a56d4ed..70bbc2f26 100644 --- a/src/utils/Sorter.js +++ b/src/utils/Sorter.js @@ -1051,7 +1051,7 @@ export default Backbone.View.extend({ * @param {Object} pos Object with position coordinates * */ move(dst, src, pos) { - const { em, activeTextModel, dropContent } = this; + const { em, dropContent } = this; const srcEl = getElement(src); const warns = []; const index = pos.method === 'after' ? pos.indexEl + 1 : pos.indexEl; @@ -1059,7 +1059,6 @@ export default Backbone.View.extend({ const targetCollection = $(dst).data('collection'); const { trgModel, srcModel, draggable } = validResult; const droppable = trgModel instanceof Backbone.Collection ? 1 : validResult.droppable; - const isTextableActive = this.isTextableActive(srcModel, trgModel); let modelToDrop, modelTemp, created; if (targetCollection && droppable && draggable) { @@ -1079,18 +1078,16 @@ export default Backbone.View.extend({ opts.avoidUpdateStyle = 1; } - if (isTextableActive) { - const viewActive = activeTextModel.getView(); - activeTextModel.trigger('active'); + if (this.isTextableActive(srcModel, trgModel)) { + trgModel.trigger('active'); const modelEl = srcModel.getEl(); delete srcModel.opt.temporary; srcModel.getView().render(); modelEl.setAttribute('data-gjs-textable', 'true'); - const { outerHTML } = modelEl; - activeTextModel.once('rte:enable', () => { - const rte = viewActive.activeRte; - rte.insertHTML && rte.insertHTML(outerHTML); - viewActive.disableEditing({ keepIds: getComponentIds(srcModel) }); + trgModel.once('rte:enable', () => { + const trgView = trgModel.getView(); + trgView.activeRte?.insertHTML(modelEl); + trgView.disableEditing({ keepIds: getComponentIds(srcModel) }); }); created = srcModel; } else {