Skip to content

Commit

Permalink
Fix built-in RTE with custom rendered components. Closes #5536
Browse files Browse the repository at this point in the history
  • Loading branch information
artf committed Nov 29, 2023
1 parent 6edc196 commit 2ce7414
Show file tree
Hide file tree
Showing 5 changed files with 30 additions and 40 deletions.
5 changes: 2 additions & 3 deletions src/dom_components/view/ComponentTextView.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,8 @@ import { ObjectAny } from '../../common';
import RichTextEditorModule from '../../rich_text_editor';
import RichTextEditor from '../../rich_text_editor/model/RichTextEditor';
import { off, on } from '../../utils/dom';
import { getModel } from '../../utils/mixins';
import { getComponentModel } from '../../utils/mixins';
import Component from '../model/Component';
import ComponentText from '../model/ComponentText';
import { getComponentIds } from '../model/Components';
import { ComponentDefinition } from '../model/types';
import ComponentView from './ComponentView';
Expand Down Expand Up @@ -180,7 +179,7 @@ export default class ComponentTextView extends ComponentView {
const range = selection.getRangeAt(0);
const textNode = range.startContainer;
const offset = range.startOffset;
const textModel = getModel(textNode) as ComponentText;
const textModel = getComponentModel(textNode);
const newCmps: (ComponentDefinition | Component)[] = [];

if (textModel && textModel.is?.('textnode')) {
Expand Down
53 changes: 22 additions & 31 deletions src/editor/model/Editor.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import { isUndefined, isArray, contains, toArray, keys, bindAll } from 'undersco
import Backbone from 'backbone';
import $ from '../../utils/cash-dom';
import Extender from '../../utils/extender';
import { getModel, hasWin, isEmptyObj, wait } from '../../utils/mixins';
import { hasWin, isEmptyObj, wait } from '../../utils/mixins';
import { AddOptions, Model, ObjectAny } from '../../common';
import Selected from './Selected';
import FrameView from '../../canvas/view/FrameView';
Expand Down Expand Up @@ -475,27 +475,26 @@ export default class EditorModel extends Model {

/**
* Select a component
* @param {Component|HTMLElement} el Component to select
* @param {Component} el Component to select
* @param {Object} [opts={}] Options, optional
* @public
*/
setSelected(el?: Component | Component[], opts: any = {}) {
const { event } = opts;
const ctrlKey = event && (event.ctrlKey || event.metaKey);
const { shiftKey } = event || {};
const els = (isArray(el) ? el : [el]).map(el => getModel(el, $)).map(cmp => cmp?.delegate?.select?.(cmp) || cmp);
const models = (isArray(el) ? el : [el])
.map(cmp => cmp?.delegate?.select?.(cmp) || cmp)
.filter(Boolean) as Component[];
const selected = this.getSelectedAll();
const mltSel = this.getConfig().multipleSelection;
let added;

// If an array is passed remove all selected
// expect those yet to be selected
const multiple = isArray(el);
multiple && this.removeSelected(selected.filter(s => !contains(els, s)));

els.forEach(el => {
let model = getModel(el, undefined);
multiple && this.removeSelected(selected.filter(s => !contains(models, s)));

models.forEach(model => {
if (model) {
this.trigger('component:select:before', model, opts);

Expand Down Expand Up @@ -554,19 +553,17 @@ export default class EditorModel extends Model {

!multiple && this.removeSelected(selected.filter(s => s !== model));
this.addSelected(model, opts);
added = model;
});
}

/**
* Add component to selection
* @param {Component|HTMLElement} el Component to select
* @param {Component|Array<Component>} component Component to select
* @param {Object} [opts={}] Options, optional
* @public
*/
addSelected(el: Component | Component[], opts: any = {}) {
const model = getModel(el, $);
const models: Component[] = isArray(model) ? model : [model];
addSelected(component: Component | Component[], opts: any = {}) {
const models: Component[] = isArray(component) ? component : [component];

models.forEach(model => {
const { selected } = this;
Expand Down Expand Up @@ -594,12 +591,11 @@ export default class EditorModel extends Model {

/**
* Remove component from selection
* @param {Component|HTMLElement} el Component to select
* @param {Component|Array<Component>} component Component to select
* @param {Object} [opts={}] Options, optional
* @public
*/
removeSelected(el: Component | Component[], opts = {}) {
const component = getModel(el, $);
removeSelected(component: Component | Component[], opts = {}) {
this.selected.removeComponent(component, opts);
const cmps: Component[] = isArray(component) ? component : [component];
cmps.forEach(component =>
Expand All @@ -612,13 +608,12 @@ export default class EditorModel extends Model {

/**
* Toggle component selection
* @param {Component|HTMLElement} el Component to select
* @param {Component|Array<Component>} component Component to select
* @param {Object} [opts={}] Options, optional
* @public
*/
toggleSelected(el: Component | Component[], opts: any = {}) {
const model = getModel(el, $);
const models = isArray(model) ? model : [model];
toggleSelected(component: Component | Component[], opts: any = {}) {
const models = isArray(component) ? component : [component];

models.forEach(model => {
if (this.selected.hasComponent(model)) {
Expand All @@ -631,7 +626,7 @@ export default class EditorModel extends Model {

/**
* Hover a component
* @param {Component|HTMLElement} cmp Component to select
* @param {Component|Array<Component>} cmp Component to select
* @param {Object} [opts={}] Options, optional
* @private
*/
Expand Down Expand Up @@ -662,27 +657,23 @@ export default class EditorModel extends Model {
}

const ev = 'component:hover';
let model = getModel(cmp, undefined) as Component | undefined;

if (!model) return;

opts.forceChange && upHovered();
this.trigger(`${ev}:before`, model, opts);
this.trigger(`${ev}:before`, cmp, opts);

// Check for valid hoverable
if (!model.get('hoverable')) {
if (!cmp.get('hoverable')) {
if (opts.useValid && !opts.abort) {
let parent = model.parent();
let parent = cmp.parent();
while (parent && !parent.get('hoverable')) parent = parent.parent();
model = parent;
cmp = parent;
} else {
return;
}
}

if (!opts.abort) {
upHovered(model, opts);
this.trigger(ev, model, opts);
upHovered(cmp, opts);
this.trigger(ev, cmp, opts);
}
}

Expand Down
2 changes: 1 addition & 1 deletion src/navigator/view/ItemView.ts
Original file line number Diff line number Diff line change
Expand Up @@ -377,7 +377,7 @@ export default class ItemView extends View {

setRoot(el: Component | string) {
el = isString(el) ? this.em.getWrapper()?.find(el)[0]! : el;
const model = getModel(el, 0);
const model = getModel(el);
if (!model) return;
this.stopListening();
this.model = model;
Expand Down
4 changes: 2 additions & 2 deletions src/rich_text_editor/model/RichTextEditor.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import { isString } from 'underscore';
import RichTextEditorModule from '..';
import EditorModel from '../../editor/model/Editor';
import { getPointerEvent, off, on } from '../../utils/dom';
import { getModel } from '../../utils/mixins';
import { getComponentModel } from '../../utils/mixins';

export interface RichTextEditorAction {
name: string;
Expand Down Expand Up @@ -416,7 +416,7 @@ export default class RichTextEditor {
const sel = doc.getSelection();

if (sel && sel.rangeCount) {
const model = getModel(el);
const model = getComponentModel(el) || em.getSelected();
const node = doc.createElement('div');
const range = sel.getRangeAt(0);
range.deleteContents();
Expand Down
6 changes: 3 additions & 3 deletions src/utils/mixins.ts
Original file line number Diff line number Diff line change
Expand Up @@ -187,11 +187,11 @@ export const deepMerge = (...args: ObjectAny[]) => {
* @param {HTMLElement|Component} el Component or HTML element
* @return {Component}
*/
const getModel = (el: any, $?: any): Component => {
let model = el;
const getModel = (el: any, $?: any): Component | undefined => {
let model;
if (!$ && el && el.__cashData) {
model = el.__cashData.model;
} else if (isElement(el)) {
} else if ($ && isElement(el)) {
model = $(el).data('model');
}
return model;
Expand Down

0 comments on commit 2ce7414

Please sign in to comment.