@ckeditor/ckeditor5-widget 35.2.0 → 35.3.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.
@@ -2,22 +2,16 @@
2
2
  * @license Copyright (c) 2003-2022, CKSource Holding sp. z o.o. All rights reserved.
3
3
  * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
4
4
  */
5
-
6
5
  /**
7
6
  * @module widget/widgetresize
8
7
  */
9
-
10
8
  import Plugin from '@ckeditor/ckeditor5-core/src/plugin';
11
9
  import Resizer from './widgetresize/resizer';
12
- import DomEmitterMixin from '@ckeditor/ckeditor5-utils/src/dom/emittermixin';
10
+ import { Emitter as DomEmitter } from '@ckeditor/ckeditor5-utils/src/dom/emittermixin';
13
11
  import global from '@ckeditor/ckeditor5-utils/src/dom/global';
14
- import ObservableMixin from '@ckeditor/ckeditor5-utils/src/observablemixin';
15
12
  import MouseObserver from '@ckeditor/ckeditor5-engine/src/view/observer/mouseobserver';
16
- import mix from '@ckeditor/ckeditor5-utils/src/mix';
17
13
  import { throttle } from 'lodash-es';
18
-
19
14
  import '../theme/widgetresize.css';
20
-
21
15
  /**
22
16
  * The widget resize feature plugin.
23
17
  *
@@ -27,294 +21,202 @@ import '../theme/widgetresize.css';
27
21
  * @mixes module:utils/observablemixin~ObservableMixin
28
22
  */
29
23
  export default class WidgetResize extends Plugin {
30
- /**
31
- * @inheritDoc
32
- */
33
- static get pluginName() {
34
- return 'WidgetResize';
35
- }
36
-
37
- /**
38
- * @inheritDoc
39
- */
40
- init() {
41
- const editing = this.editor.editing;
42
- const domDocument = global.window.document;
43
-
44
- /**
45
- * The currently selected resizer.
46
- *
47
- * @observable
48
- * @member {module:widget/widgetresize/resizer~Resizer|null} #selectedResizer
49
- */
50
- this.set( 'selectedResizer', null );
51
-
52
- /**
53
- * References an active resizer.
54
- *
55
- * Active resizer means a resizer which handle is actively used by the end user.
56
- *
57
- * @protected
58
- * @observable
59
- * @member {module:widget/widgetresize/resizer~Resizer|null} #_activeResizer
60
- */
61
- this.set( '_activeResizer', null );
62
-
63
- /**
64
- * A map of resizers created using this plugin instance.
65
- *
66
- * @protected
67
- * @type {Map.<module:engine/view/containerelement~ContainerElement, module:widget/widgetresize/resizer~Resizer>}
68
- */
69
- this._resizers = new Map();
70
-
71
- editing.view.addObserver( MouseObserver );
72
-
73
- this._observer = Object.create( DomEmitterMixin );
74
-
75
- this.listenTo( editing.view.document, 'mousedown', this._mouseDownListener.bind( this ), { priority: 'high' } );
76
-
77
- this._observer.listenTo( domDocument, 'mousemove', this._mouseMoveListener.bind( this ) );
78
- this._observer.listenTo( domDocument, 'mouseup', this._mouseUpListener.bind( this ) );
79
-
80
- const redrawSelectedResizer = () => {
81
- if ( this.selectedResizer && this.selectedResizer.isVisible ) {
82
- this.selectedResizer.redraw();
83
- }
84
- };
85
-
86
- this._redrawSelectedResizerThrottled = throttle( redrawSelectedResizer, 200 );
87
-
88
- // Redrawing on any change of the UI of the editor (including content changes).
89
- this.editor.ui.on( 'update', this._redrawSelectedResizerThrottled );
90
-
91
- // Remove view widget-resizer mappings for widgets that have been removed from the document.
92
- // https://github.com/ckeditor/ckeditor5/issues/10156
93
- // https://github.com/ckeditor/ckeditor5/issues/10266
94
- this.editor.model.document.on( 'change', () => {
95
- for ( const [ viewElement, resizer ] of this._resizers ) {
96
- if ( !viewElement.isAttached() ) {
97
- this._resizers.delete( viewElement );
98
- resizer.destroy();
99
- }
100
- }
101
- }, { priority: 'lowest' } );
102
-
103
- // Resizers need to be redrawn upon window resize, because new window might shrink resize host.
104
- this._observer.listenTo( global.window, 'resize', this._redrawSelectedResizerThrottled );
105
-
106
- const viewSelection = this.editor.editing.view.document.selection;
107
-
108
- viewSelection.on( 'change', () => {
109
- const selectedElement = viewSelection.getSelectedElement();
110
-
111
- const resizer = this.getResizerByViewElement( selectedElement ) || null;
112
- if ( resizer ) {
113
- this.select( resizer );
114
- } else {
115
- this.deselect();
116
- }
117
- } );
118
- }
119
-
120
- /**
121
- * @inheritDoc
122
- */
123
- destroy() {
124
- this._observer.stopListening();
125
-
126
- for ( const resizer of this._resizers.values() ) {
127
- resizer.destroy();
128
- }
129
-
130
- this._redrawSelectedResizerThrottled.cancel();
131
- }
132
-
133
- /**
134
- * Marks resizer as selected.
135
- *
136
- * @param {module:widget/widgetresize/resizer~Resizer} resizer
137
- */
138
- select( resizer ) {
139
- this.deselect();
140
- this.selectedResizer = resizer;
141
- this.selectedResizer.isSelected = true;
142
- }
143
-
144
- /**
145
- * Deselects currently set resizer.
146
- */
147
- deselect() {
148
- if ( this.selectedResizer ) {
149
- this.selectedResizer.isSelected = false;
150
- }
151
-
152
- this.selectedResizer = null;
153
- }
154
-
155
- /**
156
- * @param {module:widget/widgetresize~ResizerOptions} [options] Resizer options.
157
- * @returns {module:widget/widgetresize/resizer~Resizer}
158
- */
159
- attachTo( options ) {
160
- const resizer = new Resizer( options );
161
- const plugins = this.editor.plugins;
162
-
163
- resizer.attach();
164
-
165
- if ( plugins.has( 'WidgetToolbarRepository' ) ) {
166
- // Hiding widget toolbar to improve the performance
167
- // (https://github.com/ckeditor/ckeditor5-widget/pull/112#issuecomment-564528765).
168
- const widgetToolbarRepository = plugins.get( 'WidgetToolbarRepository' );
169
-
170
- resizer.on( 'begin', () => {
171
- widgetToolbarRepository.forceDisabled( 'resize' );
172
- }, { priority: 'lowest' } );
173
-
174
- resizer.on( 'cancel', () => {
175
- widgetToolbarRepository.clearForceDisabled( 'resize' );
176
- }, { priority: 'highest' } );
177
-
178
- resizer.on( 'commit', () => {
179
- widgetToolbarRepository.clearForceDisabled( 'resize' );
180
- }, { priority: 'highest' } );
181
- }
182
-
183
- this._resizers.set( options.viewElement, resizer );
184
-
185
- const viewSelection = this.editor.editing.view.document.selection;
186
- const selectedElement = viewSelection.getSelectedElement();
187
-
188
- // If the element the resizer is created for is currently focused, it should become visible.
189
- if ( this.getResizerByViewElement( selectedElement ) == resizer ) {
190
- this.select( resizer );
191
- }
192
-
193
- return resizer;
194
- }
195
-
196
- /**
197
- * Returns a resizer created for a given view element (widget element).
198
- *
199
- * @param {module:engine/view/containerelement~ContainerElement} viewElement View element associated with the resizer.
200
- * @returns {module:widget/widgetresize/resizer~Resizer|undefined}
201
- */
202
- getResizerByViewElement( viewElement ) {
203
- return this._resizers.get( viewElement );
204
- }
205
-
206
- /**
207
- * Returns a resizer that contains a given resize handle.
208
- *
209
- * @protected
210
- * @param {HTMLElement} domResizeHandle
211
- * @returns {module:widget/widgetresize/resizer~Resizer}
212
- */
213
- _getResizerByHandle( domResizeHandle ) {
214
- for ( const resizer of this._resizers.values() ) {
215
- if ( resizer.containsHandle( domResizeHandle ) ) {
216
- return resizer;
217
- }
218
- }
219
- }
220
-
221
- /**
222
- * @protected
223
- * @param {module:utils/eventinfo~EventInfo} event
224
- * @param {Event} domEventData Native DOM event.
225
- */
226
- _mouseDownListener( event, domEventData ) {
227
- const resizeHandle = domEventData.domTarget;
228
-
229
- if ( !Resizer.isResizeHandle( resizeHandle ) ) {
230
- return;
231
- }
232
-
233
- this._activeResizer = this._getResizerByHandle( resizeHandle );
234
-
235
- if ( this._activeResizer ) {
236
- this._activeResizer.begin( resizeHandle );
237
-
238
- // Do not call other events when resizing. See: #6755.
239
- event.stop();
240
- domEventData.preventDefault();
241
- }
242
- }
243
-
244
- /**
245
- * @protected
246
- * @param {module:utils/eventinfo~EventInfo} event
247
- * @param {Event} domEventData Native DOM event.
248
- */
249
- _mouseMoveListener( event, domEventData ) {
250
- if ( this._activeResizer ) {
251
- this._activeResizer.updateSize( domEventData );
252
- }
253
- }
254
-
255
- /**
256
- * @protected
257
- */
258
- _mouseUpListener() {
259
- if ( this._activeResizer ) {
260
- this._activeResizer.commit();
261
- this._activeResizer = null;
262
- }
263
- }
24
+ /**
25
+ * @inheritDoc
26
+ */
27
+ static get pluginName() {
28
+ return 'WidgetResize';
29
+ }
30
+ /**
31
+ * @inheritDoc
32
+ */
33
+ init() {
34
+ const editing = this.editor.editing;
35
+ const domDocument = global.window.document;
36
+ /**
37
+ * The currently selected resizer.
38
+ *
39
+ * @observable
40
+ * @member {module:widget/widgetresize/resizer~Resizer|null} #selectedResizer
41
+ */
42
+ this.set('selectedResizer', null);
43
+ /**
44
+ * References an active resizer.
45
+ *
46
+ * Active resizer means a resizer which handle is actively used by the end user.
47
+ *
48
+ * @protected
49
+ * @observable
50
+ * @member {module:widget/widgetresize/resizer~Resizer|null} #_activeResizer
51
+ */
52
+ this.set('_activeResizer', null);
53
+ /**
54
+ * A map of resizers created using this plugin instance.
55
+ *
56
+ * @protected
57
+ * @type {Map.<module:engine/view/containerelement~ContainerElement, module:widget/widgetresize/resizer~Resizer>}
58
+ */
59
+ this._resizers = new Map();
60
+ editing.view.addObserver(MouseObserver);
61
+ this._observer = new DomEmitter();
62
+ this.listenTo(editing.view.document, 'mousedown', this._mouseDownListener.bind(this), { priority: 'high' });
63
+ this._observer.listenTo(domDocument, 'mousemove', this._mouseMoveListener.bind(this));
64
+ this._observer.listenTo(domDocument, 'mouseup', this._mouseUpListener.bind(this));
65
+ this._redrawSelectedResizerThrottled = throttle(() => this.redrawSelectedResizer(), 200);
66
+ // Redrawing on any change of the UI of the editor (including content changes).
67
+ this.editor.ui.on('update', this._redrawSelectedResizerThrottled);
68
+ // Remove view widget-resizer mappings for widgets that have been removed from the document.
69
+ // https://github.com/ckeditor/ckeditor5/issues/10156
70
+ // https://github.com/ckeditor/ckeditor5/issues/10266
71
+ this.editor.model.document.on('change', () => {
72
+ for (const [viewElement, resizer] of this._resizers) {
73
+ if (!viewElement.isAttached()) {
74
+ this._resizers.delete(viewElement);
75
+ resizer.destroy();
76
+ }
77
+ }
78
+ }, { priority: 'lowest' });
79
+ // Resizers need to be redrawn upon window resize, because new window might shrink resize host.
80
+ this._observer.listenTo(global.window, 'resize', this._redrawSelectedResizerThrottled);
81
+ const viewSelection = this.editor.editing.view.document.selection;
82
+ viewSelection.on('change', () => {
83
+ const selectedElement = viewSelection.getSelectedElement();
84
+ const resizer = this.getResizerByViewElement(selectedElement) || null;
85
+ if (resizer) {
86
+ this.select(resizer);
87
+ }
88
+ else {
89
+ this.deselect();
90
+ }
91
+ });
92
+ }
93
+ /**
94
+ * Redraws the selected resizer if there is any selected resizer and if it is visible.
95
+ */
96
+ redrawSelectedResizer() {
97
+ if (this.selectedResizer && this.selectedResizer.isVisible) {
98
+ this.selectedResizer.redraw();
99
+ }
100
+ }
101
+ /**
102
+ * @inheritDoc
103
+ */
104
+ destroy() {
105
+ super.destroy();
106
+ this._observer.stopListening();
107
+ for (const resizer of this._resizers.values()) {
108
+ resizer.destroy();
109
+ }
110
+ this._redrawSelectedResizerThrottled.cancel();
111
+ }
112
+ /**
113
+ * Marks resizer as selected.
114
+ *
115
+ * @param {module:widget/widgetresize/resizer~Resizer} resizer
116
+ */
117
+ select(resizer) {
118
+ this.deselect();
119
+ this.selectedResizer = resizer;
120
+ this.selectedResizer.isSelected = true;
121
+ }
122
+ /**
123
+ * Deselects currently set resizer.
124
+ */
125
+ deselect() {
126
+ if (this.selectedResizer) {
127
+ this.selectedResizer.isSelected = false;
128
+ }
129
+ this.selectedResizer = null;
130
+ }
131
+ /**
132
+ * @param {module:widget/widgetresize~ResizerOptions} [options] Resizer options.
133
+ * @returns {module:widget/widgetresize/resizer~Resizer}
134
+ */
135
+ attachTo(options) {
136
+ const resizer = new Resizer(options);
137
+ const plugins = this.editor.plugins;
138
+ resizer.attach();
139
+ if (plugins.has('WidgetToolbarRepository')) {
140
+ // Hiding widget toolbar to improve the performance
141
+ // (https://github.com/ckeditor/ckeditor5-widget/pull/112#issuecomment-564528765).
142
+ const widgetToolbarRepository = plugins.get('WidgetToolbarRepository');
143
+ resizer.on('begin', () => {
144
+ widgetToolbarRepository.forceDisabled('resize');
145
+ }, { priority: 'lowest' });
146
+ resizer.on('cancel', () => {
147
+ widgetToolbarRepository.clearForceDisabled('resize');
148
+ }, { priority: 'highest' });
149
+ resizer.on('commit', () => {
150
+ widgetToolbarRepository.clearForceDisabled('resize');
151
+ }, { priority: 'highest' });
152
+ }
153
+ this._resizers.set(options.viewElement, resizer);
154
+ const viewSelection = this.editor.editing.view.document.selection;
155
+ const selectedElement = viewSelection.getSelectedElement();
156
+ // If the element the resizer is created for is currently focused, it should become visible.
157
+ if (this.getResizerByViewElement(selectedElement) == resizer) {
158
+ this.select(resizer);
159
+ }
160
+ return resizer;
161
+ }
162
+ /**
163
+ * Returns a resizer created for a given view element (widget element).
164
+ *
165
+ * @param {module:engine/view/containerelement~ContainerElement} viewElement View element associated with the resizer.
166
+ * @returns {module:widget/widgetresize/resizer~Resizer|undefined}
167
+ */
168
+ getResizerByViewElement(viewElement) {
169
+ return this._resizers.get(viewElement);
170
+ }
171
+ /**
172
+ * Returns a resizer that contains a given resize handle.
173
+ *
174
+ * @protected
175
+ * @param {HTMLElement} domResizeHandle
176
+ * @returns {module:widget/widgetresize/resizer~Resizer}
177
+ */
178
+ _getResizerByHandle(domResizeHandle) {
179
+ for (const resizer of this._resizers.values()) {
180
+ if (resizer.containsHandle(domResizeHandle)) {
181
+ return resizer;
182
+ }
183
+ }
184
+ }
185
+ /**
186
+ * @protected
187
+ * @param {module:utils/eventinfo~EventInfo} event
188
+ * @param {Event} domEventData Native DOM event.
189
+ */
190
+ _mouseDownListener(event, domEventData) {
191
+ const resizeHandle = domEventData.domTarget;
192
+ if (!Resizer.isResizeHandle(resizeHandle)) {
193
+ return;
194
+ }
195
+ this._activeResizer = this._getResizerByHandle(resizeHandle) || null;
196
+ if (this._activeResizer) {
197
+ this._activeResizer.begin(resizeHandle);
198
+ // Do not call other events when resizing. See: #6755.
199
+ event.stop();
200
+ domEventData.preventDefault();
201
+ }
202
+ }
203
+ /**
204
+ * @protected
205
+ * @param {module:utils/eventinfo~EventInfo} event
206
+ * @param {Event} domEventData Native DOM event.
207
+ */
208
+ _mouseMoveListener(event, domEventData) {
209
+ if (this._activeResizer) {
210
+ this._activeResizer.updateSize(domEventData);
211
+ }
212
+ }
213
+ /**
214
+ * @protected
215
+ */
216
+ _mouseUpListener() {
217
+ if (this._activeResizer) {
218
+ this._activeResizer.commit();
219
+ this._activeResizer = null;
220
+ }
221
+ }
264
222
  }
265
-
266
- mix( WidgetResize, ObservableMixin );
267
-
268
- /**
269
- * Interface describing a resizer. It allows to specify the resizing host, custom logic for calculating aspect ratio, etc.
270
- *
271
- * @interface ResizerOptions
272
- */
273
-
274
- /**
275
- * Editor instance associated with the resizer.
276
- *
277
- * @member {module:core/editor/editor~Editor} module:widget/widgetresize~ResizerOptions#editor
278
- */
279
-
280
- /**
281
- * @member {module:engine/model/element~Element} module:widget/widgetresize~ResizerOptions#modelElement
282
- */
283
-
284
- /**
285
- * A view of an element to be resized. Typically it's the main widget's view instance.
286
- *
287
- * @member {module:engine/view/containerelement~ContainerElement} module:widget/widgetresize~ResizerOptions#viewElement
288
- */
289
-
290
- /**
291
- * A callback to be executed once the resizing process is done.
292
- *
293
- * It receives a `Number` (`newValue`) as a parameter.
294
- *
295
- * For example, {@link module:image/imageresize~ImageResize} uses it to execute the resize image command
296
- * which puts the new value into the model.
297
- *
298
- * ```js
299
- * {
300
- * editor,
301
- * modelElement: data.item,
302
- * viewElement: widget,
303
- *
304
- * onCommit( newValue ) {
305
- * editor.execute( 'resizeImage', { width: newValue } );
306
- * }
307
- * };
308
- * ```
309
- *
310
- *
311
- * @member {Function} module:widget/widgetresize~ResizerOptions#onCommit
312
- */
313
-
314
- /**
315
- * @member {Function} module:widget/widgetresize~ResizerOptions#getResizeHost
316
- */
317
-
318
- /**
319
- * @member {Function} module:widget/widgetresize~ResizerOptions#isCentered
320
- */