/** * @license Copyright (c) 2003-2024, CKSource Holding sp. z o.o. All rights reserved. * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license */ /** * @module core/editor/editorconfig */ import type { ArrayOrItem, Translations } from '@ckeditor/ckeditor5-utils'; import type Context from '../context.js'; import type { PluginConstructor } from '../plugin.js'; import type Editor from './editor.js'; import type { MenuBarConfig } from '@ckeditor/ckeditor5-ui'; /** * CKEditor configuration options. * * An object defining the editor configuration can be passed when initializing the editor: * * ```ts * EditorClass * .create( { * toolbar: [ 'bold', 'italic' ], * image: { * styles: [ * ... * ] * } * } ) * .then( ... ) * .catch( ... ); * ``` */ export interface EditorConfig { context?: Context; /** * The list of additional plugins to load along those already available in the * editor. It extends the {@link #plugins `plugins`} configuration. * * ```ts * function MyPlugin( editor ) { * // ... * } * * const config = { * extraPlugins: [ MyPlugin ] * }; * ``` * * **Note:** This configuration works only for simple plugins which utilize the * {@link module:core/plugin~PluginInterface plugin interface} and have no dependencies. To extend a * build with complex features, try [CKEditr 5 Builder](https://ckeditor.com/ckeditor-5/builder?redirect=docs). * * **Note:** Make sure you include the new features in you toolbar configuration. Learn more * about the {@glink getting-started/setup/toolbar toolbar setup}. */ extraPlugins?: Array>; /** * The initial editor data to be used instead of the provided element's HTML content. * * ```ts * ClassicEditor * .create( document.querySelector( '#editor' ), { * initialData: '

Initial data

Foo bar.

' * } ) * .then( ... ) * .catch( ... ); * ``` * * By default, the editor is initialized with the content of the element on which this editor is initialized. * This configuration option lets you override this behavior and pass different initial data. * It is especially useful if it is difficult for your integration to put the data inside the HTML element. * * If your editor implementation uses multiple roots, you should pass an object with keys corresponding to the editor * roots names and values equal to the data that should be set in each root: * * ```ts * MultiRootEditor.create( * // Roots for the editor: * { * header: document.querySelector( '#header' ), * content: document.querySelector( '#content' ), * leftSide: document.querySelector( '#left-side' ), * rightSide: document.querySelector( '#right-side' ) * }, * // Config: * { * initialData: { * header: '

Content for header part.

', * content: '

Content for main part.

', * leftSide: '

Content for left-side box.

', * rightSide: '

Content for right-side box.

' * } * } * ) * .then( ... ) * .catch( ... ); * ``` * * See also {@link module:core/editor/editor~Editor.create Editor.create()} documentation for the editor implementation which you use. * * **Note:** If initial data is passed to `Editor.create()` in the first parameter (instead of a DOM element), and, * at the same time, `config.initialData` is set, an error will be thrown as those two options exclude themselves. * * If `config.initialData` is not set when the editor is initialized, the data received in `Editor.create()` call * will be used to set `config.initialData`. As a result, `initialData` is always set in the editor's config and * plugins can read and/or modify it during initialization. */ initialData?: string | Record; /** * The language of the editor UI and its content. * * Simple usage (change the language of the UI and the content): * * ```ts * ClassicEditor * .create( document.querySelector( '#editor' ), { * // The UI of the editor as well as its content will be in German. * language: 'de' * } ) * .then( editor => { * console.log( editor ); * } ) * .catch( error => { * console.error( error ); * } ); * ``` * * Use different languages for the UI and the content using the {@link module:core/editor/editorconfig~LanguageConfig configuration} * syntax: * * ```ts * ClassicEditor * .create( document.querySelector( '#editor' ), { * language: { * // The UI will be in English. * ui: 'en', * * // But the content will be edited in Arabic. * content: 'ar' * } * } ) * .then( editor => { * console.log( editor ); * } ) * .catch( error => { * console.error( error ); * } ); * ``` * * The language of the content has an impact on the editing experience, for instance it affects screen readers * and spell checkers. It is also particularly useful for typing in certain languages (e.g. right–to–left ones) * because it changes the default alignment of the text. * * The language codes are defined in the [ISO 639-1](https://en.wikipedia.org/wiki/ISO_639-1) standard. * * You need to add the corresponding translation file for the new UI language to work. * Translation files are available on CDN: * * ```html * * * ``` * * You can add translation using NPM as well. * * ```html * import { ClassicEditor, Essentials, Paragraph } from 'ckeditor5'; * import translations from 'ckeditor5/dist/translations/pl.js'; * * import 'ckeditor5/dist/styles.css'; * * await ClassicEditor.create( document.querySelector( '#editor' ), { * plugins: [ * Essentials, * Paragraph, * ], * toolbar: { * items: [ 'undo', 'redo' ] * }, * translations * } ); * ``` * * Check the {@glink getting-started/setup/ui-language UI language} guide for more information about * the localization options and translation process. */ language?: string | LanguageConfig; /** * The editor menu bar configuration. * * **Note**: The menu bar is not available in all editor types. Currently, only the * {@link module:editor-classic/classiceditor~ClassicEditor Classic editor} and * {@link module:editor-decoupled/decouplededitor~DecoupledEditor Decoupled editor} * support this feature. Setting the `config.menuBar` configuration for other editor types will have no effect. * * In Classic editor, the menu bar is hidden by default. Set the `isVisible` configuration flag to `true` in order to show it: * * ```ts * ClassicEditor * .create( document.querySelector( '#editor' ), { * menuBar: { * isVisible: true * } * } ) * .then( ... ); * ``` * * When using the Decoupled editor, you will need to insert the menu bar in a desired place yourself. For example: * * ```ts * DecoupledEditor * .create( document.querySelector( '#editor' ), { * toolbar: [ 'undo', 'redo', 'bold', 'italic', 'numberedList', 'bulletedList' ], * } ) * .then( editor => { * document.getElementById( '#menuBarContainer' ).appendChild( editor.ui.view.menuBarView.element ); * } ); * ``` * * **Note**: You do not have to set the `items` property in this configuration in order to use the menu bar. * By default, a {@link module:ui/menubar/utils#DefaultMenuBarItems default set of items} is used that already includes * **all core editor features**. For your convenience, there are `config.menuBar.addItems` and * `config.menuBar.removeItems` options available that will help you adjust the default configuration without setting the * entire menu bar structure from scratch (see below). * * **Removing items from the menu bar** * * You can use the `config.menuBar.removeItems` option to remove items from the default menu bar configuration. You can * remove individual buttons (e.g. "Bold" or "Block quote"), item groups (e.g. the basic styles section that * includes multiple buttons such as "Bold", "Italic", "Underline", etc.), or whole menus (e.g. the "Insert" menu). Please * refer to the {@link module:ui/menubar/utils#DefaultMenuBarItems default configuration} to see default buttons/groups/menus * and their structure. * * To remove individual buttons from the menu bar: * * ```ts * ClassicEditor * .create( document.querySelector( '#editor' ), { * menuBar: { * // Removes "Bold" and "Block quote" buttons from their respective menus. * removeItems: [ 'menuBar:bold', 'menuBar:blockQuote' ] * } * } ) * .then( ... ); * ``` * * To remove a group of buttons from the menu bar: * * ```ts * ClassicEditor * .create( document.querySelector( '#editor' ), { * menuBar: { * // Removes the entire basic styles group ("Bold", "Italic", "Underline", etc.) from the "Format" menu. * removeItems: [ 'basicStyles' ] * } * } ) * .then( ... ); * ``` * * To remove a menu from the menu bar: * * ```ts * ClassicEditor * .create( document.querySelector( '#editor' ), { * menuBar: { * // Removes the whole top-level "Insert" menu from the menu bar. * removeItems: [ 'insert' ] * } * } ) * .then( ... ); * ``` * * **Adding items to the menu bar** * * Using the `config.menuBar.addItems` option you can add individual buttons, button groups or entire menus to the structure * of the menu bar. You can add existing components that you removed from their original position, or add your own components. * * **Note**: When adding items please make sure that features (editor plugins) that bring specific menu bar items are loaded. * For instance, the "Bold" button will not show up in the menu bar unless the {@glink features/basic-styles basic styles} feature is * loaded. {@link module:core/editor/editorconfig~EditorConfig#plugins Learn more} about loading plugins. * * Each entry in the `config.menuBar.addItems` is an object with one of the following properties: * * * `item` – A name of the button to be added to a specific button group (e.g. `'menuBar:bold'` or `'myButton'`), * * `menu` – A {@link module:ui/menubar/menubarview#MenuBarMenuDefinition definition of a menu} that should be added to * the menu bar, * * `group` – A {@link module:ui/menubar/menubarview#MenuBarMenuGroupDefinition definition of a button group} that should be * added to a specific menu. * * Additionally, each entry must define the `position` property that accepts the following values: * * `'start'` – Adds a top-level menu (e.g. "Format", "Insert", etc.) at the beginning of the menu bar, * * `'start:GROUP_OR_MENU'` – Adds a button/group at the beginning of the specific group/menu, * * `'end'` – Adds a top-level menu (e.g. "Format", "Insert", etc.) at the end of the menu bar, * * `'end:GROUP_OR_MENU'` – Adds a button/group at the end of the specific group/menu, * * `'after:BUTTON_OR_GROUP_OR_MENU'` – Adds a button/group/menu right after the specific button/group/menu, * * `'before:BUTTON_OR_GROUP_OR_MENU'` – Adds a button/group/menu right after the specific button/group/menu. * * Please refer to the {@link module:ui/menubar/utils#DefaultMenuBarItems default configuration} to learn about the * names of buttons and positions they can be added at. * * To add a new top-level menu with specific buttons at the end of the menu bar: * * ```ts * ClassicEditor * .create( document.querySelector( '#editor' ), { * menuBar: { * addItems: [ * { * menu: { * menuId: 'my-menu', * label: 'My menu', * groups: [ * { * groupId: 'my-buttons', * items: [ * 'menuBar:bold', * 'menuBar:italic', * 'menuBar:underline' * ] * } * ] * }, * position: 'end' * } * ] * } * } ) * .then( ... ); * ``` * * To add a new group of buttons to the "Format" menu after basic styles buttons ("Bold", "Italic", "Underline", etc.): * * ```ts * ClassicEditor * .create( document.querySelector( '#editor' ), { * menuBar: { * addItems: [ * { * group: { * groupId: 'my-buttons', * items: [ * 'myButton1', * 'myButton2', * ] * }, * position: 'after:basicStyles' * } * ] * } * } ) * .then( ... ); * ``` * * To add a new button to the basic styles group ("Bold", "Italic", "Underline", etc.) in the "Format" menu: * * ```ts * ClassicEditor * .create( document.querySelector( '#editor' ), { * menuBar: { * addItems: [ * { * item: 'myButton', * position: 'end:basicStyles' * } * ] * } * } ) * .then( ... ); * ``` * * To add a new sub-menu in the "Format" menu: * * ```ts * ClassicEditor * .create( document.querySelector( '#editor' ), { * menuBar: { * addItems: [ * { * menu: { * menuId: 'my-sub-menu', * label: 'My sub-menu', * groups: [ * { * groupId: 'my-buttons', * items: [ * 'myButton1', * 'myButton2', * ] * } * ] * }, * position: 'after:basicStyles' * } * ] * } * } ) * .then( ... ); * ``` * * **Defining menu bar from scratch** * * If the `config.menuBar.addItems` and `config.menuBar.removeItems` options are not enough to adjust the * {@link module:ui/menubar/utils#DefaultMenuBarItems default configuration}, you can set the menu bar structure from scratch. * * For instance, to create a minimalistic menu bar configuration with just two main categories (menus), use the following code snippet: * * ```ts * ClassicEditor * .create( document.querySelector( '#editor' ), { * menuBar: { * items: [ * { * menuId: 'formatting', * label: 'Formatting', * groups: [ * { * groupId: 'basicStyles', * items: [ * 'menuBar:bold', * 'menuBar:italic', * ] * }, * { * groupId: 'misc', * items: [ * 'menuBar:heading', * 'menuBar:bulletedList', * 'menuBar:numberedList' * ] * } * ] * }, * { * menuId: 'myButtons', * label: 'My actions', * groups: [ * { * groupId: 'undo', * items: [ * 'myButton1', * 'myButton2' * ] * } * ] * } * ] * } * } ) * .then( ... ); * ``` */ menuBar?: MenuBarConfig; /** * Specifies the text displayed in the editor when there is no content (editor is empty). It is intended to * help users locate the editor in the application (form) and prompt them to input the content. Work similarly * as to the native DOM * [`placeholder` attribute](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/input#The_placeholder_attribute) * used by inputs. * * ```ts * ClassicEditor * .create( document.querySelector( '#editor' ), { * placeholder: 'Type some text...' * } ) * .then( ... ) * .catch( ... ); * ``` * * If your editor implementation uses multiple roots, you should pass an object with keys corresponding to the editor * roots names and values equal to the placeholder that should be set in each root: * * ```ts * MultiRootEditor.create( * // Roots for the editor: * { * header: document.querySelector( '#header' ), * content: document.querySelector( '#content' ), * leftSide: document.querySelector( '#left-side' ), * rightSide: document.querySelector( '#right-side' ) * }, * // Config: * { * placeholder: { * header: 'Type header...', * content: 'Type content...', * leftSide: 'Type left-side...', * rightSide: 'Type right-side...' * } * } * ) * .then( ... ) * .catch( ... ); * ``` * * The placeholder text is displayed as a pseudo–element of an empty paragraph in the editor content. * The paragraph has the `.ck-placeholder` CSS class and the `data-placeholder` attribute. * * ```html *

* ::before *

* ``` * * **Note**: Placeholder text can also be set using the `placeholder` attribute if a `