mirror of https://github.com/artf/grapesjs.git
3 changed files with 360 additions and 365 deletions
@ -1,350 +0,0 @@ |
|||
/** |
|||
* This module allows to customize the built-in toolbar of the Rich Text Editor and use commands from the [HTML Editing APIs](https://developer.mozilla.org/en-US/docs/Web/API/Document/execCommand).
|
|||
* It's highly recommended to keep this toolbar as small as possible, especially from styling commands (eg. 'fontSize') and leave this task to the Style Manager |
|||
* |
|||
* You can customize the initial state of the module from the editor initialization, by passing the following [Configuration Object](https://github.com/artf/grapesjs/blob/master/src/rich_text_editor/config/config.js)
|
|||
* ```js
|
|||
* const editor = grapesjs.init({ |
|||
* richTextEditor: { |
|||
* // options
|
|||
* } |
|||
* }) |
|||
* ``` |
|||
* |
|||
* Once the editor is instantiated you can use its API and listen to its events. Before using these methods, you should get the module from the instance. |
|||
* |
|||
* ```js
|
|||
* // Listen to events
|
|||
* editor.on('rte:enable', () => { ... }); |
|||
* |
|||
* // Use the API
|
|||
* const rte = editor.RichTextEditor; |
|||
* rte.add(...); |
|||
* ``` |
|||
* |
|||
* ## Available Events |
|||
* * `rte:enable` - RTE enabled. The view, on which RTE is enabled, is passed as an argument |
|||
* * `rte:disable` - RTE disabled. The view, on which RTE is disabled, is passed as an argument |
|||
* |
|||
* ## Methods |
|||
* * [add](#add) |
|||
* * [get](#get) |
|||
* * [getAll](#getall) |
|||
* * [remove](#remove) |
|||
* * [getToolbarEl](#gettoolbarel) |
|||
* |
|||
* @module RichTextEditor |
|||
*/ |
|||
|
|||
import { on, hasWin } from '../utils/mixins'; |
|||
import RichTextEditor from './model/RichTextEditor'; |
|||
import defaults from './config/config'; |
|||
|
|||
const eventsUp = 'change:canvasOffset frame:scroll component:update'; |
|||
|
|||
export default () => { |
|||
let toolbar; |
|||
|
|||
const hideToolbar = () => { |
|||
const style = toolbar.style; |
|||
const size = '-1000px'; |
|||
style.top = size; |
|||
style.left = size; |
|||
style.display = 'none'; |
|||
}; |
|||
|
|||
return { |
|||
customRte: null, |
|||
|
|||
/** |
|||
* Name of the module |
|||
* @type {String} |
|||
* @private |
|||
*/ |
|||
name: 'RichTextEditor', |
|||
|
|||
getConfig() { |
|||
return this.config; |
|||
}, |
|||
|
|||
/** |
|||
* Initialize module. Automatically called with a new instance of the editor |
|||
* @param {Object} opts Options |
|||
* @private |
|||
*/ |
|||
init(opts = {}) { |
|||
const config = { ...defaults, ...opts }; |
|||
const ppfx = config.pStylePrefix; |
|||
|
|||
if (ppfx) { |
|||
config.stylePrefix = ppfx + config.stylePrefix; |
|||
} |
|||
|
|||
this.config = config; |
|||
this.pfx = config.stylePrefix; |
|||
this.em = config.em; |
|||
this.actions = config.actions || []; |
|||
if (!hasWin()) return this; |
|||
toolbar = document.createElement('div'); |
|||
toolbar.className = `${ppfx}rte-toolbar ${ppfx}one-bg`; |
|||
this.initRte(document.createElement('div')); |
|||
|
|||
//Avoid closing on toolbar clicking
|
|||
on(toolbar, 'mousedown', e => e.stopPropagation()); |
|||
return this; |
|||
}, |
|||
|
|||
destroy() { |
|||
this.globalRte?.destroy(); |
|||
this.customRte?.destroy?.(); |
|||
toolbar = 0; |
|||
['actionbar', 'actions', 'em', 'config', 'globalRte', 'lastEl'].map(i => { |
|||
delete this[i]; |
|||
}); |
|||
}, |
|||
|
|||
/** |
|||
* Post render callback |
|||
* @param {View} ev |
|||
* @private |
|||
*/ |
|||
postRender(ev) { |
|||
const canvas = ev.model.get('Canvas'); |
|||
toolbar.style.pointerEvents = 'all'; |
|||
hideToolbar(); |
|||
canvas.getToolsEl().appendChild(toolbar); |
|||
}, |
|||
|
|||
/** |
|||
* Init the built-in RTE |
|||
* @param {HTMLElement} el |
|||
* @return {RichTextEditor} |
|||
* @private |
|||
*/ |
|||
initRte(el) { |
|||
let { globalRte } = this; |
|||
const { em, pfx, actionbar, config } = this; |
|||
const actionbarContainer = toolbar; |
|||
const actions = this.actions || [...config.actions]; |
|||
const classes = { |
|||
actionbar: `${pfx}actionbar`, |
|||
button: `${pfx}action`, |
|||
active: `${pfx}active`, |
|||
inactive: `${pfx}inactive`, |
|||
disabled: `${pfx}disabled`, |
|||
}; |
|||
|
|||
if (!globalRte) { |
|||
globalRte = new RichTextEditor({ |
|||
em, |
|||
el, |
|||
classes, |
|||
actions, |
|||
actionbar, |
|||
actionbarContainer, |
|||
}); |
|||
this.globalRte = globalRte; |
|||
} else { |
|||
globalRte.em = em; |
|||
globalRte.setEl(el); |
|||
} |
|||
|
|||
if (globalRte.actionbar) { |
|||
this.actionbar = globalRte.actionbar; |
|||
} |
|||
|
|||
if (globalRte.actions) { |
|||
this.actions = globalRte.actions; |
|||
} |
|||
|
|||
return globalRte; |
|||
}, |
|||
|
|||
/** |
|||
* Add a new action to the built-in RTE toolbar |
|||
* @param {string} name Action name |
|||
* @param {Object} action Action options |
|||
* @example |
|||
* rte.add('bold', { |
|||
* icon: '<b>B</b>', |
|||
* attributes: {title: 'Bold'}, |
|||
* result: rte => rte.exec('bold') |
|||
* }); |
|||
* rte.add('link', { |
|||
* icon: document.getElementById('t'), |
|||
* attributes: {title: 'Link',} |
|||
* // Example on it's easy to wrap a selected content
|
|||
* result: rte => rte.insertHTML(`<a href="#">${rte.selection()}</a>`) |
|||
* }); |
|||
* // An example with fontSize
|
|||
* rte.add('fontSize', { |
|||
* icon: `<select class="gjs-field">
|
|||
* <option>1</option> |
|||
* <option>4</option> |
|||
* <option>7</option> |
|||
* </select>`, |
|||
* // Bind the 'result' on 'change' listener
|
|||
* event: 'change', |
|||
* result: (rte, action) => rte.exec('fontSize', action.btn.firstChild.value), |
|||
* // Callback on any input change (mousedown, keydown, etc..)
|
|||
* update: (rte, action) => { |
|||
* const value = rte.doc.queryCommandValue(action.name); |
|||
* if (value != 'false') { // value is a string
|
|||
* action.btn.firstChild.value = value; |
|||
* } |
|||
* } |
|||
* }) |
|||
* // An example with state
|
|||
* const isValidAnchor = (rte) => { |
|||
* // a utility function to help determine if the selected is a valid anchor node
|
|||
* const anchor = rte.selection().anchorNode; |
|||
* const parentNode = anchor && anchor.parentNode; |
|||
* const nextSibling = anchor && anchor.nextSibling; |
|||
* return (parentNode && parentNode.nodeName == 'A') || (nextSibling && nextSibling.nodeName == 'A') |
|||
* } |
|||
* rte.add('toggleAnchor', { |
|||
* icon: `<span style="transform:rotate(45deg)">⫘</span>`, |
|||
* state: (rte, doc) => { |
|||
* if (rte && rte.selection()) { |
|||
* // `btnState` is a integer, -1 for disabled, 0 for inactive, 1 for active
|
|||
* return isValidAnchor(rte) ? btnState.ACTIVE : btnState.INACTIVE; |
|||
* } else { |
|||
* return btnState.INACTIVE; |
|||
* } |
|||
* }, |
|||
* result: (rte, action) => { |
|||
* if (isValidAnchor(rte)) { |
|||
* rte.exec('unlink'); |
|||
* } else { |
|||
* rte.insertHTML(`<a class="link" href="">${rte.selection()}</a>`); |
|||
* } |
|||
* } |
|||
* }) |
|||
*/ |
|||
add(name, action = {}) { |
|||
action.name = name; |
|||
this.globalRte?.addAction(action, { sync: 1 }); |
|||
}, |
|||
|
|||
/** |
|||
* Get the action by its name |
|||
* @param {string} name Action name |
|||
* @return {Object} |
|||
* @example |
|||
* const action = rte.get('bold'); |
|||
* // {name: 'bold', ...}
|
|||
*/ |
|||
get(name) { |
|||
let result; |
|||
this.globalRte?.getActions().forEach(action => { |
|||
if (action.name == name) { |
|||
result = action; |
|||
} |
|||
}); |
|||
return result; |
|||
}, |
|||
|
|||
/** |
|||
* Get all actions |
|||
* @return {Array} |
|||
*/ |
|||
getAll() { |
|||
return this.globalRte?.getActions(); |
|||
}, |
|||
|
|||
/** |
|||
* Remove the action from the toolbar |
|||
* @param {string} name |
|||
* @return {Object} Removed action |
|||
* @example |
|||
* const action = rte.remove('bold'); |
|||
* // {name: 'bold', ...}
|
|||
*/ |
|||
remove(name) { |
|||
const actions = this.getAll(); |
|||
const action = this.get(name); |
|||
|
|||
if (action) { |
|||
const btn = action.btn; |
|||
const index = actions.indexOf(action); |
|||
btn.parentNode.removeChild(btn); |
|||
actions.splice(index, 1); |
|||
} |
|||
|
|||
return action; |
|||
}, |
|||
|
|||
/** |
|||
* Get the toolbar element |
|||
* @return {HTMLElement} |
|||
*/ |
|||
getToolbarEl() { |
|||
return toolbar; |
|||
}, |
|||
|
|||
/** |
|||
* Triggered when the offset of the editor is changed |
|||
* @private |
|||
*/ |
|||
updatePosition() { |
|||
const { em } = this; |
|||
const un = 'px'; |
|||
const canvas = em.get('Canvas'); |
|||
const { style } = toolbar; |
|||
const pos = canvas.getTargetToElementFixed(this.lastEl, toolbar, { |
|||
event: 'rteToolbarPosUpdate', |
|||
left: 0, |
|||
}); |
|||
style.top = (pos.top || 0) + un; |
|||
style.left = (pos.left || 0) + un; |
|||
}, |
|||
|
|||
/** |
|||
* Enable rich text editor on the element |
|||
* @param {View} view Component view |
|||
* @param {Object} rte The instance of already defined RTE |
|||
* @private |
|||
* */ |
|||
async enable(view, rte, opts) { |
|||
this.lastEl = view.el; |
|||
const { customRte, em } = this; |
|||
const el = view.getChildrenContainer(); |
|||
|
|||
toolbar.style.display = ''; |
|||
const rteInst = await (customRte ? customRte.enable(el, rte) : this.initRte(el).enable(opts)); |
|||
|
|||
if (em) { |
|||
setTimeout(this.updatePosition.bind(this), 0); |
|||
em.off(eventsUp, this.updatePosition, this); |
|||
em.on(eventsUp, this.updatePosition, this); |
|||
em.trigger('rte:enable', view, rteInst); |
|||
} |
|||
|
|||
return rteInst; |
|||
}, |
|||
|
|||
/** |
|||
* Unbind rich text editor from the element |
|||
* @param {View} view |
|||
* @param {Object} rte The instance of already defined RTE |
|||
* @private |
|||
* */ |
|||
disable(view, rte) { |
|||
const { em } = this; |
|||
const customRte = this.customRte; |
|||
var el = view.getChildrenContainer(); |
|||
|
|||
if (customRte) { |
|||
customRte.disable(el, rte); |
|||
} else { |
|||
rte && rte.disable(); |
|||
} |
|||
|
|||
hideToolbar(); |
|||
if (em) { |
|||
em.off(eventsUp, this.updatePosition, this); |
|||
em.trigger('rte:disable', view, rte); |
|||
} |
|||
}, |
|||
}; |
|||
}; |
|||
@ -0,0 +1,345 @@ |
|||
/** |
|||
* This module allows to customize the built-in toolbar of the Rich Text Editor and use commands from the [HTML Editing APIs](https://developer.mozilla.org/en-US/docs/Web/API/Document/execCommand).
|
|||
* It's highly recommended to keep this toolbar as small as possible, especially from styling commands (eg. 'fontSize') and leave this task to the Style Manager |
|||
* |
|||
* You can customize the initial state of the module from the editor initialization, by passing the following [Configuration Object](https://github.com/artf/grapesjs/blob/master/src/rich_text_editor/config/config.ts)
|
|||
* ```js
|
|||
* const editor = grapesjs.init({ |
|||
* richTextEditor: { |
|||
* // options
|
|||
* } |
|||
* }) |
|||
* ``` |
|||
* |
|||
* Once the editor is instantiated you can use its API and listen to its events. Before using these methods, you should get the module from the instance. |
|||
* |
|||
* ```js
|
|||
* // Listen to events
|
|||
* editor.on('rte:enable', () => { ... }); |
|||
* |
|||
* // Use the API
|
|||
* const rte = editor.RichTextEditor; |
|||
* rte.add(...); |
|||
* ``` |
|||
* |
|||
* ## Available Events |
|||
* * `rte:enable` - RTE enabled. The view, on which RTE is enabled, is passed as an argument |
|||
* * `rte:disable` - RTE disabled. The view, on which RTE is disabled, is passed as an argument |
|||
* |
|||
* ## Methods |
|||
* * [add](#add) |
|||
* * [get](#get) |
|||
* * [getAll](#getall) |
|||
* * [remove](#remove) |
|||
* * [getToolbarEl](#gettoolbarel) |
|||
* |
|||
* @module RichTextEditor |
|||
*/ |
|||
|
|||
import { on, hasWin } from '../utils/mixins'; |
|||
import RichTextEditor, { RichTextEditorAction } from './model/RichTextEditor'; |
|||
import defaults, { RichTextEditorConfig } from './config/config'; |
|||
import { Module } from '../abstract'; |
|||
import EditorModel from '../editor/model/Editor'; |
|||
import { removeEl } from '../utils/dom'; |
|||
import ComponentView from '../dom_components/view/ComponentView'; |
|||
|
|||
const eventsUp = 'change:canvasOffset frame:scroll component:update'; |
|||
|
|||
export interface CustomRTE<T = any> { |
|||
enable: (el: HTMLElement, rte: T) => T; |
|||
disable: (el: HTMLElement, rte: T) => T; |
|||
destroy?: () => void; |
|||
} |
|||
|
|||
export default class RichTextEditorModule extends Module<RichTextEditorConfig & { pStylePrefix?: string }> { |
|||
pfx: string; |
|||
toolbar!: HTMLElement; |
|||
globalRte?: RichTextEditor; |
|||
actionbar?: HTMLElement; |
|||
lastEl?: HTMLElement; |
|||
actions?: (RichTextEditorAction | string)[]; |
|||
customRte?: CustomRTE; |
|||
|
|||
getConfig() { |
|||
return this.config; |
|||
} |
|||
|
|||
constructor(em: EditorModel) { |
|||
super(em, 'RichTextEditor', defaults); |
|||
const { config } = this; |
|||
const ppfx = config.pStylePrefix; |
|||
// if (ppfx) {
|
|||
// config.stylePrefix = ppfx + config.stylePrefix;
|
|||
// }
|
|||
|
|||
this.pfx = config.stylePrefix!; |
|||
this.actions = config.actions || []; |
|||
if (!hasWin()) return this; |
|||
const toolbar = document.createElement('div'); |
|||
toolbar.className = `${ppfx}rte-toolbar ${ppfx}one-bg`; |
|||
this.toolbar = toolbar; |
|||
this.initRte(document.createElement('div')); |
|||
|
|||
//Avoid closing on toolbar clicking
|
|||
on(toolbar, 'mousedown', e => e.stopPropagation()); |
|||
} |
|||
|
|||
destroy() { |
|||
this.globalRte?.destroy(); |
|||
this.customRte?.destroy?.(); |
|||
removeEl(this.toolbar); |
|||
} |
|||
|
|||
/** |
|||
* Post render callback |
|||
* @param {View} ev |
|||
* @private |
|||
*/ |
|||
postRender(ev: any) { |
|||
const canvas = ev.model.get('Canvas'); |
|||
this.toolbar.style.pointerEvents = 'all'; |
|||
this.hideToolbar(); |
|||
canvas.getToolsEl().appendChild(this.toolbar); |
|||
} |
|||
|
|||
/** |
|||
* Init the built-in RTE |
|||
* @param {HTMLElement} el |
|||
* @return {RichTextEditor} |
|||
* @private |
|||
*/ |
|||
initRte(el: HTMLElement) { |
|||
let { globalRte } = this; |
|||
const { em, pfx, actionbar, config } = this; |
|||
const actions = this.actions || [...config.actions!]; |
|||
const classes = { |
|||
actionbar: `${pfx}actionbar`, |
|||
button: `${pfx}action`, |
|||
active: `${pfx}active`, |
|||
inactive: `${pfx}inactive`, |
|||
disabled: `${pfx}disabled`, |
|||
}; |
|||
|
|||
if (!globalRte) { |
|||
globalRte = new RichTextEditor(em, el, { |
|||
classes, |
|||
actions, |
|||
actionbar, |
|||
actionbarContainer: this.toolbar, |
|||
}); |
|||
this.globalRte = globalRte; |
|||
} else { |
|||
globalRte.em = em; |
|||
globalRte.setEl(el); |
|||
} |
|||
|
|||
if (globalRte.actionbar) { |
|||
this.actionbar = globalRte.actionbar; |
|||
} |
|||
|
|||
if (globalRte.actions) { |
|||
this.actions = globalRte.actions; |
|||
} |
|||
|
|||
return globalRte; |
|||
} |
|||
|
|||
/** |
|||
* Add a new action to the built-in RTE toolbar |
|||
* @param {string} name Action name |
|||
* @param {Object} action Action options |
|||
* @example |
|||
* rte.add('bold', { |
|||
* icon: '<b>B</b>', |
|||
* attributes: {title: 'Bold'}, |
|||
* result: rte => rte.exec('bold') |
|||
* }); |
|||
* rte.add('link', { |
|||
* icon: document.getElementById('t'), |
|||
* attributes: {title: 'Link',} |
|||
* // Example on it's easy to wrap a selected content
|
|||
* result: rte => rte.insertHTML(`<a href="#">${rte.selection()}</a>`) |
|||
* }); |
|||
* // An example with fontSize
|
|||
* rte.add('fontSize', { |
|||
* icon: `<select class="gjs-field">
|
|||
* <option>1</option> |
|||
* <option>4</option> |
|||
* <option>7</option> |
|||
* </select>`,
|
|||
* // Bind the 'result' on 'change' listener
|
|||
* event: 'change', |
|||
* result: (rte, action) => rte.exec('fontSize', action.btn.firstChild.value), |
|||
* // Callback on any input change (mousedown, keydown, etc..)
|
|||
* update: (rte, action) => { |
|||
* const value = rte.doc.queryCommandValue(action.name); |
|||
* if (value != 'false') { // value is a string
|
|||
* action.btn.firstChild.value = value; |
|||
* } |
|||
* } |
|||
* }) |
|||
* // An example with state
|
|||
* const isValidAnchor = (rte) => { |
|||
* // a utility function to help determine if the selected is a valid anchor node
|
|||
* const anchor = rte.selection().anchorNode; |
|||
* const parentNode = anchor && anchor.parentNode; |
|||
* const nextSibling = anchor && anchor.nextSibling; |
|||
* return (parentNode && parentNode.nodeName == 'A') || (nextSibling && nextSibling.nodeName == 'A') |
|||
* } |
|||
* rte.add('toggleAnchor', { |
|||
* icon: `<span style="transform:rotate(45deg)">⫘</span>`, |
|||
* state: (rte, doc) => { |
|||
* if (rte && rte.selection()) { |
|||
* // `btnState` is a integer, -1 for disabled, 0 for inactive, 1 for active
|
|||
* return isValidAnchor(rte) ? btnState.ACTIVE : btnState.INACTIVE; |
|||
* } else { |
|||
* return btnState.INACTIVE; |
|||
* } |
|||
* }, |
|||
* result: (rte, action) => { |
|||
* if (isValidAnchor(rte)) { |
|||
* rte.exec('unlink'); |
|||
* } else { |
|||
* rte.insertHTML(`<a class="link" href="">${rte.selection()}</a>`); |
|||
* } |
|||
* } |
|||
* }) |
|||
*/ |
|||
add(name: string, action: Partial<RichTextEditorAction> = {}) { |
|||
action.name = name; |
|||
this.globalRte?.addAction(action as RichTextEditorAction, { sync: true }); |
|||
} |
|||
|
|||
/** |
|||
* Get the action by its name |
|||
* @param {string} name Action name |
|||
* @return {Object} |
|||
* @example |
|||
* const action = rte.get('bold'); |
|||
* // {name: 'bold', ...}
|
|||
*/ |
|||
get(name: string): RichTextEditorAction | undefined { |
|||
let result; |
|||
this.globalRte?.getActions().forEach(action => { |
|||
if (action.name == name) { |
|||
result = action; |
|||
} |
|||
}); |
|||
return result; |
|||
} |
|||
|
|||
/** |
|||
* Get all actions |
|||
* @return {Array} |
|||
*/ |
|||
getAll() { |
|||
return this.globalRte?.getActions() || []; |
|||
} |
|||
|
|||
/** |
|||
* Remove the action from the toolbar |
|||
* @param {string} name |
|||
* @return {Object} Removed action |
|||
* @example |
|||
* const action = rte.remove('bold'); |
|||
* // {name: 'bold', ...}
|
|||
*/ |
|||
remove(name: string) { |
|||
const actions = this.getAll(); |
|||
const action = this.get(name); |
|||
|
|||
if (action) { |
|||
const btn = action.btn; |
|||
const index = actions.indexOf(action); |
|||
btn?.parentNode?.removeChild(btn); |
|||
actions.splice(index, 1); |
|||
} |
|||
|
|||
return action; |
|||
} |
|||
|
|||
/** |
|||
* Get the toolbar element |
|||
* @return {HTMLElement} |
|||
*/ |
|||
getToolbarEl() { |
|||
return toolbar; |
|||
} |
|||
|
|||
/** |
|||
* Triggered when the offset of the editor is changed |
|||
* @private |
|||
*/ |
|||
updatePosition() { |
|||
const { em } = this; |
|||
const un = 'px'; |
|||
const canvas = em.get('Canvas'); |
|||
const { style } = this.toolbar; |
|||
const pos = canvas.getTargetToElementFixed(this.lastEl, toolbar, { |
|||
event: 'rteToolbarPosUpdate', |
|||
left: 0, |
|||
}); |
|||
style.top = (pos.top || 0) + un; |
|||
style.left = (pos.left || 0) + un; |
|||
} |
|||
|
|||
/** |
|||
* Enable rich text editor on the element |
|||
* @param {View} view Component view |
|||
* @param {Object} rte The instance of already defined RTE |
|||
* @private |
|||
* */ |
|||
async enable(view: ComponentView, rte: RichTextEditor, opts: any = {}) { |
|||
this.lastEl = view.el; |
|||
const { customRte, em } = this; |
|||
// @ts-ignore
|
|||
const el = view.getChildrenContainer(); |
|||
|
|||
this.toolbar.style.display = ''; |
|||
const rteInst = await (customRte ? customRte.enable(el, rte) : this.initRte(el).enable(opts)); |
|||
|
|||
if (em) { |
|||
setTimeout(this.updatePosition.bind(this), 0); |
|||
em.off(eventsUp, this.updatePosition, this); |
|||
em.on(eventsUp, this.updatePosition, this); |
|||
em.trigger('rte:enable', view, rteInst); |
|||
} |
|||
|
|||
return rteInst; |
|||
} |
|||
|
|||
hideToolbar() { |
|||
const style = this.toolbar.style; |
|||
const size = '-1000px'; |
|||
style.top = size; |
|||
style.left = size; |
|||
style.display = 'none'; |
|||
} |
|||
|
|||
/** |
|||
* Unbind rich text editor from the element |
|||
* @param {View} view |
|||
* @param {Object} rte The instance of already defined RTE |
|||
* @private |
|||
* */ |
|||
disable(view: ComponentView, rte: RichTextEditor) { |
|||
const { em } = this; |
|||
const customRte = this.customRte; |
|||
// @ts-ignore
|
|||
const el = view.getChildrenContainer(); |
|||
|
|||
if (customRte) { |
|||
customRte.disable(el, rte); |
|||
} else { |
|||
rte && rte.disable(); |
|||
} |
|||
|
|||
this.hideToolbar(); |
|||
|
|||
if (em) { |
|||
em.off(eventsUp, this.updatePosition, this); |
|||
em.trigger('rte:disable', view, rte); |
|||
} |
|||
} |
|||
} |
|||
Loading…
Reference in new issue