Socket
Socket
Sign inDemoInstall

@ckeditor/ckeditor5-editor-multi-root

Package Overview
Dependencies
Maintainers
1
Versions
557
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@ckeditor/ckeditor5-editor-multi-root - npm Package Compare versions

Comparing version 37.0.0-alpha.3 to 37.0.0-rc.0

src/augmentation.d.ts

2

build/editor-multi-root.js
/*!
* @license Copyright (c) 2003-2023, CKSource Holding sp. z o.o. All rights reserved.
* For licensing, see LICENSE.md.
*/(()=>{var t={704:(t,e,o)=>{t.exports=o(79)("./src/core.js")},492:(t,e,o)=>{t.exports=o(79)("./src/engine.js")},273:(t,e,o)=>{t.exports=o(79)("./src/ui.js")},209:(t,e,o)=>{t.exports=o(79)("./src/utils.js")},434:(t,e,o)=>{t.exports=o(79)("./src/watchdog.js")},79:t=>{"use strict";t.exports=CKEditor5.dll}},e={};function o(i){var r=e[i];if(void 0!==r)return r.exports;var n=e[i]={exports:{}};return t[i](n,n.exports,o),n.exports}o.d=(t,e)=>{for(var i in e)o.o(e,i)&&!o.o(t,i)&&Object.defineProperty(t,i,{enumerable:!0,get:e[i]})},o.o=(t,e)=>Object.prototype.hasOwnProperty.call(t,e),o.r=t=>{"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(t,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(t,"__esModule",{value:!0})};var i={};(()=>{"use strict";o.r(i),o.d(i,{MultiRootEditor:()=>W});var t=o(704),e=o(209),r=o(434),n=o(273),s=o(492);class c extends n.EditorUI{constructor(t,e){super(t),this.view=e}init(){const t=this.view,e=this.editor.editing.view;let o;for(const e of Object.keys(t.editables))t.editables[e].name=e;t.render(),this.focusTracker.on("change:focusedElement",((t,e,i)=>{for(const t of Object.values(this.view.editables))i===t.element&&(o=t.element)})),this.focusTracker.on("change:isFocused",((t,e,i)=>{i||(o=null)}));for(const t of Object.values(this.view.editables)){const i=t.element;this.setEditableElement(t.name,i),t.bind("isFocused").to(this.focusTracker,"isFocused",this.focusTracker,"focusedElement",((t,e)=>!!t&&(e===i||o===i))),e.attachDomRoot(i,t.name)}this._initPlaceholder(),this._initToolbar(),this.fire("ready")}destroy(){super.destroy();const t=this.view,e=this.editor.editing.view;for(const t of Object.values(this.view.editables))e.detachDomRoot(t.name);t.destroy()}_initToolbar(){const t=this.editor,e=this.view;e.toolbar.fillFromConfig(t.config.get("toolbar"),this.componentFactory),this.addToolbar(e.toolbar)}_initPlaceholder(){const t=this.editor,e=t.editing.view,o=t.config.get("placeholder");if(o)for(const t of Object.values(this.view.editables)){const i=e.document.getRoot(t.name),r="string"==typeof o?o:o[t.name];r&&(0,s.enablePlaceholder)({view:e,element:i,text:r,isDirectHost:!1,keepOnFocus:!0})}}}class l extends n.EditorUIView{constructor(t,e,o,i={}){super(t);const r=t.t;this.toolbar=new n.ToolbarView(t,{shouldGroupWhenFull:i.shouldToolbarGroupWhenFull}),this.editables={};for(const s of o){const o=new n.InlineEditableUIView(t,e,i.editableElements?i.editableElements[s]:void 0,{label:t=>r("Rich Text Editor. Editing area: %0",t.name)});this.editables[s]=o}this.editable=Object.values(this.editables)[0],this.toolbar.extendTemplate({attributes:{class:["ck-reset_all","ck-rounded-corners"],dir:t.uiLanguageDirection}})}render(){super.render(),this.registerChild(Object.values(this.editables)),this.registerChild([this.toolbar])}}const a=function(t){return null!=t&&"object"==typeof t};const d="object"==typeof global&&global&&global.Object===Object&&global;var u="object"==typeof self&&self&&self.Object===Object&&self;const h=(d||u||Function("return this")()).Symbol;var f=Object.prototype,b=f.hasOwnProperty,g=f.toString,p=h?h.toStringTag:void 0;const v=function(t){var e=b.call(t,p),o=t[p];try{t[p]=void 0;var i=!0}catch(t){}var r=g.call(t);return i&&(e?t[p]=o:delete t[p]),r};var m=Object.prototype.toString;const y=function(t){return m.call(t)};var j="[object Null]",w="[object Undefined]",E=h?h.toStringTag:void 0;const O=function(t){return null==t?void 0===t?w:j:E&&E in Object(t)?v(t):y(t)};const x=function(t,e){return function(o){return t(e(o))}}(Object.getPrototypeOf,Object);var T="[object Object]",D=Function.prototype,F=Object.prototype,S=D.toString,C=F.hasOwnProperty,P=S.call(Object);const k=function(t){if(!a(t)||O(t)!=T)return!1;var e=x(t);if(null===e)return!0;var o=C.call(e,"constructor")&&e.constructor;return"function"==typeof o&&o instanceof o&&S.call(o)==P};const R=function(t){return a(t)&&1===t.nodeType&&!k(t)};class W extends((0,t.DataApiMixin)(t.Editor)){constructor(o,i={}){const r=Object.keys(o),n=0===r.length||"string"==typeof o[r[0]];if(n&&void 0!==i.initialData)throw new e.CKEditorError("editor-create-initial-data",null);if(super(i),n||(this.sourceElements=o),void 0===this.config.get("initialData")){const t={};for(const i of r)t[i]=_(s=o[i])?(0,e.getDataFromElement)(s):s;this.config.set("initialData",t)}var s;if(!n)for(const e of r)(0,t.secureSourceElement)(this,o[e]);for(const t of r)this.model.document.createRoot("$root",t);const a={shouldToolbarGroupWhenFull:!this.config.get("toolbar.shouldNotGroupWhenFull"),editableElements:n?void 0:o},d=new l(this.locale,this.editing.view,r,a);this.ui=new c(this,d)}destroy(){const t=this.config.get("updateSourceElementOnDestroy"),o={};if(this.sourceElements)for(const e of Object.keys(this.sourceElements))o[e]=t?this.getData({rootName:e}):"";return this.ui.destroy(),super.destroy().then((()=>{if(this.sourceElements)for(const t of Object.keys(this.sourceElements))(0,e.setDataInElement)(this.sourceElements[t],o[t])}))}static create(t,o={}){return new Promise((i=>{for(const o of Object.values(t))if(_(o)&&"TEXTAREA"===o.tagName)throw new e.CKEditorError("editor-wrong-element",null);const r=new this(t,o);i(r.initPlugins().then((()=>r.ui.init())).then((()=>r.data.init(r.config.get("initialData")))).then((()=>r.fire("ready"))).then((()=>r)))}))}}function _(t){return R(t)}W.Context=t.Context,W.EditorWatchdog=r.EditorWatchdog,W.ContextWatchdog=r.ContextWatchdog})(),(window.CKEditor5=window.CKEditor5||{}).editorMultiRoot=i})();
*/(()=>{var t={704:(t,e,o)=>{t.exports=o(79)("./src/core.js")},492:(t,e,o)=>{t.exports=o(79)("./src/engine.js")},273:(t,e,o)=>{t.exports=o(79)("./src/ui.js")},209:(t,e,o)=>{t.exports=o(79)("./src/utils.js")},434:(t,e,o)=>{t.exports=o(79)("./src/watchdog.js")},79:t=>{"use strict";t.exports=CKEditor5.dll}},e={};function o(i){var s=e[i];if(void 0!==s)return s.exports;var r=e[i]={exports:{}};return t[i](r,r.exports,o),r.exports}o.d=(t,e)=>{for(var i in e)o.o(e,i)&&!o.o(t,i)&&Object.defineProperty(t,i,{enumerable:!0,get:e[i]})},o.o=(t,e)=>Object.prototype.hasOwnProperty.call(t,e),o.r=t=>{"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(t,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(t,"__esModule",{value:!0})};var i={};(()=>{"use strict";o.r(i),o.d(i,{MultiRootEditor:()=>A});var t=o(704),e=o(209),s=o(434),r=o(273),n=o(492);class a extends r.EditorUI{constructor(t,e){super(t),this.view=e,this._lastFocusedEditableElement=null}init(){this.view.render(),this.focusTracker.on("change:focusedElement",((t,e,o)=>{for(const t of Object.values(this.view.editables))o===t.element&&(this._lastFocusedEditableElement=t.element)})),this.focusTracker.on("change:isFocused",((t,e,o)=>{o||(this._lastFocusedEditableElement=null)}));for(const t of Object.values(this.view.editables))this.addEditable(t);this._initToolbar(),this.fire("ready")}addEditable(t,e){const o=t.element;this.editor.editing.view.attachDomRoot(o,t.name),this.setEditableElement(t.name,o),t.bind("isFocused").to(this.focusTracker,"isFocused",this.focusTracker,"focusedElement",((t,e)=>!!t&&(e===o||this._lastFocusedEditableElement===o))),this._initPlaceholder(t,e)}removeEditable(t){this.editor.editing.view.detachDomRoot(t.name),t.unbind("isFocused"),this.removeEditableElement(t.name)}destroy(){super.destroy();for(const t of Object.values(this.view.editables))this.removeEditable(t);this.view.destroy()}_initToolbar(){const t=this.editor,e=this.view;e.toolbar.fillFromConfig(t.config.get("toolbar"),this.componentFactory),this.addToolbar(e.toolbar)}_initPlaceholder(t,e){if(!e){const o=this.editor.config.get("placeholder");o&&(e="string"==typeof o?o:o[t.name])}if(!e)return;const o=this.editor.editing.view,i=o.document.getRoot(t.name);(0,n.enablePlaceholder)({view:o,element:i,text:e,isDirectHost:!1,keepOnFocus:!0})}}class c extends r.EditorUIView{constructor(t,e,o,i={}){super(t),this._editingView=e,this.toolbar=new r.ToolbarView(t,{shouldGroupWhenFull:i.shouldToolbarGroupWhenFull}),this.editables={};for(const t of o){const e=i.editableElements?i.editableElements[t]:void 0;this.createEditable(t,e)}this.editable=Object.values(this.editables)[0],this.toolbar.extendTemplate({attributes:{class:["ck-reset_all","ck-rounded-corners"],dir:t.uiLanguageDirection}})}createEditable(t,e){const o=this.locale.t,i=new r.InlineEditableUIView(this.locale,this._editingView,e,{label:t=>o("Rich Text Editor. Editing area: %0",t.name)});return this.editables[t]=i,i.name=t,this.isRendered&&this.registerChild(i),i}removeEditable(t){const e=this.editables[t];this.isRendered&&this.deregisterChild(e),delete this.editables[t],e.destroy()}render(){super.render(),this.registerChild(Object.values(this.editables)),this.registerChild(this.toolbar)}}const l=function(t){return null!=t&&"object"==typeof t};const d="object"==typeof global&&global&&global.Object===Object&&global;var u="object"==typeof self&&self&&self.Object===Object&&self;const h=(d||u||Function("return this")()).Symbol;var b=Object.prototype,f=b.hasOwnProperty,m=b.toString,g=h?h.toStringTag:void 0;const E=function(t){var e=f.call(t,g),o=t[g];try{t[g]=void 0;var i=!0}catch(t){}var s=m.call(t);return i&&(e?t[g]=o:delete t[g]),s};var v=Object.prototype.toString;const p=function(t){return v.call(t)};var y=h?h.toStringTag:void 0;const w=function(t){return null==t?void 0===t?"[object Undefined]":"[object Null]":y&&y in Object(t)?E(t):p(t)};const j=function(t,e){return function(o){return t(e(o))}}(Object.getPrototypeOf,Object);var O=Function.prototype,R=Object.prototype,x=O.toString,C=R.hasOwnProperty,F=x.call(Object);const T=function(t){if(!l(t)||"[object Object]"!=w(t))return!1;var e=j(t);if(null===e)return!0;var o=C.call(e,"constructor")&&e.constructor;return"function"==typeof o&&o instanceof o&&x.call(o)==F};const _=function(t){return l(t)&&1===t.nodeType&&!T(t)};class A extends((0,t.DataApiMixin)(t.Editor)){constructor(o,i={}){const s=Object.keys(o),r=0===s.length||"string"==typeof o[s[0]];if(r&&void 0!==i.initialData)throw new e.CKEditorError("editor-create-initial-data",null);if(super(i),this._registeredRootsAttributesKeys=new Set,this.sourceElements=r?{}:o,void 0===this.config.get("initialData")){const t={};for(const i of s)t[i]=D(n=o[i])?(0,e.getDataFromElement)(n):n;this.config.set("initialData",t)}var n;if(!r)for(const e of s)(0,t.secureSourceElement)(this,o[e]);for(const t of s)this.model.document.createRoot("$root",t);if(this.config.get("rootsAttributes")){const t=this.config.get("rootsAttributes");for(const[o,i]of Object.entries(t)){if(!s.includes(o))throw new e.CKEditorError("multi-root-editor-root-attributes-no-root",null);for(const t of Object.keys(i))this._registeredRootsAttributesKeys.add(t)}this.data.on("init",(()=>{this.model.enqueueChange({isUndoable:!1},(e=>{for(const[o,i]of Object.entries(t)){const t=this.model.document.getRoot(o);for(const[o,s]of Object.entries(i))null!==s&&e.setAttribute(o,s,t)}}))}))}const l={shouldToolbarGroupWhenFull:!this.config.get("toolbar.shouldNotGroupWhenFull"),editableElements:r?void 0:o},d=new c(this.locale,this.editing.view,s,l);this.ui=new a(this,d),this.model.document.on("change:data",(()=>{const t=this.model.document.differ.getChangedRoots();for(const e of t){const t=this.model.document.getRoot(e.name);"attached"==e.state?this.fire("addRoot",t):"detached"==e.state&&this.fire("detachRoot",t)}}))}destroy(){const t=this.config.get("updateSourceElementOnDestroy"),o={};if(this.sourceElements)for(const e of Object.keys(this.sourceElements))o[e]=t?this.getData({rootName:e}):"";return this.ui.destroy(),super.destroy().then((()=>{if(this.sourceElements)for(const t of Object.keys(this.sourceElements))(0,e.setDataInElement)(this.sourceElements[t],o[t])}))}addRoot(t,{data:e="",attributes:o={},elementName:i="$root",isUndoable:s=!1}={}){const r=this.data,n=this._registeredRootsAttributesKeys;function a(s){const a=s.addRoot(t,i);e&&s.insert(r.parse(e,a),a,0);for(const t of Object.keys(o))n.add(t),s.setAttribute(t,o[t],a)}s?this.model.change(a):this.model.enqueueChange({isUndoable:!1},a)}detachRoot(t,e=!1){e?this.model.change((e=>e.detachRoot(t))):this.model.enqueueChange({isUndoable:!1},(e=>e.detachRoot(t)))}createEditable(t,e){const o=this.ui.view.createEditable(t.rootName);return this.ui.addEditable(o,e),this.editing.view.forceRender(),o.element}detachEditable(t){const e=t.rootName,o=this.ui.view.editables[e];return this.ui.removeEditable(o),this.ui.view.removeEditable(e),o.element}getFullData(t){const e={};for(const o of this.model.document.getRootNames())e[o]=this.data.get({...t,rootName:o});return e}getRootsAttributes(){const t={},e=Array.from(this._registeredRootsAttributesKeys);for(const o of this.model.document.getRootNames()){t[o]={};const i=this.model.document.getRoot(o);for(const s of e)t[o][s]=i.hasAttribute(s)?i.getAttribute(s):null}return t}static create(t,o={}){return new Promise((i=>{for(const o of Object.values(t))if(D(o)&&"TEXTAREA"===o.tagName)throw new e.CKEditorError("editor-wrong-element",null);const s=new this(t,o);i(s.initPlugins().then((()=>s.ui.init())).then((()=>s.data.init(s.config.get("initialData")))).then((()=>s.fire("ready"))).then((()=>s)))}))}}function D(t){return _(t)}A.Context=t.Context,A.EditorWatchdog=s.EditorWatchdog,A.ContextWatchdog=s.ContextWatchdog})(),(window.CKEditor5=window.CKEditor5||{}).editorMultiRoot=i})();
{
"name": "@ckeditor/ckeditor5-editor-multi-root",
"version": "37.0.0-alpha.3",
"version": "37.0.0-rc.0",
"description": "Multi-root editor implementation for CKEditor 5.",

@@ -14,19 +14,19 @@ "keywords": [

"dependencies": {
"ckeditor5": "^37.0.0-alpha.3",
"ckeditor5": "^37.0.0-rc.0",
"lodash-es": "^4.17.15"
},
"devDependencies": {
"@ckeditor/ckeditor5-basic-styles": "^37.0.0-alpha.3",
"@ckeditor/ckeditor5-core": "^37.0.0-alpha.3",
"@ckeditor/ckeditor5-dev-utils": "^35.0.0",
"@ckeditor/ckeditor5-engine": "^37.0.0-alpha.3",
"@ckeditor/ckeditor5-enter": "^37.0.0-alpha.3",
"@ckeditor/ckeditor5-heading": "^37.0.0-alpha.3",
"@ckeditor/ckeditor5-paragraph": "^37.0.0-alpha.3",
"@ckeditor/ckeditor5-theme-lark": "^37.0.0-alpha.3",
"@ckeditor/ckeditor5-typing": "^37.0.0-alpha.3",
"@ckeditor/ckeditor5-ui": "^37.0.0-alpha.3",
"@ckeditor/ckeditor5-undo": "^37.0.0-alpha.3",
"@ckeditor/ckeditor5-utils": "^37.0.0-alpha.3",
"@ckeditor/ckeditor5-watchdog": "^37.0.0-alpha.3",
"@ckeditor/ckeditor5-basic-styles": "^37.0.0-rc.0",
"@ckeditor/ckeditor5-core": "^37.0.0-rc.0",
"@ckeditor/ckeditor5-dev-utils": "^36.0.0",
"@ckeditor/ckeditor5-engine": "^37.0.0-rc.0",
"@ckeditor/ckeditor5-enter": "^37.0.0-rc.0",
"@ckeditor/ckeditor5-heading": "^37.0.0-rc.0",
"@ckeditor/ckeditor5-paragraph": "^37.0.0-rc.0",
"@ckeditor/ckeditor5-theme-lark": "^37.0.0-rc.0",
"@ckeditor/ckeditor5-typing": "^37.0.0-rc.0",
"@ckeditor/ckeditor5-ui": "^37.0.0-rc.0",
"@ckeditor/ckeditor5-undo": "^37.0.0-rc.0",
"@ckeditor/ckeditor5-utils": "^37.0.0-rc.0",
"@ckeditor/ckeditor5-watchdog": "^37.0.0-rc.0",
"typescript": "^4.8.4",

@@ -37,3 +37,3 @@ "webpack": "^5.58.1",

"engines": {
"node": ">=14.0.0",
"node": ">=16.0.0",
"npm": ">=5.7.1"

@@ -40,0 +40,0 @@ },

@@ -9,1 +9,2 @@ /**

export { default as MultiRootEditor } from './multirooteditor';
import './augmentation';

@@ -9,1 +9,2 @@ /**

export { default as MultiRootEditor } from './multirooteditor';
import './augmentation';

@@ -11,2 +11,3 @@ /**

import MultiRootEditorUI from './multirooteditorui';
import { type RootElement } from 'ckeditor5/src/engine';
declare const MultiRootEditor_base: import("ckeditor5/src/utils").Mixed<typeof Editor, import("ckeditor5/src/core").DataApi>;

@@ -51,4 +52,9 @@ /**

*/
readonly sourceElements: Record<string, HTMLElement> | undefined;
readonly sourceElements: Record<string, HTMLElement>;
/**
* Holds attributes keys that were passed in {@link module:core/editor/editorconfig~EditorConfig#rootsAttributes `rootsAttributes`}
* config property and should be returned by {@link #getRootsAttributes}.
*/
private readonly _registeredRootsAttributesKeys;
/**
* Creates an instance of the multi-root editor.

@@ -91,2 +97,166 @@ *

/**
* Adds a new root to the editor.
*
* ```ts
* editor.addRoot( 'myRoot', { data: '<p>Initial root data.</p>' } );
* ```
*
* After a root is added, you will be able to modify and retrieve its data.
*
* All root names must be unique. An error will be thrown if you will try to create a root with the name same as
* an already existing, attached root. However, you can call this method for a detached root. See also {@link #detachRoot}.
*
* Whenever a root is added, the editor instance will fire {@link #event:addRoot `addRoot` event}. The event is also called when
* the root is added indirectly, e.g. by the undo feature or on a remote client during real-time collaboration.
*
* Note, that this method only adds a root to the editor model. It **does not** create a DOM editable element for the new root.
* Until such element is created (and attached to the root), the root is "virtual": it is not displayed anywhere and its data can
* be changed only using the editor API.
*
* To create a DOM editable element for the root, listen to {@link #event:addRoot `addRoot` event} and call {@link #createEditable}.
* Then, insert the DOM element in a desired place, that will depend on the integration with your application and your requirements.
*
* ```ts
* editor.on( 'addRoot', ( evt, root ) => {
* const editableElement = editor.createEditable( root );
*
* // You may want to create a more complex DOM structure here.
* //
* // Alternatively, you may want to create a DOM structure before
* // calling `editor.addRoot()` and only append `editableElement` at
* // a proper place.
*
* document.querySelector( '#editors' ).appendChild( editableElement );
* } );
*
* // ...
*
* editor.addRoot( 'myRoot' ); // Will create a root, a DOM editable element and append it to `#editors` container element.
* ```
*
* You can set root attributes on the new root while you add it:
*
* ```ts
* // Add a collapsed root at fourth position from top.
* // Keep in mind that these are just examples of attributes. You need to provide your own features that will handle the attributes.
* editor.addRoot( 'myRoot', { attributes: { isCollapsed: true, index: 4 } } );
* ```
*
* See also {@link module:core/editor/editorconfig~EditorConfig#rootsAttributes `rootsAttributes` configuration option}.
*
* Note that attributes keys of attributes added in `attributes` option are also included in {@link #getRootsAttributes} return value.
*
* By setting `isUndoable` flag to `true`, you can allow for detaching the root using the undo feature.
*
* Additionally, you can group adding multiple roots in one undo step. This can be useful if you add multiple roots that are
* combined into one, bigger UI element, and want them all to be undone together.
*
* ```ts
* let rowId = 0;
*
* editor.model.change( () => {
* editor.addRoot( 'left-row-' + rowId, { isUndoable: true } );
* editor.addRoot( 'center-row-' + rowId, { isUndoable: true } );
* editor.addRoot( 'right-row-' + rowId, { isUndoable: true } );
*
* rowId++;
* } );
* ```
*
* @param rootName Name of the root to add.
* @param options Additional options for the added root.
*/
addRoot(rootName: string, { data, attributes, elementName, isUndoable }?: AddRootOptions): void;
/**
* Detaches a root from the editor.
*
* ```ts
* editor.detachRoot( 'myRoot' );
* ```
*
* A detached root is not entirely removed from the editor model, however it can be considered removed.
*
* After a root is detached all its children are removed, all markers inside it are removed, and whenever something is inserted to it,
* it is automatically removed as well. Finally, a detached root is not returned by
* {@link module:engine/model/document~Document#getRootNames} by default.
*
* It is possible to re-add a previously detached root calling {@link #addRoot}.
*
* Whenever a root is detached, the editor instance will fire {@link #event:detachRoot `detachRoot` event}. The event is also
* called when the root is detached indirectly, e.g. by the undo feature or on a remote client during real-time collaboration.
*
* Note, that this method only detached a root in the editor model. It **does not** destroy the DOM editable element linked with
* the root and it **does not** remove the DOM element from the DOM structure of your application.
*
* To properly remove a DOM editable element after a root was detached, listen to {@link #event:detachRoot `detachRoot` event}
* and call {@link #detachEditable}. Then, remove the DOM element from your application.
*
* ```ts
* editor.on( 'detachRoot', ( evt, root ) => {
* const editableElement = editor.detachEditable( root );
*
* // You may want to do an additional DOM clean-up here.
*
* editableElement.remove();
* } );
*
* // ...
*
* editor.detachRoot( 'myRoot' ); // Will detach the root, and remove the DOM editable element.
* ```
*
* By setting `isUndoable` flag to `true`, you can allow for re-adding the root using the undo feature.
*
* Additionally, you can group detaching multiple roots in one undo step. This can be useful if the roots are combined into one,
* bigger UI element, and you want them all to be re-added together.
*
* ```ts
* editor.model.change( () => {
* editor.detachRoot( 'left-row-3', true );
* editor.detachRoot( 'center-row-3', true );
* editor.detachRoot( 'right-row-3', true );
* } );
* ```
*
* @param rootName Name of the root to detach.
* @param isUndoable Whether detaching the root can be undone (using the undo feature) or not.
*/
detachRoot(rootName: string, isUndoable?: boolean): void;
/**
* Creates and returns a new DOM editable element for the given root element.
*
* The new DOM editable is attached to the model root and can be used to modify the root content.
*
* @param root Root for which the editable element should be created.
* @param placeholder Placeholder for the editable element. If not set, placeholder value from the
* {@link module:core/editor/editorconfig~EditorConfig#placeholder editor configuration} will be used (if it was provided).
* @returns The created DOM element. Append it in a desired place in your application.
*/
createEditable(root: RootElement, placeholder?: string): HTMLElement;
/**
* Detaches the DOM editable element that was attached to the given root.
*
* @param root Root for which the editable element should be detached.
* @returns The DOM element that was detached. You may want to remove it from your application DOM structure.
*/
detachEditable(root: RootElement): HTMLElement;
/**
* Returns the document data for all attached roots.
*
* @param options Additional configuration for the retrieved data.
* Editor features may introduce more configuration options that can be set through this parameter.
* @param options.trim Whether returned data should be trimmed. This option is set to `'empty'` by default,
* which means that whenever editor content is considered empty, an empty string is returned. To turn off trimming
* use `'none'`. In such cases exact content will be returned (for example `'<p>&nbsp;</p>'` for an empty editor).
* @returns The full document data.
*/
getFullData(options?: Record<string, unknown>): Record<string, string>;
/**
* Returns currently set roots attributes for attributes specified in
* {@link module:core/editor/editorconfig~EditorConfig#rootsAttributes `rootsAttributes`} configuration option.
*
* @returns Object with roots attributes. Keys are roots names, while values are attributes set on given root.
*/
getRootsAttributes(): Record<string, RootAttributes>;
/**
* Creates a new multi-root editor instance.

@@ -245,2 +415,59 @@ *

}
/**
* Fired whenever a root is {@link ~MultiRootEditor#addRoot added or re-added} to the editor model.
*
* Use this event to {@link ~MultiRootEditor#createEditable create a DOM editable} for the added root and append the DOM element
* in a desired place in your application.
*
* The event is fired after all changes from a given batch are applied. The event is not fired, if the root was added and detached
* in the same batch.
*
* @eventName ~MultiRootEditor#addRoot
* @param root The root that was added.
*/
export type AddRootEvent = {
name: 'addRoot';
args: [root: RootElement];
};
/**
* Fired whenever a root is {@link ~MultiRootEditor#detachRoot detached} from the editor model.
*
* Use this event to {@link ~MultiRootEditor#detachEditable destroy a DOM editable} for the detached root and remove the DOM element
* from your application.
*
* The event is fired after all changes from a given batch are applied. The event is not fired, if the root was detached and re-added
* in the same batch.
*
* @eventName ~MultiRootEditor#detachRoot
* @param root The root that was detached.
*/
export type DetachRootEvent = {
name: 'detachRoot';
args: [root: RootElement];
};
/**
* Additional options available when adding a root.
*/
export type AddRootOptions = {
/**
* Initial data for the root.
*/
data?: string;
/**
* Initial attributes for the root.
*/
attributes?: RootAttributes;
/**
* Element name for the root element in the model. It can be used to set different schema rules for different roots.
*/
elementName?: string;
/**
* Whether creating the root can be undone (using the undo feature) or not.
*/
isUndoable?: boolean;
};
/**
* Attributes set on a model root element.
*/
export type RootAttributes = Record<string, unknown>;
export {};

@@ -65,5 +65,13 @@ /**

super(config);
/**
* Holds attributes keys that were passed in {@link module:core/editor/editorconfig~EditorConfig#rootsAttributes `rootsAttributes`}
* config property and should be returned by {@link #getRootsAttributes}.
*/
this._registeredRootsAttributesKeys = new Set();
if (!sourceIsData) {
this.sourceElements = sourceElementsOrData;
}
else {
this.sourceElements = {};
}
if (this.config.get('initialData') === undefined) {

@@ -86,2 +94,33 @@ // Create initial data object containing data from all roots.

}
if (this.config.get('rootsAttributes')) {
const rootsAttributes = this.config.get('rootsAttributes');
for (const [rootName, attributes] of Object.entries(rootsAttributes)) {
if (!rootNames.includes(rootName)) {
/**
* Trying to set attributes on a non-existing root.
*
* Roots specified in {@link module:core/editor/editorconfig~EditorConfig#rootsAttributes} do not match initial
* editor roots.
*
* @error multi-root-editor-root-attributes-no-root
*/
throw new CKEditorError('multi-root-editor-root-attributes-no-root', null);
}
for (const key of Object.keys(attributes)) {
this._registeredRootsAttributesKeys.add(key);
}
}
this.data.on('init', () => {
this.model.enqueueChange({ isUndoable: false }, writer => {
for (const [name, attributes] of Object.entries(rootsAttributes)) {
const root = this.model.document.getRoot(name);
for (const [key, value] of Object.entries(attributes)) {
if (value !== null) {
writer.setAttribute(key, value, root);
}
}
}
});
});
}
const options = {

@@ -93,2 +132,14 @@ shouldToolbarGroupWhenFull: !this.config.get('toolbar.shouldNotGroupWhenFull'),

this.ui = new MultiRootEditorUI(this, view);
this.model.document.on('change:data', () => {
const changedRoots = this.model.document.differ.getChangedRoots();
for (const changes of changedRoots) {
const root = this.model.document.getRoot(changes.name);
if (changes.state == 'attached') {
this.fire('addRoot', root);
}
else if (changes.state == 'detached') {
this.fire('detachRoot', root);
}
}
});
}

@@ -141,2 +192,220 @@ /**

/**
* Adds a new root to the editor.
*
* ```ts
* editor.addRoot( 'myRoot', { data: '<p>Initial root data.</p>' } );
* ```
*
* After a root is added, you will be able to modify and retrieve its data.
*
* All root names must be unique. An error will be thrown if you will try to create a root with the name same as
* an already existing, attached root. However, you can call this method for a detached root. See also {@link #detachRoot}.
*
* Whenever a root is added, the editor instance will fire {@link #event:addRoot `addRoot` event}. The event is also called when
* the root is added indirectly, e.g. by the undo feature or on a remote client during real-time collaboration.
*
* Note, that this method only adds a root to the editor model. It **does not** create a DOM editable element for the new root.
* Until such element is created (and attached to the root), the root is "virtual": it is not displayed anywhere and its data can
* be changed only using the editor API.
*
* To create a DOM editable element for the root, listen to {@link #event:addRoot `addRoot` event} and call {@link #createEditable}.
* Then, insert the DOM element in a desired place, that will depend on the integration with your application and your requirements.
*
* ```ts
* editor.on( 'addRoot', ( evt, root ) => {
* const editableElement = editor.createEditable( root );
*
* // You may want to create a more complex DOM structure here.
* //
* // Alternatively, you may want to create a DOM structure before
* // calling `editor.addRoot()` and only append `editableElement` at
* // a proper place.
*
* document.querySelector( '#editors' ).appendChild( editableElement );
* } );
*
* // ...
*
* editor.addRoot( 'myRoot' ); // Will create a root, a DOM editable element and append it to `#editors` container element.
* ```
*
* You can set root attributes on the new root while you add it:
*
* ```ts
* // Add a collapsed root at fourth position from top.
* // Keep in mind that these are just examples of attributes. You need to provide your own features that will handle the attributes.
* editor.addRoot( 'myRoot', { attributes: { isCollapsed: true, index: 4 } } );
* ```
*
* See also {@link module:core/editor/editorconfig~EditorConfig#rootsAttributes `rootsAttributes` configuration option}.
*
* Note that attributes keys of attributes added in `attributes` option are also included in {@link #getRootsAttributes} return value.
*
* By setting `isUndoable` flag to `true`, you can allow for detaching the root using the undo feature.
*
* Additionally, you can group adding multiple roots in one undo step. This can be useful if you add multiple roots that are
* combined into one, bigger UI element, and want them all to be undone together.
*
* ```ts
* let rowId = 0;
*
* editor.model.change( () => {
* editor.addRoot( 'left-row-' + rowId, { isUndoable: true } );
* editor.addRoot( 'center-row-' + rowId, { isUndoable: true } );
* editor.addRoot( 'right-row-' + rowId, { isUndoable: true } );
*
* rowId++;
* } );
* ```
*
* @param rootName Name of the root to add.
* @param options Additional options for the added root.
*/
addRoot(rootName, { data = '', attributes = {}, elementName = '$root', isUndoable = false } = {}) {
const dataController = this.data;
const registeredKeys = this._registeredRootsAttributesKeys;
if (isUndoable) {
this.model.change(_addRoot);
}
else {
this.model.enqueueChange({ isUndoable: false }, _addRoot);
}
function _addRoot(writer) {
const root = writer.addRoot(rootName, elementName);
if (data) {
writer.insert(dataController.parse(data, root), root, 0);
}
for (const key of Object.keys(attributes)) {
registeredKeys.add(key);
writer.setAttribute(key, attributes[key], root);
}
}
}
/**
* Detaches a root from the editor.
*
* ```ts
* editor.detachRoot( 'myRoot' );
* ```
*
* A detached root is not entirely removed from the editor model, however it can be considered removed.
*
* After a root is detached all its children are removed, all markers inside it are removed, and whenever something is inserted to it,
* it is automatically removed as well. Finally, a detached root is not returned by
* {@link module:engine/model/document~Document#getRootNames} by default.
*
* It is possible to re-add a previously detached root calling {@link #addRoot}.
*
* Whenever a root is detached, the editor instance will fire {@link #event:detachRoot `detachRoot` event}. The event is also
* called when the root is detached indirectly, e.g. by the undo feature or on a remote client during real-time collaboration.
*
* Note, that this method only detached a root in the editor model. It **does not** destroy the DOM editable element linked with
* the root and it **does not** remove the DOM element from the DOM structure of your application.
*
* To properly remove a DOM editable element after a root was detached, listen to {@link #event:detachRoot `detachRoot` event}
* and call {@link #detachEditable}. Then, remove the DOM element from your application.
*
* ```ts
* editor.on( 'detachRoot', ( evt, root ) => {
* const editableElement = editor.detachEditable( root );
*
* // You may want to do an additional DOM clean-up here.
*
* editableElement.remove();
* } );
*
* // ...
*
* editor.detachRoot( 'myRoot' ); // Will detach the root, and remove the DOM editable element.
* ```
*
* By setting `isUndoable` flag to `true`, you can allow for re-adding the root using the undo feature.
*
* Additionally, you can group detaching multiple roots in one undo step. This can be useful if the roots are combined into one,
* bigger UI element, and you want them all to be re-added together.
*
* ```ts
* editor.model.change( () => {
* editor.detachRoot( 'left-row-3', true );
* editor.detachRoot( 'center-row-3', true );
* editor.detachRoot( 'right-row-3', true );
* } );
* ```
*
* @param rootName Name of the root to detach.
* @param isUndoable Whether detaching the root can be undone (using the undo feature) or not.
*/
detachRoot(rootName, isUndoable = false) {
if (isUndoable) {
this.model.change(writer => writer.detachRoot(rootName));
}
else {
this.model.enqueueChange({ isUndoable: false }, writer => writer.detachRoot(rootName));
}
}
/**
* Creates and returns a new DOM editable element for the given root element.
*
* The new DOM editable is attached to the model root and can be used to modify the root content.
*
* @param root Root for which the editable element should be created.
* @param placeholder Placeholder for the editable element. If not set, placeholder value from the
* {@link module:core/editor/editorconfig~EditorConfig#placeholder editor configuration} will be used (if it was provided).
* @returns The created DOM element. Append it in a desired place in your application.
*/
createEditable(root, placeholder) {
const editable = this.ui.view.createEditable(root.rootName);
this.ui.addEditable(editable, placeholder);
this.editing.view.forceRender();
return editable.element;
}
/**
* Detaches the DOM editable element that was attached to the given root.
*
* @param root Root for which the editable element should be detached.
* @returns The DOM element that was detached. You may want to remove it from your application DOM structure.
*/
detachEditable(root) {
const rootName = root.rootName;
const editable = this.ui.view.editables[rootName];
this.ui.removeEditable(editable);
this.ui.view.removeEditable(rootName);
return editable.element;
}
/**
* Returns the document data for all attached roots.
*
* @param options Additional configuration for the retrieved data.
* Editor features may introduce more configuration options that can be set through this parameter.
* @param options.trim Whether returned data should be trimmed. This option is set to `'empty'` by default,
* which means that whenever editor content is considered empty, an empty string is returned. To turn off trimming
* use `'none'`. In such cases exact content will be returned (for example `'<p>&nbsp;</p>'` for an empty editor).
* @returns The full document data.
*/
getFullData(options) {
const data = {};
for (const rootName of this.model.document.getRootNames()) {
data[rootName] = this.data.get({ ...options, rootName });
}
return data;
}
/**
* Returns currently set roots attributes for attributes specified in
* {@link module:core/editor/editorconfig~EditorConfig#rootsAttributes `rootsAttributes`} configuration option.
*
* @returns Object with roots attributes. Keys are roots names, while values are attributes set on given root.
*/
getRootsAttributes() {
const rootsAttributes = {};
const keys = Array.from(this._registeredRootsAttributesKeys);
for (const rootName of this.model.document.getRootNames()) {
rootsAttributes[rootName] = {};
const root = this.model.document.getRoot(rootName);
for (const key of keys) {
rootsAttributes[rootName][key] = root.hasAttribute(key) ? root.getAttribute(key) : null;
}
}
return rootsAttributes;
}
/**
* Creates a new multi-root editor instance.

@@ -143,0 +412,0 @@ *

@@ -9,3 +9,3 @@ /**

import { type Editor } from 'ckeditor5/src/core';
import { EditorUI } from 'ckeditor5/src/ui';
import { EditorUI, type InlineEditableUIView } from 'ckeditor5/src/ui';
import type MultiRootEditorUIView from './multirooteditoruiview';

@@ -21,2 +21,6 @@ /**

/**
* The editable element that was focused the last time when any of the editables had focus.
*/
private _lastFocusedEditableElement;
/**
* Creates an instance of the multi-root editor UI class.

@@ -33,2 +37,26 @@ *

/**
* Adds the editable to the editor UI.
*
* After the editable is added to the editor UI it can be considered "active".
*
* The editable is attached to the editor editing pipeline, which means that it will be updated as the editor model updates and
* changing its content will be reflected in the editor model. Keystrokes, focus handling and placeholder are initialized.
*
* @param editable The editable instance to add.
* @param placeholder Placeholder for the editable element. If not set, placeholder value from the
* {@link module:core/editor/editorconfig~EditorConfig#placeholder editor configuration} will be used (if it was provided).
*/
addEditable(editable: InlineEditableUIView, placeholder?: string): void;
/**
* Removes the editable instance from the editor UI.
*
* Removed editable can be considered "deactivated".
*
* The editable is detached from the editing pipeline, so model changes are no longer reflected in it. All handling added in
* {@link #addEditable} is removed.
*
* @param editable Editable to remove from the editor UI.
*/
removeEditable(editable: InlineEditableUIView): void;
/**
* @inheritDoc

@@ -42,5 +70,9 @@ */

/**
* Enable the placeholder text on the editing roots, if any was configured.
* Enables the placeholder text on a given editable, if the placeholder was configured.
*
* @param editable Editable on which the placeholder should be set.
* @param placeholder Placeholder for the editable element. If not set, placeholder value from the
* {@link module:core/editor/editorconfig~EditorConfig#placeholder editor configuration} will be used (if it was provided).
*/
private _initPlaceholder;
}

@@ -20,2 +20,3 @@ /**

this.view = view;
this._lastFocusedEditableElement = null;
}

@@ -27,8 +28,2 @@ /**

const view = this.view;
const editor = this.editor;
const editingView = editor.editing.view;
let lastFocusedEditableElement;
for (const editableName of Object.keys(view.editables)) {
view.editables[editableName].name = editableName;
}
view.render();

@@ -43,3 +38,3 @@ // Keep track of the last focused editable element. Knowing which one was focused

if (focusedElement === editable.element) {
lastFocusedEditableElement = editable.element;
this._lastFocusedEditableElement = editable.element;
}

@@ -54,44 +49,8 @@ }

if (!isFocused) {
lastFocusedEditableElement = null;
this._lastFocusedEditableElement = null;
}
});
for (const editable of Object.values(this.view.editables)) {
// The editable UI element in DOM is available for sure only after the editor UI view has been rendered.
// But it can be available earlier if a DOM element has been passed to `MultiRootEditor.create()`.
const editableElement = editable.element;
// Register each editable UI view in the editor.
this.setEditableElement(editable.name, editableElement);
// Let the editable UI element respond to the changes in the global editor focus
// tracker. It has been added to the same tracker a few lines above but, in reality, there are
// many focusable areas in the editor, like balloons, toolbars or dropdowns and as long
// as they have focus, the editable should act like it is focused too (although technically
// it isn't), e.g. by setting the proper CSS class, visually announcing focus to the user.
// Doing otherwise will result in editable focus styles disappearing, once e.g. the
// toolbar gets focused.
editable.bind('isFocused').to(this.focusTracker, 'isFocused', this.focusTracker, 'focusedElement', (isFocused, focusedElement) => {
// When the focus tracker is blurred, it means the focus moved out of the editor UI.
// No editable will maintain focus then.
if (!isFocused) {
return false;
}
// If the focus tracker says the editor UI is focused and currently focused element
// is the editable, then the editable should be visually marked as focused too.
if (focusedElement === editableElement) {
return true;
}
// If the focus tracker says the editor UI is focused but the focused element is
// not an editable, it is possible that the editable is still (context–)focused.
// For instance, the focused element could be an input inside of a balloon attached
// to the content in the editable. In such case, the editable should remain _visually_
// focused even though technically the focus is somewhere else. The focus moved from
// the editable to the input but the focus context remained the same.
else {
return lastFocusedEditableElement === editableElement;
}
});
// Bind the editable UI element to the editing view, making it an end– and entry–point
// of the editor's engine. This is where the engine meets the UI.
editingView.attachDomRoot(editableElement, editable.name);
this.addEditable(editable);
}
this._initPlaceholder();
this._initToolbar();

@@ -101,2 +60,68 @@ this.fire('ready');

/**
* Adds the editable to the editor UI.
*
* After the editable is added to the editor UI it can be considered "active".
*
* The editable is attached to the editor editing pipeline, which means that it will be updated as the editor model updates and
* changing its content will be reflected in the editor model. Keystrokes, focus handling and placeholder are initialized.
*
* @param editable The editable instance to add.
* @param placeholder Placeholder for the editable element. If not set, placeholder value from the
* {@link module:core/editor/editorconfig~EditorConfig#placeholder editor configuration} will be used (if it was provided).
*/
addEditable(editable, placeholder) {
// The editable UI element in DOM is available for sure only after the editor UI view has been rendered.
// But it can be available earlier if a DOM element has been passed to `MultiRootEditor.create()`.
const editableElement = editable.element;
// Bind the editable UI element to the editing view, making it an end– and entry–point
// of the editor's engine. This is where the engine meets the UI.
this.editor.editing.view.attachDomRoot(editableElement, editable.name);
// Register each editable UI view in the editor.
this.setEditableElement(editable.name, editableElement);
// Let the editable UI element respond to the changes in the global editor focus
// tracker. It has been added to the same tracker a few lines above but, in reality, there are
// many focusable areas in the editor, like balloons, toolbars or dropdowns and as long
// as they have focus, the editable should act like it is focused too (although technically
// it isn't), e.g. by setting the proper CSS class, visually announcing focus to the user.
// Doing otherwise will result in editable focus styles disappearing, once e.g. the
// toolbar gets focused.
editable.bind('isFocused').to(this.focusTracker, 'isFocused', this.focusTracker, 'focusedElement', (isFocused, focusedElement) => {
// When the focus tracker is blurred, it means the focus moved out of the editor UI.
// No editable will maintain focus then.
if (!isFocused) {
return false;
}
// If the focus tracker says the editor UI is focused and currently focused element
// is the editable, then the editable should be visually marked as focused too.
if (focusedElement === editableElement) {
return true;
}
// If the focus tracker says the editor UI is focused but the focused element is
// not an editable, it is possible that the editable is still (context–)focused.
// For instance, the focused element could be an input inside of a balloon attached
// to the content in the editable. In such case, the editable should remain _visually_
// focused even though technically the focus is somewhere else. The focus moved from
// the editable to the input but the focus context remained the same.
else {
return this._lastFocusedEditableElement === editableElement;
}
});
this._initPlaceholder(editable, placeholder);
}
/**
* Removes the editable instance from the editor UI.
*
* Removed editable can be considered "deactivated".
*
* The editable is detached from the editing pipeline, so model changes are no longer reflected in it. All handling added in
* {@link #addEditable} is removed.
*
* @param editable Editable to remove from the editor UI.
*/
removeEditable(editable) {
this.editor.editing.view.detachDomRoot(editable.name);
editable.unbind('isFocused');
this.removeEditableElement(editable.name);
}
/**
* @inheritDoc

@@ -106,8 +131,6 @@ */

super.destroy();
const view = this.view;
const editingView = this.editor.editing.view;
for (const editable of Object.values(this.view.editables)) {
editingView.detachDomRoot(editable.name);
this.removeEditable(editable);
}
view.destroy();
this.view.destroy();
}

@@ -122,29 +145,32 @@ /**

toolbar.fillFromConfig(editor.config.get('toolbar'), this.componentFactory);
// Register the toolbar so it becomes available for Alt+F10 and Esc navigation.
// Register the toolbar, so it becomes available for Alt+F10 and Esc navigation.
this.addToolbar(view.toolbar);
}
/**
* Enable the placeholder text on the editing roots, if any was configured.
* Enables the placeholder text on a given editable, if the placeholder was configured.
*
* @param editable Editable on which the placeholder should be set.
* @param placeholder Placeholder for the editable element. If not set, placeholder value from the
* {@link module:core/editor/editorconfig~EditorConfig#placeholder editor configuration} will be used (if it was provided).
*/
_initPlaceholder() {
const editor = this.editor;
const editingView = editor.editing.view;
const placeholder = editor.config.get('placeholder');
_initPlaceholder(editable, placeholder) {
if (!placeholder) {
const configPlaceholder = this.editor.config.get('placeholder');
if (configPlaceholder) {
placeholder = typeof configPlaceholder === 'string' ? configPlaceholder : configPlaceholder[editable.name];
}
}
if (!placeholder) {
return;
}
for (const editable of Object.values(this.view.editables)) {
const editingRoot = editingView.document.getRoot(editable.name);
const placeholderText = typeof placeholder === 'string' ? placeholder : placeholder[editable.name];
if (placeholderText) {
enablePlaceholder({
view: editingView,
element: editingRoot,
text: placeholderText,
isDirectHost: false,
keepOnFocus: true
});
}
}
const editingView = this.editor.editing.view;
const editingRoot = editingView.document.getRoot(editable.name);
enablePlaceholder({
view: editingView,
element: editingRoot,
text: placeholder,
isDirectHost: false,
keepOnFocus: true
});
}
}

@@ -31,2 +31,6 @@ /**

/**
* The editing view instance this view is related to.
*/
private readonly _editingView;
/**
* Creates an instance of the multi-root editor UI view.

@@ -51,2 +55,19 @@ *

/**
* Creates an editable instance with given name and registers it in the editor UI view.
*
* If `editableElement` is provided, the editable instance will be created on top of it. Otherwise, the editor will create a new
* DOM element and use it instead.
*
* @param editableName The name for the editable.
* @param editableElement DOM element for which the editable should be created.
* @returns The created editable instance.
*/
createEditable(editableName: string, editableElement?: HTMLElement): InlineEditableUIView;
/**
* Destroys and removes the editable from the editor UI view.
*
* @param editableName The name of the editable that should be removed.
*/
removeEditable(editableName: string): void;
/**
* @inheritDoc

@@ -53,0 +74,0 @@ */

@@ -36,3 +36,3 @@ /**

super(locale);
const t = locale.t;
this._editingView = editingView;
this.toolbar = new ToolbarView(locale, {

@@ -44,8 +44,4 @@ shouldGroupWhenFull: options.shouldToolbarGroupWhenFull

for (const editableName of editableNames) {
const editable = new InlineEditableUIView(locale, editingView, options.editableElements ? options.editableElements[editableName] : undefined, {
label: editable => {
return t('Rich Text Editor. Editing area: %0', editable.name);
}
});
this.editables[editableName] = editable;
const editableElement = options.editableElements ? options.editableElements[editableName] : undefined;
this.createEditable(editableName, editableElement);
}

@@ -68,2 +64,39 @@ this.editable = Object.values(this.editables)[0];

/**
* Creates an editable instance with given name and registers it in the editor UI view.
*
* If `editableElement` is provided, the editable instance will be created on top of it. Otherwise, the editor will create a new
* DOM element and use it instead.
*
* @param editableName The name for the editable.
* @param editableElement DOM element for which the editable should be created.
* @returns The created editable instance.
*/
createEditable(editableName, editableElement) {
const t = this.locale.t;
const editable = new InlineEditableUIView(this.locale, this._editingView, editableElement, {
label: editable => {
return t('Rich Text Editor. Editing area: %0', editable.name);
}
});
this.editables[editableName] = editable;
editable.name = editableName;
if (this.isRendered) {
this.registerChild(editable);
}
return editable;
}
/**
* Destroys and removes the editable from the editor UI view.
*
* @param editableName The name of the editable that should be removed.
*/
removeEditable(editableName) {
const editable = this.editables[editableName];
if (this.isRendered) {
this.deregisterChild(editable);
}
delete this.editables[editableName];
editable.destroy();
}
/**
* @inheritDoc

@@ -74,4 +107,4 @@ */

this.registerChild(Object.values(this.editables));
this.registerChild([this.toolbar]);
this.registerChild(this.toolbar);
}
}
SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc