UNPKG

4.41 kBJavaScriptView Raw
1/**
2 * @license Copyright (c) 2003-2022, CKSource Holding sp. z o.o. 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
10import ContextPlugin from './contextplugin';
11import ObservableMixin from '@ckeditor/ckeditor5-utils/src/observablemixin';
12import Collection from '@ckeditor/ckeditor5-utils/src/collection';
13import 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 installation/advanced/saving-data Saving and getting data} guide.
52 *
53 * @extends module:core/contextplugin~ContextPlugin
54 */
55export 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}