@ckeditor/ckeditor5-autosave 38.1.1 → 38.2.0-alpha.1

Sign up to get free protection for your applications and to get access to all the features.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ckeditor/ckeditor5-autosave",
3
- "version": "38.1.1",
3
+ "version": "38.2.0-alpha.1",
4
4
  "description": "Autosave feature for CKEditor 5.",
5
5
  "keywords": [
6
6
  "ckeditor",
@@ -11,8 +11,9 @@
11
11
  "ckeditor5-dll"
12
12
  ],
13
13
  "main": "src/index.js",
14
+ "type": "module",
14
15
  "dependencies": {
15
- "ckeditor5": "38.1.1",
16
+ "ckeditor5": "38.2.0-alpha.1",
16
17
  "lodash-es": "^4.17.15"
17
18
  },
18
19
  "engines": {
@@ -1,18 +1,18 @@
1
- /**
2
- * @license Copyright (c) 2003-2023, 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
- import type { Autosave, AutosaveConfig } from './index';
6
- declare module '@ckeditor/ckeditor5-core' {
7
- interface PluginsMap {
8
- [Autosave.pluginName]: Autosave;
9
- }
10
- interface EditorConfig {
11
- /**
12
- * The configuration of the {@link module:autosave/autosave~Autosave autosave feature}.
13
- *
14
- * Read more in {@link module:autosave/autosave~AutosaveConfig}.
15
- */
16
- autosave?: AutosaveConfig;
17
- }
18
- }
1
+ /**
2
+ * @license Copyright (c) 2003-2023, 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
+ import type { Autosave, AutosaveConfig } from './index.js';
6
+ declare module '@ckeditor/ckeditor5-core' {
7
+ interface PluginsMap {
8
+ [Autosave.pluginName]: Autosave;
9
+ }
10
+ interface EditorConfig {
11
+ /**
12
+ * The configuration of the {@link module:autosave/autosave~Autosave autosave feature}.
13
+ *
14
+ * Read more in {@link module:autosave/autosave~AutosaveConfig}.
15
+ */
16
+ autosave?: AutosaveConfig;
17
+ }
18
+ }
@@ -1,5 +1,5 @@
1
- /**
2
- * @license Copyright (c) 2003-2023, 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
- export {};
1
+ /**
2
+ * @license Copyright (c) 2003-2023, 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
+ export {};
package/src/autosave.d.ts CHANGED
@@ -1,219 +1,219 @@
1
- /**
2
- * @license Copyright (c) 2003-2023, 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
- * @module autosave/autosave
7
- */
8
- import { Plugin, PendingActions, type Editor } from 'ckeditor5/src/core';
9
- /**
10
- * The {@link module:autosave/autosave~Autosave} plugin allows you to automatically save the data (e.g. send it to the server)
11
- * when needed (when the user changed the content).
12
- *
13
- * It listens to the {@link module:engine/model/document~Document#event:change:data `editor.model.document#change:data`}
14
- * and `window#beforeunload` events and calls the
15
- * {@link module:autosave/autosave~AutosaveAdapter#save `config.autosave.save()`} function.
16
- *
17
- * ```ts
18
- * ClassicEditor
19
- * .create( document.querySelector( '#editor' ), {
20
- * plugins: [ ArticlePluginSet, Autosave ],
21
- * toolbar: [ 'heading', '|', 'bold', 'italic', 'link', 'bulletedList', 'numberedList', 'blockQuote', 'undo', 'redo' ],
22
- * image: {
23
- * toolbar: [ 'imageStyle:block', 'imageStyle:side', '|', 'toggleImageCaption', 'imageTextAlternative' ],
24
- * },
25
- * autosave: {
26
- * save( editor: Editor ) {
27
- * // The saveData() function must return a promise
28
- * // which should be resolved when the data is successfully saved.
29
- * return saveData( editor.getData() );
30
- * }
31
- * }
32
- * } );
33
- * ```
34
- *
35
- * Read more about this feature in the {@glink features/autosave Autosave} feature guide.
36
- */
37
- export default class Autosave extends Plugin {
38
- /**
39
- * The adapter is an object with a `save()` method. That method will be called whenever
40
- * the data changes. It might be called some time after the change,
41
- * since the event is throttled for performance reasons.
42
- */
43
- adapter?: AutosaveAdapter;
44
- /**
45
- * The state of this plugin.
46
- *
47
- * The plugin can be in the following states:
48
- *
49
- * * synchronized – When all changes are saved.
50
- * * waiting – When the plugin is waiting for other changes before calling `adapter#save()` and `config.autosave.save()`.
51
- * * saving – When the provided save method is called and the plugin waits for the response.
52
- * * error &ndash When the provided save method will throw an error. This state immediately changes to the `saving` state and
53
- * the save method will be called again in the short period of time.
54
- *
55
- * @observable
56
- * @readonly
57
- */
58
- state: 'synchronized' | 'waiting' | 'saving' | 'error';
59
- /**
60
- * Debounced save method. The `save()` method is called the specified `waitingTime` after `debouncedSave()` is called,
61
- * unless a new action happens in the meantime.
62
- */
63
- private _debouncedSave;
64
- /**
65
- * The last saved document version.
66
- */
67
- private _lastDocumentVersion;
68
- /**
69
- * Promise used for asynchronous save calls.
70
- *
71
- * Created to handle the autosave call to an external data source. It resolves when that call is finished. It is re-used if
72
- * save is called before the promise has been resolved. It is set to `null` if there is no call in progress.
73
- */
74
- private _savePromise;
75
- /**
76
- * DOM emitter.
77
- */
78
- private _domEmitter;
79
- /**
80
- * The configuration of this plugins.
81
- */
82
- private _config;
83
- /**
84
- * Editor's pending actions manager.
85
- */
86
- private _pendingActions;
87
- /**
88
- * Informs whether there should be another autosave callback performed, immediately after current autosave callback finishes.
89
- *
90
- * This is set to `true` when there is a save request while autosave callback is already being processed
91
- * and the model has changed since the last save.
92
- */
93
- private _makeImmediateSave;
94
- /**
95
- * An action that will be added to the pending action manager for actions happening in that plugin.
96
- */
97
- private _action;
98
- /**
99
- * @inheritDoc
100
- */
101
- static get pluginName(): "Autosave";
102
- /**
103
- * @inheritDoc
104
- */
105
- static get requires(): readonly [typeof PendingActions];
106
- /**
107
- * @inheritDoc
108
- */
109
- constructor(editor: Editor);
110
- /**
111
- * @inheritDoc
112
- */
113
- init(): void;
114
- /**
115
- * @inheritDoc
116
- */
117
- destroy(): void;
118
- /**
119
- * Immediately calls autosave callback. All previously queued (debounced) callbacks are cleared. If there is already an autosave
120
- * callback in progress, then the requested save will be performed immediately after the current callback finishes.
121
- *
122
- * @returns A promise that will be resolved when the autosave callback is finished.
123
- */
124
- save(): Promise<void>;
125
- /**
126
- * Invokes the remaining `_save()` method call.
127
- */
128
- private _flush;
129
- /**
130
- * If the adapter is set and a new document version exists,
131
- * the `_save()` method creates a pending action and calls the `adapter.save()` method.
132
- * It waits for the result and then removes the created pending action.
133
- *
134
- * @returns A promise that will be resolved when the autosave callback is finished.
135
- */
136
- private _save;
137
- /**
138
- * Creates a pending action if it is not set already.
139
- */
140
- private _setPendingAction;
141
- /**
142
- * Saves callbacks.
143
- */
144
- private get _saveCallbacks();
145
- }
146
- /**
147
- * An interface that requires the `save()` method.
148
- *
149
- * Used by {@link module:autosave/autosave~Autosave#adapter}.
150
- */
151
- export interface AutosaveAdapter {
152
- /**
153
- * The method that will be called when the data changes. It should return a promise (e.g. in case of saving content to the database),
154
- * so the autosave plugin will wait for that action before removing it from pending actions.
155
- */
156
- save(editor: Editor): Promise<unknown>;
157
- }
158
- /**
159
- * The configuration of the {@link module:autosave/autosave~Autosave autosave feature}.
160
- *
161
- * ```ts
162
- * ClassicEditor
163
- * .create( editorElement, {
164
- * autosave: {
165
- * save( editor: Editor ) {
166
- * // The saveData() function must return a promise
167
- * // which should be resolved when the data is successfully saved.
168
- * return saveData( editor.getData() );
169
- * }
170
- * }
171
- * } );
172
- * .then( ... )
173
- * .catch( ... );
174
- * ```
175
- *
176
- * See {@link module:core/editor/editorconfig~EditorConfig all editor configuration options}.
177
- *
178
- * See also the demo of the {@glink features/autosave autosave feature}.
179
- */
180
- export interface AutosaveConfig {
181
- /**
182
- * The callback to be executed when the data needs to be saved.
183
- *
184
- * This function must return a promise which should be resolved when the data is successfully saved.
185
- *
186
- * ```ts
187
- * ClassicEditor
188
- * .create( editorElement, {
189
- * autosave: {
190
- * save( editor: Editor ) {
191
- * return saveData( editor.getData() );
192
- * }
193
- * }
194
- * } );
195
- * .then( ... )
196
- * .catch( ... );
197
- * ```
198
- */
199
- save?: (editor: Editor) => Promise<unknown>;
200
- /**
201
- * The minimum amount of time that needs to pass after the last action to call the provided callback.
202
- * By default it is 1000 ms.
203
- *
204
- * ```ts
205
- * ClassicEditor
206
- * .create( editorElement, {
207
- * autosave: {
208
- * save( editor: Editor ) {
209
- * return saveData( editor.getData() );
210
- * },
211
- * waitingTime: 2000
212
- * }
213
- * } );
214
- * .then( ... )
215
- * .catch( ... );
216
- * ```
217
- */
218
- waitingTime?: number;
219
- }
1
+ /**
2
+ * @license Copyright (c) 2003-2023, 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
+ * @module autosave/autosave
7
+ */
8
+ import { Plugin, PendingActions, type Editor } from 'ckeditor5/src/core.js';
9
+ /**
10
+ * The {@link module:autosave/autosave~Autosave} plugin allows you to automatically save the data (e.g. send it to the server)
11
+ * when needed (when the user changed the content).
12
+ *
13
+ * It listens to the {@link module:engine/model/document~Document#event:change:data `editor.model.document#change:data`}
14
+ * and `window#beforeunload` events and calls the
15
+ * {@link module:autosave/autosave~AutosaveAdapter#save `config.autosave.save()`} function.
16
+ *
17
+ * ```ts
18
+ * ClassicEditor
19
+ * .create( document.querySelector( '#editor' ), {
20
+ * plugins: [ ArticlePluginSet, Autosave ],
21
+ * toolbar: [ 'heading', '|', 'bold', 'italic', 'link', 'bulletedList', 'numberedList', 'blockQuote', 'undo', 'redo' ],
22
+ * image: {
23
+ * toolbar: [ 'imageStyle:block', 'imageStyle:side', '|', 'toggleImageCaption', 'imageTextAlternative' ],
24
+ * },
25
+ * autosave: {
26
+ * save( editor: Editor ) {
27
+ * // The saveData() function must return a promise
28
+ * // which should be resolved when the data is successfully saved.
29
+ * return saveData( editor.getData() );
30
+ * }
31
+ * }
32
+ * } );
33
+ * ```
34
+ *
35
+ * Read more about this feature in the {@glink features/autosave Autosave} feature guide.
36
+ */
37
+ export default class Autosave extends Plugin {
38
+ /**
39
+ * The adapter is an object with a `save()` method. That method will be called whenever
40
+ * the data changes. It might be called some time after the change,
41
+ * since the event is throttled for performance reasons.
42
+ */
43
+ adapter?: AutosaveAdapter;
44
+ /**
45
+ * The state of this plugin.
46
+ *
47
+ * The plugin can be in the following states:
48
+ *
49
+ * * synchronized &ndash; When all changes are saved.
50
+ * * waiting &ndash; When the plugin is waiting for other changes before calling `adapter#save()` and `config.autosave.save()`.
51
+ * * saving &ndash; When the provided save method is called and the plugin waits for the response.
52
+ * * error &ndash When the provided save method will throw an error. This state immediately changes to the `saving` state and
53
+ * the save method will be called again in the short period of time.
54
+ *
55
+ * @observable
56
+ * @readonly
57
+ */
58
+ state: 'synchronized' | 'waiting' | 'saving' | 'error';
59
+ /**
60
+ * Debounced save method. The `save()` method is called the specified `waitingTime` after `debouncedSave()` is called,
61
+ * unless a new action happens in the meantime.
62
+ */
63
+ private _debouncedSave;
64
+ /**
65
+ * The last saved document version.
66
+ */
67
+ private _lastDocumentVersion;
68
+ /**
69
+ * Promise used for asynchronous save calls.
70
+ *
71
+ * Created to handle the autosave call to an external data source. It resolves when that call is finished. It is re-used if
72
+ * save is called before the promise has been resolved. It is set to `null` if there is no call in progress.
73
+ */
74
+ private _savePromise;
75
+ /**
76
+ * DOM emitter.
77
+ */
78
+ private _domEmitter;
79
+ /**
80
+ * The configuration of this plugins.
81
+ */
82
+ private _config;
83
+ /**
84
+ * Editor's pending actions manager.
85
+ */
86
+ private _pendingActions;
87
+ /**
88
+ * Informs whether there should be another autosave callback performed, immediately after current autosave callback finishes.
89
+ *
90
+ * This is set to `true` when there is a save request while autosave callback is already being processed
91
+ * and the model has changed since the last save.
92
+ */
93
+ private _makeImmediateSave;
94
+ /**
95
+ * An action that will be added to the pending action manager for actions happening in that plugin.
96
+ */
97
+ private _action;
98
+ /**
99
+ * @inheritDoc
100
+ */
101
+ static get pluginName(): "Autosave";
102
+ /**
103
+ * @inheritDoc
104
+ */
105
+ static get requires(): readonly [typeof PendingActions];
106
+ /**
107
+ * @inheritDoc
108
+ */
109
+ constructor(editor: Editor);
110
+ /**
111
+ * @inheritDoc
112
+ */
113
+ init(): void;
114
+ /**
115
+ * @inheritDoc
116
+ */
117
+ destroy(): void;
118
+ /**
119
+ * Immediately calls autosave callback. All previously queued (debounced) callbacks are cleared. If there is already an autosave
120
+ * callback in progress, then the requested save will be performed immediately after the current callback finishes.
121
+ *
122
+ * @returns A promise that will be resolved when the autosave callback is finished.
123
+ */
124
+ save(): Promise<void>;
125
+ /**
126
+ * Invokes the remaining `_save()` method call.
127
+ */
128
+ private _flush;
129
+ /**
130
+ * If the adapter is set and a new document version exists,
131
+ * the `_save()` method creates a pending action and calls the `adapter.save()` method.
132
+ * It waits for the result and then removes the created pending action.
133
+ *
134
+ * @returns A promise that will be resolved when the autosave callback is finished.
135
+ */
136
+ private _save;
137
+ /**
138
+ * Creates a pending action if it is not set already.
139
+ */
140
+ private _setPendingAction;
141
+ /**
142
+ * Saves callbacks.
143
+ */
144
+ private get _saveCallbacks();
145
+ }
146
+ /**
147
+ * An interface that requires the `save()` method.
148
+ *
149
+ * Used by {@link module:autosave/autosave~Autosave#adapter}.
150
+ */
151
+ export interface AutosaveAdapter {
152
+ /**
153
+ * The method that will be called when the data changes. It should return a promise (e.g. in case of saving content to the database),
154
+ * so the autosave plugin will wait for that action before removing it from pending actions.
155
+ */
156
+ save(editor: Editor): Promise<unknown>;
157
+ }
158
+ /**
159
+ * The configuration of the {@link module:autosave/autosave~Autosave autosave feature}.
160
+ *
161
+ * ```ts
162
+ * ClassicEditor
163
+ * .create( editorElement, {
164
+ * autosave: {
165
+ * save( editor: Editor ) {
166
+ * // The saveData() function must return a promise
167
+ * // which should be resolved when the data is successfully saved.
168
+ * return saveData( editor.getData() );
169
+ * }
170
+ * }
171
+ * } );
172
+ * .then( ... )
173
+ * .catch( ... );
174
+ * ```
175
+ *
176
+ * See {@link module:core/editor/editorconfig~EditorConfig all editor configuration options}.
177
+ *
178
+ * See also the demo of the {@glink features/autosave autosave feature}.
179
+ */
180
+ export interface AutosaveConfig {
181
+ /**
182
+ * The callback to be executed when the data needs to be saved.
183
+ *
184
+ * This function must return a promise which should be resolved when the data is successfully saved.
185
+ *
186
+ * ```ts
187
+ * ClassicEditor
188
+ * .create( editorElement, {
189
+ * autosave: {
190
+ * save( editor: Editor ) {
191
+ * return saveData( editor.getData() );
192
+ * }
193
+ * }
194
+ * } );
195
+ * .then( ... )
196
+ * .catch( ... );
197
+ * ```
198
+ */
199
+ save?: (editor: Editor) => Promise<unknown>;
200
+ /**
201
+ * The minimum amount of time that needs to pass after the last action to call the provided callback.
202
+ * By default it is 1000 ms.
203
+ *
204
+ * ```ts
205
+ * ClassicEditor
206
+ * .create( editorElement, {
207
+ * autosave: {
208
+ * save( editor: Editor ) {
209
+ * return saveData( editor.getData() );
210
+ * },
211
+ * waitingTime: 2000
212
+ * }
213
+ * } );
214
+ * .then( ... )
215
+ * .catch( ... );
216
+ * ```
217
+ */
218
+ waitingTime?: number;
219
+ }
package/src/autosave.js CHANGED
@@ -1,228 +1,228 @@
1
- /**
2
- * @license Copyright (c) 2003-2023, 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
- * @module autosave/autosave
7
- */
8
- import { Plugin, PendingActions } from 'ckeditor5/src/core';
9
- import { DomEmitterMixin } from 'ckeditor5/src/utils';
10
- import { debounce } from 'lodash-es';
11
- /* globals window */
12
- /**
13
- * The {@link module:autosave/autosave~Autosave} plugin allows you to automatically save the data (e.g. send it to the server)
14
- * when needed (when the user changed the content).
15
- *
16
- * It listens to the {@link module:engine/model/document~Document#event:change:data `editor.model.document#change:data`}
17
- * and `window#beforeunload` events and calls the
18
- * {@link module:autosave/autosave~AutosaveAdapter#save `config.autosave.save()`} function.
19
- *
20
- * ```ts
21
- * ClassicEditor
22
- * .create( document.querySelector( '#editor' ), {
23
- * plugins: [ ArticlePluginSet, Autosave ],
24
- * toolbar: [ 'heading', '|', 'bold', 'italic', 'link', 'bulletedList', 'numberedList', 'blockQuote', 'undo', 'redo' ],
25
- * image: {
26
- * toolbar: [ 'imageStyle:block', 'imageStyle:side', '|', 'toggleImageCaption', 'imageTextAlternative' ],
27
- * },
28
- * autosave: {
29
- * save( editor: Editor ) {
30
- * // The saveData() function must return a promise
31
- * // which should be resolved when the data is successfully saved.
32
- * return saveData( editor.getData() );
33
- * }
34
- * }
35
- * } );
36
- * ```
37
- *
38
- * Read more about this feature in the {@glink features/autosave Autosave} feature guide.
39
- */
40
- export default class Autosave extends Plugin {
41
- /**
42
- * @inheritDoc
43
- */
44
- static get pluginName() {
45
- return 'Autosave';
46
- }
47
- /**
48
- * @inheritDoc
49
- */
50
- static get requires() {
51
- return [PendingActions];
52
- }
53
- /**
54
- * @inheritDoc
55
- */
56
- constructor(editor) {
57
- super(editor);
58
- /**
59
- * An action that will be added to the pending action manager for actions happening in that plugin.
60
- */
61
- this._action = null;
62
- const config = editor.config.get('autosave') || {};
63
- // A minimum amount of time that needs to pass after the last action.
64
- // After that time the provided save callbacks are being called.
65
- const waitingTime = config.waitingTime || 1000;
66
- this.set('state', 'synchronized');
67
- this._debouncedSave = debounce(this._save.bind(this), waitingTime);
68
- this._lastDocumentVersion = editor.model.document.version;
69
- this._savePromise = null;
70
- this._domEmitter = new (DomEmitterMixin())();
71
- this._config = config;
72
- this._pendingActions = editor.plugins.get(PendingActions);
73
- this._makeImmediateSave = false;
74
- }
75
- /**
76
- * @inheritDoc
77
- */
78
- init() {
79
- const editor = this.editor;
80
- const doc = editor.model.document;
81
- // Add the listener only after the editor is initialized to prevent firing save callback on data init.
82
- this.listenTo(editor, 'ready', () => {
83
- this.listenTo(doc, 'change:data', (evt, batch) => {
84
- if (!this._saveCallbacks.length) {
85
- return;
86
- }
87
- if (!batch.isLocal) {
88
- return;
89
- }
90
- if (this.state === 'synchronized') {
91
- this.state = 'waiting';
92
- // Set pending action already when we are waiting for the autosave callback.
93
- this._setPendingAction();
94
- }
95
- if (this.state === 'waiting') {
96
- this._debouncedSave();
97
- }
98
- // If the plugin is in `saving` state, it will change its state later basing on the `document.version`.
99
- // If the `document.version` will be higher than stored `#_lastDocumentVersion`, then it means, that some `change:data`
100
- // event has fired in the meantime.
101
- });
102
- });
103
- // Flush on the editor's destroy listener with the highest priority to ensure that
104
- // `editor.getData()` will be called before plugins are destroyed.
105
- this.listenTo(editor, 'destroy', () => this._flush(), { priority: 'highest' });
106
- // It's not possible to easy test it because karma uses `beforeunload` event
107
- // to warn before full page reload and this event cannot be dispatched manually.
108
- /* istanbul ignore next -- @preserve */
109
- this._domEmitter.listenTo(window, 'beforeunload', (evtInfo, domEvt) => {
110
- if (this._pendingActions.hasAny) {
111
- domEvt.returnValue = this._pendingActions.first.message;
112
- }
113
- });
114
- }
115
- /**
116
- * @inheritDoc
117
- */
118
- destroy() {
119
- // There's no need for canceling or flushing the throttled save, as
120
- // it's done on the editor's destroy event with the highest priority.
121
- this._domEmitter.stopListening();
122
- super.destroy();
123
- }
124
- /**
125
- * Immediately calls autosave callback. All previously queued (debounced) callbacks are cleared. If there is already an autosave
126
- * callback in progress, then the requested save will be performed immediately after the current callback finishes.
127
- *
128
- * @returns A promise that will be resolved when the autosave callback is finished.
129
- */
130
- save() {
131
- this._debouncedSave.cancel();
132
- return this._save();
133
- }
134
- /**
135
- * Invokes the remaining `_save()` method call.
136
- */
137
- _flush() {
138
- this._debouncedSave.flush();
139
- }
140
- /**
141
- * If the adapter is set and a new document version exists,
142
- * the `_save()` method creates a pending action and calls the `adapter.save()` method.
143
- * It waits for the result and then removes the created pending action.
144
- *
145
- * @returns A promise that will be resolved when the autosave callback is finished.
146
- */
147
- _save() {
148
- if (this._savePromise) {
149
- this._makeImmediateSave = this.editor.model.document.version > this._lastDocumentVersion;
150
- return this._savePromise;
151
- }
152
- // Make sure there is a pending action (in case if `_save()` was called through manual `save()` call).
153
- this._setPendingAction();
154
- this.state = 'saving';
155
- this._lastDocumentVersion = this.editor.model.document.version;
156
- // Wait one promise cycle to be sure that save callbacks are not called inside a conversion or when the editor's state changes.
157
- this._savePromise = Promise.resolve()
158
- // Make autosave callback.
159
- .then(() => Promise.all(this._saveCallbacks.map(cb => cb(this.editor))))
160
- // When the autosave callback is finished, always clear `this._savePromise`, no matter if it was successful or not.
161
- .finally(() => {
162
- this._savePromise = null;
163
- })
164
- // If the save was successful, we have three scenarios:
165
- //
166
- // 1. If a save was requested when an autosave callback was already processed, we need to immediately call
167
- // another autosave callback. In this case, `this._savePromise` will not be resolved until the next callback is done.
168
- // 2. Otherwise, if changes happened to the model, make a delayed autosave callback (like the change just happened).
169
- // 3. If no changes happened to the model, return to the `synchronized` state.
170
- .then(() => {
171
- if (this._makeImmediateSave) {
172
- this._makeImmediateSave = false;
173
- // Start another autosave callback. Return a promise that will be resolved after the new autosave callback.
174
- // This way promises returned by `_save()` will not be resolved until all changes are saved.
175
- //
176
- // If `save()` was called when another (most often automatic) autosave callback was already processed,
177
- // the promise returned by `save()` call will be resolved only after new changes have been saved.
178
- //
179
- // Note that it would not work correctly if `this._savePromise` is not cleared.
180
- return this._save();
181
- }
182
- else {
183
- if (this.editor.model.document.version > this._lastDocumentVersion) {
184
- this.state = 'waiting';
185
- this._debouncedSave();
186
- }
187
- else {
188
- this.state = 'synchronized';
189
- this._pendingActions.remove(this._action);
190
- this._action = null;
191
- }
192
- }
193
- })
194
- // In case of an error, retry the autosave callback after a delay (and also throw the original error).
195
- .catch(err => {
196
- // Change state to `error` so that listeners handling autosave error can be called.
197
- this.state = 'error';
198
- // Then, immediately change to the `saving` state as described above.
199
- // Being in the `saving` state ensures that the autosave callback won't be delayed further by the `change:data` listener.
200
- this.state = 'saving';
201
- this._debouncedSave();
202
- throw err;
203
- });
204
- return this._savePromise;
205
- }
206
- /**
207
- * Creates a pending action if it is not set already.
208
- */
209
- _setPendingAction() {
210
- const t = this.editor.t;
211
- if (!this._action) {
212
- this._action = this._pendingActions.add(t('Saving changes'));
213
- }
214
- }
215
- /**
216
- * Saves callbacks.
217
- */
218
- get _saveCallbacks() {
219
- const saveCallbacks = [];
220
- if (this.adapter && this.adapter.save) {
221
- saveCallbacks.push(this.adapter.save);
222
- }
223
- if (this._config.save) {
224
- saveCallbacks.push(this._config.save);
225
- }
226
- return saveCallbacks;
227
- }
228
- }
1
+ /**
2
+ * @license Copyright (c) 2003-2023, 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
+ * @module autosave/autosave
7
+ */
8
+ import { Plugin, PendingActions } from 'ckeditor5/src/core.js';
9
+ import { DomEmitterMixin } from 'ckeditor5/src/utils.js';
10
+ import { debounce } from 'lodash-es';
11
+ /* globals window */
12
+ /**
13
+ * The {@link module:autosave/autosave~Autosave} plugin allows you to automatically save the data (e.g. send it to the server)
14
+ * when needed (when the user changed the content).
15
+ *
16
+ * It listens to the {@link module:engine/model/document~Document#event:change:data `editor.model.document#change:data`}
17
+ * and `window#beforeunload` events and calls the
18
+ * {@link module:autosave/autosave~AutosaveAdapter#save `config.autosave.save()`} function.
19
+ *
20
+ * ```ts
21
+ * ClassicEditor
22
+ * .create( document.querySelector( '#editor' ), {
23
+ * plugins: [ ArticlePluginSet, Autosave ],
24
+ * toolbar: [ 'heading', '|', 'bold', 'italic', 'link', 'bulletedList', 'numberedList', 'blockQuote', 'undo', 'redo' ],
25
+ * image: {
26
+ * toolbar: [ 'imageStyle:block', 'imageStyle:side', '|', 'toggleImageCaption', 'imageTextAlternative' ],
27
+ * },
28
+ * autosave: {
29
+ * save( editor: Editor ) {
30
+ * // The saveData() function must return a promise
31
+ * // which should be resolved when the data is successfully saved.
32
+ * return saveData( editor.getData() );
33
+ * }
34
+ * }
35
+ * } );
36
+ * ```
37
+ *
38
+ * Read more about this feature in the {@glink features/autosave Autosave} feature guide.
39
+ */
40
+ export default class Autosave extends Plugin {
41
+ /**
42
+ * @inheritDoc
43
+ */
44
+ static get pluginName() {
45
+ return 'Autosave';
46
+ }
47
+ /**
48
+ * @inheritDoc
49
+ */
50
+ static get requires() {
51
+ return [PendingActions];
52
+ }
53
+ /**
54
+ * @inheritDoc
55
+ */
56
+ constructor(editor) {
57
+ super(editor);
58
+ /**
59
+ * An action that will be added to the pending action manager for actions happening in that plugin.
60
+ */
61
+ this._action = null;
62
+ const config = editor.config.get('autosave') || {};
63
+ // A minimum amount of time that needs to pass after the last action.
64
+ // After that time the provided save callbacks are being called.
65
+ const waitingTime = config.waitingTime || 1000;
66
+ this.set('state', 'synchronized');
67
+ this._debouncedSave = debounce(this._save.bind(this), waitingTime);
68
+ this._lastDocumentVersion = editor.model.document.version;
69
+ this._savePromise = null;
70
+ this._domEmitter = new (DomEmitterMixin())();
71
+ this._config = config;
72
+ this._pendingActions = editor.plugins.get(PendingActions);
73
+ this._makeImmediateSave = false;
74
+ }
75
+ /**
76
+ * @inheritDoc
77
+ */
78
+ init() {
79
+ const editor = this.editor;
80
+ const doc = editor.model.document;
81
+ // Add the listener only after the editor is initialized to prevent firing save callback on data init.
82
+ this.listenTo(editor, 'ready', () => {
83
+ this.listenTo(doc, 'change:data', (evt, batch) => {
84
+ if (!this._saveCallbacks.length) {
85
+ return;
86
+ }
87
+ if (!batch.isLocal) {
88
+ return;
89
+ }
90
+ if (this.state === 'synchronized') {
91
+ this.state = 'waiting';
92
+ // Set pending action already when we are waiting for the autosave callback.
93
+ this._setPendingAction();
94
+ }
95
+ if (this.state === 'waiting') {
96
+ this._debouncedSave();
97
+ }
98
+ // If the plugin is in `saving` state, it will change its state later basing on the `document.version`.
99
+ // If the `document.version` will be higher than stored `#_lastDocumentVersion`, then it means, that some `change:data`
100
+ // event has fired in the meantime.
101
+ });
102
+ });
103
+ // Flush on the editor's destroy listener with the highest priority to ensure that
104
+ // `editor.getData()` will be called before plugins are destroyed.
105
+ this.listenTo(editor, 'destroy', () => this._flush(), { priority: 'highest' });
106
+ // It's not possible to easy test it because karma uses `beforeunload` event
107
+ // to warn before full page reload and this event cannot be dispatched manually.
108
+ /* istanbul ignore next -- @preserve */
109
+ this._domEmitter.listenTo(window, 'beforeunload', (evtInfo, domEvt) => {
110
+ if (this._pendingActions.hasAny) {
111
+ domEvt.returnValue = this._pendingActions.first.message;
112
+ }
113
+ });
114
+ }
115
+ /**
116
+ * @inheritDoc
117
+ */
118
+ destroy() {
119
+ // There's no need for canceling or flushing the throttled save, as
120
+ // it's done on the editor's destroy event with the highest priority.
121
+ this._domEmitter.stopListening();
122
+ super.destroy();
123
+ }
124
+ /**
125
+ * Immediately calls autosave callback. All previously queued (debounced) callbacks are cleared. If there is already an autosave
126
+ * callback in progress, then the requested save will be performed immediately after the current callback finishes.
127
+ *
128
+ * @returns A promise that will be resolved when the autosave callback is finished.
129
+ */
130
+ save() {
131
+ this._debouncedSave.cancel();
132
+ return this._save();
133
+ }
134
+ /**
135
+ * Invokes the remaining `_save()` method call.
136
+ */
137
+ _flush() {
138
+ this._debouncedSave.flush();
139
+ }
140
+ /**
141
+ * If the adapter is set and a new document version exists,
142
+ * the `_save()` method creates a pending action and calls the `adapter.save()` method.
143
+ * It waits for the result and then removes the created pending action.
144
+ *
145
+ * @returns A promise that will be resolved when the autosave callback is finished.
146
+ */
147
+ _save() {
148
+ if (this._savePromise) {
149
+ this._makeImmediateSave = this.editor.model.document.version > this._lastDocumentVersion;
150
+ return this._savePromise;
151
+ }
152
+ // Make sure there is a pending action (in case if `_save()` was called through manual `save()` call).
153
+ this._setPendingAction();
154
+ this.state = 'saving';
155
+ this._lastDocumentVersion = this.editor.model.document.version;
156
+ // Wait one promise cycle to be sure that save callbacks are not called inside a conversion or when the editor's state changes.
157
+ this._savePromise = Promise.resolve()
158
+ // Make autosave callback.
159
+ .then(() => Promise.all(this._saveCallbacks.map(cb => cb(this.editor))))
160
+ // When the autosave callback is finished, always clear `this._savePromise`, no matter if it was successful or not.
161
+ .finally(() => {
162
+ this._savePromise = null;
163
+ })
164
+ // If the save was successful, we have three scenarios:
165
+ //
166
+ // 1. If a save was requested when an autosave callback was already processed, we need to immediately call
167
+ // another autosave callback. In this case, `this._savePromise` will not be resolved until the next callback is done.
168
+ // 2. Otherwise, if changes happened to the model, make a delayed autosave callback (like the change just happened).
169
+ // 3. If no changes happened to the model, return to the `synchronized` state.
170
+ .then(() => {
171
+ if (this._makeImmediateSave) {
172
+ this._makeImmediateSave = false;
173
+ // Start another autosave callback. Return a promise that will be resolved after the new autosave callback.
174
+ // This way promises returned by `_save()` will not be resolved until all changes are saved.
175
+ //
176
+ // If `save()` was called when another (most often automatic) autosave callback was already processed,
177
+ // the promise returned by `save()` call will be resolved only after new changes have been saved.
178
+ //
179
+ // Note that it would not work correctly if `this._savePromise` is not cleared.
180
+ return this._save();
181
+ }
182
+ else {
183
+ if (this.editor.model.document.version > this._lastDocumentVersion) {
184
+ this.state = 'waiting';
185
+ this._debouncedSave();
186
+ }
187
+ else {
188
+ this.state = 'synchronized';
189
+ this._pendingActions.remove(this._action);
190
+ this._action = null;
191
+ }
192
+ }
193
+ })
194
+ // In case of an error, retry the autosave callback after a delay (and also throw the original error).
195
+ .catch(err => {
196
+ // Change state to `error` so that listeners handling autosave error can be called.
197
+ this.state = 'error';
198
+ // Then, immediately change to the `saving` state as described above.
199
+ // Being in the `saving` state ensures that the autosave callback won't be delayed further by the `change:data` listener.
200
+ this.state = 'saving';
201
+ this._debouncedSave();
202
+ throw err;
203
+ });
204
+ return this._savePromise;
205
+ }
206
+ /**
207
+ * Creates a pending action if it is not set already.
208
+ */
209
+ _setPendingAction() {
210
+ const t = this.editor.t;
211
+ if (!this._action) {
212
+ this._action = this._pendingActions.add(t('Saving changes'));
213
+ }
214
+ }
215
+ /**
216
+ * Saves callbacks.
217
+ */
218
+ get _saveCallbacks() {
219
+ const saveCallbacks = [];
220
+ if (this.adapter && this.adapter.save) {
221
+ saveCallbacks.push(this.adapter.save);
222
+ }
223
+ if (this._config.save) {
224
+ saveCallbacks.push(this._config.save);
225
+ }
226
+ return saveCallbacks;
227
+ }
228
+ }
package/src/index.d.ts CHANGED
@@ -1,9 +1,9 @@
1
- /**
2
- * @license Copyright (c) 2003-2023, 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
- * @module autosave
7
- */
8
- export { default as Autosave, type AutosaveConfig } from './autosave';
9
- import './augmentation';
1
+ /**
2
+ * @license Copyright (c) 2003-2023, 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
+ * @module autosave
7
+ */
8
+ export { default as Autosave, type AutosaveConfig } from './autosave.js';
9
+ import './augmentation.js';
package/src/index.js CHANGED
@@ -1,9 +1,9 @@
1
- /**
2
- * @license Copyright (c) 2003-2023, 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
- * @module autosave
7
- */
8
- export { default as Autosave } from './autosave';
9
- import './augmentation';
1
+ /**
2
+ * @license Copyright (c) 2003-2023, 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
+ * @module autosave
7
+ */
8
+ export { default as Autosave } from './autosave.js';
9
+ import './augmentation.js';
@@ -1 +0,0 @@
1
- {"version":3,"sources":["webpack://CKEditor5.autosave/./src/autosave.js","webpack://CKEditor5.autosave/delegated \"./src/core.js\" from dll-reference CKEditor5.dll","webpack://CKEditor5.autosave/delegated \"./src/utils.js\" from dll-reference CKEditor5.dll","webpack://CKEditor5.autosave/external var \"CKEditor5.dll\"","webpack://CKEditor5.autosave/javascript/node_modules/lodash-es/_Symbol.js","webpack://CKEditor5.autosave/javascript/node_modules/lodash-es/_baseGetTag.js","webpack://CKEditor5.autosave/javascript/node_modules/lodash-es/_baseTrim.js","webpack://CKEditor5.autosave/javascript/node_modules/lodash-es/_freeGlobal.js","webpack://CKEditor5.autosave/javascript/node_modules/lodash-es/_getRawTag.js","webpack://CKEditor5.autosave/javascript/node_modules/lodash-es/_objectToString.js","webpack://CKEditor5.autosave/javascript/node_modules/lodash-es/_root.js","webpack://CKEditor5.autosave/javascript/node_modules/lodash-es/_trimmedEndIndex.js","webpack://CKEditor5.autosave/javascript/node_modules/lodash-es/debounce.js","webpack://CKEditor5.autosave/javascript/node_modules/lodash-es/isObject.js","webpack://CKEditor5.autosave/javascript/node_modules/lodash-es/isObjectLike.js","webpack://CKEditor5.autosave/javascript/node_modules/lodash-es/isSymbol.js","webpack://CKEditor5.autosave/javascript/node_modules/lodash-es/now.js","webpack://CKEditor5.autosave/javascript/node_modules/lodash-es/toNumber.js","webpack://CKEditor5.autosave/webpack/bootstrap","webpack://CKEditor5.autosave/webpack/runtime/define property getters","webpack://CKEditor5.autosave/webpack/runtime/hasOwnProperty shorthand","webpack://CKEditor5.autosave/webpack/runtime/make namespace object","webpack://CKEditor5.autosave/./src/index.js"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;AAAA;AACA;AACA;AACA;;AAEA;AACA;AACA;;AAE4D;AACgB;AACvC;;AAErC;;AAEA;AACA,QAAQ,yCAAyC;AACjD;AACA;AACA,sBAAsB;AACtB;AACA,IAAI,8EAA8E;AAClF;AACA;AACA;AACA;AACA;AACA;AACA;AACA,OAAO;AACP;AACA;AACA;AACA;AACA;AACA;AACA;AACA,OAAO;AACP;AACA,wCAAwC;AACxC,mBAAmB,iEAAiE;AACpF;AACA;AACA;AACe,uBAAuB,sDAAM;AAC5C;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA,WAAW,8DAAc;AACzB;;AAEA;AACA;AACA;AACA;AACA;;AAEA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA,cAAc,0CAA0C;AACxD;;AAEA;AACA;AACA;AACA;AACA;AACA,4BAA4B;AAC5B,uBAAuB;AACvB,sBAAsB;AACtB;AACA;AACA;AACA;AACA,cAAc,mCAAmC;AACjD;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA,YAAY;AACZ;AACA,wBAAwB,qDAAQ;;AAEhC;AACA;AACA;AACA;AACA,YAAY;AACZ;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA,YAAY;AACZ;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA,YAAY;AACZ;AACA,oCAAoC,gEAAe;;AAEnD;AACA;AACA;AACA;AACA,YAAY;AACZ;AACA;;AAEA;AACA;AACA;AACA;AACA,cAAc,2CAA2C;AACzD;AACA,6CAA6C,8DAAc;;AAE3D;AACA;AACA;AACA;AACA;AACA;AACA;AACA,YAAY;AACZ;AACA;;AAEA;AACA;AACA;AACA;AACA,cAAc,QAAQ;AACtB;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;AACA,KAAK;AACL,IAAI;;AAEJ;AACA;AACA,2DAA2D,sBAAsB;;AAEjF;AACA;AACA;AACA;AACA;AACA;AACA;AACA,IAAI;AACJ;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA,cAAc,SAAS;AACvB;AACA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA,cAAc,SAAS;AACvB;AACA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,KAAK;AACL;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,MAAM;AACN;AACA;AACA;AACA,OAAO;AACP;AACA;AACA;AACA;AACA;AACA,KAAK;AACL;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;;AAEA;AACA,KAAK;;AAEL;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA,WAAW;AACX;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;;AAEA,wDAAG,YAAY,gEAAe;;AAE9B;AACA;AACA;AACA,YAAY,gDAAgD;AAC5D;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA,WAAW,kCAAkC;AAC7C,aAAa;AACb;;AAEA;AACA,6BAA6B,yDAAyD;AACtF;AACA,iBAAiB,8CAA8C;AAC/D;AACA,YAAY,yCAAyC;AACrD;;AAEA;AACA,6BAA6B,yDAAyD;AACtF;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,OAAO;AACP;AACA;AACA;AACA,QAAQ,oFAAoF;AAC5F;AACA,6BAA6B,2EAA2E;AACxG;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,OAAO;AACP;AACA;AACA;AACA;AACA,WAAW,kCAAkC;AAC7C,aAAa;AACb;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,QAAQ;AACR;AACA;AACA,OAAO;AACP;AACA;AACA;AACA,YAAY,QAAQ;AACpB;;;;;;;;;;;AC5bA;;;;;;;;;;ACAA;;;;;;;;;;;ACAA;;;;;;;;;;;;;;;;ACA8B;;AAE9B;AACA,aAAa,uDAAW;;AAExB,iEAAe,MAAM,EAAC;;;;;;;;;;;;;;;;;;;ACLY;AACM;AACU;;AAElD;AACA;AACA;;AAEA;AACA,qBAAqB,kDAAM,GAAG,8DAAkB;;AAEhD;AACA;AACA;AACA;AACA,WAAW,GAAG;AACd,aAAa,QAAQ;AACrB;AACA;AACA;AACA;AACA;AACA;AACA,MAAM,yDAAS;AACf,MAAM,8DAAc;AACpB;;AAEA,iEAAe,UAAU,EAAC;;;;;;;;;;;;;;;;;AC3B0B;;AAEpD;AACA;;AAEA;AACA;AACA;AACA;AACA,WAAW,QAAQ;AACnB,aAAa,QAAQ;AACrB;AACA;AACA;AACA,sBAAsB,+DAAe;AACrC;AACA;;AAEA,iEAAe,QAAQ,EAAC;;;;;;;;;;;;;;;;AClBxB;AACA;;AAEA,iEAAe,UAAU,EAAC;;;;;;;;;;;;;;;;;ACHQ;;AAElC;AACA;;AAEA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA,qBAAqB,kDAAM,GAAG,8DAAkB;;AAEhD;AACA;AACA;AACA;AACA,WAAW,GAAG;AACd,aAAa,QAAQ;AACrB;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,IAAI;;AAEJ;AACA;AACA;AACA;AACA,MAAM;AACN;AACA;AACA;AACA;AACA;;AAEA,iEAAe,SAAS,EAAC;;;;;;;;;;;;;;;;AC7CzB;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA,WAAW,GAAG;AACd,aAAa,QAAQ;AACrB;AACA;AACA;AACA;;AAEA,iEAAe,cAAc,EAAC;;;;;;;;;;;;;;;;;ACrBY;;AAE1C;AACA;;AAEA;AACA,WAAW,sDAAU;;AAErB,iEAAe,IAAI,EAAC;;;;;;;;;;;;;;;;ACRpB;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA,WAAW,QAAQ;AACnB,aAAa,QAAQ;AACrB;AACA;AACA;;AAEA;AACA;AACA;;AAEA,iEAAe,eAAe,EAAC;;;;;;;;;;;;;;;;;;;AClBM;AACV;AACU;;AAErC;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,WAAW,UAAU;AACrB,WAAW,QAAQ;AACnB,WAAW,QAAQ,WAAW;AAC9B,WAAW,SAAS;AACpB;AACA,WAAW,QAAQ;AACnB;AACA,WAAW,SAAS;AACpB;AACA,aAAa,UAAU;AACvB;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,IAAI;AACJ;AACA;AACA,+CAA+C,iBAAiB;AAChE;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,SAAS,wDAAQ;AACjB,MAAM,wDAAQ;AACd;AACA;AACA,iCAAiC,wDAAQ;AACzC;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA,eAAe,mDAAG;AAClB;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA,yDAAyD,mDAAG;AAC5D;;AAEA;AACA,eAAe,mDAAG;AAClB;;AAEA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA,iEAAe,QAAQ,EAAC;;;;;;;;;;;;;;;;AC9LxB;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,WAAW,GAAG;AACd,aAAa,SAAS;AACtB;AACA;AACA,gBAAgB;AAChB;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA,iEAAe,QAAQ,EAAC;;;;;;;;;;;;;;;;AC9BxB;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,WAAW,GAAG;AACd,aAAa,SAAS;AACtB;AACA;AACA,oBAAoB;AACpB;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA,iEAAe,YAAY,EAAC;;;;;;;;;;;;;;;;;;AC5Bc;AACG;;AAE7C;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,WAAW,GAAG;AACd,aAAa,SAAS;AACtB;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,KAAK,4DAAY,WAAW,0DAAU;AACtC;;AAEA,iEAAe,QAAQ,EAAC;;;;;;;;;;;;;;;;;AC5BM;;AAE9B;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,aAAa,QAAQ;AACrB;AACA;AACA;AACA;AACA,IAAI;AACJ;AACA;AACA;AACA,SAAS,yDAAa;AACtB;;AAEA,iEAAe,GAAG,EAAC;;;;;;;;;;;;;;;;;;;ACtBmB;AACD;AACA;;AAErC;AACA;;AAEA;AACA;;AAEA;AACA;;AAEA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,WAAW,GAAG;AACd,aAAa,QAAQ;AACrB;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,MAAM,wDAAQ;AACd;AACA;AACA,MAAM,wDAAQ;AACd;AACA,YAAY,wDAAQ;AACpB;AACA;AACA;AACA;AACA,UAAU,wDAAQ;AAClB;AACA;AACA;AACA;AACA;;AAEA,iEAAe,QAAQ,EAAC;;;;;;;UC/DxB;UACA;;UAEA;UACA;UACA;UACA;UACA;UACA;UACA;UACA;UACA;UACA;UACA;UACA;UACA;;UAEA;UACA;;UAEA;UACA;UACA;;;;;WCtBA;WACA;WACA;WACA;WACA,yCAAyC,wCAAwC;WACjF;WACA;WACA;;;;;WCPA;;;;;WCAA;WACA;WACA;WACA,uDAAuD,iBAAiB;WACxE;WACA,gDAAgD,aAAa;WAC7D;;;;;;;;;;;;;;;;ACNA;AACA;AACA;AACA;;AAEA;AACA;AACA;;AAEiD","file":"autosave.js","sourcesContent":["/**\n * @license Copyright (c) 2003-2022, CKSource Holding sp. z o.o. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n\n/**\n * @module autosave/autosave\n */\n\nimport { Plugin, PendingActions } from 'ckeditor5/src/core';\nimport { DomEmitterMixin, ObservableMixin, mix } from 'ckeditor5/src/utils';\nimport { debounce } from 'lodash-es';\n\n/* globals window */\n\n/**\n * The {@link module:autosave/autosave~Autosave} plugin allows you to automatically save the data (e.g. send it to the server)\n * when needed (when the user changed the content).\n *\n * It listens to the {@link module:engine/model/document~Document#event:change:data `editor.model.document#change:data`}\n * and `window#beforeunload` events and calls the\n * {@link module:autosave/autosave~AutosaveAdapter#save `config.autosave.save()`} function.\n *\n *\t\tClassicEditor\n *\t\t\t.create( document.querySelector( '#editor' ), {\n *\t\t\t\tplugins: [ ArticlePluginSet, Autosave ],\n *\t\t\t\ttoolbar: [ 'heading', '|', 'bold', 'italic', 'link', 'bulletedList', 'numberedList', 'blockQuote', 'undo', 'redo' ],\n *\t\t\t\timage: {\n *\t\t\t\t\ttoolbar: [ 'imageStyle:block', 'imageStyle:side', '|', 'toggleImageCaption', 'imageTextAlternative' ],\n *\t\t\t\t},\n *\t\t\t\tautosave: {\n *\t\t\t\t\tsave( editor ) {\n *\t\t\t\t\t\t// The saveData() function must return a promise\n *\t\t\t\t\t\t// which should be resolved when the data is successfully saved.\n *\t\t\t\t\t\treturn saveData( editor.getData() );\n *\t\t\t\t\t}\n *\t\t\t\t}\n *\t\t\t} );\n *\n * Read more about this feature in the {@glink installation/advanced/saving-data#autosave-feature Autosave feature}\n * section of the {@glink installation/advanced/saving-data Saving and getting data}.\n *\n * @extends module:core/plugin~Plugin\n */\nexport default class Autosave extends Plugin {\n\t/**\n\t * @inheritDoc\n\t */\n\tstatic get pluginName() {\n\t\treturn 'Autosave';\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\tstatic get requires() {\n\t\treturn [ PendingActions ];\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\tconstructor( editor ) {\n\t\tsuper( editor );\n\n\t\tconst config = editor.config.get( 'autosave' ) || {};\n\n\t\t// A minimum amount of time that needs to pass after the last action.\n\t\t// After that time the provided save callbacks are being called.\n\t\tconst waitingTime = config.waitingTime || 1000;\n\n\t\t/**\n\t\t * The adapter is an object with a `save()` method. That method will be called whenever\n\t\t * the data changes. It might be called some time after the change,\n\t\t * since the event is throttled for performance reasons.\n\t\t *\n\t\t * @member {module:autosave/autosave~AutosaveAdapter} #adapter\n\t\t */\n\n\t\t/**\n\t\t * The state of this plugin.\n\t\t *\n\t\t * The plugin can be in the following states:\n\t\t *\n\t\t * * synchronized &ndash; When all changes are saved.\n\t\t * * waiting &ndash; When the plugin is waiting for other changes before calling `adapter#save()` and `config.autosave.save()`.\n\t\t * * saving &ndash; When the provided save method is called and the plugin waits for the response.\n\t\t * * error &ndash When the provided save method will throw an error. This state immediately changes to the `saving` state and\n\t\t * the save method will be called again in the short period of time.\n\t\t *\n\t\t * @readonly\n\t\t * @member {'synchronized'|'waiting'|'saving'} #state\n\t\t */\n\t\tthis.set( 'state', 'synchronized' );\n\n\t\t/**\n\t\t * Debounced save method. The `save()` method is called the specified `waitingTime` after `debouncedSave()` is called,\n\t\t * unless a new action happens in the meantime.\n\t\t *\n\t\t * @private\n\t\t * @type {Function}\n\t\t */\n\t\tthis._debouncedSave = debounce( this._save.bind( this ), waitingTime );\n\n\t\t/**\n\t\t * The last saved document version.\n\t\t *\n\t\t * @private\n\t\t * @type {Number}\n\t\t */\n\t\tthis._lastDocumentVersion = editor.model.document.version;\n\n\t\t/**\n\t\t * Promise used for asynchronous save calls.\n\t\t *\n\t\t * Created to handle the autosave call to an external data source. It resolves when that call is finished. It is re-used if\n\t\t * save is called before the promise has been resolved. It is set to `null` if there is no call in progress.\n\t\t *\n\t\t * @type {Promise|null}\n\t\t * @private\n\t\t */\n\t\tthis._savePromise = null;\n\n\t\t/**\n\t\t * DOM emitter.\n\t\t *\n\t\t * @private\n\t\t * @type {DomEmitterMixin}\n\t\t */\n\t\tthis._domEmitter = Object.create( DomEmitterMixin );\n\n\t\t/**\n\t\t * The configuration of this plugins.\n\t\t *\n\t\t * @private\n\t\t * @type {Object}\n\t\t */\n\t\tthis._config = config;\n\n\t\t/**\n\t\t * Editor's pending actions manager.\n\t\t *\n\t\t * @private\n\t\t * @member {module:core/pendingactions~PendingActions} #_pendingActions\n\t\t */\n\t\tthis._pendingActions = editor.plugins.get( PendingActions );\n\n\t\t/**\n\t\t * Informs whether there should be another autosave callback performed, immediately after current autosave callback finishes.\n\t\t *\n\t\t * This is set to `true` when there is a save request while autosave callback is already being processed\n\t\t * and the model has changed since the last save.\n\t\t *\n\t\t * @private\n\t\t * @type {Boolean}\n\t\t */\n\t\tthis._makeImmediateSave = false;\n\n\t\t/**\n\t\t * An action that will be added to the pending action manager for actions happening in that plugin.\n\t\t *\n\t\t * @private\n\t\t * @member {Object} #_action\n\t\t */\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\tinit() {\n\t\tconst editor = this.editor;\n\t\tconst doc = editor.model.document;\n\n\t\t// Add the listener only after the editor is initialized to prevent firing save callback on data init.\n\t\tthis.listenTo( editor, 'ready', () => {\n\t\t\tthis.listenTo( doc, 'change:data', ( evt, batch ) => {\n\t\t\t\tif ( !this._saveCallbacks.length ) {\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\tif ( !batch.isLocal ) {\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\tif ( this.state === 'synchronized' ) {\n\t\t\t\t\tthis.state = 'waiting';\n\t\t\t\t\t// Set pending action already when we are waiting for the autosave callback.\n\t\t\t\t\tthis._setPendingAction();\n\t\t\t\t}\n\n\t\t\t\tif ( this.state === 'waiting' ) {\n\t\t\t\t\tthis._debouncedSave();\n\t\t\t\t}\n\n\t\t\t\t// If the plugin is in `saving` state, it will change its state later basing on the `document.version`.\n\t\t\t\t// If the `document.version` will be higher than stored `#_lastDocumentVersion`, then it means, that some `change:data`\n\t\t\t\t// event has fired in the meantime.\n\t\t\t} );\n\t\t} );\n\n\t\t// Flush on the editor's destroy listener with the highest priority to ensure that\n\t\t// `editor.getData()` will be called before plugins are destroyed.\n\t\tthis.listenTo( editor, 'destroy', () => this._flush(), { priority: 'highest' } );\n\n\t\t// It's not possible to easy test it because karma uses `beforeunload` event\n\t\t// to warn before full page reload and this event cannot be dispatched manually.\n\t\t/* istanbul ignore next */\n\t\tthis._domEmitter.listenTo( window, 'beforeunload', ( evtInfo, domEvt ) => {\n\t\t\tif ( this._pendingActions.hasAny ) {\n\t\t\t\tdomEvt.returnValue = this._pendingActions.first.message;\n\t\t\t}\n\t\t} );\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\tdestroy() {\n\t\t// There's no need for canceling or flushing the throttled save, as\n\t\t// it's done on the editor's destroy event with the highest priority.\n\n\t\tthis._domEmitter.stopListening();\n\t\tsuper.destroy();\n\t}\n\n\t/**\n\t * Immediately calls autosave callback. All previously queued (debounced) callbacks are cleared. If there is already an autosave\n\t * callback in progress, then the requested save will be performed immediately after the current callback finishes.\n\t *\n\t * @returns {Promise} A promise that will be resolved when the autosave callback is finished.\n\t */\n\tsave() {\n\t\tthis._debouncedSave.cancel();\n\n\t\treturn this._save();\n\t}\n\n\t/**\n\t * Invokes the remaining `_save()` method call.\n\t *\n\t * @protected\n\t */\n\t_flush() {\n\t\tthis._debouncedSave.flush();\n\t}\n\n\t/**\n\t * If the adapter is set and a new document version exists,\n\t * the `_save()` method creates a pending action and calls the `adapter.save()` method.\n\t * It waits for the result and then removes the created pending action.\n\t *\n\t * @private\n\t * @returns {Promise} A promise that will be resolved when the autosave callback is finished.\n\t */\n\t_save() {\n\t\tif ( this._savePromise ) {\n\t\t\tthis._makeImmediateSave = this.editor.model.document.version > this._lastDocumentVersion;\n\n\t\t\treturn this._savePromise;\n\t\t}\n\n\t\t// Make sure there is a pending action (in case if `_save()` was called through manual `save()` call).\n\t\tthis._setPendingAction();\n\n\t\tthis.state = 'saving';\n\t\tthis._lastDocumentVersion = this.editor.model.document.version;\n\n\t\t// Wait one promise cycle to be sure that save callbacks are not called inside a conversion or when the editor's state changes.\n\t\tthis._savePromise = Promise.resolve()\n\t\t\t// Make autosave callback.\n\t\t\t.then( () => Promise.all(\n\t\t\t\tthis._saveCallbacks.map( cb => cb( this.editor ) )\n\t\t\t) )\n\t\t\t// When the autosave callback is finished, always clear `this._savePromise`, no matter if it was successful or not.\n\t\t\t.finally( () => {\n\t\t\t\tthis._savePromise = null;\n\t\t\t} )\n\t\t\t// If the save was successful, we have three scenarios:\n\t\t\t//\n\t\t\t// 1. If a save was requested when an autosave callback was already processed, we need to immediately call\n\t\t\t// another autosave callback. In this case, `this._savePromise` will not be resolved until the next callback is done.\n\t\t\t// 2. Otherwise, if changes happened to the model, make a delayed autosave callback (like the change just happened).\n\t\t\t// 3. If no changes happened to the model, return to the `synchronized` state.\n\t\t\t.then( () => {\n\t\t\t\tif ( this._makeImmediateSave ) {\n\t\t\t\t\tthis._makeImmediateSave = false;\n\n\t\t\t\t\t// Start another autosave callback. Return a promise that will be resolved after the new autosave callback.\n\t\t\t\t\t// This way promises returned by `_save()` will not be resolved until all changes are saved.\n\t\t\t\t\t//\n\t\t\t\t\t// If `save()` was called when another (most often automatic) autosave callback was already processed,\n\t\t\t\t\t// the promise returned by `save()` call will be resolved only after new changes have been saved.\n\t\t\t\t\t//\n\t\t\t\t\t// Note that it would not work correctly if `this._savePromise` is not cleared.\n\t\t\t\t\treturn this._save();\n\t\t\t\t} else {\n\t\t\t\t\tif ( this.editor.model.document.version > this._lastDocumentVersion ) {\n\t\t\t\t\t\tthis.state = 'waiting';\n\t\t\t\t\t\tthis._debouncedSave();\n\t\t\t\t\t} else {\n\t\t\t\t\t\tthis.state = 'synchronized';\n\t\t\t\t\t\tthis._pendingActions.remove( this._action );\n\t\t\t\t\t\tthis._action = null;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t} )\n\t\t\t// In case of an error, retry the autosave callback after a delay (and also throw the original error).\n\t\t\t.catch( err => {\n\t\t\t\t// Change state to `error` so that listeners handling autosave error can be called.\n\t\t\t\tthis.state = 'error';\n\t\t\t\t// Then, immediately change to the `saving` state as described above.\n\t\t\t\t// Being in the `saving` state ensures that the autosave callback won't be delayed further by the `change:data` listener.\n\t\t\t\tthis.state = 'saving';\n\n\t\t\t\tthis._debouncedSave();\n\n\t\t\t\tthrow err;\n\t\t\t} );\n\n\t\treturn this._savePromise;\n\t}\n\n\t/**\n\t * Creates a pending action if it is not set already.\n\t *\n\t * @private\n\t */\n\t_setPendingAction() {\n\t\tconst t = this.editor.t;\n\n\t\tif ( !this._action ) {\n\t\t\tthis._action = this._pendingActions.add( t( 'Saving changes' ) );\n\t\t}\n\t}\n\n\t/**\n\t * Saves callbacks.\n\t *\n\t * @private\n\t * @type {Array.<Function>}\n\t */\n\tget _saveCallbacks() {\n\t\tconst saveCallbacks = [];\n\n\t\tif ( this.adapter && this.adapter.save ) {\n\t\t\tsaveCallbacks.push( this.adapter.save );\n\t\t}\n\n\t\tif ( this._config.save ) {\n\t\t\tsaveCallbacks.push( this._config.save );\n\t\t}\n\n\t\treturn saveCallbacks;\n\t}\n}\n\nmix( Autosave, ObservableMixin );\n\n/**\n * An interface that requires the `save()` method.\n *\n * Used by {@link module:autosave/autosave~Autosave#adapter}.\n *\n * @interface module:autosave/autosave~AutosaveAdapter\n */\n\n/**\n * The method that will be called when the data changes. It should return a promise (e.g. in case of saving content to the database),\n * so the autosave plugin will wait for that action before removing it from pending actions.\n *\n * @method #save\n * @param {module:core/editor/editor~Editor} editor The editor instance.\n * @returns {Promise.<*>}\n */\n\n/**\n * The configuration of the {@link module:autosave/autosave~Autosave autosave feature}.\n *\n * Read more in {@link module:autosave/autosave~AutosaveConfig}.\n *\n * @member {module:autosave/autosave~AutosaveConfig} module:core/editor/editorconfig~EditorConfig#autosave\n */\n\n/**\n * The configuration of the {@link module:autosave/autosave~Autosave autosave feature}.\n *\n *\t\tClassicEditor\n *\t\t\t.create( editorElement, {\n *\t\t\t\tautosave: {\n *\t\t\t\t\tsave( editor ) {\n *\t\t\t\t\t\t// The saveData() function must return a promise\n *\t\t\t\t\t\t// which should be resolved when the data is successfully saved.\n *\t\t\t\t\t\treturn saveData( editor.getData() );\n *\t\t\t\t\t}\n *\t\t\t\t}\n *\t\t\t} );\n *\t\t\t.then( ... )\n *\t\t\t.catch( ... );\n *\n * See {@link module:core/editor/editorconfig~EditorConfig all editor configuration options}.\n *\n * See also the demo of the {@glink installation/advanced/saving-data#autosave-feature autosave feature}.\n *\n * @interface AutosaveConfig\n */\n\n/**\n * The callback to be executed when the data needs to be saved.\n *\n * This function must return a promise which should be resolved when the data is successfully saved.\n *\n *\t\tClassicEditor\n *\t\t\t.create( editorElement, {\n *\t\t\t\tautosave: {\n *\t\t\t\t\tsave( editor ) {\n *\t\t\t\t\t\treturn saveData( editor.getData() );\n *\t\t\t\t\t}\n *\t\t\t\t}\n *\t\t\t} );\n *\t\t\t.then( ... )\n *\t\t\t.catch( ... );\n *\n * @method module:autosave/autosave~AutosaveConfig#save\n * @param {module:core/editor/editor~Editor} editor The editor instance.\n * @returns {Promise.<*>}\n */\n\n/**\n * The minimum amount of time that needs to pass after the last action to call the provided callback.\n * By default it is 1000 ms.\n *\n *\t\tClassicEditor\n *\t\t\t.create( editorElement, {\n *\t\t\t\tautosave: {\n *\t\t\t\t\tsave( editor ) {\n *\t\t\t\t\t\treturn saveData( editor.getData() );\n *\t\t\t\t\t},\n *\t\t\t\t\twaitingTime: 2000\n *\t\t\t\t}\n *\t\t\t} );\n *\t\t\t.then( ... )\n *\t\t\t.catch( ... );\n *\n * @member {Number} module:autosave/autosave~AutosaveConfig#waitingTime\n */\n","module.exports = (__webpack_require__(/*! dll-reference CKEditor5.dll */ \"dll-reference CKEditor5.dll\"))(\"./src/core.js\");","module.exports = (__webpack_require__(/*! dll-reference CKEditor5.dll */ \"dll-reference CKEditor5.dll\"))(\"./src/utils.js\");","module.exports = CKEditor5.dll;","import root from './_root.js';\n\n/** Built-in value references. */\nvar Symbol = root.Symbol;\n\nexport default Symbol;\n","import Symbol from './_Symbol.js';\nimport getRawTag from './_getRawTag.js';\nimport objectToString from './_objectToString.js';\n\n/** `Object#toString` result references. */\nvar nullTag = '[object Null]',\n undefinedTag = '[object Undefined]';\n\n/** Built-in value references. */\nvar symToStringTag = Symbol ? Symbol.toStringTag : undefined;\n\n/**\n * The base implementation of `getTag` without fallbacks for buggy environments.\n *\n * @private\n * @param {*} value The value to query.\n * @returns {string} Returns the `toStringTag`.\n */\nfunction baseGetTag(value) {\n if (value == null) {\n return value === undefined ? undefinedTag : nullTag;\n }\n return (symToStringTag && symToStringTag in Object(value))\n ? getRawTag(value)\n : objectToString(value);\n}\n\nexport default baseGetTag;\n","import trimmedEndIndex from './_trimmedEndIndex.js';\n\n/** Used to match leading whitespace. */\nvar reTrimStart = /^\\s+/;\n\n/**\n * The base implementation of `_.trim`.\n *\n * @private\n * @param {string} string The string to trim.\n * @returns {string} Returns the trimmed string.\n */\nfunction baseTrim(string) {\n return string\n ? string.slice(0, trimmedEndIndex(string) + 1).replace(reTrimStart, '')\n : string;\n}\n\nexport default baseTrim;\n","/** Detect free variable `global` from Node.js. */\nvar freeGlobal = typeof global == 'object' && global && global.Object === Object && global;\n\nexport default freeGlobal;\n","import Symbol from './_Symbol.js';\n\n/** Used for built-in method references. */\nvar objectProto = Object.prototype;\n\n/** Used to check objects for own properties. */\nvar hasOwnProperty = objectProto.hasOwnProperty;\n\n/**\n * Used to resolve the\n * [`toStringTag`](http://ecma-international.org/ecma-262/7.0/#sec-object.prototype.tostring)\n * of values.\n */\nvar nativeObjectToString = objectProto.toString;\n\n/** Built-in value references. */\nvar symToStringTag = Symbol ? Symbol.toStringTag : undefined;\n\n/**\n * A specialized version of `baseGetTag` which ignores `Symbol.toStringTag` values.\n *\n * @private\n * @param {*} value The value to query.\n * @returns {string} Returns the raw `toStringTag`.\n */\nfunction getRawTag(value) {\n var isOwn = hasOwnProperty.call(value, symToStringTag),\n tag = value[symToStringTag];\n\n try {\n value[symToStringTag] = undefined;\n var unmasked = true;\n } catch (e) {}\n\n var result = nativeObjectToString.call(value);\n if (unmasked) {\n if (isOwn) {\n value[symToStringTag] = tag;\n } else {\n delete value[symToStringTag];\n }\n }\n return result;\n}\n\nexport default getRawTag;\n","/** Used for built-in method references. */\nvar objectProto = Object.prototype;\n\n/**\n * Used to resolve the\n * [`toStringTag`](http://ecma-international.org/ecma-262/7.0/#sec-object.prototype.tostring)\n * of values.\n */\nvar nativeObjectToString = objectProto.toString;\n\n/**\n * Converts `value` to a string using `Object.prototype.toString`.\n *\n * @private\n * @param {*} value The value to convert.\n * @returns {string} Returns the converted string.\n */\nfunction objectToString(value) {\n return nativeObjectToString.call(value);\n}\n\nexport default objectToString;\n","import freeGlobal from './_freeGlobal.js';\n\n/** Detect free variable `self`. */\nvar freeSelf = typeof self == 'object' && self && self.Object === Object && self;\n\n/** Used as a reference to the global object. */\nvar root = freeGlobal || freeSelf || Function('return this')();\n\nexport default root;\n","/** Used to match a single whitespace character. */\nvar reWhitespace = /\\s/;\n\n/**\n * Used by `_.trim` and `_.trimEnd` to get the index of the last non-whitespace\n * character of `string`.\n *\n * @private\n * @param {string} string The string to inspect.\n * @returns {number} Returns the index of the last non-whitespace character.\n */\nfunction trimmedEndIndex(string) {\n var index = string.length;\n\n while (index-- && reWhitespace.test(string.charAt(index))) {}\n return index;\n}\n\nexport default trimmedEndIndex;\n","import isObject from './isObject.js';\nimport now from './now.js';\nimport toNumber from './toNumber.js';\n\n/** Error message constants. */\nvar FUNC_ERROR_TEXT = 'Expected a function';\n\n/* Built-in method references for those with the same name as other `lodash` methods. */\nvar nativeMax = Math.max,\n nativeMin = Math.min;\n\n/**\n * Creates a debounced function that delays invoking `func` until after `wait`\n * milliseconds have elapsed since the last time the debounced function was\n * invoked. The debounced function comes with a `cancel` method to cancel\n * delayed `func` invocations and a `flush` method to immediately invoke them.\n * Provide `options` to indicate whether `func` should be invoked on the\n * leading and/or trailing edge of the `wait` timeout. The `func` is invoked\n * with the last arguments provided to the debounced function. Subsequent\n * calls to the debounced function return the result of the last `func`\n * invocation.\n *\n * **Note:** If `leading` and `trailing` options are `true`, `func` is\n * invoked on the trailing edge of the timeout only if the debounced function\n * is invoked more than once during the `wait` timeout.\n *\n * If `wait` is `0` and `leading` is `false`, `func` invocation is deferred\n * until to the next tick, similar to `setTimeout` with a timeout of `0`.\n *\n * See [David Corbacho's article](https://css-tricks.com/debouncing-throttling-explained-examples/)\n * for details over the differences between `_.debounce` and `_.throttle`.\n *\n * @static\n * @memberOf _\n * @since 0.1.0\n * @category Function\n * @param {Function} func The function to debounce.\n * @param {number} [wait=0] The number of milliseconds to delay.\n * @param {Object} [options={}] The options object.\n * @param {boolean} [options.leading=false]\n * Specify invoking on the leading edge of the timeout.\n * @param {number} [options.maxWait]\n * The maximum time `func` is allowed to be delayed before it's invoked.\n * @param {boolean} [options.trailing=true]\n * Specify invoking on the trailing edge of the timeout.\n * @returns {Function} Returns the new debounced function.\n * @example\n *\n * // Avoid costly calculations while the window size is in flux.\n * jQuery(window).on('resize', _.debounce(calculateLayout, 150));\n *\n * // Invoke `sendMail` when clicked, debouncing subsequent calls.\n * jQuery(element).on('click', _.debounce(sendMail, 300, {\n * 'leading': true,\n * 'trailing': false\n * }));\n *\n * // Ensure `batchLog` is invoked once after 1 second of debounced calls.\n * var debounced = _.debounce(batchLog, 250, { 'maxWait': 1000 });\n * var source = new EventSource('/stream');\n * jQuery(source).on('message', debounced);\n *\n * // Cancel the trailing debounced invocation.\n * jQuery(window).on('popstate', debounced.cancel);\n */\nfunction debounce(func, wait, options) {\n var lastArgs,\n lastThis,\n maxWait,\n result,\n timerId,\n lastCallTime,\n lastInvokeTime = 0,\n leading = false,\n maxing = false,\n trailing = true;\n\n if (typeof func != 'function') {\n throw new TypeError(FUNC_ERROR_TEXT);\n }\n wait = toNumber(wait) || 0;\n if (isObject(options)) {\n leading = !!options.leading;\n maxing = 'maxWait' in options;\n maxWait = maxing ? nativeMax(toNumber(options.maxWait) || 0, wait) : maxWait;\n trailing = 'trailing' in options ? !!options.trailing : trailing;\n }\n\n function invokeFunc(time) {\n var args = lastArgs,\n thisArg = lastThis;\n\n lastArgs = lastThis = undefined;\n lastInvokeTime = time;\n result = func.apply(thisArg, args);\n return result;\n }\n\n function leadingEdge(time) {\n // Reset any `maxWait` timer.\n lastInvokeTime = time;\n // Start the timer for the trailing edge.\n timerId = setTimeout(timerExpired, wait);\n // Invoke the leading edge.\n return leading ? invokeFunc(time) : result;\n }\n\n function remainingWait(time) {\n var timeSinceLastCall = time - lastCallTime,\n timeSinceLastInvoke = time - lastInvokeTime,\n timeWaiting = wait - timeSinceLastCall;\n\n return maxing\n ? nativeMin(timeWaiting, maxWait - timeSinceLastInvoke)\n : timeWaiting;\n }\n\n function shouldInvoke(time) {\n var timeSinceLastCall = time - lastCallTime,\n timeSinceLastInvoke = time - lastInvokeTime;\n\n // Either this is the first call, activity has stopped and we're at the\n // trailing edge, the system time has gone backwards and we're treating\n // it as the trailing edge, or we've hit the `maxWait` limit.\n return (lastCallTime === undefined || (timeSinceLastCall >= wait) ||\n (timeSinceLastCall < 0) || (maxing && timeSinceLastInvoke >= maxWait));\n }\n\n function timerExpired() {\n var time = now();\n if (shouldInvoke(time)) {\n return trailingEdge(time);\n }\n // Restart the timer.\n timerId = setTimeout(timerExpired, remainingWait(time));\n }\n\n function trailingEdge(time) {\n timerId = undefined;\n\n // Only invoke if we have `lastArgs` which means `func` has been\n // debounced at least once.\n if (trailing && lastArgs) {\n return invokeFunc(time);\n }\n lastArgs = lastThis = undefined;\n return result;\n }\n\n function cancel() {\n if (timerId !== undefined) {\n clearTimeout(timerId);\n }\n lastInvokeTime = 0;\n lastArgs = lastCallTime = lastThis = timerId = undefined;\n }\n\n function flush() {\n return timerId === undefined ? result : trailingEdge(now());\n }\n\n function debounced() {\n var time = now(),\n isInvoking = shouldInvoke(time);\n\n lastArgs = arguments;\n lastThis = this;\n lastCallTime = time;\n\n if (isInvoking) {\n if (timerId === undefined) {\n return leadingEdge(lastCallTime);\n }\n if (maxing) {\n // Handle invocations in a tight loop.\n clearTimeout(timerId);\n timerId = setTimeout(timerExpired, wait);\n return invokeFunc(lastCallTime);\n }\n }\n if (timerId === undefined) {\n timerId = setTimeout(timerExpired, wait);\n }\n return result;\n }\n debounced.cancel = cancel;\n debounced.flush = flush;\n return debounced;\n}\n\nexport default debounce;\n","/**\n * Checks if `value` is the\n * [language type](http://www.ecma-international.org/ecma-262/7.0/#sec-ecmascript-language-types)\n * of `Object`. (e.g. arrays, functions, objects, regexes, `new Number(0)`, and `new String('')`)\n *\n * @static\n * @memberOf _\n * @since 0.1.0\n * @category Lang\n * @param {*} value The value to check.\n * @returns {boolean} Returns `true` if `value` is an object, else `false`.\n * @example\n *\n * _.isObject({});\n * // => true\n *\n * _.isObject([1, 2, 3]);\n * // => true\n *\n * _.isObject(_.noop);\n * // => true\n *\n * _.isObject(null);\n * // => false\n */\nfunction isObject(value) {\n var type = typeof value;\n return value != null && (type == 'object' || type == 'function');\n}\n\nexport default isObject;\n","/**\n * Checks if `value` is object-like. A value is object-like if it's not `null`\n * and has a `typeof` result of \"object\".\n *\n * @static\n * @memberOf _\n * @since 4.0.0\n * @category Lang\n * @param {*} value The value to check.\n * @returns {boolean} Returns `true` if `value` is object-like, else `false`.\n * @example\n *\n * _.isObjectLike({});\n * // => true\n *\n * _.isObjectLike([1, 2, 3]);\n * // => true\n *\n * _.isObjectLike(_.noop);\n * // => false\n *\n * _.isObjectLike(null);\n * // => false\n */\nfunction isObjectLike(value) {\n return value != null && typeof value == 'object';\n}\n\nexport default isObjectLike;\n","import baseGetTag from './_baseGetTag.js';\nimport isObjectLike from './isObjectLike.js';\n\n/** `Object#toString` result references. */\nvar symbolTag = '[object Symbol]';\n\n/**\n * Checks if `value` is classified as a `Symbol` primitive or object.\n *\n * @static\n * @memberOf _\n * @since 4.0.0\n * @category Lang\n * @param {*} value The value to check.\n * @returns {boolean} Returns `true` if `value` is a symbol, else `false`.\n * @example\n *\n * _.isSymbol(Symbol.iterator);\n * // => true\n *\n * _.isSymbol('abc');\n * // => false\n */\nfunction isSymbol(value) {\n return typeof value == 'symbol' ||\n (isObjectLike(value) && baseGetTag(value) == symbolTag);\n}\n\nexport default isSymbol;\n","import root from './_root.js';\n\n/**\n * Gets the timestamp of the number of milliseconds that have elapsed since\n * the Unix epoch (1 January 1970 00:00:00 UTC).\n *\n * @static\n * @memberOf _\n * @since 2.4.0\n * @category Date\n * @returns {number} Returns the timestamp.\n * @example\n *\n * _.defer(function(stamp) {\n * console.log(_.now() - stamp);\n * }, _.now());\n * // => Logs the number of milliseconds it took for the deferred invocation.\n */\nvar now = function() {\n return root.Date.now();\n};\n\nexport default now;\n","import baseTrim from './_baseTrim.js';\nimport isObject from './isObject.js';\nimport isSymbol from './isSymbol.js';\n\n/** Used as references for various `Number` constants. */\nvar NAN = 0 / 0;\n\n/** Used to detect bad signed hexadecimal string values. */\nvar reIsBadHex = /^[-+]0x[0-9a-f]+$/i;\n\n/** Used to detect binary string values. */\nvar reIsBinary = /^0b[01]+$/i;\n\n/** Used to detect octal string values. */\nvar reIsOctal = /^0o[0-7]+$/i;\n\n/** Built-in method references without a dependency on `root`. */\nvar freeParseInt = parseInt;\n\n/**\n * Converts `value` to a number.\n *\n * @static\n * @memberOf _\n * @since 4.0.0\n * @category Lang\n * @param {*} value The value to process.\n * @returns {number} Returns the number.\n * @example\n *\n * _.toNumber(3.2);\n * // => 3.2\n *\n * _.toNumber(Number.MIN_VALUE);\n * // => 5e-324\n *\n * _.toNumber(Infinity);\n * // => Infinity\n *\n * _.toNumber('3.2');\n * // => 3.2\n */\nfunction toNumber(value) {\n if (typeof value == 'number') {\n return value;\n }\n if (isSymbol(value)) {\n return NAN;\n }\n if (isObject(value)) {\n var other = typeof value.valueOf == 'function' ? value.valueOf() : value;\n value = isObject(other) ? (other + '') : other;\n }\n if (typeof value != 'string') {\n return value === 0 ? value : +value;\n }\n value = baseTrim(value);\n var isBinary = reIsBinary.test(value);\n return (isBinary || reIsOctal.test(value))\n ? freeParseInt(value.slice(2), isBinary ? 2 : 8)\n : (reIsBadHex.test(value) ? NAN : +value);\n}\n\nexport default toNumber;\n","// The module cache\nvar __webpack_module_cache__ = {};\n\n// The require function\nfunction __webpack_require__(moduleId) {\n\t// Check if module is in cache\n\tvar cachedModule = __webpack_module_cache__[moduleId];\n\tif (cachedModule !== undefined) {\n\t\treturn cachedModule.exports;\n\t}\n\t// Create a new module (and put it into the cache)\n\tvar module = __webpack_module_cache__[moduleId] = {\n\t\t// no module.id needed\n\t\t// no module.loaded needed\n\t\texports: {}\n\t};\n\n\t// Execute the module function\n\t__webpack_modules__[moduleId](module, module.exports, __webpack_require__);\n\n\t// Return the exports of the module\n\treturn module.exports;\n}\n\n","// define getter functions for harmony exports\n__webpack_require__.d = (exports, definition) => {\n\tfor(var key in definition) {\n\t\tif(__webpack_require__.o(definition, key) && !__webpack_require__.o(exports, key)) {\n\t\t\tObject.defineProperty(exports, key, { enumerable: true, get: definition[key] });\n\t\t}\n\t}\n};","__webpack_require__.o = (obj, prop) => (Object.prototype.hasOwnProperty.call(obj, prop))","// define __esModule on exports\n__webpack_require__.r = (exports) => {\n\tif(typeof Symbol !== 'undefined' && Symbol.toStringTag) {\n\t\tObject.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });\n\t}\n\tObject.defineProperty(exports, '__esModule', { value: true });\n};","/**\n * @license Copyright (c) 2003-2022, CKSource Holding sp. z o.o. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n\n/**\n * @module autosave\n */\n\nexport { default as Autosave } from './autosave';\n"],"sourceRoot":""}