@ckeditor/ckeditor5-widget 0.0.0-nightly-20240602.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/README.md +0 -6
- package/dist/index.js +479 -581
- package/dist/index.js.map +1 -1
- package/dist/types/highlightstack.d.ts +1 -1
- package/dist/types/widgetresize/resizer.d.ts +1 -1
- package/dist/types/widgetresize/resizerstate.d.ts +1 -1
- package/lang/contexts.json +1 -2
- package/package.json +7 -7
- package/src/highlightstack.d.ts +1 -1
- package/src/highlightstack.js +1 -1
- package/src/widget.js +0 -4
- package/src/widgetresize/resizer.d.ts +1 -1
- package/src/widgetresize/resizer.js +1 -1
- package/src/widgetresize/resizerstate.d.ts +1 -1
- package/src/widgetresize/resizerstate.js +1 -1
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
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
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
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
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
|
-
|
65
|
-
|
66
|
-
|
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
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
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
|
-
|
188
|
-
|
189
|
-
|
190
|
-
|
191
|
-
|
192
|
-
|
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
|
-
|
550
|
-
|
551
|
-
|
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
|
-
|
570
|
-
|
548
|
+
* @inheritDoc
|
549
|
+
*/ static get requires() {
|
571
550
|
return [
|
572
551
|
Enter,
|
573
552
|
Delete
|
574
553
|
];
|
575
554
|
}
|
576
555
|
/**
|
577
|
-
|
578
|
-
|
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
|
-
|
611
|
-
|
589
|
+
* @inheritDoc
|
590
|
+
*/ destroy() {
|
612
591
|
super.destroy();
|
613
592
|
this._currentFakeCaretModelElement = null;
|
614
593
|
}
|
615
594
|
/**
|
616
|
-
|
617
|
-
|
618
|
-
|
619
|
-
|
620
|
-
|
621
|
-
|
622
|
-
|
623
|
-
|
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
|
-
|
636
|
-
|
637
|
-
|
638
|
-
|
639
|
-
|
640
|
-
|
641
|
-
|
642
|
-
|
643
|
-
|
644
|
-
|
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
|
-
|
654
|
-
|
655
|
-
|
656
|
-
|
657
|
-
|
658
|
-
|
659
|
-
|
660
|
-
|
661
|
-
|
662
|
-
|
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
|
-
|
681
|
-
|
682
|
-
|
683
|
-
|
684
|
-
|
685
|
-
|
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
|
-
|
712
|
-
|
713
|
-
|
714
|
-
|
715
|
-
|
716
|
-
|
717
|
-
|
718
|
-
|
719
|
-
|
720
|
-
|
721
|
-
|
722
|
-
|
723
|
-
|
724
|
-
|
725
|
-
|
726
|
-
|
727
|
-
|
728
|
-
|
729
|
-
|
730
|
-
|
731
|
-
|
732
|
-
|
733
|
-
|
734
|
-
|
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
|
-
|
823
|
-
|
824
|
-
|
825
|
-
|
826
|
-
|
827
|
-
|
828
|
-
|
829
|
-
|
830
|
-
|
831
|
-
|
832
|
-
|
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
|
-
|
858
|
-
|
859
|
-
|
860
|
-
|
861
|
-
|
862
|
-
|
863
|
-
|
864
|
-
|
865
|
-
|
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
|
-
|
895
|
-
|
896
|
-
|
897
|
-
|
898
|
-
|
899
|
-
|
900
|
-
|
901
|
-
|
902
|
-
|
903
|
-
|
904
|
-
|
905
|
-
|
906
|
-
|
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
|
-
|
927
|
-
|
928
|
-
|
929
|
-
|
930
|
-
|
931
|
-
|
932
|
-
|
933
|
-
|
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
|
-
|
953
|
-
|
954
|
-
|
955
|
-
|
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
|
-
|
973
|
-
|
974
|
-
|
975
|
-
|
976
|
-
|
977
|
-
|
978
|
-
|
979
|
-
|
980
|
-
|
981
|
-
|
982
|
-
|
983
|
-
|
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
|
-
|
1015
|
-
|
1016
|
-
|
1017
|
-
|
1018
|
-
|
1019
|
-
|
1020
|
-
|
1021
|
-
|
1022
|
-
|
1023
|
-
|
1024
|
-
|
1025
|
-
|
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
|
-
|
1060
|
-
|
1061
|
-
|
1062
|
-
|
1063
|
-
|
1064
|
-
|
1065
|
-
|
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
|
-
|
1131
|
-
|
1132
|
-
|
1133
|
-
|
1134
|
-
|
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
|
-
|
1161
|
-
|
1162
|
-
|
1163
|
-
|
1164
|
-
|
1165
|
-
|
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
|
-
|
1186
|
-
|
1187
|
-
|
1188
|
-
|
1189
|
-
|
1190
|
-
|
1191
|
-
|
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
|
-
|
1468
|
-
|
1469
|
-
|
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
|
-
|
1489
|
-
|
1460
|
+
* @inheritDoc
|
1461
|
+
*/ static get requires() {
|
1490
1462
|
return [
|
1491
1463
|
WidgetTypeAround,
|
1492
1464
|
Delete
|
1493
1465
|
];
|
1494
1466
|
}
|
1495
1467
|
/**
|
1496
|
-
|
1497
|
-
|
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
|
-
|
1693
|
-
|
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
|
-
|
1731
|
-
|
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
|
-
|
1751
|
-
|
1752
|
-
|
1753
|
-
|
1754
|
-
|
1755
|
-
|
1756
|
-
|
1757
|
-
|
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
|
-
|
1813
|
-
|
1814
|
-
|
1815
|
-
|
1816
|
-
|
1817
|
-
|
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
|
-
|
1829
|
-
|
1830
|
-
|
1831
|
-
|
1832
|
-
|
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
|
-
|
1860
|
-
|
1861
|
-
|
1862
|
-
|
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
|
-
|
1869
|
-
|
1870
|
-
|
1871
|
-
|
1872
|
-
|
1873
|
-
|
1874
|
-
|
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
|
-
|
1896
|
-
|
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
|
-
|
1904
|
-
|
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
|
-
|
1926
|
-
|
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
|
-
|
2039
|
-
|
1983
|
+
* @inheritDoc
|
1984
|
+
*/ static get requires() {
|
2040
1985
|
return [
|
2041
1986
|
ContextualBalloon
|
2042
1987
|
];
|
2043
1988
|
}
|
2044
1989
|
/**
|
2045
|
-
|
2046
|
-
|
1990
|
+
* @inheritDoc
|
1991
|
+
*/ static get pluginName() {
|
2047
1992
|
return 'WidgetToolbarRepository';
|
2048
1993
|
}
|
2049
1994
|
/**
|
2050
|
-
|
2051
|
-
|
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
|
-
|
2086
|
-
|
2087
|
-
|
2088
|
-
|
2089
|
-
|
2090
|
-
|
2091
|
-
|
2092
|
-
|
2093
|
-
|
2094
|
-
|
2095
|
-
|
2096
|
-
|
2097
|
-
|
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
|
-
|
2102
|
-
|
2103
|
-
|
2104
|
-
|
2105
|
-
|
2106
|
-
|
2107
|
-
|
2108
|
-
|
2109
|
-
|
2110
|
-
|
2111
|
-
|
2112
|
-
|
2113
|
-
|
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
|
-
|
2125
|
-
|
2126
|
-
|
2127
|
-
|
2128
|
-
|
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
|
-
|
2156
|
-
|
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
|
-
|
2189
|
-
|
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
|
-
|
2195
|
-
|
2196
|
-
|
2197
|
-
|
2198
|
-
|
2199
|
-
|
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
|
-
|
2307
|
-
|
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
|
-
|
2312
|
-
|
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
|
-
|
2317
|
-
|
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
|
-
|
2322
|
-
|
2227
|
+
* A width to height ratio of the resized image.
|
2228
|
+
*/ get aspectRatio() {
|
2323
2229
|
return this._aspectRatio;
|
2324
2230
|
}
|
2325
2231
|
/**
|
2326
|
-
|
2327
|
-
|
2328
|
-
|
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
|
-
|
2405
|
-
|
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
|
-
|
2501
|
-
|
2502
|
-
|
2503
|
-
|
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
|
-
|
2508
|
-
|
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
|
-
|
2516
|
-
|
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
|
-
|
2524
|
-
|
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
|
-
|
2557
|
-
|
2558
|
-
|
2559
|
-
|
2560
|
-
|
2561
|
-
|
2562
|
-
|
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
|
-
|
2570
|
-
|
2571
|
-
|
2572
|
-
|
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
|
-
|
2600
|
-
|
2601
|
-
|
2602
|
-
|
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
|
-
|
2613
|
-
|
2614
|
-
|
2615
|
-
|
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
|
-
|
2620
|
-
|
2494
|
+
* Destroys the resizer.
|
2495
|
+
*/ destroy() {
|
2621
2496
|
this.cancel();
|
2622
2497
|
}
|
2623
2498
|
/**
|
2624
|
-
|
2625
|
-
|
2626
|
-
|
2627
|
-
|
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
|
-
|
2683
|
-
|
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
|
-
|
2692
|
-
|
2693
|
-
|
2694
|
-
|
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
|
-
|
2741
|
-
|
2742
|
-
|
2743
|
-
|
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
|
-
|
2749
|
-
|
2750
|
-
|
2751
|
-
|
2752
|
-
|
2753
|
-
|
2754
|
-
|
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
|
-
|
2760
|
-
|
2761
|
-
|
2762
|
-
|
2763
|
-
|
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
|
-
|
2768
|
-
|
2769
|
-
|
2770
|
-
|
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
|
-
|
2788
|
-
|
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
|
-
|
2818
|
-
|
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
|
-
|
2828
|
-
|
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
|
-
|
2871
|
-
|
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
|
-
|
2878
|
-
|
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
|
-
|
2888
|
-
|
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
|
-
|
2895
|
-
|
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
|
-
|
2903
|
-
|
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
|
-
|
2938
|
-
|
2939
|
-
|
2940
|
-
|
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
|
-
|
2945
|
-
|
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
|
-
|
2954
|
-
|
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
|
-
|
2969
|
-
|
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 };
|