@ckeditor/ckeditor5-core 30.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (111) hide show
  1. package/LICENSE.md +17 -0
  2. package/README.md +18 -0
  3. package/lang/contexts.json +8 -0
  4. package/lang/translations/af.po +41 -0
  5. package/lang/translations/ar.po +41 -0
  6. package/lang/translations/ast.po +41 -0
  7. package/lang/translations/az.po +41 -0
  8. package/lang/translations/bg.po +41 -0
  9. package/lang/translations/ca.po +41 -0
  10. package/lang/translations/cs.po +41 -0
  11. package/lang/translations/da.po +41 -0
  12. package/lang/translations/de-ch.po +41 -0
  13. package/lang/translations/de.po +41 -0
  14. package/lang/translations/el.po +41 -0
  15. package/lang/translations/en-au.po +41 -0
  16. package/lang/translations/en-gb.po +41 -0
  17. package/lang/translations/en.po +41 -0
  18. package/lang/translations/eo.po +41 -0
  19. package/lang/translations/es.po +41 -0
  20. package/lang/translations/et.po +41 -0
  21. package/lang/translations/eu.po +41 -0
  22. package/lang/translations/fa.po +41 -0
  23. package/lang/translations/fi.po +41 -0
  24. package/lang/translations/fr.po +41 -0
  25. package/lang/translations/gl.po +41 -0
  26. package/lang/translations/he.po +41 -0
  27. package/lang/translations/hi.po +41 -0
  28. package/lang/translations/hr.po +41 -0
  29. package/lang/translations/hu.po +41 -0
  30. package/lang/translations/id.po +41 -0
  31. package/lang/translations/it.po +41 -0
  32. package/lang/translations/ja.po +41 -0
  33. package/lang/translations/km.po +41 -0
  34. package/lang/translations/kn.po +41 -0
  35. package/lang/translations/ko.po +41 -0
  36. package/lang/translations/ku.po +41 -0
  37. package/lang/translations/lt.po +41 -0
  38. package/lang/translations/lv.po +41 -0
  39. package/lang/translations/nb.po +41 -0
  40. package/lang/translations/ne.po +41 -0
  41. package/lang/translations/nl.po +41 -0
  42. package/lang/translations/no.po +41 -0
  43. package/lang/translations/oc.po +41 -0
  44. package/lang/translations/pl.po +41 -0
  45. package/lang/translations/pt-br.po +41 -0
  46. package/lang/translations/pt.po +41 -0
  47. package/lang/translations/ro.po +41 -0
  48. package/lang/translations/ru.po +41 -0
  49. package/lang/translations/sk.po +41 -0
  50. package/lang/translations/sl.po +41 -0
  51. package/lang/translations/sq.po +41 -0
  52. package/lang/translations/sr-latn.po +41 -0
  53. package/lang/translations/sr.po +41 -0
  54. package/lang/translations/sv.po +41 -0
  55. package/lang/translations/th.po +41 -0
  56. package/lang/translations/tk.po +41 -0
  57. package/lang/translations/tr.po +41 -0
  58. package/lang/translations/tt.po +41 -0
  59. package/lang/translations/ug.po +41 -0
  60. package/lang/translations/uk.po +41 -0
  61. package/lang/translations/vi.po +41 -0
  62. package/lang/translations/zh-cn.po +41 -0
  63. package/lang/translations/zh.po +41 -0
  64. package/package.json +65 -0
  65. package/src/command.js +244 -0
  66. package/src/commandcollection.js +109 -0
  67. package/src/context.js +355 -0
  68. package/src/contextplugin.js +61 -0
  69. package/src/editingkeystrokehandler.js +72 -0
  70. package/src/editor/editor.js +448 -0
  71. package/src/editor/editorconfig.jsdoc +325 -0
  72. package/src/editor/editorui.js +275 -0
  73. package/src/editor/editorwithui.jsdoc +29 -0
  74. package/src/editor/utils/attachtoform.js +67 -0
  75. package/src/editor/utils/dataapimixin.js +81 -0
  76. package/src/editor/utils/elementapimixin.js +65 -0
  77. package/src/editor/utils/securesourceelement.js +49 -0
  78. package/src/index.js +95 -0
  79. package/src/multicommand.js +101 -0
  80. package/src/pendingactions.js +155 -0
  81. package/src/plugin.js +292 -0
  82. package/src/plugincollection.js +597 -0
  83. package/theme/icons/align-bottom.svg +1 -0
  84. package/theme/icons/align-center.svg +1 -0
  85. package/theme/icons/align-justify.svg +1 -0
  86. package/theme/icons/align-left.svg +1 -0
  87. package/theme/icons/align-middle.svg +1 -0
  88. package/theme/icons/align-right.svg +1 -0
  89. package/theme/icons/align-top.svg +1 -0
  90. package/theme/icons/cancel.svg +1 -0
  91. package/theme/icons/caption.svg +1 -0
  92. package/theme/icons/check.svg +1 -0
  93. package/theme/icons/cog.svg +1 -0
  94. package/theme/icons/eraser.svg +1 -0
  95. package/theme/icons/image.svg +1 -0
  96. package/theme/icons/low-vision.svg +1 -0
  97. package/theme/icons/object-center.svg +1 -0
  98. package/theme/icons/object-full-width.svg +1 -0
  99. package/theme/icons/object-inline-left.svg +1 -0
  100. package/theme/icons/object-inline-right.svg +1 -0
  101. package/theme/icons/object-inline.svg +1 -0
  102. package/theme/icons/object-left.svg +1 -0
  103. package/theme/icons/object-right.svg +1 -0
  104. package/theme/icons/object-size-full.svg +1 -0
  105. package/theme/icons/object-size-large.svg +1 -0
  106. package/theme/icons/object-size-medium.svg +1 -0
  107. package/theme/icons/object-size-small.svg +1 -0
  108. package/theme/icons/pencil.svg +1 -0
  109. package/theme/icons/pilcrow.svg +1 -0
  110. package/theme/icons/quote.svg +1 -0
  111. package/theme/icons/three-vertical-dots.svg +1 -0
@@ -0,0 +1,81 @@
1
+ /**
2
+ * @license Copyright (c) 2003-2021, CKSource - Frederico Knabben. All rights reserved.
3
+ * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
4
+ */
5
+
6
+ /**
7
+ * @module core/editor/utils/dataapimixin
8
+ */
9
+
10
+ /**
11
+ * Implementation of the {@link module:core/editor/utils/dataapimixin~DataApi}.
12
+ *
13
+ * @mixin DataApiMixin
14
+ * @implements module:core/editor/utils/dataapimixin~DataApi
15
+ */
16
+ const DataApiMixin = {
17
+ /**
18
+ * @inheritDoc
19
+ */
20
+ setData( data ) {
21
+ this.data.set( data );
22
+ },
23
+
24
+ /**
25
+ * @inheritDoc
26
+ */
27
+ getData( options ) {
28
+ return this.data.get( options );
29
+ }
30
+ };
31
+
32
+ export default DataApiMixin;
33
+
34
+ /**
35
+ * Interface defining editor methods for setting and getting data to and from the editor's main root element
36
+ * using the {@link module:core/editor/editor~Editor#data data pipeline}.
37
+ *
38
+ * This interface is not a part of the {@link module:core/editor/editor~Editor} class because one may want to implement
39
+ * an editor with multiple root elements, in which case the methods for setting and getting data will need to be implemented
40
+ * differently.
41
+ *
42
+ * @interface DataApi
43
+ */
44
+
45
+ /**
46
+ * Sets the data in the editor.
47
+ *
48
+ * editor.setData( '<p>This is editor!</p>' );
49
+ *
50
+ * By default the editor accepts HTML. This can be controlled by injecting a different data processor.
51
+ * See the {@glink features/markdown Markdown output} guide for more details.
52
+ *
53
+ * Note: Not only is the format of the data configurable, but the type of the `setData()`'s parameter does not
54
+ * have to be a string either. You can e.g. accept an object or a DOM `DocumentFragment` if you consider this
55
+ * the right format for you.
56
+ *
57
+ * @method #setData
58
+ * @param {String} data Input data.
59
+ */
60
+
61
+ /**
62
+ * Gets the data from the editor.
63
+ *
64
+ * editor.getData(); // -> '<p>This is editor!</p>'
65
+ *
66
+ * By default the editor outputs HTML. This can be controlled by injecting a different data processor.
67
+ * See the {@glink features/markdown Markdown output} guide for more details.
68
+ *
69
+ * Note: Not only is the format of the data configurable, but the type of the `getData()`'s return value does not
70
+ * have to be a string either. You can e.g. return an object or a DOM `DocumentFragment` if you consider this
71
+ * the right format for you.
72
+ *
73
+ * @method #getData
74
+ * @param {Object} [options] Additional configuration for the retrieved data.
75
+ * Editor features may introduce more configuration options that can be set through this parameter.
76
+ * @param {String} [options.rootName='main'] Root name.
77
+ * @param {String} [options.trim='empty'] Whether returned data should be trimmed. This option is set to `'empty'` by default,
78
+ * which means that whenever editor content is considered empty, an empty string is returned. To turn off trimming
79
+ * use `'none'`. In such cases exact content will be returned (for example `'<p>&nbsp;</p>'` for an empty editor).
80
+ * @returns {String} Output data.
81
+ */
@@ -0,0 +1,65 @@
1
+ /**
2
+ * @license Copyright (c) 2003-2021, CKSource - Frederico Knabben. All rights reserved.
3
+ * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
4
+ */
5
+
6
+ import CKEditorError from '@ckeditor/ckeditor5-utils/src/ckeditorerror';
7
+ import setDataInElement from '@ckeditor/ckeditor5-utils/src/dom/setdatainelement';
8
+
9
+ /**
10
+ * @module core/editor/utils/elementapimixin
11
+ */
12
+
13
+ /**
14
+ * Implementation of the {@link module:core/editor/utils/elementapimixin~ElementApi}.
15
+ *
16
+ * @mixin ElementApiMixin
17
+ * @implements module:core/editor/utils/elementapimixin~ElementApi
18
+ */
19
+ const ElementApiMixin = {
20
+ /**
21
+ * @inheritDoc
22
+ */
23
+ updateSourceElement() {
24
+ if ( !this.sourceElement ) {
25
+ /**
26
+ * Cannot update the source element of a detached editor.
27
+ *
28
+ * The {@link ~ElementApi#updateSourceElement `updateSourceElement()`} method cannot be called if you did not
29
+ * pass an element to `Editor.create()`.
30
+ *
31
+ * @error editor-missing-sourceelement
32
+ */
33
+ throw new CKEditorError(
34
+ 'editor-missing-sourceelement',
35
+ this
36
+ );
37
+ }
38
+
39
+ setDataInElement( this.sourceElement, this.data.get() );
40
+ }
41
+ };
42
+
43
+ export default ElementApiMixin;
44
+
45
+ /**
46
+ * Interface describing an editor that replaced a DOM element (was "initialized on an element").
47
+ *
48
+ * Such an editor should provide a method to
49
+ * {@link module:core/editor/utils/elementapimixin~ElementApi#updateSourceElement update the replaced element with the current data}.
50
+ *
51
+ * @interface ElementApi
52
+ */
53
+
54
+ /**
55
+ * The element on which the editor has been initialized.
56
+ *
57
+ * @readonly
58
+ * @member {HTMLElement} #sourceElement
59
+ */
60
+
61
+ /**
62
+ * Updates the {@link #sourceElement editor source element}'s content with the data.
63
+ *
64
+ * @method #updateSourceElement
65
+ */
@@ -0,0 +1,49 @@
1
+ /**
2
+ * @license Copyright (c) 2003-2021, CKSource - Frederico Knabben. All rights reserved.
3
+ * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
4
+ */
5
+
6
+ import CKEditorError from '@ckeditor/ckeditor5-utils/src/ckeditorerror';
7
+
8
+ /**
9
+ * @module core/editor/utils/securesourceelement
10
+ */
11
+
12
+ /**
13
+ * Marks the source element on which the editor was initialized. This prevents other editor instances from using this element.
14
+ *
15
+ * Running multiple editor instances on the same source element causes various issues and it is
16
+ * crucial this helper is called as soon as the source element is known to prevent collisions.
17
+ *
18
+ * @param {module:core/editor/editor~Editor} editor Editor instance.
19
+ */
20
+ export default function secureSourceElement( editor ) {
21
+ const sourceElement = editor.sourceElement;
22
+
23
+ // If the editor was initialized without specifying an element, we don't need to secure anything.
24
+ if ( !sourceElement ) {
25
+ return;
26
+ }
27
+
28
+ if ( sourceElement.ckeditorInstance ) {
29
+ /**
30
+ * A DOM element used to create the editor (e.g.
31
+ * {@link module:editor-inline/inlineeditor~InlineEditor.create `InlineEditor.create()`})
32
+ * has already been used to create another editor instance. Make sure each editor is
33
+ * created with an unique DOM element.
34
+ *
35
+ * @error editor-source-element-already-used
36
+ * @param {HTMLElement} element DOM element that caused the collision.
37
+ */
38
+ throw new CKEditorError(
39
+ 'editor-source-element-already-used',
40
+ editor
41
+ );
42
+ }
43
+
44
+ sourceElement.ckeditorInstance = editor;
45
+
46
+ editor.once( 'destroy', () => {
47
+ delete sourceElement.ckeditorInstance;
48
+ } );
49
+ }
package/src/index.js ADDED
@@ -0,0 +1,95 @@
1
+ /**
2
+ * @license Copyright (c) 2003-2021, CKSource - Frederico Knabben. All rights reserved.
3
+ * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
4
+ */
5
+
6
+ /**
7
+ * @module core
8
+ */
9
+
10
+ export { default as Plugin } from './plugin';
11
+ export { default as Command } from './command';
12
+ export { default as MultiCommand } from './multicommand';
13
+
14
+ export { default as Context } from './context';
15
+ export { default as ContextPlugin } from './contextplugin';
16
+
17
+ export { default as Editor } from './editor/editor';
18
+ export { default as EditorUI } from './editor/editorui';
19
+
20
+ export { default as attachToForm } from './editor/utils/attachtoform';
21
+ export { default as DataApiMixin } from './editor/utils/dataapimixin';
22
+ export { default as ElementApiMixin } from './editor/utils/elementapimixin';
23
+ export { default as secureSourceElement } from './editor/utils/securesourceelement';
24
+
25
+ export { default as PendingActions } from './pendingactions';
26
+
27
+ import cancel from './../theme/icons/cancel.svg';
28
+ import caption from './../theme/icons/caption.svg';
29
+ import check from './../theme/icons/check.svg';
30
+ import cog from './../theme/icons/cog.svg';
31
+ import eraser from './../theme/icons/eraser.svg';
32
+ import lowVision from './../theme/icons/low-vision.svg';
33
+ import image from './../theme/icons/image.svg';
34
+
35
+ import alignBottom from './../theme/icons/align-bottom.svg';
36
+ import alignMiddle from './../theme/icons/align-middle.svg';
37
+ import alignTop from './../theme/icons/align-top.svg';
38
+ import alignLeft from './../theme/icons/align-left.svg';
39
+ import alignCenter from './../theme/icons/align-center.svg';
40
+ import alignRight from './../theme/icons/align-right.svg';
41
+ import alignJustify from './../theme/icons/align-justify.svg';
42
+
43
+ import objectBlockLeft from './../theme/icons/object-left.svg';
44
+ import objectCenter from './../theme/icons/object-center.svg';
45
+ import objectBlockRight from './../theme/icons/object-right.svg';
46
+ import objectFullWidth from './../theme/icons/object-full-width.svg';
47
+ import objectInline from './../theme/icons/object-inline.svg';
48
+ import objectLeft from './../theme/icons/object-inline-left.svg';
49
+ import objectRight from './../theme/icons/object-inline-right.svg';
50
+
51
+ import objectSizeFull from './../theme/icons/object-size-full.svg';
52
+ import objectSizeLarge from './../theme/icons/object-size-large.svg';
53
+ import objectSizeSmall from './../theme/icons/object-size-small.svg';
54
+ import objectSizeMedium from './../theme/icons/object-size-medium.svg';
55
+
56
+ import pencil from './../theme/icons/pencil.svg';
57
+ import pilcrow from './../theme/icons/pilcrow.svg';
58
+ import quote from './../theme/icons/quote.svg';
59
+ import threeVerticalDots from './../theme/icons/three-vertical-dots.svg';
60
+
61
+ export const icons = {
62
+ cancel,
63
+ caption,
64
+ check,
65
+ cog,
66
+ eraser,
67
+ lowVision,
68
+ image,
69
+
70
+ alignBottom,
71
+ alignMiddle,
72
+ alignTop,
73
+ alignLeft,
74
+ alignCenter,
75
+ alignRight,
76
+ alignJustify,
77
+
78
+ objectLeft,
79
+ objectCenter,
80
+ objectRight,
81
+ objectFullWidth,
82
+ objectInline,
83
+ objectBlockLeft,
84
+ objectBlockRight,
85
+
86
+ objectSizeFull,
87
+ objectSizeLarge,
88
+ objectSizeSmall,
89
+ objectSizeMedium,
90
+
91
+ pencil,
92
+ pilcrow,
93
+ quote,
94
+ threeVerticalDots
95
+ };
@@ -0,0 +1,101 @@
1
+ /**
2
+ * @license Copyright (c) 2003-2021, CKSource - Frederico Knabben. All rights reserved.
3
+ * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
4
+ */
5
+
6
+ import Command from './command';
7
+
8
+ /**
9
+ * @module core/multicommand
10
+ */
11
+
12
+ /**
13
+ * A CKEditor command that aggregates other commands.
14
+ *
15
+ * This command is used to proxy multiple commands. The multi-command is enabled when
16
+ * at least one of its registered child commands is enabled.
17
+ * When executing a multi-command the first command that is enabled will be executed.
18
+ *
19
+ * const multiCommand = new MultiCommand( editor );
20
+ *
21
+ * const commandFoo = new Command( editor );
22
+ * const commandBar = new Command( editor );
23
+ *
24
+ * // Register child commands.
25
+ * multiCommand.registerChildCommand( commandFoo );
26
+ * multiCommand.registerChildCommand( commandBar );
27
+ *
28
+ * // Enable one of the commands.
29
+ * commandBar.isEnabled = true;
30
+ *
31
+ * multiCommand.execute(); // Will execute commandBar.
32
+ *
33
+ * @extends module:core/command~Command
34
+ */
35
+ export default class MultiCommand extends Command {
36
+ /**
37
+ * @inheritDoc
38
+ */
39
+ constructor( editor ) {
40
+ super( editor );
41
+
42
+ /**
43
+ * Registered child commands.
44
+ *
45
+ * @type {Array.<module:core/command~Command>}
46
+ * @private
47
+ */
48
+ this._childCommands = [];
49
+ }
50
+
51
+ /**
52
+ * @inheritDoc
53
+ */
54
+ refresh() {
55
+ // Override base command refresh(): the command's state is changed when one of child commands changes states.
56
+ }
57
+
58
+ /**
59
+ * Executes the first of it registered child commands.
60
+ *
61
+ * @returns {*} The value returned by the {@link module:core/command~Command#execute `command.execute()`}.
62
+ */
63
+ execute( ...args ) {
64
+ const command = this._getFirstEnabledCommand();
65
+
66
+ return command != null && command.execute( args );
67
+ }
68
+
69
+ /**
70
+ * Registers a child command.
71
+ *
72
+ * @param {module:core/command~Command} command
73
+ */
74
+ registerChildCommand( command ) {
75
+ this._childCommands.push( command );
76
+
77
+ // Change multi command enabled state when one of registered commands changes state.
78
+ command.on( 'change:isEnabled', () => this._checkEnabled() );
79
+
80
+ this._checkEnabled();
81
+ }
82
+
83
+ /**
84
+ * Checks if any of child commands is enabled.
85
+ *
86
+ * @private
87
+ */
88
+ _checkEnabled() {
89
+ this.isEnabled = !!this._getFirstEnabledCommand();
90
+ }
91
+
92
+ /**
93
+ * Returns a first enabled command or undefined if none of them is enabled.
94
+ *
95
+ * @returns {module:core/command~Command|undefined}
96
+ * @private
97
+ */
98
+ _getFirstEnabledCommand() {
99
+ return this._childCommands.find( command => command.isEnabled );
100
+ }
101
+ }
@@ -0,0 +1,155 @@
1
+ /**
2
+ * @license Copyright (c) 2003-2021, CKSource - Frederico Knabben. All rights reserved.
3
+ * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
4
+ */
5
+
6
+ /**
7
+ * @module core/pendingactions
8
+ */
9
+
10
+ import ContextPlugin from './contextplugin';
11
+ import ObservableMixin from '@ckeditor/ckeditor5-utils/src/observablemixin';
12
+ import Collection from '@ckeditor/ckeditor5-utils/src/collection';
13
+ import CKEditorError from '@ckeditor/ckeditor5-utils/src/ckeditorerror';
14
+
15
+ /**
16
+ * The list of pending editor actions.
17
+ *
18
+ * This plugin should be used to synchronise plugins that execute long-lasting actions
19
+ * (e.g. file upload) with the editor integration. It gives the developer who integrates the editor
20
+ * an easy way to check if there are any actions pending whenever such information is needed.
21
+ * All plugins that register a pending action also provide a message about the action that is ongoing
22
+ * which can be displayed to the user. This lets them decide if they want to interrupt the action or wait.
23
+ *
24
+ * Adding and updating a pending action:
25
+ *
26
+ * const pendingActions = editor.plugins.get( 'PendingActions' );
27
+ * const action = pendingActions.add( 'Upload in progress: 0%.' );
28
+ *
29
+ * // You can update the message:
30
+ * action.message = 'Upload in progress: 10%.';
31
+ *
32
+ * Removing a pending action:
33
+ *
34
+ * const pendingActions = editor.plugins.get( 'PendingActions' );
35
+ * const action = pendingActions.add( 'Unsaved changes.' );
36
+ *
37
+ * pendingActions.remove( action );
38
+ *
39
+ * Getting pending actions:
40
+ *
41
+ * const pendingActions = editor.plugins.get( 'PendingActions' );
42
+ *
43
+ * const action1 = pendingActions.add( 'Action 1' );
44
+ * const action2 = pendingActions.add( 'Action 2' );
45
+ *
46
+ * pendingActions.first; // Returns action1
47
+ * Array.from( pendingActions ); // Returns [ action1, action2 ]
48
+ *
49
+ * This plugin is used by features like {@link module:upload/filerepository~FileRepository} to register their ongoing actions
50
+ * and by features like {@link module:autosave/autosave~Autosave} to detect whether there are any ongoing actions.
51
+ * Read more about saving the data in the {@glink builds/guides/integration/saving-data Saving and getting data} guide.
52
+ *
53
+ * @extends module:core/contextplugin~ContextPlugin
54
+ */
55
+ export default class PendingActions extends ContextPlugin {
56
+ /**
57
+ * @inheritDoc
58
+ */
59
+ static get pluginName() {
60
+ return 'PendingActions';
61
+ }
62
+
63
+ /**
64
+ * @inheritDoc
65
+ */
66
+ init() {
67
+ /**
68
+ * Defines whether there is any registered pending action.
69
+ *
70
+ * @readonly
71
+ * @observable
72
+ * @member {Boolean} #hasAny
73
+ */
74
+ this.set( 'hasAny', false );
75
+
76
+ /**
77
+ * A list of pending actions.
78
+ *
79
+ * @private
80
+ * @type {module:utils/collection~Collection}
81
+ */
82
+ this._actions = new Collection( { idProperty: '_id' } );
83
+ this._actions.delegate( 'add', 'remove' ).to( this );
84
+ }
85
+
86
+ /**
87
+ * Adds an action to the list of pending actions.
88
+ *
89
+ * This method returns an action object with an observable message property.
90
+ * The action object can be later used in the {@link #remove} method. It also allows you to change the message.
91
+ *
92
+ * @param {String} message The action message.
93
+ * @returns {Object} An observable object that represents a pending action.
94
+ */
95
+ add( message ) {
96
+ if ( typeof message !== 'string' ) {
97
+ /**
98
+ * The message must be a string.
99
+ *
100
+ * @error pendingactions-add-invalid-message
101
+ */
102
+ throw new CKEditorError( 'pendingactions-add-invalid-message', this );
103
+ }
104
+
105
+ const action = Object.create( ObservableMixin );
106
+
107
+ action.set( 'message', message );
108
+ this._actions.add( action );
109
+ this.hasAny = true;
110
+
111
+ return action;
112
+ }
113
+
114
+ /**
115
+ * Removes an action from the list of pending actions.
116
+ *
117
+ * @param {Object} action An action object.
118
+ */
119
+ remove( action ) {
120
+ this._actions.remove( action );
121
+ this.hasAny = !!this._actions.length;
122
+ }
123
+
124
+ /**
125
+ * Returns the first action from the list or null when list is empty
126
+ *
127
+ * returns {Object|null} The pending action object.
128
+ */
129
+ get first() {
130
+ return this._actions.get( 0 );
131
+ }
132
+
133
+ /**
134
+ * Iterable interface.
135
+ *
136
+ * @returns {Iterable.<*>}
137
+ */
138
+ [ Symbol.iterator ]() {
139
+ return this._actions[ Symbol.iterator ]();
140
+ }
141
+
142
+ /**
143
+ * Fired when an action is added to the list.
144
+ *
145
+ * @event add
146
+ * @param {Object} action The added action.
147
+ */
148
+
149
+ /**
150
+ * Fired when an action is removed from the list.
151
+ *
152
+ * @event remove
153
+ * @param {Object} action The removed action.
154
+ */
155
+ }