Provides a common, higher-level environment for solutions that use multiple Editor editors
or plugins that work outside the editor. Use it instead of Editor.createEditor.create()
in advanced application integrations.
Config
ckeditor5-utils下Config是一種類似于lodash get
效果的類,可以通過get(obj, 'a.b.c')
或set(obj, 'a.b.c', 123)
來獲取或設(shè)置對象obj={a : { b: {c: 1}}}
翰舌,用來封裝或操作配置嚣潜。如:
let config = new Config( {
creator: 'inline',
language: 'pl',
resize: {
minHeight: 300,
maxHeight: 800,
icon: {
path: 'xyz'
}
},
toolbar: 'top',
options: {
foo: [
{ bar: 'b' },
{ bar: 'a' },
{ bar: 'z' }
]
}
//
expect( config.get( 'creator' ) ).to.equal( 'inline' );
config.set( {
option1: 1,
option2: {
subOption21: 21
}
} );
expect( config.get( 'option1' ) ).to.equal( 1 );
expect( config.get( 'option2.subOption21' ) ).to.equal( 21 );
Context
Provides a common, higher-level environment for solutions that use multiple editors or plugins that work outside the editor.
All configuration options passed to a context will be used as default options for editor instances initialized in that context.
Context plugins passed to a context instance will be shared among all editor instances initialized in this context. These will be the same plugin instances for all the editors.
- 例1
// Creates and initializes a new context instance.
const commonConfig = { ... }; // Configuration for all the plugins and editors.
const editorPlugins = [ ... ]; // Regular plugins here.
Context
.create( {
// Only context plugins here.
plugins: [ ... ],
// Configure the language for all the editors (it cannot be overwritten).
language: { ... },
// Configuration for context plugins.
comments: { ... },
...
// Default configuration for editor plugins.
toolbar: { ... },
image: { ... },
...
} )
.then( context => {
const promises = [];
promises.push( ClassicEditor.create(
document.getElementById( 'editor1' ),
{
editorPlugins,
context
}
) );
promises.push( ClassicEditor.create(
document.getElementById( 'editor2' ),
{
editorPlugins,
context,
toolbar: { ... } // You can overwrite the configuration of the context.
}
) );
return Promise.all( promises );
} );
- 例2,通過builtinPlugins設(shè)置內(nèi)置插件
// An array of plugins built into the `Context` class.
// It is used in CKEditor 5 builds featuring `Context` to provide a list of context plugins which are later automatically initialized during the context initialization.
// They will be automatically initialized by `Context` unless `config.plugins` is passed.
// Build some context plugins into the Context class first.
Context.builtinPlugins = [ FooPlugin, BarPlugin ];
// Normally, you need to define config.plugins, but since Context.builtinPlugins was
// defined, now you can call create() without any configuration.
Context
.create()
.then( context => {
context.plugins.get( FooPlugin ); // -> An instance of the Foo plugin.
context.plugins.get( BarPlugin ); // -> An instance of the Bar plugin.
} );
- 例3椅贱,通過
defaultConfig
設(shè)置默認(rèn)配置
Context.defaultConfig = {
foo: 1,
bar: 2
};
Context
.create()
.then( context => {
context.config.get( 'foo' ); // -> 1
context.config.get( 'bar' ); // -> 2
} );
// The default options can be overridden by the configuration passed to create().
Context
.create( { bar: 3 } )
.then( context => {
context.config.get( 'foo' ); // -> 1
context.config.get( 'bar' ); // -> 3
} );
new Context(config)實例化過程
- 通過傳參
config
和defaultConfig
(參見例3)給Config
類生成實例賦給this.config
- 以
plugins
為key懂算,builtinPlugins
(參見例2)為value只冻,更新this.config
-
this.plugins = new PluginCollection( this, availablePlugins );
,PluginCollection實例化過程如下:
- 通過Locale生成對象賦給
this.locale
(詳見ckeditor5/locale:國際化方案):
this.locale = new Locale( {
uiLanguage: typeof languageConfig === 'string' ? languageConfig : languageConfig.ui,
contentLanguage: this.config.get( 'language.content' )
} );
this.t = this.locale.t;
-
this.editors = new Collection();
计技,Collection
用于對editor實例進(jìn)行諸如新增喜德、刪除和查找等管理工作。
基本使用示例
const collection = new Collection( [ { id: 'John' }, { id: 'Mike' } ] );
console.log( collection.get( 0 ) ); // -> { id: 'John' }
console.log( collection.get( 1 ) ); // -> { id: 'Mike' }
console.log( collection.get( 'Mike' ) ); // -> { id: 'Mike' }
// Or
const collection = new Collection();
collection.add( { id: 'John' } );
console.log( collection.get( 0 ) ); // -> { id: 'John' }
// Or you can always pass a configuration object as the last argument of the constructor:
const emptyCollection = new Collection( { idProperty: 'name' } );
emptyCollection.add( { name: 'John' } );
console.log( collection.get( 'John' ) ); // -> { name: 'John' }
const nonEmptyCollection = new Collection( [ { name: 'John' } ], { idProperty: 'name' } );
nonEmptyCollection.add( { name: 'George' } );
console.log( collection.get( 'George' ) ); // -> { name: 'George' }
console.log( collection.get( 'John' ) ); // -> { name: 'John' }
bindTo垮媒、as和using
// Binds and synchronizes the collection with another one.
// The binding can be a simple factory:
class FactoryClass {
constructor( data ) {
this.label = data.label;
}
}
const source = new Collection( { idProperty: 'label' } );
const target = new Collection();
target.bindTo( source ).as( FactoryClass );
source.add( { label: 'foo' } );
source.add( { label: 'bar' } );
console.log( target.length ); // 2
console.log( target.get( 1 ).label ); // 'bar'
source.remove( 0 );
console.log( target.length ); // 1
console.log( target.get( 0 ).label ); // 'bar'
// or the factory driven by a custom callback:
class FooClass {
constructor( data ) {
this.label = data.label;
}
}
class BarClass {
constructor( data ) {
this.label = data.label;
}
}
const source = new Collection( { idProperty: 'label' } );
const target = new Collection();
target.bindTo( source ).using( ( item ) => {
if ( item.label == 'foo' ) {
return new FooClass( item );
} else {
return new BarClass( item );
}
} );
source.add( { label: 'foo' } );
source.add( { label: 'bar' } );
console.log( target.length ); // 2
console.log( target.get( 0 ) instanceof FooClass ); // true
console.log( target.get( 1 ) instanceof BarClass ); // true
// or the factory out of property name:
const source = new Collection( { idProperty: 'label' } );
const target = new Collection();
target.bindTo( source ).using( 'label' );
source.add( { label: { value: 'foo' } } );
source.add( { label: { value: 'bar' } } );
console.log( target.length ); // 2
console.log( target.get( 0 ).value ); // 'foo'
console.log( target.get( 1 ).value ); // 'bar'
// It's possible to skip specified items by returning falsy value:
const source = new Collection();
const target = new Collection();
target.bindTo( source ).using( item => {
if ( item.hidden ) {
return null;
}
return item;
} );
source.add( { hidden: true } );
source.add( { hidden: false } );
console.log( source.length ); // 2
console.log( target.length ); // 1
-
this._contextOwner
初始化為null
舍悯,在_addEditor
方法中會對其賦值:
/*
Reference to the editor which created the context.
Null when the context was created outside of the editor.
It is used to destroy the context when removing the editor that has created the context.
*/
this._contextOwner = null;
在editor.js
中,會調(diào)用Context
方法和_addEditor
class Editor {
constructor(config = {}) {
this._context = config.context || new Context( { language: config.language } );
this._context._addEditor( this, !config.context );
}
}
- _addEditor
// Adds a reference to the editor which is used with this context.
// This method should only be used by the editor.
_addEditor( editor, isContextOwner ) {
if ( this._contextOwner ) {
/**
* Cannot add multiple editors to the context which is created by the editor.
*
* @error context-addeditor-private-context
*/
throw new CKEditorError( 'context-addeditor-private-context' );
}
this.editors.add( editor );
if ( isContextOwner ) {
this._contextOwner = editor;
}
}