@ckeditor/ckeditor5-widget 0.0.0-nightly-20240509.0 → 0.0.0-nightly-20240511.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 +577 -479
- package/dist/index.js.map +1 -1
- package/package.json +7 -7
package/dist/index.js
CHANGED
@@ -10,12 +10,23 @@ 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
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
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) {
|
19
30
|
const stack = this._stack;
|
20
31
|
// Save top descriptor and insert new one. If top is changed - fire event.
|
21
32
|
const oldTop = stack[0];
|
@@ -31,11 +42,11 @@ class HighlightStack extends /* #__PURE__ */ EmitterMixin() {
|
|
31
42
|
}
|
32
43
|
}
|
33
44
|
/**
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
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) {
|
39
50
|
const stack = this._stack;
|
40
51
|
const oldTop = stack[0];
|
41
52
|
this._removeDescriptor(id);
|
@@ -50,9 +61,9 @@ class HighlightStack extends /* #__PURE__ */ EmitterMixin() {
|
|
50
61
|
}
|
51
62
|
}
|
52
63
|
/**
|
53
|
-
|
54
|
-
|
55
|
-
|
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) {
|
56
67
|
const stack = this._stack;
|
57
68
|
const index = stack.findIndex((item)=>item.id === descriptor.id);
|
58
69
|
// Inserting exact same descriptor - do nothing.
|
@@ -72,10 +83,10 @@ class HighlightStack extends /* #__PURE__ */ EmitterMixin() {
|
|
72
83
|
stack.splice(i, 0, descriptor);
|
73
84
|
}
|
74
85
|
/**
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
86
|
+
* Removes descriptor with given id from the stack.
|
87
|
+
*
|
88
|
+
* @param id Descriptor's id.
|
89
|
+
*/ _removeDescriptor(id) {
|
79
90
|
const stack = this._stack;
|
80
91
|
const index = stack.findIndex((item)=>item.id === id);
|
81
92
|
// If descriptor with same id is on the list - remove it.
|
@@ -83,10 +94,6 @@ class HighlightStack extends /* #__PURE__ */ EmitterMixin() {
|
|
83
94
|
stack.splice(index, 1);
|
84
95
|
}
|
85
96
|
}
|
86
|
-
constructor(){
|
87
|
-
super(...arguments);
|
88
|
-
this._stack = [];
|
89
|
-
}
|
90
97
|
}
|
91
98
|
/**
|
92
99
|
* Compares two descriptors by checking their priority and class list.
|
@@ -177,12 +184,12 @@ var dragHandleIcon = "<svg viewBox=\"0 0 16 16\" xmlns=\"http://www.w3.org/2000/
|
|
177
184
|
*/ function toWidget(element, writer, options = {}) {
|
178
185
|
if (!element.is('containerElement')) {
|
179
186
|
/**
|
180
|
-
|
181
|
-
|
182
|
-
|
183
|
-
|
184
|
-
|
185
|
-
|
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, {
|
186
193
|
element
|
187
194
|
});
|
188
195
|
}
|
@@ -538,23 +545,37 @@ const POSSIBLE_INSERTION_POSITIONS = [
|
|
538
545
|
// Do the SVG parsing once and then clone the result <svg> DOM element for each new button.
|
539
546
|
const RETURN_ARROW_ICON_ELEMENT = new DOMParser().parseFromString(returnIcon, 'image/svg+xml').firstChild;
|
540
547
|
const PLUGIN_DISABLED_EDITING_ROOT_CLASS = 'ck-widget__type-around_disabled';
|
541
|
-
|
542
|
-
|
543
|
-
|
544
|
-
|
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() {
|
545
566
|
return 'WidgetTypeAround';
|
546
567
|
}
|
547
568
|
/**
|
548
|
-
|
549
|
-
|
569
|
+
* @inheritDoc
|
570
|
+
*/ static get requires() {
|
550
571
|
return [
|
551
572
|
Enter,
|
552
573
|
Delete
|
553
574
|
];
|
554
575
|
}
|
555
576
|
/**
|
556
|
-
|
557
|
-
|
577
|
+
* @inheritDoc
|
578
|
+
*/ init() {
|
558
579
|
const editor = this.editor;
|
559
580
|
const editingView = editor.editing.view;
|
560
581
|
// Set a CSS class on the view editing root when the plugin is disabled so all the buttons
|
@@ -586,20 +607,20 @@ class WidgetTypeAround extends Plugin {
|
|
586
607
|
this._enableDeleteContentIntegration();
|
587
608
|
}
|
588
609
|
/**
|
589
|
-
|
590
|
-
|
610
|
+
* @inheritDoc
|
611
|
+
*/ destroy() {
|
591
612
|
super.destroy();
|
592
613
|
this._currentFakeCaretModelElement = null;
|
593
614
|
}
|
594
615
|
/**
|
595
|
-
|
596
|
-
|
597
|
-
|
598
|
-
|
599
|
-
|
600
|
-
|
601
|
-
|
602
|
-
|
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) {
|
603
624
|
const editor = this.editor;
|
604
625
|
const editingView = editor.editing.view;
|
605
626
|
const attributesToCopy = editor.model.schema.getAttributesWithProperty(widgetModelElement, 'copyOnReplace', true);
|
@@ -611,16 +632,16 @@ class WidgetTypeAround extends Plugin {
|
|
611
632
|
editingView.scrollToTheSelection();
|
612
633
|
}
|
613
634
|
/**
|
614
|
-
|
615
|
-
|
616
|
-
|
617
|
-
|
618
|
-
|
619
|
-
|
620
|
-
|
621
|
-
|
622
|
-
|
623
|
-
|
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) {
|
624
645
|
this.listenTo(emitter, event, (...args)=>{
|
625
646
|
// Do not respond if the plugin is disabled.
|
626
647
|
if (this.isEnabled) {
|
@@ -629,16 +650,16 @@ class WidgetTypeAround extends Plugin {
|
|
629
650
|
}, options);
|
630
651
|
}
|
631
652
|
/**
|
632
|
-
|
633
|
-
|
634
|
-
|
635
|
-
|
636
|
-
|
637
|
-
|
638
|
-
|
639
|
-
|
640
|
-
|
641
|
-
|
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() {
|
642
663
|
const editor = this.editor;
|
643
664
|
const model = editor.model;
|
644
665
|
const modelSelection = model.document.selection;
|
@@ -656,12 +677,12 @@ class WidgetTypeAround extends Plugin {
|
|
656
677
|
return true;
|
657
678
|
}
|
658
679
|
/**
|
659
|
-
|
660
|
-
|
661
|
-
|
662
|
-
|
663
|
-
|
664
|
-
|
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() {
|
665
686
|
const editor = this.editor;
|
666
687
|
const schema = editor.model.schema;
|
667
688
|
const t = editor.locale.t;
|
@@ -687,30 +708,30 @@ class WidgetTypeAround extends Plugin {
|
|
687
708
|
});
|
688
709
|
}
|
689
710
|
/**
|
690
|
-
|
691
|
-
|
692
|
-
|
693
|
-
|
694
|
-
|
695
|
-
|
696
|
-
|
697
|
-
|
698
|
-
|
699
|
-
|
700
|
-
|
701
|
-
|
702
|
-
|
703
|
-
|
704
|
-
|
705
|
-
|
706
|
-
|
707
|
-
|
708
|
-
|
709
|
-
|
710
|
-
|
711
|
-
|
712
|
-
|
713
|
-
|
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() {
|
714
735
|
const editor = this.editor;
|
715
736
|
const model = editor.model;
|
716
737
|
const modelSelection = model.document.selection;
|
@@ -798,17 +819,17 @@ class WidgetTypeAround extends Plugin {
|
|
798
819
|
}
|
799
820
|
}
|
800
821
|
/**
|
801
|
-
|
802
|
-
|
803
|
-
|
804
|
-
|
805
|
-
|
806
|
-
|
807
|
-
|
808
|
-
|
809
|
-
|
810
|
-
|
811
|
-
|
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) {
|
812
833
|
const editor = this.editor;
|
813
834
|
const model = editor.model;
|
814
835
|
const modelSelection = model.document.selection;
|
@@ -833,15 +854,15 @@ class WidgetTypeAround extends Plugin {
|
|
833
854
|
}
|
834
855
|
}
|
835
856
|
/**
|
836
|
-
|
837
|
-
|
838
|
-
|
839
|
-
|
840
|
-
|
841
|
-
|
842
|
-
|
843
|
-
|
844
|
-
|
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) {
|
845
866
|
const editor = this.editor;
|
846
867
|
const model = editor.model;
|
847
868
|
const modelSelection = model.document.selection;
|
@@ -870,19 +891,19 @@ class WidgetTypeAround extends Plugin {
|
|
870
891
|
});
|
871
892
|
}
|
872
893
|
/**
|
873
|
-
|
874
|
-
|
875
|
-
|
876
|
-
|
877
|
-
|
878
|
-
|
879
|
-
|
880
|
-
|
881
|
-
|
882
|
-
|
883
|
-
|
884
|
-
|
885
|
-
|
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) {
|
886
907
|
const editor = this.editor;
|
887
908
|
const model = editor.model;
|
888
909
|
const schema = model.schema;
|
@@ -902,14 +923,14 @@ class WidgetTypeAround extends Plugin {
|
|
902
923
|
return false;
|
903
924
|
}
|
904
925
|
/**
|
905
|
-
|
906
|
-
|
907
|
-
|
908
|
-
|
909
|
-
|
910
|
-
|
911
|
-
|
912
|
-
|
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) {
|
913
934
|
const editor = this.editor;
|
914
935
|
const model = editor.model;
|
915
936
|
const schema = model.schema;
|
@@ -928,10 +949,10 @@ class WidgetTypeAround extends Plugin {
|
|
928
949
|
return false;
|
929
950
|
}
|
930
951
|
/**
|
931
|
-
|
932
|
-
|
933
|
-
|
934
|
-
|
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() {
|
935
956
|
const editor = this.editor;
|
936
957
|
const editingView = editor.editing.view;
|
937
958
|
this._listenToIfEnabled(editingView.document, 'mousedown', (evt, domEventData)=>{
|
@@ -948,18 +969,18 @@ class WidgetTypeAround extends Plugin {
|
|
948
969
|
});
|
949
970
|
}
|
950
971
|
/**
|
951
|
-
|
952
|
-
|
953
|
-
|
954
|
-
|
955
|
-
|
956
|
-
|
957
|
-
|
958
|
-
|
959
|
-
|
960
|
-
|
961
|
-
|
962
|
-
|
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() {
|
963
984
|
const editor = this.editor;
|
964
985
|
const selection = editor.model.document.selection;
|
965
986
|
const editingView = editor.editing.view;
|
@@ -990,18 +1011,18 @@ class WidgetTypeAround extends Plugin {
|
|
990
1011
|
});
|
991
1012
|
}
|
992
1013
|
/**
|
993
|
-
|
994
|
-
|
995
|
-
|
996
|
-
|
997
|
-
|
998
|
-
|
999
|
-
|
1000
|
-
|
1001
|
-
|
1002
|
-
|
1003
|
-
|
1004
|
-
|
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() {
|
1005
1026
|
const editor = this.editor;
|
1006
1027
|
const viewDocument = editor.editing.view.document;
|
1007
1028
|
// Note: The priority must precede the default Input plugin insertText handler.
|
@@ -1035,13 +1056,13 @@ class WidgetTypeAround extends Plugin {
|
|
1035
1056
|
}
|
1036
1057
|
}
|
1037
1058
|
/**
|
1038
|
-
|
1039
|
-
|
1040
|
-
|
1041
|
-
|
1042
|
-
|
1043
|
-
|
1044
|
-
|
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() {
|
1045
1066
|
const editor = this.editor;
|
1046
1067
|
const editingView = editor.editing.view;
|
1047
1068
|
const model = editor.model;
|
@@ -1106,11 +1127,11 @@ class WidgetTypeAround extends Plugin {
|
|
1106
1127
|
});
|
1107
1128
|
}
|
1108
1129
|
/**
|
1109
|
-
|
1110
|
-
|
1111
|
-
|
1112
|
-
|
1113
|
-
|
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() {
|
1114
1135
|
const editor = this.editor;
|
1115
1136
|
const model = this.editor.model;
|
1116
1137
|
const documentSelection = model.document.selection;
|
@@ -1136,12 +1157,12 @@ class WidgetTypeAround extends Plugin {
|
|
1136
1157
|
});
|
1137
1158
|
}
|
1138
1159
|
/**
|
1139
|
-
|
1140
|
-
|
1141
|
-
|
1142
|
-
|
1143
|
-
|
1144
|
-
|
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() {
|
1145
1166
|
const editor = this.editor;
|
1146
1167
|
const model = this.editor.model;
|
1147
1168
|
const documentSelection = model.document.selection;
|
@@ -1161,13 +1182,13 @@ class WidgetTypeAround extends Plugin {
|
|
1161
1182
|
});
|
1162
1183
|
}
|
1163
1184
|
/**
|
1164
|
-
|
1165
|
-
|
1166
|
-
|
1167
|
-
|
1168
|
-
|
1169
|
-
|
1170
|
-
|
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() {
|
1171
1192
|
const editor = this.editor;
|
1172
1193
|
const model = this.editor.model;
|
1173
1194
|
const documentSelection = model.document.selection;
|
@@ -1184,14 +1205,6 @@ class WidgetTypeAround extends Plugin {
|
|
1184
1205
|
priority: 'high'
|
1185
1206
|
});
|
1186
1207
|
}
|
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
|
-
}
|
1195
1208
|
}
|
1196
1209
|
/**
|
1197
1210
|
* Injects the type around UI into a view widget instance.
|
@@ -1450,23 +1463,38 @@ function selectionWillShrink(selection, isForward) {
|
|
1450
1463
|
return !selection.isCollapsed && selection.isBackward == isForward;
|
1451
1464
|
}
|
1452
1465
|
|
1453
|
-
|
1454
|
-
|
1455
|
-
|
1456
|
-
|
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() {
|
1457
1485
|
return 'Widget';
|
1458
1486
|
}
|
1459
1487
|
/**
|
1460
|
-
|
1461
|
-
|
1488
|
+
* @inheritDoc
|
1489
|
+
*/ static get requires() {
|
1462
1490
|
return [
|
1463
1491
|
WidgetTypeAround,
|
1464
1492
|
Delete
|
1465
1493
|
];
|
1466
1494
|
}
|
1467
1495
|
/**
|
1468
|
-
|
1469
|
-
|
1496
|
+
* @inheritDoc
|
1497
|
+
*/ init() {
|
1470
1498
|
const editor = this.editor;
|
1471
1499
|
const view = editor.editing.view;
|
1472
1500
|
const viewDocument = view.document;
|
@@ -1661,8 +1689,8 @@ class Widget extends Plugin {
|
|
1661
1689
|
});
|
1662
1690
|
}
|
1663
1691
|
/**
|
1664
|
-
|
1665
|
-
|
1692
|
+
* Handles {@link module:engine/view/document~Document#event:mousedown mousedown} events on widget elements.
|
1693
|
+
*/ _onMousedown(eventInfo, domEventData) {
|
1666
1694
|
const editor = this.editor;
|
1667
1695
|
const view = editor.editing.view;
|
1668
1696
|
const viewDocument = view.document;
|
@@ -1699,8 +1727,8 @@ class Widget extends Plugin {
|
|
1699
1727
|
this._setSelectionOverElement(modelElement);
|
1700
1728
|
}
|
1701
1729
|
/**
|
1702
|
-
|
1703
|
-
|
1730
|
+
* Selects entire block content, e.g. on triple click it selects entire paragraph.
|
1731
|
+
*/ _selectBlockContent(element) {
|
1704
1732
|
const editor = this.editor;
|
1705
1733
|
const model = editor.model;
|
1706
1734
|
const mapper = editor.editing.mapper;
|
@@ -1719,14 +1747,14 @@ class Widget extends Plugin {
|
|
1719
1747
|
return true;
|
1720
1748
|
}
|
1721
1749
|
/**
|
1722
|
-
|
1723
|
-
|
1724
|
-
|
1725
|
-
|
1726
|
-
|
1727
|
-
|
1728
|
-
|
1729
|
-
|
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) {
|
1730
1758
|
const keyCode = domEventData.keyCode;
|
1731
1759
|
const model = this.editor.model;
|
1732
1760
|
const schema = model.schema;
|
@@ -1781,12 +1809,12 @@ class Widget extends Plugin {
|
|
1781
1809
|
}
|
1782
1810
|
}
|
1783
1811
|
/**
|
1784
|
-
|
1785
|
-
|
1786
|
-
|
1787
|
-
|
1788
|
-
|
1789
|
-
|
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) {
|
1790
1818
|
const model = this.editor.model;
|
1791
1819
|
const schema = model.schema;
|
1792
1820
|
const objectElement = model.document.selection.getSelectedElement();
|
@@ -1797,11 +1825,11 @@ class Widget extends Plugin {
|
|
1797
1825
|
}
|
1798
1826
|
}
|
1799
1827
|
/**
|
1800
|
-
|
1801
|
-
|
1802
|
-
|
1803
|
-
|
1804
|
-
|
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) {
|
1805
1833
|
const modelDocument = this.editor.model.document;
|
1806
1834
|
const modelSelection = modelDocument.selection;
|
1807
1835
|
// Do nothing when the read only mode is enabled.
|
@@ -1828,22 +1856,22 @@ class Widget extends Plugin {
|
|
1828
1856
|
}
|
1829
1857
|
}
|
1830
1858
|
/**
|
1831
|
-
|
1832
|
-
|
1833
|
-
|
1834
|
-
|
1859
|
+
* Sets {@link module:engine/model/selection~Selection document's selection} over given element.
|
1860
|
+
*
|
1861
|
+
* @internal
|
1862
|
+
*/ _setSelectionOverElement(element) {
|
1835
1863
|
this.editor.model.change((writer)=>{
|
1836
1864
|
writer.setSelection(writer.createRangeOn(element));
|
1837
1865
|
});
|
1838
1866
|
}
|
1839
1867
|
/**
|
1840
|
-
|
1841
|
-
|
1842
|
-
|
1843
|
-
|
1844
|
-
|
1845
|
-
|
1846
|
-
|
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) {
|
1847
1875
|
const model = this.editor.model;
|
1848
1876
|
const schema = model.schema;
|
1849
1877
|
const modelSelection = model.document.selection;
|
@@ -1864,16 +1892,16 @@ class Widget extends Plugin {
|
|
1864
1892
|
return null;
|
1865
1893
|
}
|
1866
1894
|
/**
|
1867
|
-
|
1868
|
-
|
1895
|
+
* Removes CSS class from previously selected widgets.
|
1896
|
+
*/ _clearPreviouslySelectedWidgets(writer) {
|
1869
1897
|
for (const widget of this._previouslySelected){
|
1870
1898
|
writer.removeClass(WIDGET_SELECTED_CLASS_NAME, widget);
|
1871
1899
|
}
|
1872
1900
|
this._previouslySelected.clear();
|
1873
1901
|
}
|
1874
1902
|
/**
|
1875
|
-
|
1876
|
-
|
1903
|
+
* Moves the document selection into the first nested editable.
|
1904
|
+
*/ _selectFirstNestedEditable() {
|
1877
1905
|
const editor = this.editor;
|
1878
1906
|
const view = this.editor.editing.view;
|
1879
1907
|
const viewDocument = view.document;
|
@@ -1894,8 +1922,8 @@ class Widget extends Plugin {
|
|
1894
1922
|
return false;
|
1895
1923
|
}
|
1896
1924
|
/**
|
1897
|
-
|
1898
|
-
|
1925
|
+
* Updates the document selection so that it selects first ancestor widget.
|
1926
|
+
*/ _selectAncestorWidget() {
|
1899
1927
|
const editor = this.editor;
|
1900
1928
|
const mapper = editor.editing.mapper;
|
1901
1929
|
const selection = editor.editing.view.document.selection;
|
@@ -1914,12 +1942,6 @@ class Widget extends Plugin {
|
|
1914
1942
|
});
|
1915
1943
|
return true;
|
1916
1944
|
}
|
1917
|
-
constructor(){
|
1918
|
-
super(...arguments);
|
1919
|
-
/**
|
1920
|
-
* Holds previously selected widgets.
|
1921
|
-
*/ this._previouslySelected = new Set();
|
1922
|
-
}
|
1923
1945
|
}
|
1924
1946
|
/**
|
1925
1947
|
* Returns `true` when element is a nested editable or is placed inside one.
|
@@ -1982,22 +2004,51 @@ class Widget extends Plugin {
|
|
1982
2004
|
return null;
|
1983
2005
|
}
|
1984
2006
|
|
1985
|
-
|
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;
|
1986
2037
|
/**
|
1987
|
-
|
1988
|
-
|
2038
|
+
* @inheritDoc
|
2039
|
+
*/ static get requires() {
|
1989
2040
|
return [
|
1990
2041
|
ContextualBalloon
|
1991
2042
|
];
|
1992
2043
|
}
|
1993
2044
|
/**
|
1994
|
-
|
1995
|
-
|
2045
|
+
* @inheritDoc
|
2046
|
+
*/ static get pluginName() {
|
1996
2047
|
return 'WidgetToolbarRepository';
|
1997
2048
|
}
|
1998
2049
|
/**
|
1999
|
-
|
2000
|
-
|
2050
|
+
* @inheritDoc
|
2051
|
+
*/ init() {
|
2001
2052
|
const editor = this.editor;
|
2002
2053
|
// Disables the default balloon toolbar for all widgets.
|
2003
2054
|
if (editor.plugins.has('BalloonToolbar')) {
|
@@ -2031,35 +2082,35 @@ class WidgetToolbarRepository extends Plugin {
|
|
2031
2082
|
}
|
2032
2083
|
}
|
2033
2084
|
/**
|
2034
|
-
|
2035
|
-
|
2036
|
-
|
2037
|
-
|
2038
|
-
|
2039
|
-
|
2040
|
-
|
2041
|
-
|
2042
|
-
|
2043
|
-
|
2044
|
-
|
2045
|
-
|
2046
|
-
|
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' }) {
|
2047
2098
|
// Trying to register a toolbar without any item.
|
2048
2099
|
if (!items.length) {
|
2049
2100
|
/**
|
2050
|
-
|
2051
|
-
|
2052
|
-
|
2053
|
-
|
2054
|
-
|
2055
|
-
|
2056
|
-
|
2057
|
-
|
2058
|
-
|
2059
|
-
|
2060
|
-
|
2061
|
-
|
2062
|
-
|
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', {
|
2063
2114
|
toolbarId
|
2064
2115
|
});
|
2065
2116
|
return;
|
@@ -2070,11 +2121,11 @@ class WidgetToolbarRepository extends Plugin {
|
|
2070
2121
|
toolbarView.ariaLabel = ariaLabel || t('Widget toolbar');
|
2071
2122
|
if (this._toolbarDefinitions.has(toolbarId)) {
|
2072
2123
|
/**
|
2073
|
-
|
2074
|
-
|
2075
|
-
|
2076
|
-
|
2077
|
-
|
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, {
|
2078
2129
|
toolbarId
|
2079
2130
|
});
|
2080
2131
|
}
|
@@ -2101,8 +2152,8 @@ class WidgetToolbarRepository extends Plugin {
|
|
2101
2152
|
this._toolbarDefinitions.set(toolbarId, toolbarDefinition);
|
2102
2153
|
}
|
2103
2154
|
/**
|
2104
|
-
|
2105
|
-
|
2155
|
+
* Iterates over stored toolbars and makes them visible or hidden.
|
2156
|
+
*/ _updateToolbarsVisibility() {
|
2106
2157
|
let maxRelatedElementDepth = 0;
|
2107
2158
|
let deepestRelatedElement = null;
|
2108
2159
|
let deepestToolbarDefinition = null;
|
@@ -2134,18 +2185,18 @@ class WidgetToolbarRepository extends Plugin {
|
|
2134
2185
|
}
|
2135
2186
|
}
|
2136
2187
|
/**
|
2137
|
-
|
2138
|
-
|
2188
|
+
* Hides the given toolbar.
|
2189
|
+
*/ _hideToolbar(toolbarDefinition) {
|
2139
2190
|
this._balloon.remove(toolbarDefinition.view);
|
2140
2191
|
this.stopListening(this._balloon, 'change:visibleView');
|
2141
2192
|
}
|
2142
2193
|
/**
|
2143
|
-
|
2144
|
-
|
2145
|
-
|
2146
|
-
|
2147
|
-
|
2148
|
-
|
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) {
|
2149
2200
|
if (this._isToolbarVisible(toolbarDefinition)) {
|
2150
2201
|
repositionContextualBalloon(this.editor, relatedElement);
|
2151
2202
|
} else if (!this._isToolbarInBalloon(toolbarDefinition)) {
|
@@ -2178,12 +2229,6 @@ class WidgetToolbarRepository extends Plugin {
|
|
2178
2229
|
_isToolbarInBalloon(toolbar) {
|
2179
2230
|
return this._balloon.hasView(toolbar.view);
|
2180
2231
|
}
|
2181
|
-
constructor(){
|
2182
|
-
super(...arguments);
|
2183
|
-
/**
|
2184
|
-
* A map of toolbar definitions.
|
2185
|
-
*/ this._toolbarDefinitions = new Map();
|
2186
|
-
}
|
2187
2232
|
}
|
2188
2233
|
function repositionContextualBalloon(editor, relatedElement) {
|
2189
2234
|
const balloon = editor.plugins.get('ContextualBalloon');
|
@@ -2211,31 +2256,76 @@ function isWidgetSelected(selection) {
|
|
2211
2256
|
return !!(viewElement && isWidget(viewElement));
|
2212
2257
|
}
|
2213
2258
|
|
2214
|
-
|
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
|
+
}
|
2215
2305
|
/**
|
2216
|
-
|
2217
|
-
|
2306
|
+
* The original width (pixels) of the resized object when the resize process was started.
|
2307
|
+
*/ get originalWidth() {
|
2218
2308
|
return this._originalWidth;
|
2219
2309
|
}
|
2220
2310
|
/**
|
2221
|
-
|
2222
|
-
|
2311
|
+
* The original height (pixels) of the resized object when the resize process was started.
|
2312
|
+
*/ get originalHeight() {
|
2223
2313
|
return this._originalHeight;
|
2224
2314
|
}
|
2225
2315
|
/**
|
2226
|
-
|
2227
|
-
|
2316
|
+
* The original width (percents) of the resized object when the resize process was started.
|
2317
|
+
*/ get originalWidthPercents() {
|
2228
2318
|
return this._originalWidthPercents;
|
2229
2319
|
}
|
2230
2320
|
/**
|
2231
|
-
|
2232
|
-
|
2321
|
+
* A width to height ratio of the resized image.
|
2322
|
+
*/ get aspectRatio() {
|
2233
2323
|
return this._aspectRatio;
|
2234
2324
|
}
|
2235
2325
|
/**
|
2236
|
-
|
2237
|
-
|
2238
|
-
|
2326
|
+
*
|
2327
|
+
* @param domResizeHandle The handle used to calculate the reference point.
|
2328
|
+
*/ begin(domResizeHandle, domHandleHost, domResizeHost) {
|
2239
2329
|
const clientRect = new Rect(domHandleHost);
|
2240
2330
|
this.activeHandlePosition = getHandlePosition(domResizeHandle);
|
2241
2331
|
this._referenceCoordinates = getAbsoluteBoundaryPoint(domHandleHost, getOppositePosition(this.activeHandlePosition));
|
@@ -2256,19 +2346,6 @@ class ResizeState extends /* #__PURE__ */ ObservableMixin() {
|
|
2256
2346
|
this.proposedHandleHostWidth = newSize.handleHostWidth;
|
2257
2347
|
this.proposedHandleHostHeight = newSize.handleHostHeight;
|
2258
2348
|
}
|
2259
|
-
/**
|
2260
|
-
* @param options Resizer options.
|
2261
|
-
*/ constructor(options){
|
2262
|
-
super();
|
2263
|
-
this.set('activeHandlePosition', null);
|
2264
|
-
this.set('proposedWidthPercents', null);
|
2265
|
-
this.set('proposedWidth', null);
|
2266
|
-
this.set('proposedHeight', null);
|
2267
|
-
this.set('proposedHandleHostWidth', null);
|
2268
|
-
this.set('proposedHandleHostHeight', null);
|
2269
|
-
this._options = options;
|
2270
|
-
this._referenceCoordinates = null;
|
2271
|
-
}
|
2272
2349
|
}
|
2273
2350
|
/**
|
2274
2351
|
* Returns coordinates of the top-left corner of an element, relative to the document's top-left corner.
|
@@ -2323,33 +2400,9 @@ class ResizeState extends /* #__PURE__ */ ObservableMixin() {
|
|
2323
2400
|
return `${replacements[parts[0]]}-${replacements[parts[1]]}`;
|
2324
2401
|
}
|
2325
2402
|
|
2326
|
-
|
2327
|
-
|
2328
|
-
|
2329
|
-
*
|
2330
|
-
* @internal
|
2331
|
-
* @param options An object defining the resizer options, used for setting the proper size label.
|
2332
|
-
* @param resizeState The `ResizeState` class instance, used for keeping the `SizeView` state up to date.
|
2333
|
-
*/ _bindToState(options, resizeState) {
|
2334
|
-
this.bind('_isVisible').to(resizeState, 'proposedWidth', resizeState, 'proposedHeight', (width, height)=>width !== null && height !== null);
|
2335
|
-
this.bind('_label').to(resizeState, 'proposedHandleHostWidth', resizeState, 'proposedHandleHostHeight', resizeState, 'proposedWidthPercents', (width, height, widthPercents)=>{
|
2336
|
-
if (options.unit === 'px') {
|
2337
|
-
return `${width}×${height}`;
|
2338
|
-
} else {
|
2339
|
-
return `${widthPercents}%`;
|
2340
|
-
}
|
2341
|
-
});
|
2342
|
-
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.
|
2343
|
-
(position, width, height)=>width < 50 || height < 50 ? 'above-center' : position);
|
2344
|
-
}
|
2345
|
-
/**
|
2346
|
-
* A method used for cleaning up. It removes the bindings and hides the view.
|
2347
|
-
*
|
2348
|
-
* @internal
|
2349
|
-
*/ _dismiss() {
|
2350
|
-
this.unbind();
|
2351
|
-
this._isVisible = false;
|
2352
|
-
}
|
2403
|
+
/**
|
2404
|
+
* A view displaying the proposed new element size during the resizing.
|
2405
|
+
*/ class SizeView extends View {
|
2353
2406
|
constructor(){
|
2354
2407
|
super();
|
2355
2408
|
const bind = this.bindTemplate;
|
@@ -2372,35 +2425,103 @@ class SizeView extends View {
|
|
2372
2425
|
]
|
2373
2426
|
});
|
2374
2427
|
}
|
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
|
+
}
|
2375
2454
|
}
|
2376
2455
|
|
2377
|
-
|
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;
|
2378
2464
|
/**
|
2379
|
-
|
2380
|
-
|
2381
|
-
|
2382
|
-
|
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
|
+
}
|
2499
|
+
/**
|
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() {
|
2383
2504
|
return this._state;
|
2384
2505
|
}
|
2385
2506
|
/**
|
2386
|
-
|
2387
|
-
|
2507
|
+
* Makes resizer visible in the UI.
|
2508
|
+
*/ show() {
|
2388
2509
|
const editingView = this._options.editor.editing.view;
|
2389
2510
|
editingView.change((writer)=>{
|
2390
2511
|
writer.removeClass('ck-hidden', this._viewResizerWrapper);
|
2391
2512
|
});
|
2392
2513
|
}
|
2393
2514
|
/**
|
2394
|
-
|
2395
|
-
|
2515
|
+
* Hides resizer in the UI.
|
2516
|
+
*/ hide() {
|
2396
2517
|
const editingView = this._options.editor.editing.view;
|
2397
2518
|
editingView.change((writer)=>{
|
2398
2519
|
writer.addClass('ck-hidden', this._viewResizerWrapper);
|
2399
2520
|
});
|
2400
2521
|
}
|
2401
2522
|
/**
|
2402
|
-
|
2403
|
-
|
2523
|
+
* Attaches the resizer to the DOM.
|
2524
|
+
*/ attach() {
|
2404
2525
|
// eslint-disable-next-line @typescript-eslint/no-this-alias
|
2405
2526
|
const that = this;
|
2406
2527
|
const widgetElement = this._options.viewElement;
|
@@ -2432,23 +2553,23 @@ class Resizer extends /* #__PURE__ */ ObservableMixin() {
|
|
2432
2553
|
});
|
2433
2554
|
}
|
2434
2555
|
/**
|
2435
|
-
|
2436
|
-
|
2437
|
-
|
2438
|
-
|
2439
|
-
|
2440
|
-
|
2441
|
-
|
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) {
|
2442
2563
|
this._state = new ResizeState(this._options);
|
2443
2564
|
this._sizeView._bindToState(this._options, this.state);
|
2444
2565
|
this._initialViewWidth = this._options.viewElement.getStyle('width');
|
2445
2566
|
this.state.begin(domResizeHandle, this._getHandleHost(), this._getResizeHost());
|
2446
2567
|
}
|
2447
2568
|
/**
|
2448
|
-
|
2449
|
-
|
2450
|
-
|
2451
|
-
|
2569
|
+
* Updates the proposed size based on `domEventData`.
|
2570
|
+
*
|
2571
|
+
* @fires updateSize
|
2572
|
+
*/ updateSize(domEventData) {
|
2452
2573
|
const newSize = this._proposeNewSize(domEventData);
|
2453
2574
|
const editingView = this._options.editor.editing.view;
|
2454
2575
|
editingView.change((writer)=>{
|
@@ -2475,10 +2596,10 @@ class Resizer extends /* #__PURE__ */ ObservableMixin() {
|
|
2475
2596
|
});
|
2476
2597
|
}
|
2477
2598
|
/**
|
2478
|
-
|
2479
|
-
|
2480
|
-
|
2481
|
-
|
2599
|
+
* Applies the geometry proposed with the resizer.
|
2600
|
+
*
|
2601
|
+
* @fires commit
|
2602
|
+
*/ commit() {
|
2482
2603
|
const unit = this._options.unit || '%';
|
2483
2604
|
const newValue = (unit === '%' ? this.state.proposedWidthPercents : this.state.proposedWidth) + unit;
|
2484
2605
|
// Both cleanup and onCommit callback are very likely to make view changes. Ensure that it is made in a single step.
|
@@ -2488,22 +2609,22 @@ class Resizer extends /* #__PURE__ */ ObservableMixin() {
|
|
2488
2609
|
});
|
2489
2610
|
}
|
2490
2611
|
/**
|
2491
|
-
|
2492
|
-
|
2493
|
-
|
2494
|
-
|
2612
|
+
* Cancels and rejects the proposed resize dimensions, hiding the UI.
|
2613
|
+
*
|
2614
|
+
* @fires cancel
|
2615
|
+
*/ cancel() {
|
2495
2616
|
this._cleanup();
|
2496
2617
|
}
|
2497
2618
|
/**
|
2498
|
-
|
2499
|
-
|
2619
|
+
* Destroys the resizer.
|
2620
|
+
*/ destroy() {
|
2500
2621
|
this.cancel();
|
2501
2622
|
}
|
2502
2623
|
/**
|
2503
|
-
|
2504
|
-
|
2505
|
-
|
2506
|
-
|
2624
|
+
* Redraws the resizer.
|
2625
|
+
*
|
2626
|
+
* @param handleHostRect Handle host rectangle might be given to improve performance.
|
2627
|
+
*/ redraw(handleHostRect) {
|
2507
2628
|
const domWrapper = this._domResizerWrapper;
|
2508
2629
|
// Refresh only if resizer exists in the DOM.
|
2509
2630
|
if (!existsInDom(domWrapper)) {
|
@@ -2558,8 +2679,8 @@ class Resizer extends /* #__PURE__ */ ObservableMixin() {
|
|
2558
2679
|
return domElement.classList.contains('ck-widget__resizer__handle');
|
2559
2680
|
}
|
2560
2681
|
/**
|
2561
|
-
|
2562
|
-
|
2682
|
+
* Cleans up the context state.
|
2683
|
+
*/ _cleanup() {
|
2563
2684
|
this._sizeView._dismiss();
|
2564
2685
|
const editingView = this._options.editor.editing.view;
|
2565
2686
|
editingView.change((writer)=>{
|
@@ -2567,10 +2688,10 @@ class Resizer extends /* #__PURE__ */ ObservableMixin() {
|
|
2567
2688
|
});
|
2568
2689
|
}
|
2569
2690
|
/**
|
2570
|
-
|
2571
|
-
|
2572
|
-
|
2573
|
-
|
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) {
|
2574
2695
|
const state = this.state;
|
2575
2696
|
const currentCoordinates = extractCoordinates(domEventData);
|
2576
2697
|
const isCentered = this._options.isCentered ? this._options.isCentered(this) : true;
|
@@ -2616,37 +2737,37 @@ class Resizer extends /* #__PURE__ */ ObservableMixin() {
|
|
2616
2737
|
};
|
2617
2738
|
}
|
2618
2739
|
/**
|
2619
|
-
|
2620
|
-
|
2621
|
-
|
2622
|
-
|
2740
|
+
* Obtains the resize host.
|
2741
|
+
*
|
2742
|
+
* Resize host is an object that receives dimensions which are the result of resizing.
|
2743
|
+
*/ _getResizeHost() {
|
2623
2744
|
const widgetWrapper = this._domResizerWrapper.parentElement;
|
2624
2745
|
return this._options.getResizeHost(widgetWrapper);
|
2625
2746
|
}
|
2626
2747
|
/**
|
2627
|
-
|
2628
|
-
|
2629
|
-
|
2630
|
-
|
2631
|
-
|
2632
|
-
|
2633
|
-
|
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() {
|
2634
2755
|
const widgetWrapper = this._domResizerWrapper.parentElement;
|
2635
2756
|
return this._options.getHandleHost(widgetWrapper);
|
2636
2757
|
}
|
2637
2758
|
/**
|
2638
|
-
|
2639
|
-
|
2640
|
-
|
2641
|
-
|
2642
|
-
|
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() {
|
2643
2764
|
return this._options.editor.editing.view.domConverter.mapViewToDom(this._viewResizerWrapper);
|
2644
2765
|
}
|
2645
2766
|
/**
|
2646
|
-
|
2647
|
-
|
2648
|
-
|
2649
|
-
|
2767
|
+
* Renders the resize handles in the DOM.
|
2768
|
+
*
|
2769
|
+
* @param domElement The resizer wrapper.
|
2770
|
+
*/ _appendHandles(domElement) {
|
2650
2771
|
const resizerPositions = [
|
2651
2772
|
'top-left',
|
2652
2773
|
'top-right',
|
@@ -2663,39 +2784,13 @@ class Resizer extends /* #__PURE__ */ ObservableMixin() {
|
|
2663
2784
|
}
|
2664
2785
|
}
|
2665
2786
|
/**
|
2666
|
-
|
2667
|
-
|
2787
|
+
* Sets up the {@link #_sizeView} property and adds it to the passed `domElement`.
|
2788
|
+
*/ _appendSizeUI(domElement) {
|
2668
2789
|
this._sizeView = new SizeView();
|
2669
2790
|
// Make sure icon#element is rendered before passing to appendChild().
|
2670
2791
|
this._sizeView.render();
|
2671
2792
|
domElement.appendChild(this._sizeView.element);
|
2672
2793
|
}
|
2673
|
-
/**
|
2674
|
-
* @param options Resizer options.
|
2675
|
-
*/ constructor(options){
|
2676
|
-
super();
|
2677
|
-
/**
|
2678
|
-
* A wrapper that is controlled by the resizer. This is usually a widget element.
|
2679
|
-
*/ this._viewResizerWrapper = null;
|
2680
|
-
this._options = options;
|
2681
|
-
this.set('isEnabled', true);
|
2682
|
-
this.set('isSelected', false);
|
2683
|
-
this.bind('isVisible').to(this, 'isEnabled', this, 'isSelected', (isEnabled, isSelected)=>isEnabled && isSelected);
|
2684
|
-
this.decorate('begin');
|
2685
|
-
this.decorate('cancel');
|
2686
|
-
this.decorate('commit');
|
2687
|
-
this.decorate('updateSize');
|
2688
|
-
this.on('commit', (event)=>{
|
2689
|
-
// State might not be initialized yet. In this case, prevent further handling and make sure that the resizer is
|
2690
|
-
// cleaned up (#5195).
|
2691
|
-
if (!this.state.proposedWidth && !this.state.proposedWidthPercents) {
|
2692
|
-
this._cleanup();
|
2693
|
-
event.stop();
|
2694
|
-
}
|
2695
|
-
}, {
|
2696
|
-
priority: 'high'
|
2697
|
-
});
|
2698
|
-
}
|
2699
2794
|
}
|
2700
2795
|
/**
|
2701
2796
|
* @param resizerPosition Expected resizer position like `"top-left"`, `"bottom-right"`.
|
@@ -2713,15 +2808,24 @@ function existsInDom(element) {
|
|
2713
2808
|
return element && element.ownerDocument && element.ownerDocument.contains(element);
|
2714
2809
|
}
|
2715
2810
|
|
2716
|
-
|
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 {
|
2717
2816
|
/**
|
2718
|
-
|
2719
|
-
|
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() {
|
2720
2824
|
return 'WidgetResize';
|
2721
2825
|
}
|
2722
2826
|
/**
|
2723
|
-
|
2724
|
-
|
2827
|
+
* @inheritDoc
|
2828
|
+
*/ init() {
|
2725
2829
|
const editing = this.editor.editing;
|
2726
2830
|
const domDocument = global.window.document;
|
2727
2831
|
this.set('selectedResizer', null);
|
@@ -2763,15 +2867,15 @@ class WidgetResize extends Plugin {
|
|
2763
2867
|
});
|
2764
2868
|
}
|
2765
2869
|
/**
|
2766
|
-
|
2767
|
-
|
2870
|
+
* Redraws the selected resizer if there is any selected resizer and if it is visible.
|
2871
|
+
*/ redrawSelectedResizer() {
|
2768
2872
|
if (this.selectedResizer && this.selectedResizer.isVisible) {
|
2769
2873
|
this.selectedResizer.redraw();
|
2770
2874
|
}
|
2771
2875
|
}
|
2772
2876
|
/**
|
2773
|
-
|
2774
|
-
|
2877
|
+
* @inheritDoc
|
2878
|
+
*/ destroy() {
|
2775
2879
|
super.destroy();
|
2776
2880
|
this._observer.stopListening();
|
2777
2881
|
for (const resizer of this._resizers.values()){
|
@@ -2780,23 +2884,23 @@ class WidgetResize extends Plugin {
|
|
2780
2884
|
this._redrawSelectedResizerThrottled.cancel();
|
2781
2885
|
}
|
2782
2886
|
/**
|
2783
|
-
|
2784
|
-
|
2887
|
+
* Marks resizer as selected.
|
2888
|
+
*/ select(resizer) {
|
2785
2889
|
this.deselect();
|
2786
2890
|
this.selectedResizer = resizer;
|
2787
2891
|
this.selectedResizer.isSelected = true;
|
2788
2892
|
}
|
2789
2893
|
/**
|
2790
|
-
|
2791
|
-
|
2894
|
+
* Deselects currently set resizer.
|
2895
|
+
*/ deselect() {
|
2792
2896
|
if (this.selectedResizer) {
|
2793
2897
|
this.selectedResizer.isSelected = false;
|
2794
2898
|
}
|
2795
2899
|
this.selectedResizer = null;
|
2796
2900
|
}
|
2797
2901
|
/**
|
2798
|
-
|
2799
|
-
|
2902
|
+
* @param options Resizer options.
|
2903
|
+
*/ attachTo(options) {
|
2800
2904
|
const resizer = new Resizer(options);
|
2801
2905
|
const plugins = this.editor.plugins;
|
2802
2906
|
resizer.attach();
|
@@ -2830,15 +2934,15 @@ class WidgetResize extends Plugin {
|
|
2830
2934
|
return resizer;
|
2831
2935
|
}
|
2832
2936
|
/**
|
2833
|
-
|
2834
|
-
|
2835
|
-
|
2836
|
-
|
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) {
|
2837
2941
|
return this._resizers.get(viewElement);
|
2838
2942
|
}
|
2839
2943
|
/**
|
2840
|
-
|
2841
|
-
|
2944
|
+
* Returns a resizer that contains a given resize handle.
|
2945
|
+
*/ _getResizerByHandle(domResizeHandle) {
|
2842
2946
|
for (const resizer of this._resizers.values()){
|
2843
2947
|
if (resizer.containsHandle(domResizeHandle)) {
|
2844
2948
|
return resizer;
|
@@ -2846,8 +2950,8 @@ class WidgetResize extends Plugin {
|
|
2846
2950
|
}
|
2847
2951
|
}
|
2848
2952
|
/**
|
2849
|
-
|
2850
|
-
|
2953
|
+
* @param domEventData Native DOM event.
|
2954
|
+
*/ _mouseDownListener(event, domEventData) {
|
2851
2955
|
const resizeHandle = domEventData.domTarget;
|
2852
2956
|
if (!Resizer.isResizeHandle(resizeHandle)) {
|
2853
2957
|
return;
|
@@ -2861,8 +2965,8 @@ class WidgetResize extends Plugin {
|
|
2861
2965
|
}
|
2862
2966
|
}
|
2863
2967
|
/**
|
2864
|
-
|
2865
|
-
|
2968
|
+
* @param domEventData Native DOM event.
|
2969
|
+
*/ _mouseMoveListener(event, domEventData) {
|
2866
2970
|
if (this._activeResizer) {
|
2867
2971
|
this._activeResizer.updateSize(domEventData);
|
2868
2972
|
}
|
@@ -2873,12 +2977,6 @@ class WidgetResize extends Plugin {
|
|
2873
2977
|
this._activeResizer = null;
|
2874
2978
|
}
|
2875
2979
|
}
|
2876
|
-
constructor(){
|
2877
|
-
super(...arguments);
|
2878
|
-
/**
|
2879
|
-
* A map of resizers created using this plugin instance.
|
2880
|
-
*/ this._resizers = new Map();
|
2881
|
-
}
|
2882
2980
|
}
|
2883
2981
|
|
2884
2982
|
export { WIDGET_CLASS_NAME, WIDGET_SELECTED_CLASS_NAME, Widget, WidgetResize, WidgetToolbarRepository, WidgetTypeAround, calculateResizeHostAncestorWidth, calculateResizeHostPercentageWidth, findOptimalInsertionRange, getLabel, isWidget, setHighlightHandling, setLabel, toWidget, toWidgetEditable, viewToModelPositionOutsideModelElement };
|