@ckeditor/ckeditor5-widget 0.0.0-nightly-20240603.0 → 0.0.0-nightly-20240604.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.

Potentially problematic release.


This version of @ckeditor/ckeditor5-widget might be problematic. Click here for more details.

package/dist/index.js CHANGED
@@ -10,23 +10,12 @@ import { IconView, Template, ContextualBalloon, ToolbarView, BalloonPanelView, V
10
10
  import { Enter } from '@ckeditor/ckeditor5-enter/dist/index.js';
11
11
  import { throttle } from 'lodash-es';
12
12
 
13
- /**
14
- * Class used to handle the correct order of highlights on elements.
15
- *
16
- * When different highlights are applied to same element the correct order should be preserved:
17
- *
18
- * * highlight with highest priority should be applied,
19
- * * if two highlights have same priority - sort by CSS class provided in
20
- * {@link module:engine/conversion/downcasthelpers~HighlightDescriptor}.
21
- *
22
- * This way, highlight will be applied with the same rules it is applied on texts.
23
- */ class HighlightStack extends /* #__PURE__ */ EmitterMixin() {
24
- _stack = [];
25
- /**
26
- * Adds highlight descriptor to the stack.
27
- *
28
- * @fires change:top
29
- */ add(descriptor, writer) {
13
+ class HighlightStack extends EmitterMixin() {
14
+ /**
15
+ * Adds highlight descriptor to the stack.
16
+ *
17
+ * @fires change:top
18
+ */ add(descriptor, writer) {
30
19
  const stack = this._stack;
31
20
  // Save top descriptor and insert new one. If top is changed - fire event.
32
21
  const oldTop = stack[0];
@@ -42,11 +31,11 @@ import { throttle } from 'lodash-es';
42
31
  }
43
32
  }
44
33
  /**
45
- * Removes highlight descriptor from the stack.
46
- *
47
- * @fires change:top
48
- * @param id Id of the descriptor to remove.
49
- */ remove(id, writer) {
34
+ * Removes highlight descriptor from the stack.
35
+ *
36
+ * @fires change:top
37
+ * @param id Id of the descriptor to remove.
38
+ */ remove(id, writer) {
50
39
  const stack = this._stack;
51
40
  const oldTop = stack[0];
52
41
  this._removeDescriptor(id);
@@ -61,9 +50,9 @@ import { throttle } from 'lodash-es';
61
50
  }
62
51
  }
63
52
  /**
64
- * Inserts a given descriptor in correct place in the stack. It also takes care about updating information
65
- * when descriptor with same id is already present.
66
- */ _insertDescriptor(descriptor) {
53
+ * Inserts a given descriptor in correct place in the stack. It also takes care about updating information
54
+ * when descriptor with same id is already present.
55
+ */ _insertDescriptor(descriptor) {
67
56
  const stack = this._stack;
68
57
  const index = stack.findIndex((item)=>item.id === descriptor.id);
69
58
  // Inserting exact same descriptor - do nothing.
@@ -83,10 +72,10 @@ import { throttle } from 'lodash-es';
83
72
  stack.splice(i, 0, descriptor);
84
73
  }
85
74
  /**
86
- * Removes descriptor with given id from the stack.
87
- *
88
- * @param id Descriptor's id.
89
- */ _removeDescriptor(id) {
75
+ * Removes descriptor with given id from the stack.
76
+ *
77
+ * @param id Descriptor's id.
78
+ */ _removeDescriptor(id) {
90
79
  const stack = this._stack;
91
80
  const index = stack.findIndex((item)=>item.id === id);
92
81
  // If descriptor with same id is on the list - remove it.
@@ -94,6 +83,10 @@ import { throttle } from 'lodash-es';
94
83
  stack.splice(index, 1);
95
84
  }
96
85
  }
86
+ constructor(){
87
+ super(...arguments);
88
+ this._stack = [];
89
+ }
97
90
  }
98
91
  /**
99
92
  * Compares two descriptors by checking their priority and class list.
@@ -184,12 +177,12 @@ var dragHandleIcon = "<svg viewBox=\"0 0 16 16\" xmlns=\"http://www.w3.org/2000/
184
177
  */ function toWidget(element, writer, options = {}) {
185
178
  if (!element.is('containerElement')) {
186
179
  /**
187
- * The element passed to `toWidget()` must be a {@link module:engine/view/containerelement~ContainerElement}
188
- * instance.
189
- *
190
- * @error widget-to-widget-wrong-element-type
191
- * @param element The view element passed to `toWidget()`.
192
- */ throw new CKEditorError('widget-to-widget-wrong-element-type', null, {
180
+ * The element passed to `toWidget()` must be a {@link module:engine/view/containerelement~ContainerElement}
181
+ * instance.
182
+ *
183
+ * @error widget-to-widget-wrong-element-type
184
+ * @param element The view element passed to `toWidget()`.
185
+ */ throw new CKEditorError('widget-to-widget-wrong-element-type', null, {
193
186
  element
194
187
  });
195
188
  }
@@ -545,37 +538,23 @@ const POSSIBLE_INSERTION_POSITIONS = [
545
538
  // Do the SVG parsing once and then clone the result <svg> DOM element for each new button.
546
539
  const RETURN_ARROW_ICON_ELEMENT = new DOMParser().parseFromString(returnIcon, 'image/svg+xml').firstChild;
547
540
  const PLUGIN_DISABLED_EDITING_ROOT_CLASS = 'ck-widget__type-around_disabled';
548
- /**
549
- * A plugin that allows users to type around widgets where normally it is impossible to place the caret due
550
- * to limitations of web browsers. These "tight spots" occur, for instance, before (or after) a widget being
551
- * the first (or last) child of its parent or between two block widgets.
552
- *
553
- * This plugin extends the {@link module:widget/widget~Widget `Widget`} plugin and injects the user interface
554
- * with two buttons into each widget instance in the editor. Each of the buttons can be clicked by the
555
- * user if the widget is next to the "tight spot". Once clicked, a paragraph is created with the selection anchored
556
- * in it so that users can type (or insert content, paste, etc.) straight away.
557
- */ class WidgetTypeAround extends Plugin {
558
- /**
559
- * A reference to the model widget element that has the fake caret active
560
- * on either side of it. It is later used to remove CSS classes associated with the fake caret
561
- * when the widget no longer needs it.
562
- */ _currentFakeCaretModelElement = null;
563
- /**
564
- * @inheritDoc
565
- */ static get pluginName() {
541
+ class WidgetTypeAround extends Plugin {
542
+ /**
543
+ * @inheritDoc
544
+ */ static get pluginName() {
566
545
  return 'WidgetTypeAround';
567
546
  }
568
547
  /**
569
- * @inheritDoc
570
- */ static get requires() {
548
+ * @inheritDoc
549
+ */ static get requires() {
571
550
  return [
572
551
  Enter,
573
552
  Delete
574
553
  ];
575
554
  }
576
555
  /**
577
- * @inheritDoc
578
- */ init() {
556
+ * @inheritDoc
557
+ */ init() {
579
558
  const editor = this.editor;
580
559
  const editingView = editor.editing.view;
581
560
  // Set a CSS class on the view editing root when the plugin is disabled so all the buttons
@@ -607,20 +586,20 @@ const PLUGIN_DISABLED_EDITING_ROOT_CLASS = 'ck-widget__type-around_disabled';
607
586
  this._enableDeleteContentIntegration();
608
587
  }
609
588
  /**
610
- * @inheritDoc
611
- */ destroy() {
589
+ * @inheritDoc
590
+ */ destroy() {
612
591
  super.destroy();
613
592
  this._currentFakeCaretModelElement = null;
614
593
  }
615
594
  /**
616
- * Inserts a new paragraph next to a widget element with the selection anchored in it.
617
- *
618
- * **Note**: This method is heavily user-oriented and will both focus the editing view and scroll
619
- * the viewport to the selection in the inserted paragraph.
620
- *
621
- * @param widgetModelElement The model widget element next to which a paragraph is inserted.
622
- * @param position The position where the paragraph is inserted. Either `'before'` or `'after'` the widget.
623
- */ _insertParagraph(widgetModelElement, position) {
595
+ * Inserts a new paragraph next to a widget element with the selection anchored in it.
596
+ *
597
+ * **Note**: This method is heavily user-oriented and will both focus the editing view and scroll
598
+ * the viewport to the selection in the inserted paragraph.
599
+ *
600
+ * @param widgetModelElement The model widget element next to which a paragraph is inserted.
601
+ * @param position The position where the paragraph is inserted. Either `'before'` or `'after'` the widget.
602
+ */ _insertParagraph(widgetModelElement, position) {
624
603
  const editor = this.editor;
625
604
  const editingView = editor.editing.view;
626
605
  const attributesToCopy = editor.model.schema.getAttributesWithProperty(widgetModelElement, 'copyOnReplace', true);
@@ -632,16 +611,16 @@ const PLUGIN_DISABLED_EDITING_ROOT_CLASS = 'ck-widget__type-around_disabled';
632
611
  editingView.scrollToTheSelection();
633
612
  }
634
613
  /**
635
- * A wrapper for the {@link module:utils/emittermixin~Emitter#listenTo} method that executes the callbacks only
636
- * when the plugin {@link #isEnabled is enabled}.
637
- *
638
- * @param emitter The object that fires the event.
639
- * @param event The name of the event.
640
- * @param callback The function to be called on event.
641
- * @param options Additional options.
642
- * @param options.priority The priority of this event callback. The higher the priority value the sooner
643
- * the callback will be fired. Events having the same priority are called in the order they were added.
644
- */ _listenToIfEnabled(emitter, event, callback, options) {
614
+ * A wrapper for the {@link module:utils/emittermixin~Emitter#listenTo} method that executes the callbacks only
615
+ * when the plugin {@link #isEnabled is enabled}.
616
+ *
617
+ * @param emitter The object that fires the event.
618
+ * @param event The name of the event.
619
+ * @param callback The function to be called on event.
620
+ * @param options Additional options.
621
+ * @param options.priority The priority of this event callback. The higher the priority value the sooner
622
+ * the callback will be fired. Events having the same priority are called in the order they were added.
623
+ */ _listenToIfEnabled(emitter, event, callback, options) {
645
624
  this.listenTo(emitter, event, (...args)=>{
646
625
  // Do not respond if the plugin is disabled.
647
626
  if (this.isEnabled) {
@@ -650,16 +629,16 @@ const PLUGIN_DISABLED_EDITING_ROOT_CLASS = 'ck-widget__type-around_disabled';
650
629
  }, options);
651
630
  }
652
631
  /**
653
- * Similar to {@link #_insertParagraph}, this method inserts a paragraph except that it
654
- * does not expect a position. Instead, it performs the insertion next to a selected widget
655
- * according to the `widget-type-around` model selection attribute value (fake caret position).
656
- *
657
- * Because this method requires the `widget-type-around` attribute to be set,
658
- * the insertion can only happen when the widget's fake caret is active (e.g. activated
659
- * using the keyboard).
660
- *
661
- * @returns Returns `true` when the paragraph was inserted (the attribute was present) and `false` otherwise.
662
- */ _insertParagraphAccordingToFakeCaretPosition() {
632
+ * Similar to {@link #_insertParagraph}, this method inserts a paragraph except that it
633
+ * does not expect a position. Instead, it performs the insertion next to a selected widget
634
+ * according to the `widget-type-around` model selection attribute value (fake caret position).
635
+ *
636
+ * Because this method requires the `widget-type-around` attribute to be set,
637
+ * the insertion can only happen when the widget's fake caret is active (e.g. activated
638
+ * using the keyboard).
639
+ *
640
+ * @returns Returns `true` when the paragraph was inserted (the attribute was present) and `false` otherwise.
641
+ */ _insertParagraphAccordingToFakeCaretPosition() {
663
642
  const editor = this.editor;
664
643
  const model = editor.model;
665
644
  const modelSelection = model.document.selection;
@@ -677,12 +656,12 @@ const PLUGIN_DISABLED_EDITING_ROOT_CLASS = 'ck-widget__type-around_disabled';
677
656
  return true;
678
657
  }
679
658
  /**
680
- * Creates a listener in the editing conversion pipeline that injects the widget type around
681
- * UI into every single widget instance created in the editor.
682
- *
683
- * The UI is delivered as a {@link module:engine/view/uielement~UIElement}
684
- * wrapper which renders DOM buttons that users can use to insert paragraphs.
685
- */ _enableTypeAroundUIInjection() {
659
+ * Creates a listener in the editing conversion pipeline that injects the widget type around
660
+ * UI into every single widget instance created in the editor.
661
+ *
662
+ * The UI is delivered as a {@link module:engine/view/uielement~UIElement}
663
+ * wrapper which renders DOM buttons that users can use to insert paragraphs.
664
+ */ _enableTypeAroundUIInjection() {
686
665
  const editor = this.editor;
687
666
  const schema = editor.model.schema;
688
667
  const t = editor.locale.t;
@@ -708,30 +687,30 @@ const PLUGIN_DISABLED_EDITING_ROOT_CLASS = 'ck-widget__type-around_disabled';
708
687
  });
709
688
  }
710
689
  /**
711
- * Brings support for the fake caret that appears when either:
712
- *
713
- * * the selection moves to a widget from a position next to it using arrow keys,
714
- * * the arrow key is pressed when the widget is already selected.
715
- *
716
- * The fake caret lets the user know that they can start typing or just press
717
- * <kbd>Enter</kbd> to insert a paragraph at the position next to a widget as suggested by the fake caret.
718
- *
719
- * The fake caret disappears when the user changes the selection or the editor
720
- * gets blurred.
721
- *
722
- * The whole idea is as follows:
723
- *
724
- * 1. A user does one of the 2 scenarios described at the beginning.
725
- * 2. The "keydown" listener is executed and the decision is made whether to show or hide the fake caret.
726
- * 3. If it should show up, the `widget-type-around` model selection attribute is set indicating
727
- * on which side of the widget it should appear.
728
- * 4. The selection dispatcher reacts to the selection attribute and sets CSS classes responsible for the
729
- * fake caret on the view widget.
730
- * 5. If the fake caret should disappear, the selection attribute is removed and the dispatcher
731
- * does the CSS class clean-up in the view.
732
- * 6. Additionally, `change:range` and `FocusTracker#isFocused` listeners also remove the selection
733
- * attribute (the former also removes widget CSS classes).
734
- */ _enableTypeAroundFakeCaretActivationUsingKeyboardArrows() {
690
+ * Brings support for the fake caret that appears when either:
691
+ *
692
+ * * the selection moves to a widget from a position next to it using arrow keys,
693
+ * * the arrow key is pressed when the widget is already selected.
694
+ *
695
+ * The fake caret lets the user know that they can start typing or just press
696
+ * <kbd>Enter</kbd> to insert a paragraph at the position next to a widget as suggested by the fake caret.
697
+ *
698
+ * The fake caret disappears when the user changes the selection or the editor
699
+ * gets blurred.
700
+ *
701
+ * The whole idea is as follows:
702
+ *
703
+ * 1. A user does one of the 2 scenarios described at the beginning.
704
+ * 2. The "keydown" listener is executed and the decision is made whether to show or hide the fake caret.
705
+ * 3. If it should show up, the `widget-type-around` model selection attribute is set indicating
706
+ * on which side of the widget it should appear.
707
+ * 4. The selection dispatcher reacts to the selection attribute and sets CSS classes responsible for the
708
+ * fake caret on the view widget.
709
+ * 5. If the fake caret should disappear, the selection attribute is removed and the dispatcher
710
+ * does the CSS class clean-up in the view.
711
+ * 6. Additionally, `change:range` and `FocusTracker#isFocused` listeners also remove the selection
712
+ * attribute (the former also removes widget CSS classes).
713
+ */ _enableTypeAroundFakeCaretActivationUsingKeyboardArrows() {
735
714
  const editor = this.editor;
736
715
  const model = editor.model;
737
716
  const modelSelection = model.document.selection;
@@ -819,17 +798,17 @@ const PLUGIN_DISABLED_EDITING_ROOT_CLASS = 'ck-widget__type-around_disabled';
819
798
  }
820
799
  }
821
800
  /**
822
- * A listener executed on each "keydown" in the view document, a part of
823
- * {@link #_enableTypeAroundFakeCaretActivationUsingKeyboardArrows}.
824
- *
825
- * It decides whether the arrow keypress should activate the fake caret or not (also whether it should
826
- * be deactivated).
827
- *
828
- * The fake caret activation is done by setting the `widget-type-around` model selection attribute
829
- * in this listener, and stopping and preventing the event that would normally be handled by the widget
830
- * plugin that is responsible for the regular keyboard navigation near/across all widgets (that
831
- * includes inline widgets, which are ignored by the widget type around plugin).
832
- */ _handleArrowKeyPress(evt, domEventData) {
801
+ * A listener executed on each "keydown" in the view document, a part of
802
+ * {@link #_enableTypeAroundFakeCaretActivationUsingKeyboardArrows}.
803
+ *
804
+ * It decides whether the arrow keypress should activate the fake caret or not (also whether it should
805
+ * be deactivated).
806
+ *
807
+ * The fake caret activation is done by setting the `widget-type-around` model selection attribute
808
+ * in this listener, and stopping and preventing the event that would normally be handled by the widget
809
+ * plugin that is responsible for the regular keyboard navigation near/across all widgets (that
810
+ * includes inline widgets, which are ignored by the widget type around plugin).
811
+ */ _handleArrowKeyPress(evt, domEventData) {
833
812
  const editor = this.editor;
834
813
  const model = editor.model;
835
814
  const modelSelection = model.document.selection;
@@ -854,15 +833,15 @@ const PLUGIN_DISABLED_EDITING_ROOT_CLASS = 'ck-widget__type-around_disabled';
854
833
  }
855
834
  }
856
835
  /**
857
- * Handles the keyboard navigation on "keydown" when a widget is currently selected and activates or deactivates
858
- * the fake caret for that widget, depending on the current value of the `widget-type-around` model
859
- * selection attribute and the direction of the pressed arrow key.
860
- *
861
- * @param isForward `true` when the pressed arrow key was responsible for the forward model selection movement
862
- * as in {@link module:utils/keyboard~isForwardArrowKeyCode}.
863
- * @returns Returns `true` when the keypress was handled and no other keydown listener of the editor should
864
- * process the event any further. Returns `false` otherwise.
865
- */ _handleArrowKeyPressOnSelectedWidget(isForward) {
836
+ * Handles the keyboard navigation on "keydown" when a widget is currently selected and activates or deactivates
837
+ * the fake caret for that widget, depending on the current value of the `widget-type-around` model
838
+ * selection attribute and the direction of the pressed arrow key.
839
+ *
840
+ * @param isForward `true` when the pressed arrow key was responsible for the forward model selection movement
841
+ * as in {@link module:utils/keyboard~isForwardArrowKeyCode}.
842
+ * @returns Returns `true` when the keypress was handled and no other keydown listener of the editor should
843
+ * process the event any further. Returns `false` otherwise.
844
+ */ _handleArrowKeyPressOnSelectedWidget(isForward) {
866
845
  const editor = this.editor;
867
846
  const model = editor.model;
868
847
  const modelSelection = model.document.selection;
@@ -891,19 +870,19 @@ const PLUGIN_DISABLED_EDITING_ROOT_CLASS = 'ck-widget__type-around_disabled';
891
870
  });
892
871
  }
893
872
  /**
894
- * Handles the keyboard navigation on "keydown" when **no** widget is selected but the selection is **directly** next
895
- * to one and upon the fake caret should become active for this widget upon arrow keypress
896
- * (AKA entering/selecting the widget).
897
- *
898
- * **Note**: This code mirrors the implementation from the widget plugin but also adds the selection attribute.
899
- * Unfortunately, there is no safe way to let the widget plugin do the selection part first and then just set the
900
- * selection attribute here in the widget type around plugin. This is why this code must duplicate some from the widget plugin.
901
- *
902
- * @param isForward `true` when the pressed arrow key was responsible for the forward model selection movement
903
- * as in {@link module:utils/keyboard~isForwardArrowKeyCode}.
904
- * @returns Returns `true` when the keypress was handled and no other keydown listener of the editor should
905
- * process the event any further. Returns `false` otherwise.
906
- */ _handleArrowKeyPressWhenSelectionNextToAWidget(isForward) {
873
+ * Handles the keyboard navigation on "keydown" when **no** widget is selected but the selection is **directly** next
874
+ * to one and upon the fake caret should become active for this widget upon arrow keypress
875
+ * (AKA entering/selecting the widget).
876
+ *
877
+ * **Note**: This code mirrors the implementation from the widget plugin but also adds the selection attribute.
878
+ * Unfortunately, there is no safe way to let the widget plugin do the selection part first and then just set the
879
+ * selection attribute here in the widget type around plugin. This is why this code must duplicate some from the widget plugin.
880
+ *
881
+ * @param isForward `true` when the pressed arrow key was responsible for the forward model selection movement
882
+ * as in {@link module:utils/keyboard~isForwardArrowKeyCode}.
883
+ * @returns Returns `true` when the keypress was handled and no other keydown listener of the editor should
884
+ * process the event any further. Returns `false` otherwise.
885
+ */ _handleArrowKeyPressWhenSelectionNextToAWidget(isForward) {
907
886
  const editor = this.editor;
908
887
  const model = editor.model;
909
888
  const schema = model.schema;
@@ -923,14 +902,14 @@ const PLUGIN_DISABLED_EDITING_ROOT_CLASS = 'ck-widget__type-around_disabled';
923
902
  return false;
924
903
  }
925
904
  /**
926
- * Handles the keyboard navigation on "keydown" when a widget is currently selected (together with some other content)
927
- * and the widget is the first or last element in the selection. It activates or deactivates the fake caret for that widget.
928
- *
929
- * @param isForward `true` when the pressed arrow key was responsible for the forward model selection movement
930
- * as in {@link module:utils/keyboard~isForwardArrowKeyCode}.
931
- * @returns Returns `true` when the keypress was handled and no other keydown listener of the editor should
932
- * process the event any further. Returns `false` otherwise.
933
- */ _handleArrowKeyPressWhenNonCollapsedSelection(isForward) {
905
+ * Handles the keyboard navigation on "keydown" when a widget is currently selected (together with some other content)
906
+ * and the widget is the first or last element in the selection. It activates or deactivates the fake caret for that widget.
907
+ *
908
+ * @param isForward `true` when the pressed arrow key was responsible for the forward model selection movement
909
+ * as in {@link module:utils/keyboard~isForwardArrowKeyCode}.
910
+ * @returns Returns `true` when the keypress was handled and no other keydown listener of the editor should
911
+ * process the event any further. Returns `false` otherwise.
912
+ */ _handleArrowKeyPressWhenNonCollapsedSelection(isForward) {
934
913
  const editor = this.editor;
935
914
  const model = editor.model;
936
915
  const schema = model.schema;
@@ -949,10 +928,10 @@ const PLUGIN_DISABLED_EDITING_ROOT_CLASS = 'ck-widget__type-around_disabled';
949
928
  return false;
950
929
  }
951
930
  /**
952
- * Registers a `mousedown` listener for the view document which intercepts events
953
- * coming from the widget type around UI, which happens when a user clicks one of the buttons
954
- * that insert a paragraph next to a widget.
955
- */ _enableInsertingParagraphsOnButtonClick() {
931
+ * Registers a `mousedown` listener for the view document which intercepts events
932
+ * coming from the widget type around UI, which happens when a user clicks one of the buttons
933
+ * that insert a paragraph next to a widget.
934
+ */ _enableInsertingParagraphsOnButtonClick() {
956
935
  const editor = this.editor;
957
936
  const editingView = editor.editing.view;
958
937
  this._listenToIfEnabled(editingView.document, 'mousedown', (evt, domEventData)=>{
@@ -969,18 +948,18 @@ const PLUGIN_DISABLED_EDITING_ROOT_CLASS = 'ck-widget__type-around_disabled';
969
948
  });
970
949
  }
971
950
  /**
972
- * Creates the <kbd>Enter</kbd> key listener on the view document that allows the user to insert a paragraph
973
- * near the widget when either:
974
- *
975
- * * The fake caret was first activated using the arrow keys,
976
- * * The entire widget is selected in the model.
977
- *
978
- * In the first case, the new paragraph is inserted according to the `widget-type-around` selection
979
- * attribute (see {@link #_handleArrowKeyPress}).
980
- *
981
- * In the second case, the new paragraph is inserted based on whether a soft (<kbd>Shift</kbd>+<kbd>Enter</kbd>) keystroke
982
- * was pressed or not.
983
- */ _enableInsertingParagraphsOnEnterKeypress() {
951
+ * Creates the <kbd>Enter</kbd> key listener on the view document that allows the user to insert a paragraph
952
+ * near the widget when either:
953
+ *
954
+ * * The fake caret was first activated using the arrow keys,
955
+ * * The entire widget is selected in the model.
956
+ *
957
+ * In the first case, the new paragraph is inserted according to the `widget-type-around` selection
958
+ * attribute (see {@link #_handleArrowKeyPress}).
959
+ *
960
+ * In the second case, the new paragraph is inserted based on whether a soft (<kbd>Shift</kbd>+<kbd>Enter</kbd>) keystroke
961
+ * was pressed or not.
962
+ */ _enableInsertingParagraphsOnEnterKeypress() {
984
963
  const editor = this.editor;
985
964
  const selection = editor.model.document.selection;
986
965
  const editingView = editor.editing.view;
@@ -1011,18 +990,18 @@ const PLUGIN_DISABLED_EDITING_ROOT_CLASS = 'ck-widget__type-around_disabled';
1011
990
  });
1012
991
  }
1013
992
  /**
1014
- * Similar to the {@link #_enableInsertingParagraphsOnEnterKeypress}, it allows the user
1015
- * to insert a paragraph next to a widget when the fake caret was activated using arrow
1016
- * keys but it responds to typing instead of <kbd>Enter</kbd>.
1017
- *
1018
- * Listener enabled by this method will insert a new paragraph according to the `widget-type-around`
1019
- * model selection attribute as the user simply starts typing, which creates the impression that the fake caret
1020
- * behaves like a real one rendered by the browser (AKA your text appears where the caret was).
1021
- *
1022
- * **Note**: At the moment this listener creates 2 undo steps: one for the `insertParagraph` command
1023
- * and another one for actual typing. It is not a disaster but this may need to be fixed
1024
- * sooner or later.
1025
- */ _enableInsertingParagraphsOnTypingKeystroke() {
993
+ * Similar to the {@link #_enableInsertingParagraphsOnEnterKeypress}, it allows the user
994
+ * to insert a paragraph next to a widget when the fake caret was activated using arrow
995
+ * keys but it responds to typing instead of <kbd>Enter</kbd>.
996
+ *
997
+ * Listener enabled by this method will insert a new paragraph according to the `widget-type-around`
998
+ * model selection attribute as the user simply starts typing, which creates the impression that the fake caret
999
+ * behaves like a real one rendered by the browser (AKA your text appears where the caret was).
1000
+ *
1001
+ * **Note**: At the moment this listener creates 2 undo steps: one for the `insertParagraph` command
1002
+ * and another one for actual typing. It is not a disaster but this may need to be fixed
1003
+ * sooner or later.
1004
+ */ _enableInsertingParagraphsOnTypingKeystroke() {
1026
1005
  const editor = this.editor;
1027
1006
  const viewDocument = editor.editing.view.document;
1028
1007
  // Note: The priority must precede the default Input plugin insertText handler.
@@ -1056,13 +1035,13 @@ const PLUGIN_DISABLED_EDITING_ROOT_CLASS = 'ck-widget__type-around_disabled';
1056
1035
  }
1057
1036
  }
1058
1037
  /**
1059
- * It creates a "delete" event listener on the view document to handle cases when the <kbd>Delete</kbd> or <kbd>Backspace</kbd>
1060
- * is pressed and the fake caret is currently active.
1061
- *
1062
- * The fake caret should create an illusion of a real browser caret so that when it appears before or after
1063
- * a widget, pressing <kbd>Delete</kbd> or <kbd>Backspace</kbd> should remove a widget or delete the content
1064
- * before or after a widget (depending on the content surrounding the widget).
1065
- */ _enableDeleteIntegration() {
1038
+ * It creates a "delete" event listener on the view document to handle cases when the <kbd>Delete</kbd> or <kbd>Backspace</kbd>
1039
+ * is pressed and the fake caret is currently active.
1040
+ *
1041
+ * The fake caret should create an illusion of a real browser caret so that when it appears before or after
1042
+ * a widget, pressing <kbd>Delete</kbd> or <kbd>Backspace</kbd> should remove a widget or delete the content
1043
+ * before or after a widget (depending on the content surrounding the widget).
1044
+ */ _enableDeleteIntegration() {
1066
1045
  const editor = this.editor;
1067
1046
  const editingView = editor.editing.view;
1068
1047
  const model = editor.model;
@@ -1127,11 +1106,11 @@ const PLUGIN_DISABLED_EDITING_ROOT_CLASS = 'ck-widget__type-around_disabled';
1127
1106
  });
1128
1107
  }
1129
1108
  /**
1130
- * Attaches the {@link module:engine/model/model~Model#event:insertContent} event listener that, for instance, allows the user to paste
1131
- * content near a widget when the fake caret is first activated using the arrow keys.
1132
- *
1133
- * The content is inserted according to the `widget-type-around` selection attribute (see {@link #_handleArrowKeyPress}).
1134
- */ _enableInsertContentIntegration() {
1109
+ * Attaches the {@link module:engine/model/model~Model#event:insertContent} event listener that, for instance, allows the user to paste
1110
+ * content near a widget when the fake caret is first activated using the arrow keys.
1111
+ *
1112
+ * The content is inserted according to the `widget-type-around` selection attribute (see {@link #_handleArrowKeyPress}).
1113
+ */ _enableInsertContentIntegration() {
1135
1114
  const editor = this.editor;
1136
1115
  const model = this.editor.model;
1137
1116
  const documentSelection = model.document.selection;
@@ -1157,12 +1136,12 @@ const PLUGIN_DISABLED_EDITING_ROOT_CLASS = 'ck-widget__type-around_disabled';
1157
1136
  });
1158
1137
  }
1159
1138
  /**
1160
- * Attaches the {@link module:engine/model/model~Model#event:insertObject} event listener that modifies the
1161
- * `options.findOptimalPosition`parameter to position of fake caret in relation to selected element
1162
- * to reflect user's intent of desired insertion position.
1163
- *
1164
- * The object is inserted according to the `widget-type-around` selection attribute (see {@link #_handleArrowKeyPress}).
1165
- */ _enableInsertObjectIntegration() {
1139
+ * Attaches the {@link module:engine/model/model~Model#event:insertObject} event listener that modifies the
1140
+ * `options.findOptimalPosition`parameter to position of fake caret in relation to selected element
1141
+ * to reflect user's intent of desired insertion position.
1142
+ *
1143
+ * The object is inserted according to the `widget-type-around` selection attribute (see {@link #_handleArrowKeyPress}).
1144
+ */ _enableInsertObjectIntegration() {
1166
1145
  const editor = this.editor;
1167
1146
  const model = this.editor.model;
1168
1147
  const documentSelection = model.document.selection;
@@ -1182,13 +1161,13 @@ const PLUGIN_DISABLED_EDITING_ROOT_CLASS = 'ck-widget__type-around_disabled';
1182
1161
  });
1183
1162
  }
1184
1163
  /**
1185
- * Attaches the {@link module:engine/model/model~Model#event:deleteContent} event listener to block the event when the fake
1186
- * caret is active.
1187
- *
1188
- * This is required for cases that trigger {@link module:engine/model/model~Model#deleteContent `model.deleteContent()`}
1189
- * before calling {@link module:engine/model/model~Model#insertContent `model.insertContent()`} like, for instance,
1190
- * plain text pasting.
1191
- */ _enableDeleteContentIntegration() {
1164
+ * Attaches the {@link module:engine/model/model~Model#event:deleteContent} event listener to block the event when the fake
1165
+ * caret is active.
1166
+ *
1167
+ * This is required for cases that trigger {@link module:engine/model/model~Model#deleteContent `model.deleteContent()`}
1168
+ * before calling {@link module:engine/model/model~Model#insertContent `model.insertContent()`} like, for instance,
1169
+ * plain text pasting.
1170
+ */ _enableDeleteContentIntegration() {
1192
1171
  const editor = this.editor;
1193
1172
  const model = this.editor.model;
1194
1173
  const documentSelection = model.document.selection;
@@ -1205,6 +1184,14 @@ const PLUGIN_DISABLED_EDITING_ROOT_CLASS = 'ck-widget__type-around_disabled';
1205
1184
  priority: 'high'
1206
1185
  });
1207
1186
  }
1187
+ constructor(){
1188
+ super(...arguments);
1189
+ /**
1190
+ * A reference to the model widget element that has the fake caret active
1191
+ * on either side of it. It is later used to remove CSS classes associated with the fake caret
1192
+ * when the widget no longer needs it.
1193
+ */ this._currentFakeCaretModelElement = null;
1194
+ }
1208
1195
  }
1209
1196
  /**
1210
1197
  * Injects the type around UI into a view widget instance.
@@ -1463,38 +1450,23 @@ function selectionWillShrink(selection, isForward) {
1463
1450
  return !selection.isCollapsed && selection.isBackward == isForward;
1464
1451
  }
1465
1452
 
1466
- /**
1467
- * The widget plugin. It enables base support for widgets.
1468
- *
1469
- * See {@glink api/widget package page} for more details and documentation.
1470
- *
1471
- * This plugin enables multiple behaviors required by widgets:
1472
- *
1473
- * * The model to view selection converter for the editing pipeline (it handles widget custom selection rendering).
1474
- * If a converted selection wraps around a widget element, that selection is marked as
1475
- * {@link module:engine/view/selection~Selection#isFake fake}. Additionally, the `ck-widget_selected` CSS class
1476
- * is added to indicate that widget has been selected.
1477
- * * The mouse and keyboard events handling on and around widget elements.
1478
- */ class Widget extends Plugin {
1479
- /**
1480
- * Holds previously selected widgets.
1481
- */ _previouslySelected = new Set();
1482
- /**
1483
- * @inheritDoc
1484
- */ static get pluginName() {
1453
+ class Widget extends Plugin {
1454
+ /**
1455
+ * @inheritDoc
1456
+ */ static get pluginName() {
1485
1457
  return 'Widget';
1486
1458
  }
1487
1459
  /**
1488
- * @inheritDoc
1489
- */ static get requires() {
1460
+ * @inheritDoc
1461
+ */ static get requires() {
1490
1462
  return [
1491
1463
  WidgetTypeAround,
1492
1464
  Delete
1493
1465
  ];
1494
1466
  }
1495
1467
  /**
1496
- * @inheritDoc
1497
- */ init() {
1468
+ * @inheritDoc
1469
+ */ init() {
1498
1470
  const editor = this.editor;
1499
1471
  const view = editor.editing.view;
1500
1472
  const viewDocument = view.document;
@@ -1651,10 +1623,6 @@ function selectionWillShrink(selection, isForward) {
1651
1623
  id: 'widget',
1652
1624
  label: t('Keystrokes that can be used when a widget is selected (for example: image, table, etc.)'),
1653
1625
  keystrokes: [
1654
- {
1655
- label: t('Move focus from an editable area back to the parent widget'),
1656
- keystroke: 'Esc'
1657
- },
1658
1626
  {
1659
1627
  label: t('Insert a new paragraph directly after a widget'),
1660
1628
  keystroke: 'Enter'
@@ -1689,8 +1657,8 @@ function selectionWillShrink(selection, isForward) {
1689
1657
  });
1690
1658
  }
1691
1659
  /**
1692
- * Handles {@link module:engine/view/document~Document#event:mousedown mousedown} events on widget elements.
1693
- */ _onMousedown(eventInfo, domEventData) {
1660
+ * Handles {@link module:engine/view/document~Document#event:mousedown mousedown} events on widget elements.
1661
+ */ _onMousedown(eventInfo, domEventData) {
1694
1662
  const editor = this.editor;
1695
1663
  const view = editor.editing.view;
1696
1664
  const viewDocument = view.document;
@@ -1727,8 +1695,8 @@ function selectionWillShrink(selection, isForward) {
1727
1695
  this._setSelectionOverElement(modelElement);
1728
1696
  }
1729
1697
  /**
1730
- * Selects entire block content, e.g. on triple click it selects entire paragraph.
1731
- */ _selectBlockContent(element) {
1698
+ * Selects entire block content, e.g. on triple click it selects entire paragraph.
1699
+ */ _selectBlockContent(element) {
1732
1700
  const editor = this.editor;
1733
1701
  const model = editor.model;
1734
1702
  const mapper = editor.editing.mapper;
@@ -1747,14 +1715,14 @@ function selectionWillShrink(selection, isForward) {
1747
1715
  return true;
1748
1716
  }
1749
1717
  /**
1750
- * Handles {@link module:engine/view/document~Document#event:keydown keydown} events and changes
1751
- * the model selection when:
1752
- *
1753
- * * arrow key is pressed when the widget is selected,
1754
- * * the selection is next to a widget and the widget should become selected upon the arrow key press.
1755
- *
1756
- * See {@link #_preventDefaultOnArrowKeyPress}.
1757
- */ _handleSelectionChangeOnArrowKeyPress(eventInfo, domEventData) {
1718
+ * Handles {@link module:engine/view/document~Document#event:keydown keydown} events and changes
1719
+ * the model selection when:
1720
+ *
1721
+ * * arrow key is pressed when the widget is selected,
1722
+ * * the selection is next to a widget and the widget should become selected upon the arrow key press.
1723
+ *
1724
+ * See {@link #_preventDefaultOnArrowKeyPress}.
1725
+ */ _handleSelectionChangeOnArrowKeyPress(eventInfo, domEventData) {
1758
1726
  const keyCode = domEventData.keyCode;
1759
1727
  const model = this.editor.model;
1760
1728
  const schema = model.schema;
@@ -1809,12 +1777,12 @@ function selectionWillShrink(selection, isForward) {
1809
1777
  }
1810
1778
  }
1811
1779
  /**
1812
- * Handles {@link module:engine/view/document~Document#event:keydown keydown} events and prevents
1813
- * the default browser behavior to make sure the fake selection is not being moved from a fake selection
1814
- * container.
1815
- *
1816
- * See {@link #_handleSelectionChangeOnArrowKeyPress}.
1817
- */ _preventDefaultOnArrowKeyPress(eventInfo, domEventData) {
1780
+ * Handles {@link module:engine/view/document~Document#event:keydown keydown} events and prevents
1781
+ * the default browser behavior to make sure the fake selection is not being moved from a fake selection
1782
+ * container.
1783
+ *
1784
+ * See {@link #_handleSelectionChangeOnArrowKeyPress}.
1785
+ */ _preventDefaultOnArrowKeyPress(eventInfo, domEventData) {
1818
1786
  const model = this.editor.model;
1819
1787
  const schema = model.schema;
1820
1788
  const objectElement = model.document.selection.getSelectedElement();
@@ -1825,11 +1793,11 @@ function selectionWillShrink(selection, isForward) {
1825
1793
  }
1826
1794
  }
1827
1795
  /**
1828
- * Handles delete keys: backspace and delete.
1829
- *
1830
- * @param isForward Set to true if delete was performed in forward direction.
1831
- * @returns Returns `true` if keys were handled correctly.
1832
- */ _handleDelete(isForward) {
1796
+ * Handles delete keys: backspace and delete.
1797
+ *
1798
+ * @param isForward Set to true if delete was performed in forward direction.
1799
+ * @returns Returns `true` if keys were handled correctly.
1800
+ */ _handleDelete(isForward) {
1833
1801
  const modelDocument = this.editor.model.document;
1834
1802
  const modelSelection = modelDocument.selection;
1835
1803
  // Do nothing when the read only mode is enabled.
@@ -1856,22 +1824,22 @@ function selectionWillShrink(selection, isForward) {
1856
1824
  }
1857
1825
  }
1858
1826
  /**
1859
- * Sets {@link module:engine/model/selection~Selection document's selection} over given element.
1860
- *
1861
- * @internal
1862
- */ _setSelectionOverElement(element) {
1827
+ * Sets {@link module:engine/model/selection~Selection document's selection} over given element.
1828
+ *
1829
+ * @internal
1830
+ */ _setSelectionOverElement(element) {
1863
1831
  this.editor.model.change((writer)=>{
1864
1832
  writer.setSelection(writer.createRangeOn(element));
1865
1833
  });
1866
1834
  }
1867
1835
  /**
1868
- * Checks if {@link module:engine/model/element~Element element} placed next to the current
1869
- * {@link module:engine/model/selection~Selection model selection} exists and is marked in
1870
- * {@link module:engine/model/schema~Schema schema} as `object`.
1871
- *
1872
- * @internal
1873
- * @param forward Direction of checking.
1874
- */ _getObjectElementNextToSelection(forward) {
1836
+ * Checks if {@link module:engine/model/element~Element element} placed next to the current
1837
+ * {@link module:engine/model/selection~Selection model selection} exists and is marked in
1838
+ * {@link module:engine/model/schema~Schema schema} as `object`.
1839
+ *
1840
+ * @internal
1841
+ * @param forward Direction of checking.
1842
+ */ _getObjectElementNextToSelection(forward) {
1875
1843
  const model = this.editor.model;
1876
1844
  const schema = model.schema;
1877
1845
  const modelSelection = model.document.selection;
@@ -1892,16 +1860,16 @@ function selectionWillShrink(selection, isForward) {
1892
1860
  return null;
1893
1861
  }
1894
1862
  /**
1895
- * Removes CSS class from previously selected widgets.
1896
- */ _clearPreviouslySelectedWidgets(writer) {
1863
+ * Removes CSS class from previously selected widgets.
1864
+ */ _clearPreviouslySelectedWidgets(writer) {
1897
1865
  for (const widget of this._previouslySelected){
1898
1866
  writer.removeClass(WIDGET_SELECTED_CLASS_NAME, widget);
1899
1867
  }
1900
1868
  this._previouslySelected.clear();
1901
1869
  }
1902
1870
  /**
1903
- * Moves the document selection into the first nested editable.
1904
- */ _selectFirstNestedEditable() {
1871
+ * Moves the document selection into the first nested editable.
1872
+ */ _selectFirstNestedEditable() {
1905
1873
  const editor = this.editor;
1906
1874
  const view = this.editor.editing.view;
1907
1875
  const viewDocument = view.document;
@@ -1922,8 +1890,8 @@ function selectionWillShrink(selection, isForward) {
1922
1890
  return false;
1923
1891
  }
1924
1892
  /**
1925
- * Updates the document selection so that it selects first ancestor widget.
1926
- */ _selectAncestorWidget() {
1893
+ * Updates the document selection so that it selects first ancestor widget.
1894
+ */ _selectAncestorWidget() {
1927
1895
  const editor = this.editor;
1928
1896
  const mapper = editor.editing.mapper;
1929
1897
  const selection = editor.editing.view.document.selection;
@@ -1942,6 +1910,12 @@ function selectionWillShrink(selection, isForward) {
1942
1910
  });
1943
1911
  return true;
1944
1912
  }
1913
+ constructor(){
1914
+ super(...arguments);
1915
+ /**
1916
+ * Holds previously selected widgets.
1917
+ */ this._previouslySelected = new Set();
1918
+ }
1945
1919
  }
1946
1920
  /**
1947
1921
  * Returns `true` when element is a nested editable or is placed inside one.
@@ -2004,51 +1978,22 @@ function selectionWillShrink(selection, isForward) {
2004
1978
  return null;
2005
1979
  }
2006
1980
 
2007
- /**
2008
- * Widget toolbar repository plugin. A central point for registering widget toolbars. This plugin handles the whole
2009
- * toolbar rendering process and exposes a concise API.
2010
- *
2011
- * To add a toolbar for your widget use the {@link ~WidgetToolbarRepository#register `WidgetToolbarRepository#register()`} method.
2012
- *
2013
- * The following example comes from the {@link module:image/imagetoolbar~ImageToolbar} plugin:
2014
- *
2015
- * ```ts
2016
- * class ImageToolbar extends Plugin {
2017
- * static get requires() {
2018
- * return [ WidgetToolbarRepository ];
2019
- * }
2020
- *
2021
- * afterInit() {
2022
- * const editor = this.editor;
2023
- * const widgetToolbarRepository = editor.plugins.get( WidgetToolbarRepository );
2024
- *
2025
- * widgetToolbarRepository.register( 'image', {
2026
- * items: editor.config.get( 'image.toolbar' ),
2027
- * getRelatedElement: getClosestSelectedImageWidget
2028
- * } );
2029
- * }
2030
- * }
2031
- * ```
2032
- */ class WidgetToolbarRepository extends Plugin {
2033
- /**
2034
- * A map of toolbar definitions.
2035
- */ _toolbarDefinitions = new Map();
2036
- _balloon;
1981
+ class WidgetToolbarRepository extends Plugin {
2037
1982
  /**
2038
- * @inheritDoc
2039
- */ static get requires() {
1983
+ * @inheritDoc
1984
+ */ static get requires() {
2040
1985
  return [
2041
1986
  ContextualBalloon
2042
1987
  ];
2043
1988
  }
2044
1989
  /**
2045
- * @inheritDoc
2046
- */ static get pluginName() {
1990
+ * @inheritDoc
1991
+ */ static get pluginName() {
2047
1992
  return 'WidgetToolbarRepository';
2048
1993
  }
2049
1994
  /**
2050
- * @inheritDoc
2051
- */ init() {
1995
+ * @inheritDoc
1996
+ */ init() {
2052
1997
  const editor = this.editor;
2053
1998
  // Disables the default balloon toolbar for all widgets.
2054
1999
  if (editor.plugins.has('BalloonToolbar')) {
@@ -2082,35 +2027,35 @@ function selectionWillShrink(selection, isForward) {
2082
2027
  }
2083
2028
  }
2084
2029
  /**
2085
- * Registers toolbar in the WidgetToolbarRepository. It renders it in the `ContextualBalloon` based on the value of the invoked
2086
- * `getRelatedElement` function. Toolbar items are gathered from `items` array.
2087
- * The balloon's CSS class is by default `ck-toolbar-container` and may be override with the `balloonClassName` option.
2088
- *
2089
- * Note: This method should be called in the {@link module:core/plugin~PluginInterface#afterInit `Plugin#afterInit()`}
2090
- * callback (or later) to make sure that the given toolbar items were already registered by other plugins.
2091
- *
2092
- * @param toolbarId An id for the toolbar. Used to
2093
- * @param options.ariaLabel Label used by assistive technologies to describe this toolbar element.
2094
- * @param options.items Array of toolbar items.
2095
- * @param options.getRelatedElement Callback which returns an element the toolbar should be attached to.
2096
- * @param options.balloonClassName CSS class for the widget balloon.
2097
- */ register(toolbarId, { ariaLabel, items, getRelatedElement, balloonClassName = 'ck-toolbar-container' }) {
2030
+ * Registers toolbar in the WidgetToolbarRepository. It renders it in the `ContextualBalloon` based on the value of the invoked
2031
+ * `getRelatedElement` function. Toolbar items are gathered from `items` array.
2032
+ * The balloon's CSS class is by default `ck-toolbar-container` and may be override with the `balloonClassName` option.
2033
+ *
2034
+ * Note: This method should be called in the {@link module:core/plugin~PluginInterface#afterInit `Plugin#afterInit()`}
2035
+ * callback (or later) to make sure that the given toolbar items were already registered by other plugins.
2036
+ *
2037
+ * @param toolbarId An id for the toolbar. Used to
2038
+ * @param options.ariaLabel Label used by assistive technologies to describe this toolbar element.
2039
+ * @param options.items Array of toolbar items.
2040
+ * @param options.getRelatedElement Callback which returns an element the toolbar should be attached to.
2041
+ * @param options.balloonClassName CSS class for the widget balloon.
2042
+ */ register(toolbarId, { ariaLabel, items, getRelatedElement, balloonClassName = 'ck-toolbar-container' }) {
2098
2043
  // Trying to register a toolbar without any item.
2099
2044
  if (!items.length) {
2100
2045
  /**
2101
- * When {@link module:widget/widgettoolbarrepository~WidgetToolbarRepository#register registering} a new widget toolbar, you
2102
- * need to provide a non-empty array with the items that will be inserted into the toolbar.
2103
- *
2104
- * If you see this error when integrating the editor, you likely forgot to configure one of the widget toolbars.
2105
- *
2106
- * See for instance:
2107
- *
2108
- * * {@link module:table/tableconfig~TableConfig#contentToolbar `config.table.contentToolbar`}
2109
- * * {@link module:image/imageconfig~ImageConfig#toolbar `config.image.toolbar`}
2110
- *
2111
- * @error widget-toolbar-no-items
2112
- * @param toolbarId The id of the toolbar that has not been configured correctly.
2113
- */ logWarning('widget-toolbar-no-items', {
2046
+ * When {@link module:widget/widgettoolbarrepository~WidgetToolbarRepository#register registering} a new widget toolbar, you
2047
+ * need to provide a non-empty array with the items that will be inserted into the toolbar.
2048
+ *
2049
+ * If you see this error when integrating the editor, you likely forgot to configure one of the widget toolbars.
2050
+ *
2051
+ * See for instance:
2052
+ *
2053
+ * * {@link module:table/tableconfig~TableConfig#contentToolbar `config.table.contentToolbar`}
2054
+ * * {@link module:image/imageconfig~ImageConfig#toolbar `config.image.toolbar`}
2055
+ *
2056
+ * @error widget-toolbar-no-items
2057
+ * @param toolbarId The id of the toolbar that has not been configured correctly.
2058
+ */ logWarning('widget-toolbar-no-items', {
2114
2059
  toolbarId
2115
2060
  });
2116
2061
  return;
@@ -2121,11 +2066,11 @@ function selectionWillShrink(selection, isForward) {
2121
2066
  toolbarView.ariaLabel = ariaLabel || t('Widget toolbar');
2122
2067
  if (this._toolbarDefinitions.has(toolbarId)) {
2123
2068
  /**
2124
- * Toolbar with the given id was already added.
2125
- *
2126
- * @error widget-toolbar-duplicated
2127
- * @param toolbarId Toolbar id.
2128
- */ throw new CKEditorError('widget-toolbar-duplicated', this, {
2069
+ * Toolbar with the given id was already added.
2070
+ *
2071
+ * @error widget-toolbar-duplicated
2072
+ * @param toolbarId Toolbar id.
2073
+ */ throw new CKEditorError('widget-toolbar-duplicated', this, {
2129
2074
  toolbarId
2130
2075
  });
2131
2076
  }
@@ -2152,8 +2097,8 @@ function selectionWillShrink(selection, isForward) {
2152
2097
  this._toolbarDefinitions.set(toolbarId, toolbarDefinition);
2153
2098
  }
2154
2099
  /**
2155
- * Iterates over stored toolbars and makes them visible or hidden.
2156
- */ _updateToolbarsVisibility() {
2100
+ * Iterates over stored toolbars and makes them visible or hidden.
2101
+ */ _updateToolbarsVisibility() {
2157
2102
  let maxRelatedElementDepth = 0;
2158
2103
  let deepestRelatedElement = null;
2159
2104
  let deepestToolbarDefinition = null;
@@ -2185,18 +2130,18 @@ function selectionWillShrink(selection, isForward) {
2185
2130
  }
2186
2131
  }
2187
2132
  /**
2188
- * Hides the given toolbar.
2189
- */ _hideToolbar(toolbarDefinition) {
2133
+ * Hides the given toolbar.
2134
+ */ _hideToolbar(toolbarDefinition) {
2190
2135
  this._balloon.remove(toolbarDefinition.view);
2191
2136
  this.stopListening(this._balloon, 'change:visibleView');
2192
2137
  }
2193
2138
  /**
2194
- * Shows up the toolbar if the toolbar is not visible.
2195
- * Otherwise, repositions the toolbar's balloon when toolbar's view is the most top view in balloon stack.
2196
- *
2197
- * It might happen here that the toolbar's view is under another view. Then do nothing as the other toolbar view
2198
- * should be still visible after the {@link module:ui/editorui/editorui~EditorUI#event:update}.
2199
- */ _showToolbar(toolbarDefinition, relatedElement) {
2139
+ * Shows up the toolbar if the toolbar is not visible.
2140
+ * Otherwise, repositions the toolbar's balloon when toolbar's view is the most top view in balloon stack.
2141
+ *
2142
+ * It might happen here that the toolbar's view is under another view. Then do nothing as the other toolbar view
2143
+ * should be still visible after the {@link module:ui/editorui/editorui~EditorUI#event:update}.
2144
+ */ _showToolbar(toolbarDefinition, relatedElement) {
2200
2145
  if (this._isToolbarVisible(toolbarDefinition)) {
2201
2146
  repositionContextualBalloon(this.editor, relatedElement);
2202
2147
  } else if (!this._isToolbarInBalloon(toolbarDefinition)) {
@@ -2229,6 +2174,12 @@ function selectionWillShrink(selection, isForward) {
2229
2174
  _isToolbarInBalloon(toolbar) {
2230
2175
  return this._balloon.hasView(toolbar.view);
2231
2176
  }
2177
+ constructor(){
2178
+ super(...arguments);
2179
+ /**
2180
+ * A map of toolbar definitions.
2181
+ */ this._toolbarDefinitions = new Map();
2182
+ }
2232
2183
  }
2233
2184
  function repositionContextualBalloon(editor, relatedElement) {
2234
2185
  const balloon = editor.plugins.get('ContextualBalloon');
@@ -2256,76 +2207,31 @@ function isWidgetSelected(selection) {
2256
2207
  return !!(viewElement && isWidget(viewElement));
2257
2208
  }
2258
2209
 
2259
- /**
2260
- * Stores the internal state of a single resizable object.
2261
- */ class ResizeState extends /* #__PURE__ */ ObservableMixin() {
2262
- /**
2263
- * The reference point of the resizer where the dragging started. It is used to measure the distance the user cursor
2264
- * traveled, so how much the image should be enlarged.
2265
- * This information is only known after the DOM was rendered, so it will be updated later.
2266
- *
2267
- * @internal
2268
- */ _referenceCoordinates;
2269
- /**
2270
- * Resizer options.
2271
- */ _options;
2272
- /**
2273
- * The original width (pixels) of the resized object when the resize process was started.
2274
- *
2275
- * @readonly
2276
- */ _originalWidth;
2277
- /**
2278
- * The original height (pixels) of the resized object when the resize process was started.
2279
- *
2280
- * @readonly
2281
- */ _originalHeight;
2282
- /**
2283
- * The original width (percents) of the resized object when the resize process was started.
2284
- *
2285
- * @readonly
2286
- */ _originalWidthPercents;
2287
- /**
2288
- * A width to height ratio of the resized image.
2289
- *
2290
- * @readonly
2291
- */ _aspectRatio;
2292
- /**
2293
- * @param options Resizer options.
2294
- */ constructor(options){
2295
- super();
2296
- this.set('activeHandlePosition', null);
2297
- this.set('proposedWidthPercents', null);
2298
- this.set('proposedWidth', null);
2299
- this.set('proposedHeight', null);
2300
- this.set('proposedHandleHostWidth', null);
2301
- this.set('proposedHandleHostHeight', null);
2302
- this._options = options;
2303
- this._referenceCoordinates = null;
2304
- }
2210
+ class ResizeState extends ObservableMixin() {
2305
2211
  /**
2306
- * The original width (pixels) of the resized object when the resize process was started.
2307
- */ get originalWidth() {
2212
+ * The original width (pixels) of the resized object when the resize process was started.
2213
+ */ get originalWidth() {
2308
2214
  return this._originalWidth;
2309
2215
  }
2310
2216
  /**
2311
- * The original height (pixels) of the resized object when the resize process was started.
2312
- */ get originalHeight() {
2217
+ * The original height (pixels) of the resized object when the resize process was started.
2218
+ */ get originalHeight() {
2313
2219
  return this._originalHeight;
2314
2220
  }
2315
2221
  /**
2316
- * The original width (percents) of the resized object when the resize process was started.
2317
- */ get originalWidthPercents() {
2222
+ * The original width (percents) of the resized object when the resize process was started.
2223
+ */ get originalWidthPercents() {
2318
2224
  return this._originalWidthPercents;
2319
2225
  }
2320
2226
  /**
2321
- * A width to height ratio of the resized image.
2322
- */ get aspectRatio() {
2227
+ * A width to height ratio of the resized image.
2228
+ */ get aspectRatio() {
2323
2229
  return this._aspectRatio;
2324
2230
  }
2325
2231
  /**
2326
- *
2327
- * @param domResizeHandle The handle used to calculate the reference point.
2328
- */ begin(domResizeHandle, domHandleHost, domResizeHost) {
2232
+ *
2233
+ * @param domResizeHandle The handle used to calculate the reference point.
2234
+ */ begin(domResizeHandle, domHandleHost, domResizeHost) {
2329
2235
  const clientRect = new Rect(domHandleHost);
2330
2236
  this.activeHandlePosition = getHandlePosition(domResizeHandle);
2331
2237
  this._referenceCoordinates = getAbsoluteBoundaryPoint(domHandleHost, getOppositePosition(this.activeHandlePosition));
@@ -2346,6 +2252,19 @@ function isWidgetSelected(selection) {
2346
2252
  this.proposedHandleHostWidth = newSize.handleHostWidth;
2347
2253
  this.proposedHandleHostHeight = newSize.handleHostHeight;
2348
2254
  }
2255
+ /**
2256
+ * @param options Resizer options.
2257
+ */ constructor(options){
2258
+ super();
2259
+ this.set('activeHandlePosition', null);
2260
+ this.set('proposedWidthPercents', null);
2261
+ this.set('proposedWidth', null);
2262
+ this.set('proposedHeight', null);
2263
+ this.set('proposedHandleHostWidth', null);
2264
+ this.set('proposedHandleHostHeight', null);
2265
+ this._options = options;
2266
+ this._referenceCoordinates = null;
2267
+ }
2349
2268
  }
2350
2269
  /**
2351
2270
  * Returns coordinates of the top-left corner of an element, relative to the document's top-left corner.
@@ -2400,9 +2319,33 @@ function isWidgetSelected(selection) {
2400
2319
  return `${replacements[parts[0]]}-${replacements[parts[1]]}`;
2401
2320
  }
2402
2321
 
2403
- /**
2404
- * A view displaying the proposed new element size during the resizing.
2405
- */ class SizeView extends View {
2322
+ class SizeView extends View {
2323
+ /**
2324
+ * A method used for binding the `SizeView` instance properties to the `ResizeState` instance observable properties.
2325
+ *
2326
+ * @internal
2327
+ * @param options An object defining the resizer options, used for setting the proper size label.
2328
+ * @param resizeState The `ResizeState` class instance, used for keeping the `SizeView` state up to date.
2329
+ */ _bindToState(options, resizeState) {
2330
+ this.bind('_isVisible').to(resizeState, 'proposedWidth', resizeState, 'proposedHeight', (width, height)=>width !== null && height !== null);
2331
+ this.bind('_label').to(resizeState, 'proposedHandleHostWidth', resizeState, 'proposedHandleHostHeight', resizeState, 'proposedWidthPercents', (width, height, widthPercents)=>{
2332
+ if (options.unit === 'px') {
2333
+ return `${width}×${height}`;
2334
+ } else {
2335
+ return `${widthPercents}%`;
2336
+ }
2337
+ });
2338
+ this.bind('_viewPosition').to(resizeState, 'activeHandlePosition', resizeState, 'proposedHandleHostWidth', resizeState, 'proposedHandleHostHeight', // If the widget is too small to contain the size label, display the label above.
2339
+ (position, width, height)=>width < 50 || height < 50 ? 'above-center' : position);
2340
+ }
2341
+ /**
2342
+ * A method used for cleaning up. It removes the bindings and hides the view.
2343
+ *
2344
+ * @internal
2345
+ */ _dismiss() {
2346
+ this.unbind();
2347
+ this._isVisible = false;
2348
+ }
2406
2349
  constructor(){
2407
2350
  super();
2408
2351
  const bind = this.bindTemplate;
@@ -2425,103 +2368,35 @@ function isWidgetSelected(selection) {
2425
2368
  ]
2426
2369
  });
2427
2370
  }
2428
- /**
2429
- * A method used for binding the `SizeView` instance properties to the `ResizeState` instance observable properties.
2430
- *
2431
- * @internal
2432
- * @param options An object defining the resizer options, used for setting the proper size label.
2433
- * @param resizeState The `ResizeState` class instance, used for keeping the `SizeView` state up to date.
2434
- */ _bindToState(options, resizeState) {
2435
- this.bind('_isVisible').to(resizeState, 'proposedWidth', resizeState, 'proposedHeight', (width, height)=>width !== null && height !== null);
2436
- this.bind('_label').to(resizeState, 'proposedHandleHostWidth', resizeState, 'proposedHandleHostHeight', resizeState, 'proposedWidthPercents', (width, height, widthPercents)=>{
2437
- if (options.unit === 'px') {
2438
- return `${width}×${height}`;
2439
- } else {
2440
- return `${widthPercents}%`;
2441
- }
2442
- });
2443
- this.bind('_viewPosition').to(resizeState, 'activeHandlePosition', resizeState, 'proposedHandleHostWidth', resizeState, 'proposedHandleHostHeight', // If the widget is too small to contain the size label, display the label above.
2444
- (position, width, height)=>width < 50 || height < 50 ? 'above-center' : position);
2445
- }
2446
- /**
2447
- * A method used for cleaning up. It removes the bindings and hides the view.
2448
- *
2449
- * @internal
2450
- */ _dismiss() {
2451
- this.unbind();
2452
- this._isVisible = false;
2453
- }
2454
2371
  }
2455
2372
 
2456
- /**
2457
- * Represents a resizer for a single resizable object.
2458
- */ class Resizer extends /* #__PURE__ */ ObservableMixin() {
2459
- /**
2460
- * Stores the state of the resizable host geometry, such as the original width, the currently proposed height, etc.
2461
- *
2462
- * Note that a new state is created for each resize transaction.
2463
- */ _state;
2464
- /**
2465
- * A view displaying the proposed new element size during the resizing.
2466
- */ _sizeView;
2467
- /**
2468
- * Options passed to the {@link #constructor}.
2469
- */ _options;
2470
- /**
2471
- * A wrapper that is controlled by the resizer. This is usually a widget element.
2472
- */ _viewResizerWrapper = null;
2473
- /**
2474
- * The width of the resized {@link module:widget/widgetresize~ResizerOptions#viewElement viewElement} before the resizing started.
2475
- */ _initialViewWidth;
2476
- /**
2477
- * @param options Resizer options.
2478
- */ constructor(options){
2479
- super();
2480
- this._options = options;
2481
- this.set('isEnabled', true);
2482
- this.set('isSelected', false);
2483
- this.bind('isVisible').to(this, 'isEnabled', this, 'isSelected', (isEnabled, isSelected)=>isEnabled && isSelected);
2484
- this.decorate('begin');
2485
- this.decorate('cancel');
2486
- this.decorate('commit');
2487
- this.decorate('updateSize');
2488
- this.on('commit', (event)=>{
2489
- // State might not be initialized yet. In this case, prevent further handling and make sure that the resizer is
2490
- // cleaned up (#5195).
2491
- if (!this.state.proposedWidth && !this.state.proposedWidthPercents) {
2492
- this._cleanup();
2493
- event.stop();
2494
- }
2495
- }, {
2496
- priority: 'high'
2497
- });
2498
- }
2373
+ class Resizer extends ObservableMixin() {
2499
2374
  /**
2500
- * Stores the state of the resizable host geometry, such as the original width, the currently proposed height, etc.
2501
- *
2502
- * Note that a new state is created for each resize transaction.
2503
- */ get state() {
2375
+ * Stores the state of the resizable host geometry, such as the original width, the currently proposed height, etc.
2376
+ *
2377
+ * Note that a new state is created for each resize transaction.
2378
+ */ get state() {
2504
2379
  return this._state;
2505
2380
  }
2506
2381
  /**
2507
- * Makes resizer visible in the UI.
2508
- */ show() {
2382
+ * Makes resizer visible in the UI.
2383
+ */ show() {
2509
2384
  const editingView = this._options.editor.editing.view;
2510
2385
  editingView.change((writer)=>{
2511
2386
  writer.removeClass('ck-hidden', this._viewResizerWrapper);
2512
2387
  });
2513
2388
  }
2514
2389
  /**
2515
- * Hides resizer in the UI.
2516
- */ hide() {
2390
+ * Hides resizer in the UI.
2391
+ */ hide() {
2517
2392
  const editingView = this._options.editor.editing.view;
2518
2393
  editingView.change((writer)=>{
2519
2394
  writer.addClass('ck-hidden', this._viewResizerWrapper);
2520
2395
  });
2521
2396
  }
2522
2397
  /**
2523
- * Attaches the resizer to the DOM.
2524
- */ attach() {
2398
+ * Attaches the resizer to the DOM.
2399
+ */ attach() {
2525
2400
  // eslint-disable-next-line @typescript-eslint/no-this-alias
2526
2401
  const that = this;
2527
2402
  const widgetElement = this._options.viewElement;
@@ -2553,23 +2428,23 @@ function isWidgetSelected(selection) {
2553
2428
  });
2554
2429
  }
2555
2430
  /**
2556
- * Starts the resizing process.
2557
- *
2558
- * Creates a new {@link #state} for the current process.
2559
- *
2560
- * @fires begin
2561
- * @param domResizeHandle Clicked handle.
2562
- */ begin(domResizeHandle) {
2431
+ * Starts the resizing process.
2432
+ *
2433
+ * Creates a new {@link #state} for the current process.
2434
+ *
2435
+ * @fires begin
2436
+ * @param domResizeHandle Clicked handle.
2437
+ */ begin(domResizeHandle) {
2563
2438
  this._state = new ResizeState(this._options);
2564
2439
  this._sizeView._bindToState(this._options, this.state);
2565
2440
  this._initialViewWidth = this._options.viewElement.getStyle('width');
2566
2441
  this.state.begin(domResizeHandle, this._getHandleHost(), this._getResizeHost());
2567
2442
  }
2568
2443
  /**
2569
- * Updates the proposed size based on `domEventData`.
2570
- *
2571
- * @fires updateSize
2572
- */ updateSize(domEventData) {
2444
+ * Updates the proposed size based on `domEventData`.
2445
+ *
2446
+ * @fires updateSize
2447
+ */ updateSize(domEventData) {
2573
2448
  const newSize = this._proposeNewSize(domEventData);
2574
2449
  const editingView = this._options.editor.editing.view;
2575
2450
  editingView.change((writer)=>{
@@ -2596,10 +2471,10 @@ function isWidgetSelected(selection) {
2596
2471
  });
2597
2472
  }
2598
2473
  /**
2599
- * Applies the geometry proposed with the resizer.
2600
- *
2601
- * @fires commit
2602
- */ commit() {
2474
+ * Applies the geometry proposed with the resizer.
2475
+ *
2476
+ * @fires commit
2477
+ */ commit() {
2603
2478
  const unit = this._options.unit || '%';
2604
2479
  const newValue = (unit === '%' ? this.state.proposedWidthPercents : this.state.proposedWidth) + unit;
2605
2480
  // Both cleanup and onCommit callback are very likely to make view changes. Ensure that it is made in a single step.
@@ -2609,22 +2484,22 @@ function isWidgetSelected(selection) {
2609
2484
  });
2610
2485
  }
2611
2486
  /**
2612
- * Cancels and rejects the proposed resize dimensions, hiding the UI.
2613
- *
2614
- * @fires cancel
2615
- */ cancel() {
2487
+ * Cancels and rejects the proposed resize dimensions, hiding the UI.
2488
+ *
2489
+ * @fires cancel
2490
+ */ cancel() {
2616
2491
  this._cleanup();
2617
2492
  }
2618
2493
  /**
2619
- * Destroys the resizer.
2620
- */ destroy() {
2494
+ * Destroys the resizer.
2495
+ */ destroy() {
2621
2496
  this.cancel();
2622
2497
  }
2623
2498
  /**
2624
- * Redraws the resizer.
2625
- *
2626
- * @param handleHostRect Handle host rectangle might be given to improve performance.
2627
- */ redraw(handleHostRect) {
2499
+ * Redraws the resizer.
2500
+ *
2501
+ * @param handleHostRect Handle host rectangle might be given to improve performance.
2502
+ */ redraw(handleHostRect) {
2628
2503
  const domWrapper = this._domResizerWrapper;
2629
2504
  // Refresh only if resizer exists in the DOM.
2630
2505
  if (!existsInDom(domWrapper)) {
@@ -2679,8 +2554,8 @@ function isWidgetSelected(selection) {
2679
2554
  return domElement.classList.contains('ck-widget__resizer__handle');
2680
2555
  }
2681
2556
  /**
2682
- * Cleans up the context state.
2683
- */ _cleanup() {
2557
+ * Cleans up the context state.
2558
+ */ _cleanup() {
2684
2559
  this._sizeView._dismiss();
2685
2560
  const editingView = this._options.editor.editing.view;
2686
2561
  editingView.change((writer)=>{
@@ -2688,10 +2563,10 @@ function isWidgetSelected(selection) {
2688
2563
  });
2689
2564
  }
2690
2565
  /**
2691
- * Calculates the proposed size as the resize handles are dragged.
2692
- *
2693
- * @param domEventData Event data that caused the size update request. It should be used to calculate the proposed size.
2694
- */ _proposeNewSize(domEventData) {
2566
+ * Calculates the proposed size as the resize handles are dragged.
2567
+ *
2568
+ * @param domEventData Event data that caused the size update request. It should be used to calculate the proposed size.
2569
+ */ _proposeNewSize(domEventData) {
2695
2570
  const state = this.state;
2696
2571
  const currentCoordinates = extractCoordinates(domEventData);
2697
2572
  const isCentered = this._options.isCentered ? this._options.isCentered(this) : true;
@@ -2737,37 +2612,37 @@ function isWidgetSelected(selection) {
2737
2612
  };
2738
2613
  }
2739
2614
  /**
2740
- * Obtains the resize host.
2741
- *
2742
- * Resize host is an object that receives dimensions which are the result of resizing.
2743
- */ _getResizeHost() {
2615
+ * Obtains the resize host.
2616
+ *
2617
+ * Resize host is an object that receives dimensions which are the result of resizing.
2618
+ */ _getResizeHost() {
2744
2619
  const widgetWrapper = this._domResizerWrapper.parentElement;
2745
2620
  return this._options.getResizeHost(widgetWrapper);
2746
2621
  }
2747
2622
  /**
2748
- * Obtains the handle host.
2749
- *
2750
- * Handle host is an object that the handles are aligned to.
2751
- *
2752
- * Handle host will not always be an entire widget itself. Take an image as an example. The image widget
2753
- * contains an image and a caption. Only the image should be surrounded with handles.
2754
- */ _getHandleHost() {
2623
+ * Obtains the handle host.
2624
+ *
2625
+ * Handle host is an object that the handles are aligned to.
2626
+ *
2627
+ * Handle host will not always be an entire widget itself. Take an image as an example. The image widget
2628
+ * contains an image and a caption. Only the image should be surrounded with handles.
2629
+ */ _getHandleHost() {
2755
2630
  const widgetWrapper = this._domResizerWrapper.parentElement;
2756
2631
  return this._options.getHandleHost(widgetWrapper);
2757
2632
  }
2758
2633
  /**
2759
- * DOM container of the entire resize UI.
2760
- *
2761
- * Note that this property will have a value only after the element bound with the resizer is rendered
2762
- * (otherwise `null`).
2763
- */ get _domResizerWrapper() {
2634
+ * DOM container of the entire resize UI.
2635
+ *
2636
+ * Note that this property will have a value only after the element bound with the resizer is rendered
2637
+ * (otherwise `null`).
2638
+ */ get _domResizerWrapper() {
2764
2639
  return this._options.editor.editing.view.domConverter.mapViewToDom(this._viewResizerWrapper);
2765
2640
  }
2766
2641
  /**
2767
- * Renders the resize handles in the DOM.
2768
- *
2769
- * @param domElement The resizer wrapper.
2770
- */ _appendHandles(domElement) {
2642
+ * Renders the resize handles in the DOM.
2643
+ *
2644
+ * @param domElement The resizer wrapper.
2645
+ */ _appendHandles(domElement) {
2771
2646
  const resizerPositions = [
2772
2647
  'top-left',
2773
2648
  'top-right',
@@ -2784,13 +2659,39 @@ function isWidgetSelected(selection) {
2784
2659
  }
2785
2660
  }
2786
2661
  /**
2787
- * Sets up the {@link #_sizeView} property and adds it to the passed `domElement`.
2788
- */ _appendSizeUI(domElement) {
2662
+ * Sets up the {@link #_sizeView} property and adds it to the passed `domElement`.
2663
+ */ _appendSizeUI(domElement) {
2789
2664
  this._sizeView = new SizeView();
2790
2665
  // Make sure icon#element is rendered before passing to appendChild().
2791
2666
  this._sizeView.render();
2792
2667
  domElement.appendChild(this._sizeView.element);
2793
2668
  }
2669
+ /**
2670
+ * @param options Resizer options.
2671
+ */ constructor(options){
2672
+ super();
2673
+ /**
2674
+ * A wrapper that is controlled by the resizer. This is usually a widget element.
2675
+ */ this._viewResizerWrapper = null;
2676
+ this._options = options;
2677
+ this.set('isEnabled', true);
2678
+ this.set('isSelected', false);
2679
+ this.bind('isVisible').to(this, 'isEnabled', this, 'isSelected', (isEnabled, isSelected)=>isEnabled && isSelected);
2680
+ this.decorate('begin');
2681
+ this.decorate('cancel');
2682
+ this.decorate('commit');
2683
+ this.decorate('updateSize');
2684
+ this.on('commit', (event)=>{
2685
+ // State might not be initialized yet. In this case, prevent further handling and make sure that the resizer is
2686
+ // cleaned up (#5195).
2687
+ if (!this.state.proposedWidth && !this.state.proposedWidthPercents) {
2688
+ this._cleanup();
2689
+ event.stop();
2690
+ }
2691
+ }, {
2692
+ priority: 'high'
2693
+ });
2694
+ }
2794
2695
  }
2795
2696
  /**
2796
2697
  * @param resizerPosition Expected resizer position like `"top-left"`, `"bottom-right"`.
@@ -2808,24 +2709,15 @@ function existsInDom(element) {
2808
2709
  return element && element.ownerDocument && element.ownerDocument.contains(element);
2809
2710
  }
2810
2711
 
2811
- /**
2812
- * The widget resize feature plugin.
2813
- *
2814
- * Use the {@link module:widget/widgetresize~WidgetResize#attachTo} method to create a resizer for the specified widget.
2815
- */ class WidgetResize extends Plugin {
2712
+ class WidgetResize extends Plugin {
2816
2713
  /**
2817
- * A map of resizers created using this plugin instance.
2818
- */ _resizers = new Map();
2819
- _observer;
2820
- _redrawSelectedResizerThrottled;
2821
- /**
2822
- * @inheritDoc
2823
- */ static get pluginName() {
2714
+ * @inheritDoc
2715
+ */ static get pluginName() {
2824
2716
  return 'WidgetResize';
2825
2717
  }
2826
2718
  /**
2827
- * @inheritDoc
2828
- */ init() {
2719
+ * @inheritDoc
2720
+ */ init() {
2829
2721
  const editing = this.editor.editing;
2830
2722
  const domDocument = global.window.document;
2831
2723
  this.set('selectedResizer', null);
@@ -2867,15 +2759,15 @@ function existsInDom(element) {
2867
2759
  });
2868
2760
  }
2869
2761
  /**
2870
- * Redraws the selected resizer if there is any selected resizer and if it is visible.
2871
- */ redrawSelectedResizer() {
2762
+ * Redraws the selected resizer if there is any selected resizer and if it is visible.
2763
+ */ redrawSelectedResizer() {
2872
2764
  if (this.selectedResizer && this.selectedResizer.isVisible) {
2873
2765
  this.selectedResizer.redraw();
2874
2766
  }
2875
2767
  }
2876
2768
  /**
2877
- * @inheritDoc
2878
- */ destroy() {
2769
+ * @inheritDoc
2770
+ */ destroy() {
2879
2771
  super.destroy();
2880
2772
  this._observer.stopListening();
2881
2773
  for (const resizer of this._resizers.values()){
@@ -2884,23 +2776,23 @@ function existsInDom(element) {
2884
2776
  this._redrawSelectedResizerThrottled.cancel();
2885
2777
  }
2886
2778
  /**
2887
- * Marks resizer as selected.
2888
- */ select(resizer) {
2779
+ * Marks resizer as selected.
2780
+ */ select(resizer) {
2889
2781
  this.deselect();
2890
2782
  this.selectedResizer = resizer;
2891
2783
  this.selectedResizer.isSelected = true;
2892
2784
  }
2893
2785
  /**
2894
- * Deselects currently set resizer.
2895
- */ deselect() {
2786
+ * Deselects currently set resizer.
2787
+ */ deselect() {
2896
2788
  if (this.selectedResizer) {
2897
2789
  this.selectedResizer.isSelected = false;
2898
2790
  }
2899
2791
  this.selectedResizer = null;
2900
2792
  }
2901
2793
  /**
2902
- * @param options Resizer options.
2903
- */ attachTo(options) {
2794
+ * @param options Resizer options.
2795
+ */ attachTo(options) {
2904
2796
  const resizer = new Resizer(options);
2905
2797
  const plugins = this.editor.plugins;
2906
2798
  resizer.attach();
@@ -2934,15 +2826,15 @@ function existsInDom(element) {
2934
2826
  return resizer;
2935
2827
  }
2936
2828
  /**
2937
- * Returns a resizer created for a given view element (widget element).
2938
- *
2939
- * @param viewElement View element associated with the resizer.
2940
- */ getResizerByViewElement(viewElement) {
2829
+ * Returns a resizer created for a given view element (widget element).
2830
+ *
2831
+ * @param viewElement View element associated with the resizer.
2832
+ */ getResizerByViewElement(viewElement) {
2941
2833
  return this._resizers.get(viewElement);
2942
2834
  }
2943
2835
  /**
2944
- * Returns a resizer that contains a given resize handle.
2945
- */ _getResizerByHandle(domResizeHandle) {
2836
+ * Returns a resizer that contains a given resize handle.
2837
+ */ _getResizerByHandle(domResizeHandle) {
2946
2838
  for (const resizer of this._resizers.values()){
2947
2839
  if (resizer.containsHandle(domResizeHandle)) {
2948
2840
  return resizer;
@@ -2950,8 +2842,8 @@ function existsInDom(element) {
2950
2842
  }
2951
2843
  }
2952
2844
  /**
2953
- * @param domEventData Native DOM event.
2954
- */ _mouseDownListener(event, domEventData) {
2845
+ * @param domEventData Native DOM event.
2846
+ */ _mouseDownListener(event, domEventData) {
2955
2847
  const resizeHandle = domEventData.domTarget;
2956
2848
  if (!Resizer.isResizeHandle(resizeHandle)) {
2957
2849
  return;
@@ -2965,8 +2857,8 @@ function existsInDom(element) {
2965
2857
  }
2966
2858
  }
2967
2859
  /**
2968
- * @param domEventData Native DOM event.
2969
- */ _mouseMoveListener(event, domEventData) {
2860
+ * @param domEventData Native DOM event.
2861
+ */ _mouseMoveListener(event, domEventData) {
2970
2862
  if (this._activeResizer) {
2971
2863
  this._activeResizer.updateSize(domEventData);
2972
2864
  }
@@ -2977,6 +2869,12 @@ function existsInDom(element) {
2977
2869
  this._activeResizer = null;
2978
2870
  }
2979
2871
  }
2872
+ constructor(){
2873
+ super(...arguments);
2874
+ /**
2875
+ * A map of resizers created using this plugin instance.
2876
+ */ this._resizers = new Map();
2877
+ }
2980
2878
  }
2981
2879
 
2982
2880
  export { WIDGET_CLASS_NAME, WIDGET_SELECTED_CLASS_NAME, Widget, WidgetResize, WidgetToolbarRepository, WidgetTypeAround, calculateResizeHostAncestorWidth, calculateResizeHostPercentageWidth, findOptimalInsertionRange, getLabel, isWidget, setHighlightHandling, setLabel, toWidget, toWidgetEditable, viewToModelPositionOutsideModelElement };