@ckeditor/ckeditor5-widget 0.0.0-nightly-20241218.0 → 0.0.0-nightly-20241219.1
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 +460 -428
- package/dist/index.js.map +1 -1
- package/package.json +7 -7
package/dist/index.js
CHANGED
@@ -21,15 +21,12 @@ import { throttle } from 'lodash-es';
|
|
21
21
|
*
|
22
22
|
* This way, highlight will be applied with the same rules it is applied on texts.
|
23
23
|
*/ class HighlightStack extends /* #__PURE__ */ EmitterMixin() {
|
24
|
-
|
25
|
-
super(...arguments);
|
26
|
-
this._stack = [];
|
27
|
-
}
|
24
|
+
_stack = [];
|
28
25
|
/**
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
26
|
+
* Adds highlight descriptor to the stack.
|
27
|
+
*
|
28
|
+
* @fires change:top
|
29
|
+
*/ add(descriptor, writer) {
|
33
30
|
const stack = this._stack;
|
34
31
|
// Save top descriptor and insert new one. If top is changed - fire event.
|
35
32
|
const oldTop = stack[0];
|
@@ -45,11 +42,11 @@ import { throttle } from 'lodash-es';
|
|
45
42
|
}
|
46
43
|
}
|
47
44
|
/**
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
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) {
|
53
50
|
const stack = this._stack;
|
54
51
|
const oldTop = stack[0];
|
55
52
|
this._removeDescriptor(id);
|
@@ -64,9 +61,9 @@ import { throttle } from 'lodash-es';
|
|
64
61
|
}
|
65
62
|
}
|
66
63
|
/**
|
67
|
-
|
68
|
-
|
69
|
-
|
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) {
|
70
67
|
const stack = this._stack;
|
71
68
|
const index = stack.findIndex((item)=>item.id === descriptor.id);
|
72
69
|
// Inserting exact same descriptor - do nothing.
|
@@ -86,10 +83,10 @@ import { throttle } from 'lodash-es';
|
|
86
83
|
stack.splice(i, 0, descriptor);
|
87
84
|
}
|
88
85
|
/**
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
86
|
+
* Removes descriptor with given id from the stack.
|
87
|
+
*
|
88
|
+
* @param id Descriptor's id.
|
89
|
+
*/ _removeDescriptor(id) {
|
93
90
|
const stack = this._stack;
|
94
91
|
const index = stack.findIndex((item)=>item.id === id);
|
95
92
|
// If descriptor with same id is on the list - remove it.
|
@@ -187,12 +184,12 @@ var dragHandleIcon = "<svg viewBox=\"0 0 16 16\" xmlns=\"http://www.w3.org/2000/
|
|
187
184
|
*/ function toWidget(element, writer, options = {}) {
|
188
185
|
if (!element.is('containerElement')) {
|
189
186
|
/**
|
190
|
-
|
191
|
-
|
192
|
-
|
193
|
-
|
194
|
-
|
195
|
-
|
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, {
|
196
193
|
element
|
197
194
|
});
|
198
195
|
}
|
@@ -558,35 +555,32 @@ const PLUGIN_DISABLED_EDITING_ROOT_CLASS = 'ck-widget__type-around_disabled';
|
|
558
555
|
* user if the widget is next to the "tight spot". Once clicked, a paragraph is created with the selection anchored
|
559
556
|
* in it so that users can type (or insert content, paste, etc.) straight away.
|
560
557
|
*/ class WidgetTypeAround extends Plugin {
|
561
|
-
constructor(){
|
562
|
-
super(...arguments);
|
563
|
-
/**
|
564
|
-
* A reference to the model widget element that has the fake caret active
|
565
|
-
* on either side of it. It is later used to remove CSS classes associated with the fake caret
|
566
|
-
* when the widget no longer needs it.
|
567
|
-
*/ this._currentFakeCaretModelElement = null;
|
568
|
-
}
|
569
558
|
/**
|
570
|
-
|
571
|
-
|
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() {
|
572
566
|
return 'WidgetTypeAround';
|
573
567
|
}
|
574
568
|
/**
|
575
|
-
|
576
|
-
|
569
|
+
* @inheritDoc
|
570
|
+
*/ static get isOfficialPlugin() {
|
577
571
|
return true;
|
578
572
|
}
|
579
573
|
/**
|
580
|
-
|
581
|
-
|
574
|
+
* @inheritDoc
|
575
|
+
*/ static get requires() {
|
582
576
|
return [
|
583
577
|
Enter,
|
584
578
|
Delete
|
585
579
|
];
|
586
580
|
}
|
587
581
|
/**
|
588
|
-
|
589
|
-
|
582
|
+
* @inheritDoc
|
583
|
+
*/ init() {
|
590
584
|
const editor = this.editor;
|
591
585
|
const editingView = editor.editing.view;
|
592
586
|
// Set a CSS class on the view editing root when the plugin is disabled so all the buttons
|
@@ -618,20 +612,20 @@ const PLUGIN_DISABLED_EDITING_ROOT_CLASS = 'ck-widget__type-around_disabled';
|
|
618
612
|
this._enableDeleteContentIntegration();
|
619
613
|
}
|
620
614
|
/**
|
621
|
-
|
622
|
-
|
615
|
+
* @inheritDoc
|
616
|
+
*/ destroy() {
|
623
617
|
super.destroy();
|
624
618
|
this._currentFakeCaretModelElement = null;
|
625
619
|
}
|
626
620
|
/**
|
627
|
-
|
628
|
-
|
629
|
-
|
630
|
-
|
631
|
-
|
632
|
-
|
633
|
-
|
634
|
-
|
621
|
+
* Inserts a new paragraph next to a widget element with the selection anchored in it.
|
622
|
+
*
|
623
|
+
* **Note**: This method is heavily user-oriented and will both focus the editing view and scroll
|
624
|
+
* the viewport to the selection in the inserted paragraph.
|
625
|
+
*
|
626
|
+
* @param widgetModelElement The model widget element next to which a paragraph is inserted.
|
627
|
+
* @param position The position where the paragraph is inserted. Either `'before'` or `'after'` the widget.
|
628
|
+
*/ _insertParagraph(widgetModelElement, position) {
|
635
629
|
const editor = this.editor;
|
636
630
|
const editingView = editor.editing.view;
|
637
631
|
const attributesToCopy = editor.model.schema.getAttributesWithProperty(widgetModelElement, 'copyOnReplace', true);
|
@@ -643,16 +637,16 @@ const PLUGIN_DISABLED_EDITING_ROOT_CLASS = 'ck-widget__type-around_disabled';
|
|
643
637
|
editingView.scrollToTheSelection();
|
644
638
|
}
|
645
639
|
/**
|
646
|
-
|
647
|
-
|
648
|
-
|
649
|
-
|
650
|
-
|
651
|
-
|
652
|
-
|
653
|
-
|
654
|
-
|
655
|
-
|
640
|
+
* A wrapper for the {@link module:utils/emittermixin~Emitter#listenTo} method that executes the callbacks only
|
641
|
+
* when the plugin {@link #isEnabled is enabled}.
|
642
|
+
*
|
643
|
+
* @param emitter The object that fires the event.
|
644
|
+
* @param event The name of the event.
|
645
|
+
* @param callback The function to be called on event.
|
646
|
+
* @param options Additional options.
|
647
|
+
* @param options.priority The priority of this event callback. The higher the priority value the sooner
|
648
|
+
* the callback will be fired. Events having the same priority are called in the order they were added.
|
649
|
+
*/ _listenToIfEnabled(emitter, event, callback, options) {
|
656
650
|
this.listenTo(emitter, event, (...args)=>{
|
657
651
|
// Do not respond if the plugin is disabled.
|
658
652
|
if (this.isEnabled) {
|
@@ -661,16 +655,16 @@ const PLUGIN_DISABLED_EDITING_ROOT_CLASS = 'ck-widget__type-around_disabled';
|
|
661
655
|
}, options);
|
662
656
|
}
|
663
657
|
/**
|
664
|
-
|
665
|
-
|
666
|
-
|
667
|
-
|
668
|
-
|
669
|
-
|
670
|
-
|
671
|
-
|
672
|
-
|
673
|
-
|
658
|
+
* Similar to {@link #_insertParagraph}, this method inserts a paragraph except that it
|
659
|
+
* does not expect a position. Instead, it performs the insertion next to a selected widget
|
660
|
+
* according to the `widget-type-around` model selection attribute value (fake caret position).
|
661
|
+
*
|
662
|
+
* Because this method requires the `widget-type-around` attribute to be set,
|
663
|
+
* the insertion can only happen when the widget's fake caret is active (e.g. activated
|
664
|
+
* using the keyboard).
|
665
|
+
*
|
666
|
+
* @returns Returns `true` when the paragraph was inserted (the attribute was present) and `false` otherwise.
|
667
|
+
*/ _insertParagraphAccordingToFakeCaretPosition() {
|
674
668
|
const editor = this.editor;
|
675
669
|
const model = editor.model;
|
676
670
|
const modelSelection = model.document.selection;
|
@@ -688,12 +682,12 @@ const PLUGIN_DISABLED_EDITING_ROOT_CLASS = 'ck-widget__type-around_disabled';
|
|
688
682
|
return true;
|
689
683
|
}
|
690
684
|
/**
|
691
|
-
|
692
|
-
|
693
|
-
|
694
|
-
|
695
|
-
|
696
|
-
|
685
|
+
* Creates a listener in the editing conversion pipeline that injects the widget type around
|
686
|
+
* UI into every single widget instance created in the editor.
|
687
|
+
*
|
688
|
+
* The UI is delivered as a {@link module:engine/view/uielement~UIElement}
|
689
|
+
* wrapper which renders DOM buttons that users can use to insert paragraphs.
|
690
|
+
*/ _enableTypeAroundUIInjection() {
|
697
691
|
const editor = this.editor;
|
698
692
|
const schema = editor.model.schema;
|
699
693
|
const t = editor.locale.t;
|
@@ -719,30 +713,30 @@ const PLUGIN_DISABLED_EDITING_ROOT_CLASS = 'ck-widget__type-around_disabled';
|
|
719
713
|
});
|
720
714
|
}
|
721
715
|
/**
|
722
|
-
|
723
|
-
|
724
|
-
|
725
|
-
|
726
|
-
|
727
|
-
|
728
|
-
|
729
|
-
|
730
|
-
|
731
|
-
|
732
|
-
|
733
|
-
|
734
|
-
|
735
|
-
|
736
|
-
|
737
|
-
|
738
|
-
|
739
|
-
|
740
|
-
|
741
|
-
|
742
|
-
|
743
|
-
|
744
|
-
|
745
|
-
|
716
|
+
* Brings support for the fake caret that appears when either:
|
717
|
+
*
|
718
|
+
* * the selection moves to a widget from a position next to it using arrow keys,
|
719
|
+
* * the arrow key is pressed when the widget is already selected.
|
720
|
+
*
|
721
|
+
* The fake caret lets the user know that they can start typing or just press
|
722
|
+
* <kbd>Enter</kbd> to insert a paragraph at the position next to a widget as suggested by the fake caret.
|
723
|
+
*
|
724
|
+
* The fake caret disappears when the user changes the selection or the editor
|
725
|
+
* gets blurred.
|
726
|
+
*
|
727
|
+
* The whole idea is as follows:
|
728
|
+
*
|
729
|
+
* 1. A user does one of the 2 scenarios described at the beginning.
|
730
|
+
* 2. The "keydown" listener is executed and the decision is made whether to show or hide the fake caret.
|
731
|
+
* 3. If it should show up, the `widget-type-around` model selection attribute is set indicating
|
732
|
+
* on which side of the widget it should appear.
|
733
|
+
* 4. The selection dispatcher reacts to the selection attribute and sets CSS classes responsible for the
|
734
|
+
* fake caret on the view widget.
|
735
|
+
* 5. If the fake caret should disappear, the selection attribute is removed and the dispatcher
|
736
|
+
* does the CSS class clean-up in the view.
|
737
|
+
* 6. Additionally, `change:range` and `FocusTracker#isFocused` listeners also remove the selection
|
738
|
+
* attribute (the former also removes widget CSS classes).
|
739
|
+
*/ _enableTypeAroundFakeCaretActivationUsingKeyboardArrows() {
|
746
740
|
const editor = this.editor;
|
747
741
|
const model = editor.model;
|
748
742
|
const modelSelection = model.document.selection;
|
@@ -830,17 +824,17 @@ const PLUGIN_DISABLED_EDITING_ROOT_CLASS = 'ck-widget__type-around_disabled';
|
|
830
824
|
}
|
831
825
|
}
|
832
826
|
/**
|
833
|
-
|
834
|
-
|
835
|
-
|
836
|
-
|
837
|
-
|
838
|
-
|
839
|
-
|
840
|
-
|
841
|
-
|
842
|
-
|
843
|
-
|
827
|
+
* A listener executed on each "keydown" in the view document, a part of
|
828
|
+
* {@link #_enableTypeAroundFakeCaretActivationUsingKeyboardArrows}.
|
829
|
+
*
|
830
|
+
* It decides whether the arrow keypress should activate the fake caret or not (also whether it should
|
831
|
+
* be deactivated).
|
832
|
+
*
|
833
|
+
* The fake caret activation is done by setting the `widget-type-around` model selection attribute
|
834
|
+
* in this listener, and stopping and preventing the event that would normally be handled by the widget
|
835
|
+
* plugin that is responsible for the regular keyboard navigation near/across all widgets (that
|
836
|
+
* includes inline widgets, which are ignored by the widget type around plugin).
|
837
|
+
*/ _handleArrowKeyPress(evt, domEventData) {
|
844
838
|
const editor = this.editor;
|
845
839
|
const model = editor.model;
|
846
840
|
const modelSelection = model.document.selection;
|
@@ -865,15 +859,15 @@ const PLUGIN_DISABLED_EDITING_ROOT_CLASS = 'ck-widget__type-around_disabled';
|
|
865
859
|
}
|
866
860
|
}
|
867
861
|
/**
|
868
|
-
|
869
|
-
|
870
|
-
|
871
|
-
|
872
|
-
|
873
|
-
|
874
|
-
|
875
|
-
|
876
|
-
|
862
|
+
* Handles the keyboard navigation on "keydown" when a widget is currently selected and activates or deactivates
|
863
|
+
* the fake caret for that widget, depending on the current value of the `widget-type-around` model
|
864
|
+
* selection attribute and the direction of the pressed arrow key.
|
865
|
+
*
|
866
|
+
* @param isForward `true` when the pressed arrow key was responsible for the forward model selection movement
|
867
|
+
* as in {@link module:utils/keyboard~isForwardArrowKeyCode}.
|
868
|
+
* @returns Returns `true` when the keypress was handled and no other keydown listener of the editor should
|
869
|
+
* process the event any further. Returns `false` otherwise.
|
870
|
+
*/ _handleArrowKeyPressOnSelectedWidget(isForward) {
|
877
871
|
const editor = this.editor;
|
878
872
|
const model = editor.model;
|
879
873
|
const modelSelection = model.document.selection;
|
@@ -902,19 +896,19 @@ const PLUGIN_DISABLED_EDITING_ROOT_CLASS = 'ck-widget__type-around_disabled';
|
|
902
896
|
});
|
903
897
|
}
|
904
898
|
/**
|
905
|
-
|
906
|
-
|
907
|
-
|
908
|
-
|
909
|
-
|
910
|
-
|
911
|
-
|
912
|
-
|
913
|
-
|
914
|
-
|
915
|
-
|
916
|
-
|
917
|
-
|
899
|
+
* Handles the keyboard navigation on "keydown" when **no** widget is selected but the selection is **directly** next
|
900
|
+
* to one and upon the fake caret should become active for this widget upon arrow keypress
|
901
|
+
* (AKA entering/selecting the widget).
|
902
|
+
*
|
903
|
+
* **Note**: This code mirrors the implementation from the widget plugin but also adds the selection attribute.
|
904
|
+
* Unfortunately, there is no safe way to let the widget plugin do the selection part first and then just set the
|
905
|
+
* selection attribute here in the widget type around plugin. This is why this code must duplicate some from the widget plugin.
|
906
|
+
*
|
907
|
+
* @param isForward `true` when the pressed arrow key was responsible for the forward model selection movement
|
908
|
+
* as in {@link module:utils/keyboard~isForwardArrowKeyCode}.
|
909
|
+
* @returns Returns `true` when the keypress was handled and no other keydown listener of the editor should
|
910
|
+
* process the event any further. Returns `false` otherwise.
|
911
|
+
*/ _handleArrowKeyPressWhenSelectionNextToAWidget(isForward) {
|
918
912
|
const editor = this.editor;
|
919
913
|
const model = editor.model;
|
920
914
|
const schema = model.schema;
|
@@ -934,14 +928,14 @@ const PLUGIN_DISABLED_EDITING_ROOT_CLASS = 'ck-widget__type-around_disabled';
|
|
934
928
|
return false;
|
935
929
|
}
|
936
930
|
/**
|
937
|
-
|
938
|
-
|
939
|
-
|
940
|
-
|
941
|
-
|
942
|
-
|
943
|
-
|
944
|
-
|
931
|
+
* Handles the keyboard navigation on "keydown" when a widget is currently selected (together with some other content)
|
932
|
+
* and the widget is the first or last element in the selection. It activates or deactivates the fake caret for that widget.
|
933
|
+
*
|
934
|
+
* @param isForward `true` when the pressed arrow key was responsible for the forward model selection movement
|
935
|
+
* as in {@link module:utils/keyboard~isForwardArrowKeyCode}.
|
936
|
+
* @returns Returns `true` when the keypress was handled and no other keydown listener of the editor should
|
937
|
+
* process the event any further. Returns `false` otherwise.
|
938
|
+
*/ _handleArrowKeyPressWhenNonCollapsedSelection(isForward) {
|
945
939
|
const editor = this.editor;
|
946
940
|
const model = editor.model;
|
947
941
|
const schema = model.schema;
|
@@ -960,10 +954,10 @@ const PLUGIN_DISABLED_EDITING_ROOT_CLASS = 'ck-widget__type-around_disabled';
|
|
960
954
|
return false;
|
961
955
|
}
|
962
956
|
/**
|
963
|
-
|
964
|
-
|
965
|
-
|
966
|
-
|
957
|
+
* Registers a `mousedown` listener for the view document which intercepts events
|
958
|
+
* coming from the widget type around UI, which happens when a user clicks one of the buttons
|
959
|
+
* that insert a paragraph next to a widget.
|
960
|
+
*/ _enableInsertingParagraphsOnButtonClick() {
|
967
961
|
const editor = this.editor;
|
968
962
|
const editingView = editor.editing.view;
|
969
963
|
this._listenToIfEnabled(editingView.document, 'mousedown', (evt, domEventData)=>{
|
@@ -980,18 +974,18 @@ const PLUGIN_DISABLED_EDITING_ROOT_CLASS = 'ck-widget__type-around_disabled';
|
|
980
974
|
});
|
981
975
|
}
|
982
976
|
/**
|
983
|
-
|
984
|
-
|
985
|
-
|
986
|
-
|
987
|
-
|
988
|
-
|
989
|
-
|
990
|
-
|
991
|
-
|
992
|
-
|
993
|
-
|
994
|
-
|
977
|
+
* Creates the <kbd>Enter</kbd> key listener on the view document that allows the user to insert a paragraph
|
978
|
+
* near the widget when either:
|
979
|
+
*
|
980
|
+
* * The fake caret was first activated using the arrow keys,
|
981
|
+
* * The entire widget is selected in the model.
|
982
|
+
*
|
983
|
+
* In the first case, the new paragraph is inserted according to the `widget-type-around` selection
|
984
|
+
* attribute (see {@link #_handleArrowKeyPress}).
|
985
|
+
*
|
986
|
+
* In the second case, the new paragraph is inserted based on whether a soft (<kbd>Shift</kbd>+<kbd>Enter</kbd>) keystroke
|
987
|
+
* was pressed or not.
|
988
|
+
*/ _enableInsertingParagraphsOnEnterKeypress() {
|
995
989
|
const editor = this.editor;
|
996
990
|
const selection = editor.model.document.selection;
|
997
991
|
const editingView = editor.editing.view;
|
@@ -1022,18 +1016,18 @@ const PLUGIN_DISABLED_EDITING_ROOT_CLASS = 'ck-widget__type-around_disabled';
|
|
1022
1016
|
});
|
1023
1017
|
}
|
1024
1018
|
/**
|
1025
|
-
|
1026
|
-
|
1027
|
-
|
1028
|
-
|
1029
|
-
|
1030
|
-
|
1031
|
-
|
1032
|
-
|
1033
|
-
|
1034
|
-
|
1035
|
-
|
1036
|
-
|
1019
|
+
* Similar to the {@link #_enableInsertingParagraphsOnEnterKeypress}, it allows the user
|
1020
|
+
* to insert a paragraph next to a widget when the fake caret was activated using arrow
|
1021
|
+
* keys but it responds to typing instead of <kbd>Enter</kbd>.
|
1022
|
+
*
|
1023
|
+
* Listener enabled by this method will insert a new paragraph according to the `widget-type-around`
|
1024
|
+
* model selection attribute as the user simply starts typing, which creates the impression that the fake caret
|
1025
|
+
* behaves like a real one rendered by the browser (AKA your text appears where the caret was).
|
1026
|
+
*
|
1027
|
+
* **Note**: At the moment this listener creates 2 undo steps: one for the `insertParagraph` command
|
1028
|
+
* and another one for actual typing. It is not a disaster but this may need to be fixed
|
1029
|
+
* sooner or later.
|
1030
|
+
*/ _enableInsertingParagraphsOnTypingKeystroke() {
|
1037
1031
|
const editor = this.editor;
|
1038
1032
|
const viewDocument = editor.editing.view.document;
|
1039
1033
|
// Note: The priority must precede the default Input plugin insertText handler.
|
@@ -1067,13 +1061,13 @@ const PLUGIN_DISABLED_EDITING_ROOT_CLASS = 'ck-widget__type-around_disabled';
|
|
1067
1061
|
}
|
1068
1062
|
}
|
1069
1063
|
/**
|
1070
|
-
|
1071
|
-
|
1072
|
-
|
1073
|
-
|
1074
|
-
|
1075
|
-
|
1076
|
-
|
1064
|
+
* It creates a "delete" event listener on the view document to handle cases when the <kbd>Delete</kbd> or <kbd>Backspace</kbd>
|
1065
|
+
* is pressed and the fake caret is currently active.
|
1066
|
+
*
|
1067
|
+
* The fake caret should create an illusion of a real browser caret so that when it appears before or after
|
1068
|
+
* a widget, pressing <kbd>Delete</kbd> or <kbd>Backspace</kbd> should remove a widget or delete the content
|
1069
|
+
* before or after a widget (depending on the content surrounding the widget).
|
1070
|
+
*/ _enableDeleteIntegration() {
|
1077
1071
|
const editor = this.editor;
|
1078
1072
|
const editingView = editor.editing.view;
|
1079
1073
|
const model = editor.model;
|
@@ -1138,11 +1132,11 @@ const PLUGIN_DISABLED_EDITING_ROOT_CLASS = 'ck-widget__type-around_disabled';
|
|
1138
1132
|
});
|
1139
1133
|
}
|
1140
1134
|
/**
|
1141
|
-
|
1142
|
-
|
1143
|
-
|
1144
|
-
|
1145
|
-
|
1135
|
+
* Attaches the {@link module:engine/model/model~Model#event:insertContent} event listener that, for instance, allows the user to paste
|
1136
|
+
* content near a widget when the fake caret is first activated using the arrow keys.
|
1137
|
+
*
|
1138
|
+
* The content is inserted according to the `widget-type-around` selection attribute (see {@link #_handleArrowKeyPress}).
|
1139
|
+
*/ _enableInsertContentIntegration() {
|
1146
1140
|
const editor = this.editor;
|
1147
1141
|
const model = this.editor.model;
|
1148
1142
|
const documentSelection = model.document.selection;
|
@@ -1168,12 +1162,12 @@ const PLUGIN_DISABLED_EDITING_ROOT_CLASS = 'ck-widget__type-around_disabled';
|
|
1168
1162
|
});
|
1169
1163
|
}
|
1170
1164
|
/**
|
1171
|
-
|
1172
|
-
|
1173
|
-
|
1174
|
-
|
1175
|
-
|
1176
|
-
|
1165
|
+
* Attaches the {@link module:engine/model/model~Model#event:insertObject} event listener that modifies the
|
1166
|
+
* `options.findOptimalPosition`parameter to position of fake caret in relation to selected element
|
1167
|
+
* to reflect user's intent of desired insertion position.
|
1168
|
+
*
|
1169
|
+
* The object is inserted according to the `widget-type-around` selection attribute (see {@link #_handleArrowKeyPress}).
|
1170
|
+
*/ _enableInsertObjectIntegration() {
|
1177
1171
|
const editor = this.editor;
|
1178
1172
|
const model = this.editor.model;
|
1179
1173
|
const documentSelection = model.document.selection;
|
@@ -1193,13 +1187,13 @@ const PLUGIN_DISABLED_EDITING_ROOT_CLASS = 'ck-widget__type-around_disabled';
|
|
1193
1187
|
});
|
1194
1188
|
}
|
1195
1189
|
/**
|
1196
|
-
|
1197
|
-
|
1198
|
-
|
1199
|
-
|
1200
|
-
|
1201
|
-
|
1202
|
-
|
1190
|
+
* Attaches the {@link module:engine/model/model~Model#event:deleteContent} event listener to block the event when the fake
|
1191
|
+
* caret is active.
|
1192
|
+
*
|
1193
|
+
* This is required for cases that trigger {@link module:engine/model/model~Model#deleteContent `model.deleteContent()`}
|
1194
|
+
* before calling {@link module:engine/model/model~Model#insertContent `model.insertContent()`} like, for instance,
|
1195
|
+
* plain text pasting.
|
1196
|
+
*/ _enableDeleteContentIntegration() {
|
1203
1197
|
const editor = this.editor;
|
1204
1198
|
const model = this.editor.model;
|
1205
1199
|
const documentSelection = model.document.selection;
|
@@ -1487,33 +1481,30 @@ function selectionWillShrink(selection, isForward) {
|
|
1487
1481
|
* is added to indicate that widget has been selected.
|
1488
1482
|
* * The mouse and keyboard events handling on and around widget elements.
|
1489
1483
|
*/ class Widget extends Plugin {
|
1490
|
-
constructor(){
|
1491
|
-
super(...arguments);
|
1492
|
-
/**
|
1493
|
-
* Holds previously selected widgets.
|
1494
|
-
*/ this._previouslySelected = new Set();
|
1495
|
-
}
|
1496
1484
|
/**
|
1497
|
-
|
1498
|
-
|
1485
|
+
* Holds previously selected widgets.
|
1486
|
+
*/ _previouslySelected = new Set();
|
1487
|
+
/**
|
1488
|
+
* @inheritDoc
|
1489
|
+
*/ static get pluginName() {
|
1499
1490
|
return 'Widget';
|
1500
1491
|
}
|
1501
1492
|
/**
|
1502
|
-
|
1503
|
-
|
1493
|
+
* @inheritDoc
|
1494
|
+
*/ static get isOfficialPlugin() {
|
1504
1495
|
return true;
|
1505
1496
|
}
|
1506
1497
|
/**
|
1507
|
-
|
1508
|
-
|
1498
|
+
* @inheritDoc
|
1499
|
+
*/ static get requires() {
|
1509
1500
|
return [
|
1510
1501
|
WidgetTypeAround,
|
1511
1502
|
Delete
|
1512
1503
|
];
|
1513
1504
|
}
|
1514
1505
|
/**
|
1515
|
-
|
1516
|
-
|
1506
|
+
* @inheritDoc
|
1507
|
+
*/ init() {
|
1517
1508
|
const editor = this.editor;
|
1518
1509
|
const view = editor.editing.view;
|
1519
1510
|
const viewDocument = view.document;
|
@@ -1708,8 +1699,8 @@ function selectionWillShrink(selection, isForward) {
|
|
1708
1699
|
});
|
1709
1700
|
}
|
1710
1701
|
/**
|
1711
|
-
|
1712
|
-
|
1702
|
+
* Handles {@link module:engine/view/document~Document#event:mousedown mousedown} events on widget elements.
|
1703
|
+
*/ _onMousedown(eventInfo, domEventData) {
|
1713
1704
|
const editor = this.editor;
|
1714
1705
|
const view = editor.editing.view;
|
1715
1706
|
const viewDocument = view.document;
|
@@ -1757,8 +1748,8 @@ function selectionWillShrink(selection, isForward) {
|
|
1757
1748
|
this._setSelectionOverElement(modelElement);
|
1758
1749
|
}
|
1759
1750
|
/**
|
1760
|
-
|
1761
|
-
|
1751
|
+
* Selects entire block content, e.g. on triple click it selects entire paragraph.
|
1752
|
+
*/ _selectBlockContent(element) {
|
1762
1753
|
const editor = this.editor;
|
1763
1754
|
const model = editor.model;
|
1764
1755
|
const mapper = editor.editing.mapper;
|
@@ -1777,14 +1768,14 @@ function selectionWillShrink(selection, isForward) {
|
|
1777
1768
|
return true;
|
1778
1769
|
}
|
1779
1770
|
/**
|
1780
|
-
|
1781
|
-
|
1782
|
-
|
1783
|
-
|
1784
|
-
|
1785
|
-
|
1786
|
-
|
1787
|
-
|
1771
|
+
* Handles {@link module:engine/view/document~Document#event:keydown keydown} events and changes
|
1772
|
+
* the model selection when:
|
1773
|
+
*
|
1774
|
+
* * arrow key is pressed when the widget is selected,
|
1775
|
+
* * the selection is next to a widget and the widget should become selected upon the arrow key press.
|
1776
|
+
*
|
1777
|
+
* See {@link #_preventDefaultOnArrowKeyPress}.
|
1778
|
+
*/ _handleSelectionChangeOnArrowKeyPress(eventInfo, domEventData) {
|
1788
1779
|
const keyCode = domEventData.keyCode;
|
1789
1780
|
const model = this.editor.model;
|
1790
1781
|
const schema = model.schema;
|
@@ -1839,12 +1830,12 @@ function selectionWillShrink(selection, isForward) {
|
|
1839
1830
|
}
|
1840
1831
|
}
|
1841
1832
|
/**
|
1842
|
-
|
1843
|
-
|
1844
|
-
|
1845
|
-
|
1846
|
-
|
1847
|
-
|
1833
|
+
* Handles {@link module:engine/view/document~Document#event:keydown keydown} events and prevents
|
1834
|
+
* the default browser behavior to make sure the fake selection is not being moved from a fake selection
|
1835
|
+
* container.
|
1836
|
+
*
|
1837
|
+
* See {@link #_handleSelectionChangeOnArrowKeyPress}.
|
1838
|
+
*/ _preventDefaultOnArrowKeyPress(eventInfo, domEventData) {
|
1848
1839
|
const model = this.editor.model;
|
1849
1840
|
const schema = model.schema;
|
1850
1841
|
const objectElement = model.document.selection.getSelectedElement();
|
@@ -1855,11 +1846,11 @@ function selectionWillShrink(selection, isForward) {
|
|
1855
1846
|
}
|
1856
1847
|
}
|
1857
1848
|
/**
|
1858
|
-
|
1859
|
-
|
1860
|
-
|
1861
|
-
|
1862
|
-
|
1849
|
+
* Handles delete keys: backspace and delete.
|
1850
|
+
*
|
1851
|
+
* @param isForward Set to true if delete was performed in forward direction.
|
1852
|
+
* @returns Returns `true` if keys were handled correctly.
|
1853
|
+
*/ _handleDelete(isForward) {
|
1863
1854
|
const modelDocument = this.editor.model.document;
|
1864
1855
|
const modelSelection = modelDocument.selection;
|
1865
1856
|
// Do nothing when the read only mode is enabled.
|
@@ -1886,22 +1877,22 @@ function selectionWillShrink(selection, isForward) {
|
|
1886
1877
|
}
|
1887
1878
|
}
|
1888
1879
|
/**
|
1889
|
-
|
1890
|
-
|
1891
|
-
|
1892
|
-
|
1880
|
+
* Sets {@link module:engine/model/selection~Selection document's selection} over given element.
|
1881
|
+
*
|
1882
|
+
* @internal
|
1883
|
+
*/ _setSelectionOverElement(element) {
|
1893
1884
|
this.editor.model.change((writer)=>{
|
1894
1885
|
writer.setSelection(writer.createRangeOn(element));
|
1895
1886
|
});
|
1896
1887
|
}
|
1897
1888
|
/**
|
1898
|
-
|
1899
|
-
|
1900
|
-
|
1901
|
-
|
1902
|
-
|
1903
|
-
|
1904
|
-
|
1889
|
+
* Checks if {@link module:engine/model/element~Element element} placed next to the current
|
1890
|
+
* {@link module:engine/model/selection~Selection model selection} exists and is marked in
|
1891
|
+
* {@link module:engine/model/schema~Schema schema} as `object`.
|
1892
|
+
*
|
1893
|
+
* @internal
|
1894
|
+
* @param forward Direction of checking.
|
1895
|
+
*/ _getObjectElementNextToSelection(forward) {
|
1905
1896
|
const model = this.editor.model;
|
1906
1897
|
const schema = model.schema;
|
1907
1898
|
const modelSelection = model.document.selection;
|
@@ -1922,16 +1913,16 @@ function selectionWillShrink(selection, isForward) {
|
|
1922
1913
|
return null;
|
1923
1914
|
}
|
1924
1915
|
/**
|
1925
|
-
|
1926
|
-
|
1916
|
+
* Removes CSS class from previously selected widgets.
|
1917
|
+
*/ _clearPreviouslySelectedWidgets(writer) {
|
1927
1918
|
for (const widget of this._previouslySelected){
|
1928
1919
|
writer.removeClass(WIDGET_SELECTED_CLASS_NAME, widget);
|
1929
1920
|
}
|
1930
1921
|
this._previouslySelected.clear();
|
1931
1922
|
}
|
1932
1923
|
/**
|
1933
|
-
|
1934
|
-
|
1924
|
+
* Moves the document selection into the first nested editable.
|
1925
|
+
*/ _selectFirstNestedEditable() {
|
1935
1926
|
const editor = this.editor;
|
1936
1927
|
const view = this.editor.editing.view;
|
1937
1928
|
const viewDocument = view.document;
|
@@ -1952,8 +1943,8 @@ function selectionWillShrink(selection, isForward) {
|
|
1952
1943
|
return false;
|
1953
1944
|
}
|
1954
1945
|
/**
|
1955
|
-
|
1956
|
-
|
1946
|
+
* Updates the document selection so that it selects first ancestor widget.
|
1947
|
+
*/ _selectAncestorWidget() {
|
1957
1948
|
const editor = this.editor;
|
1958
1949
|
const mapper = editor.editing.mapper;
|
1959
1950
|
const selection = editor.editing.view.document.selection;
|
@@ -2100,32 +2091,30 @@ function selectionWillShrink(selection, isForward) {
|
|
2100
2091
|
* }
|
2101
2092
|
* ```
|
2102
2093
|
*/ class WidgetToolbarRepository extends Plugin {
|
2103
|
-
constructor(){
|
2104
|
-
super(...arguments);
|
2105
|
-
/**
|
2106
|
-
* A map of toolbar definitions.
|
2107
|
-
*/ this._toolbarDefinitions = new Map();
|
2108
|
-
}
|
2109
2094
|
/**
|
2110
|
-
|
2111
|
-
|
2095
|
+
* A map of toolbar definitions.
|
2096
|
+
*/ _toolbarDefinitions = new Map();
|
2097
|
+
_balloon;
|
2098
|
+
/**
|
2099
|
+
* @inheritDoc
|
2100
|
+
*/ static get requires() {
|
2112
2101
|
return [
|
2113
2102
|
ContextualBalloon
|
2114
2103
|
];
|
2115
2104
|
}
|
2116
2105
|
/**
|
2117
|
-
|
2118
|
-
|
2106
|
+
* @inheritDoc
|
2107
|
+
*/ static get pluginName() {
|
2119
2108
|
return 'WidgetToolbarRepository';
|
2120
2109
|
}
|
2121
2110
|
/**
|
2122
|
-
|
2123
|
-
|
2111
|
+
* @inheritDoc
|
2112
|
+
*/ static get isOfficialPlugin() {
|
2124
2113
|
return true;
|
2125
2114
|
}
|
2126
2115
|
/**
|
2127
|
-
|
2128
|
-
|
2116
|
+
* @inheritDoc
|
2117
|
+
*/ init() {
|
2129
2118
|
const editor = this.editor;
|
2130
2119
|
// Disables the default balloon toolbar for all widgets.
|
2131
2120
|
if (editor.plugins.has('BalloonToolbar')) {
|
@@ -2159,35 +2148,35 @@ function selectionWillShrink(selection, isForward) {
|
|
2159
2148
|
}
|
2160
2149
|
}
|
2161
2150
|
/**
|
2162
|
-
|
2163
|
-
|
2164
|
-
|
2165
|
-
|
2166
|
-
|
2167
|
-
|
2168
|
-
|
2169
|
-
|
2170
|
-
|
2171
|
-
|
2172
|
-
|
2173
|
-
|
2174
|
-
|
2151
|
+
* Registers toolbar in the WidgetToolbarRepository. It renders it in the `ContextualBalloon` based on the value of the invoked
|
2152
|
+
* `getRelatedElement` function. Toolbar items are gathered from `items` array.
|
2153
|
+
* The balloon's CSS class is by default `ck-toolbar-container` and may be override with the `balloonClassName` option.
|
2154
|
+
*
|
2155
|
+
* Note: This method should be called in the {@link module:core/plugin~PluginInterface#afterInit `Plugin#afterInit()`}
|
2156
|
+
* callback (or later) to make sure that the given toolbar items were already registered by other plugins.
|
2157
|
+
*
|
2158
|
+
* @param toolbarId An id for the toolbar. Used to
|
2159
|
+
* @param options.ariaLabel Label used by assistive technologies to describe this toolbar element.
|
2160
|
+
* @param options.items Array of toolbar items.
|
2161
|
+
* @param options.getRelatedElement Callback which returns an element the toolbar should be attached to.
|
2162
|
+
* @param options.balloonClassName CSS class for the widget balloon.
|
2163
|
+
*/ register(toolbarId, { ariaLabel, items, getRelatedElement, balloonClassName = 'ck-toolbar-container' }) {
|
2175
2164
|
// Trying to register a toolbar without any item.
|
2176
2165
|
if (!items.length) {
|
2177
2166
|
/**
|
2178
|
-
|
2179
|
-
|
2180
|
-
|
2181
|
-
|
2182
|
-
|
2183
|
-
|
2184
|
-
|
2185
|
-
|
2186
|
-
|
2187
|
-
|
2188
|
-
|
2189
|
-
|
2190
|
-
|
2167
|
+
* When {@link module:widget/widgettoolbarrepository~WidgetToolbarRepository#register registering} a new widget toolbar, you
|
2168
|
+
* need to provide a non-empty array with the items that will be inserted into the toolbar.
|
2169
|
+
*
|
2170
|
+
* If you see this error when integrating the editor, you likely forgot to configure one of the widget toolbars.
|
2171
|
+
*
|
2172
|
+
* See for instance:
|
2173
|
+
*
|
2174
|
+
* * {@link module:table/tableconfig~TableConfig#contentToolbar `config.table.contentToolbar`}
|
2175
|
+
* * {@link module:image/imageconfig~ImageConfig#toolbar `config.image.toolbar`}
|
2176
|
+
*
|
2177
|
+
* @error widget-toolbar-no-items
|
2178
|
+
* @param toolbarId The id of the toolbar that has not been configured correctly.
|
2179
|
+
*/ logWarning('widget-toolbar-no-items', {
|
2191
2180
|
toolbarId
|
2192
2181
|
});
|
2193
2182
|
return;
|
@@ -2198,11 +2187,11 @@ function selectionWillShrink(selection, isForward) {
|
|
2198
2187
|
toolbarView.ariaLabel = ariaLabel || t('Widget toolbar');
|
2199
2188
|
if (this._toolbarDefinitions.has(toolbarId)) {
|
2200
2189
|
/**
|
2201
|
-
|
2202
|
-
|
2203
|
-
|
2204
|
-
|
2205
|
-
|
2190
|
+
* Toolbar with the given id was already added.
|
2191
|
+
*
|
2192
|
+
* @error widget-toolbar-duplicated
|
2193
|
+
* @param toolbarId Toolbar id.
|
2194
|
+
*/ throw new CKEditorError('widget-toolbar-duplicated', this, {
|
2206
2195
|
toolbarId
|
2207
2196
|
});
|
2208
2197
|
}
|
@@ -2229,8 +2218,8 @@ function selectionWillShrink(selection, isForward) {
|
|
2229
2218
|
this._toolbarDefinitions.set(toolbarId, toolbarDefinition);
|
2230
2219
|
}
|
2231
2220
|
/**
|
2232
|
-
|
2233
|
-
|
2221
|
+
* Iterates over stored toolbars and makes them visible or hidden.
|
2222
|
+
*/ _updateToolbarsVisibility() {
|
2234
2223
|
let maxRelatedElementDepth = 0;
|
2235
2224
|
let deepestRelatedElement = null;
|
2236
2225
|
let deepestToolbarDefinition = null;
|
@@ -2262,18 +2251,18 @@ function selectionWillShrink(selection, isForward) {
|
|
2262
2251
|
}
|
2263
2252
|
}
|
2264
2253
|
/**
|
2265
|
-
|
2266
|
-
|
2254
|
+
* Hides the given toolbar.
|
2255
|
+
*/ _hideToolbar(toolbarDefinition) {
|
2267
2256
|
this._balloon.remove(toolbarDefinition.view);
|
2268
2257
|
this.stopListening(this._balloon, 'change:visibleView');
|
2269
2258
|
}
|
2270
2259
|
/**
|
2271
|
-
|
2272
|
-
|
2273
|
-
|
2274
|
-
|
2275
|
-
|
2276
|
-
|
2260
|
+
* Shows up the toolbar if the toolbar is not visible.
|
2261
|
+
* Otherwise, repositions the toolbar's balloon when toolbar's view is the most top view in balloon stack.
|
2262
|
+
*
|
2263
|
+
* It might happen here that the toolbar's view is under another view. Then do nothing as the other toolbar view
|
2264
|
+
* should be still visible after the {@link module:ui/editorui/editorui~EditorUI#event:update}.
|
2265
|
+
*/ _showToolbar(toolbarDefinition, relatedElement) {
|
2277
2266
|
if (this._isToolbarVisible(toolbarDefinition)) {
|
2278
2267
|
repositionContextualBalloon(this.editor, relatedElement);
|
2279
2268
|
} else if (!this._isToolbarInBalloon(toolbarDefinition)) {
|
@@ -2337,8 +2326,38 @@ function isWidgetSelected(selection) {
|
|
2337
2326
|
* Stores the internal state of a single resizable object.
|
2338
2327
|
*/ class ResizeState extends /* #__PURE__ */ ObservableMixin() {
|
2339
2328
|
/**
|
2340
|
-
|
2341
|
-
|
2329
|
+
* The reference point of the resizer where the dragging started. It is used to measure the distance the user cursor
|
2330
|
+
* traveled, so how much the image should be enlarged.
|
2331
|
+
* This information is only known after the DOM was rendered, so it will be updated later.
|
2332
|
+
*
|
2333
|
+
* @internal
|
2334
|
+
*/ _referenceCoordinates;
|
2335
|
+
/**
|
2336
|
+
* Resizer options.
|
2337
|
+
*/ _options;
|
2338
|
+
/**
|
2339
|
+
* The original width (pixels) of the resized object when the resize process was started.
|
2340
|
+
*
|
2341
|
+
* @readonly
|
2342
|
+
*/ _originalWidth;
|
2343
|
+
/**
|
2344
|
+
* The original height (pixels) of the resized object when the resize process was started.
|
2345
|
+
*
|
2346
|
+
* @readonly
|
2347
|
+
*/ _originalHeight;
|
2348
|
+
/**
|
2349
|
+
* The original width (percents) of the resized object when the resize process was started.
|
2350
|
+
*
|
2351
|
+
* @readonly
|
2352
|
+
*/ _originalWidthPercents;
|
2353
|
+
/**
|
2354
|
+
* A width to height ratio of the resized image.
|
2355
|
+
*
|
2356
|
+
* @readonly
|
2357
|
+
*/ _aspectRatio;
|
2358
|
+
/**
|
2359
|
+
* @param options Resizer options.
|
2360
|
+
*/ constructor(options){
|
2342
2361
|
super();
|
2343
2362
|
this.set('activeHandlePosition', null);
|
2344
2363
|
this.set('proposedWidthPercents', null);
|
@@ -2350,29 +2369,29 @@ function isWidgetSelected(selection) {
|
|
2350
2369
|
this._referenceCoordinates = null;
|
2351
2370
|
}
|
2352
2371
|
/**
|
2353
|
-
|
2354
|
-
|
2372
|
+
* The original width (pixels) of the resized object when the resize process was started.
|
2373
|
+
*/ get originalWidth() {
|
2355
2374
|
return this._originalWidth;
|
2356
2375
|
}
|
2357
2376
|
/**
|
2358
|
-
|
2359
|
-
|
2377
|
+
* The original height (pixels) of the resized object when the resize process was started.
|
2378
|
+
*/ get originalHeight() {
|
2360
2379
|
return this._originalHeight;
|
2361
2380
|
}
|
2362
2381
|
/**
|
2363
|
-
|
2364
|
-
|
2382
|
+
* The original width (percents) of the resized object when the resize process was started.
|
2383
|
+
*/ get originalWidthPercents() {
|
2365
2384
|
return this._originalWidthPercents;
|
2366
2385
|
}
|
2367
2386
|
/**
|
2368
|
-
|
2369
|
-
|
2387
|
+
* A width to height ratio of the resized image.
|
2388
|
+
*/ get aspectRatio() {
|
2370
2389
|
return this._aspectRatio;
|
2371
2390
|
}
|
2372
2391
|
/**
|
2373
|
-
|
2374
|
-
|
2375
|
-
|
2392
|
+
*
|
2393
|
+
* @param domResizeHandle The handle used to calculate the reference point.
|
2394
|
+
*/ begin(domResizeHandle, domHandleHost, domResizeHost) {
|
2376
2395
|
const clientRect = new Rect(domHandleHost);
|
2377
2396
|
this.activeHandlePosition = getHandlePosition(domResizeHandle);
|
2378
2397
|
this._referenceCoordinates = getAbsoluteBoundaryPoint(domHandleHost, getOppositePosition(this.activeHandlePosition));
|
@@ -2473,12 +2492,12 @@ function isWidgetSelected(selection) {
|
|
2473
2492
|
});
|
2474
2493
|
}
|
2475
2494
|
/**
|
2476
|
-
|
2477
|
-
|
2478
|
-
|
2479
|
-
|
2480
|
-
|
2481
|
-
|
2495
|
+
* A method used for binding the `SizeView` instance properties to the `ResizeState` instance observable properties.
|
2496
|
+
*
|
2497
|
+
* @internal
|
2498
|
+
* @param options An object defining the resizer options, used for setting the proper size label.
|
2499
|
+
* @param resizeState The `ResizeState` class instance, used for keeping the `SizeView` state up to date.
|
2500
|
+
*/ _bindToState(options, resizeState) {
|
2482
2501
|
this.bind('_isVisible').to(resizeState, 'proposedWidth', resizeState, 'proposedHeight', (width, height)=>width !== null && height !== null);
|
2483
2502
|
this.bind('_label').to(resizeState, 'proposedHandleHostWidth', resizeState, 'proposedHandleHostHeight', resizeState, 'proposedWidthPercents', (width, height, widthPercents)=>{
|
2484
2503
|
if (options.unit === 'px') {
|
@@ -2491,10 +2510,10 @@ function isWidgetSelected(selection) {
|
|
2491
2510
|
(position, width, height)=>width < 50 || height < 50 ? 'above-center' : position);
|
2492
2511
|
}
|
2493
2512
|
/**
|
2494
|
-
|
2495
|
-
|
2496
|
-
|
2497
|
-
|
2513
|
+
* A method used for cleaning up. It removes the bindings and hides the view.
|
2514
|
+
*
|
2515
|
+
* @internal
|
2516
|
+
*/ _dismiss() {
|
2498
2517
|
this.unbind();
|
2499
2518
|
this._isVisible = false;
|
2500
2519
|
}
|
@@ -2504,12 +2523,26 @@ function isWidgetSelected(selection) {
|
|
2504
2523
|
* Represents a resizer for a single resizable object.
|
2505
2524
|
*/ class Resizer extends /* #__PURE__ */ ObservableMixin() {
|
2506
2525
|
/**
|
2507
|
-
|
2508
|
-
|
2526
|
+
* Stores the state of the resizable host geometry, such as the original width, the currently proposed height, etc.
|
2527
|
+
*
|
2528
|
+
* Note that a new state is created for each resize transaction.
|
2529
|
+
*/ _state;
|
2530
|
+
/**
|
2531
|
+
* A view displaying the proposed new element size during the resizing.
|
2532
|
+
*/ _sizeView;
|
2533
|
+
/**
|
2534
|
+
* Options passed to the {@link #constructor}.
|
2535
|
+
*/ _options;
|
2536
|
+
/**
|
2537
|
+
* A wrapper that is controlled by the resizer. This is usually a widget element.
|
2538
|
+
*/ _viewResizerWrapper = null;
|
2539
|
+
/**
|
2540
|
+
* The width of the resized {@link module:widget/widgetresize~ResizerOptions#viewElement viewElement} before the resizing started.
|
2541
|
+
*/ _initialViewWidth;
|
2542
|
+
/**
|
2543
|
+
* @param options Resizer options.
|
2544
|
+
*/ constructor(options){
|
2509
2545
|
super();
|
2510
|
-
/**
|
2511
|
-
* A wrapper that is controlled by the resizer. This is usually a widget element.
|
2512
|
-
*/ this._viewResizerWrapper = null;
|
2513
2546
|
this._options = options;
|
2514
2547
|
this.set('isEnabled', true);
|
2515
2548
|
this.set('isSelected', false);
|
@@ -2530,31 +2563,31 @@ function isWidgetSelected(selection) {
|
|
2530
2563
|
});
|
2531
2564
|
}
|
2532
2565
|
/**
|
2533
|
-
|
2534
|
-
|
2535
|
-
|
2536
|
-
|
2566
|
+
* Stores the state of the resizable host geometry, such as the original width, the currently proposed height, etc.
|
2567
|
+
*
|
2568
|
+
* Note that a new state is created for each resize transaction.
|
2569
|
+
*/ get state() {
|
2537
2570
|
return this._state;
|
2538
2571
|
}
|
2539
2572
|
/**
|
2540
|
-
|
2541
|
-
|
2573
|
+
* Makes resizer visible in the UI.
|
2574
|
+
*/ show() {
|
2542
2575
|
const editingView = this._options.editor.editing.view;
|
2543
2576
|
editingView.change((writer)=>{
|
2544
2577
|
writer.removeClass('ck-hidden', this._viewResizerWrapper);
|
2545
2578
|
});
|
2546
2579
|
}
|
2547
2580
|
/**
|
2548
|
-
|
2549
|
-
|
2581
|
+
* Hides resizer in the UI.
|
2582
|
+
*/ hide() {
|
2550
2583
|
const editingView = this._options.editor.editing.view;
|
2551
2584
|
editingView.change((writer)=>{
|
2552
2585
|
writer.addClass('ck-hidden', this._viewResizerWrapper);
|
2553
2586
|
});
|
2554
2587
|
}
|
2555
2588
|
/**
|
2556
|
-
|
2557
|
-
|
2589
|
+
* Attaches the resizer to the DOM.
|
2590
|
+
*/ attach() {
|
2558
2591
|
// eslint-disable-next-line @typescript-eslint/no-this-alias
|
2559
2592
|
const that = this;
|
2560
2593
|
const widgetElement = this._options.viewElement;
|
@@ -2586,23 +2619,23 @@ function isWidgetSelected(selection) {
|
|
2586
2619
|
});
|
2587
2620
|
}
|
2588
2621
|
/**
|
2589
|
-
|
2590
|
-
|
2591
|
-
|
2592
|
-
|
2593
|
-
|
2594
|
-
|
2595
|
-
|
2622
|
+
* Starts the resizing process.
|
2623
|
+
*
|
2624
|
+
* Creates a new {@link #state} for the current process.
|
2625
|
+
*
|
2626
|
+
* @fires begin
|
2627
|
+
* @param domResizeHandle Clicked handle.
|
2628
|
+
*/ begin(domResizeHandle) {
|
2596
2629
|
this._state = new ResizeState(this._options);
|
2597
2630
|
this._sizeView._bindToState(this._options, this.state);
|
2598
2631
|
this._initialViewWidth = this._options.viewElement.getStyle('width');
|
2599
2632
|
this.state.begin(domResizeHandle, this._getHandleHost(), this._getResizeHost());
|
2600
2633
|
}
|
2601
2634
|
/**
|
2602
|
-
|
2603
|
-
|
2604
|
-
|
2605
|
-
|
2635
|
+
* Updates the proposed size based on `domEventData`.
|
2636
|
+
*
|
2637
|
+
* @fires updateSize
|
2638
|
+
*/ updateSize(domEventData) {
|
2606
2639
|
const newSize = this._proposeNewSize(domEventData);
|
2607
2640
|
const editingView = this._options.editor.editing.view;
|
2608
2641
|
editingView.change((writer)=>{
|
@@ -2629,10 +2662,10 @@ function isWidgetSelected(selection) {
|
|
2629
2662
|
});
|
2630
2663
|
}
|
2631
2664
|
/**
|
2632
|
-
|
2633
|
-
|
2634
|
-
|
2635
|
-
|
2665
|
+
* Applies the geometry proposed with the resizer.
|
2666
|
+
*
|
2667
|
+
* @fires commit
|
2668
|
+
*/ commit() {
|
2636
2669
|
const unit = this._options.unit || '%';
|
2637
2670
|
const newValue = (unit === '%' ? this.state.proposedWidthPercents : this.state.proposedWidth) + unit;
|
2638
2671
|
// Both cleanup and onCommit callback are very likely to make view changes. Ensure that it is made in a single step.
|
@@ -2642,22 +2675,22 @@ function isWidgetSelected(selection) {
|
|
2642
2675
|
});
|
2643
2676
|
}
|
2644
2677
|
/**
|
2645
|
-
|
2646
|
-
|
2647
|
-
|
2648
|
-
|
2678
|
+
* Cancels and rejects the proposed resize dimensions, hiding the UI.
|
2679
|
+
*
|
2680
|
+
* @fires cancel
|
2681
|
+
*/ cancel() {
|
2649
2682
|
this._cleanup();
|
2650
2683
|
}
|
2651
2684
|
/**
|
2652
|
-
|
2653
|
-
|
2685
|
+
* Destroys the resizer.
|
2686
|
+
*/ destroy() {
|
2654
2687
|
this.cancel();
|
2655
2688
|
}
|
2656
2689
|
/**
|
2657
|
-
|
2658
|
-
|
2659
|
-
|
2660
|
-
|
2690
|
+
* Redraws the resizer.
|
2691
|
+
*
|
2692
|
+
* @param handleHostRect Handle host rectangle might be given to improve performance.
|
2693
|
+
*/ redraw(handleHostRect) {
|
2661
2694
|
const domWrapper = this._domResizerWrapper;
|
2662
2695
|
// Refresh only if resizer exists in the DOM.
|
2663
2696
|
if (!existsInDom(domWrapper)) {
|
@@ -2712,8 +2745,8 @@ function isWidgetSelected(selection) {
|
|
2712
2745
|
return domElement.classList.contains('ck-widget__resizer__handle');
|
2713
2746
|
}
|
2714
2747
|
/**
|
2715
|
-
|
2716
|
-
|
2748
|
+
* Cleans up the context state.
|
2749
|
+
*/ _cleanup() {
|
2717
2750
|
this._sizeView._dismiss();
|
2718
2751
|
const editingView = this._options.editor.editing.view;
|
2719
2752
|
editingView.change((writer)=>{
|
@@ -2721,10 +2754,10 @@ function isWidgetSelected(selection) {
|
|
2721
2754
|
});
|
2722
2755
|
}
|
2723
2756
|
/**
|
2724
|
-
|
2725
|
-
|
2726
|
-
|
2727
|
-
|
2757
|
+
* Calculates the proposed size as the resize handles are dragged.
|
2758
|
+
*
|
2759
|
+
* @param domEventData Event data that caused the size update request. It should be used to calculate the proposed size.
|
2760
|
+
*/ _proposeNewSize(domEventData) {
|
2728
2761
|
const state = this.state;
|
2729
2762
|
const currentCoordinates = extractCoordinates(domEventData);
|
2730
2763
|
const isCentered = this._options.isCentered ? this._options.isCentered(this) : true;
|
@@ -2770,37 +2803,37 @@ function isWidgetSelected(selection) {
|
|
2770
2803
|
};
|
2771
2804
|
}
|
2772
2805
|
/**
|
2773
|
-
|
2774
|
-
|
2775
|
-
|
2776
|
-
|
2806
|
+
* Obtains the resize host.
|
2807
|
+
*
|
2808
|
+
* Resize host is an object that receives dimensions which are the result of resizing.
|
2809
|
+
*/ _getResizeHost() {
|
2777
2810
|
const widgetWrapper = this._domResizerWrapper.parentElement;
|
2778
2811
|
return this._options.getResizeHost(widgetWrapper);
|
2779
2812
|
}
|
2780
2813
|
/**
|
2781
|
-
|
2782
|
-
|
2783
|
-
|
2784
|
-
|
2785
|
-
|
2786
|
-
|
2787
|
-
|
2814
|
+
* Obtains the handle host.
|
2815
|
+
*
|
2816
|
+
* Handle host is an object that the handles are aligned to.
|
2817
|
+
*
|
2818
|
+
* Handle host will not always be an entire widget itself. Take an image as an example. The image widget
|
2819
|
+
* contains an image and a caption. Only the image should be surrounded with handles.
|
2820
|
+
*/ _getHandleHost() {
|
2788
2821
|
const widgetWrapper = this._domResizerWrapper.parentElement;
|
2789
2822
|
return this._options.getHandleHost(widgetWrapper);
|
2790
2823
|
}
|
2791
2824
|
/**
|
2792
|
-
|
2793
|
-
|
2794
|
-
|
2795
|
-
|
2796
|
-
|
2825
|
+
* DOM container of the entire resize UI.
|
2826
|
+
*
|
2827
|
+
* Note that this property will have a value only after the element bound with the resizer is rendered
|
2828
|
+
* (otherwise `null`).
|
2829
|
+
*/ get _domResizerWrapper() {
|
2797
2830
|
return this._options.editor.editing.view.domConverter.mapViewToDom(this._viewResizerWrapper);
|
2798
2831
|
}
|
2799
2832
|
/**
|
2800
|
-
|
2801
|
-
|
2802
|
-
|
2803
|
-
|
2833
|
+
* Renders the resize handles in the DOM.
|
2834
|
+
*
|
2835
|
+
* @param domElement The resizer wrapper.
|
2836
|
+
*/ _appendHandles(domElement) {
|
2804
2837
|
const resizerPositions = [
|
2805
2838
|
'top-left',
|
2806
2839
|
'top-right',
|
@@ -2817,8 +2850,8 @@ function isWidgetSelected(selection) {
|
|
2817
2850
|
}
|
2818
2851
|
}
|
2819
2852
|
/**
|
2820
|
-
|
2821
|
-
|
2853
|
+
* Sets up the {@link #_sizeView} property and adds it to the passed `domElement`.
|
2854
|
+
*/ _appendSizeUI(domElement) {
|
2822
2855
|
this._sizeView = new SizeView();
|
2823
2856
|
// Make sure icon#element is rendered before passing to appendChild().
|
2824
2857
|
this._sizeView.render();
|
@@ -2846,25 +2879,24 @@ function existsInDom(element) {
|
|
2846
2879
|
*
|
2847
2880
|
* Use the {@link module:widget/widgetresize~WidgetResize#attachTo} method to create a resizer for the specified widget.
|
2848
2881
|
*/ class WidgetResize extends Plugin {
|
2849
|
-
constructor(){
|
2850
|
-
super(...arguments);
|
2851
|
-
/**
|
2852
|
-
* A map of resizers created using this plugin instance.
|
2853
|
-
*/ this._resizers = new Map();
|
2854
|
-
}
|
2855
2882
|
/**
|
2856
|
-
|
2857
|
-
|
2883
|
+
* A map of resizers created using this plugin instance.
|
2884
|
+
*/ _resizers = new Map();
|
2885
|
+
_observer;
|
2886
|
+
_redrawSelectedResizerThrottled;
|
2887
|
+
/**
|
2888
|
+
* @inheritDoc
|
2889
|
+
*/ static get pluginName() {
|
2858
2890
|
return 'WidgetResize';
|
2859
2891
|
}
|
2860
2892
|
/**
|
2861
|
-
|
2862
|
-
|
2893
|
+
* @inheritDoc
|
2894
|
+
*/ static get isOfficialPlugin() {
|
2863
2895
|
return true;
|
2864
2896
|
}
|
2865
2897
|
/**
|
2866
|
-
|
2867
|
-
|
2898
|
+
* @inheritDoc
|
2899
|
+
*/ init() {
|
2868
2900
|
const editing = this.editor.editing;
|
2869
2901
|
const domDocument = global.window.document;
|
2870
2902
|
this.set('selectedResizer', null);
|
@@ -2906,15 +2938,15 @@ function existsInDom(element) {
|
|
2906
2938
|
});
|
2907
2939
|
}
|
2908
2940
|
/**
|
2909
|
-
|
2910
|
-
|
2941
|
+
* Redraws the selected resizer if there is any selected resizer and if it is visible.
|
2942
|
+
*/ redrawSelectedResizer() {
|
2911
2943
|
if (this.selectedResizer && this.selectedResizer.isVisible) {
|
2912
2944
|
this.selectedResizer.redraw();
|
2913
2945
|
}
|
2914
2946
|
}
|
2915
2947
|
/**
|
2916
|
-
|
2917
|
-
|
2948
|
+
* @inheritDoc
|
2949
|
+
*/ destroy() {
|
2918
2950
|
super.destroy();
|
2919
2951
|
this._observer.stopListening();
|
2920
2952
|
for (const resizer of this._resizers.values()){
|
@@ -2923,23 +2955,23 @@ function existsInDom(element) {
|
|
2923
2955
|
this._redrawSelectedResizerThrottled.cancel();
|
2924
2956
|
}
|
2925
2957
|
/**
|
2926
|
-
|
2927
|
-
|
2958
|
+
* Marks resizer as selected.
|
2959
|
+
*/ select(resizer) {
|
2928
2960
|
this.deselect();
|
2929
2961
|
this.selectedResizer = resizer;
|
2930
2962
|
this.selectedResizer.isSelected = true;
|
2931
2963
|
}
|
2932
2964
|
/**
|
2933
|
-
|
2934
|
-
|
2965
|
+
* Deselects currently set resizer.
|
2966
|
+
*/ deselect() {
|
2935
2967
|
if (this.selectedResizer) {
|
2936
2968
|
this.selectedResizer.isSelected = false;
|
2937
2969
|
}
|
2938
2970
|
this.selectedResizer = null;
|
2939
2971
|
}
|
2940
2972
|
/**
|
2941
|
-
|
2942
|
-
|
2973
|
+
* @param options Resizer options.
|
2974
|
+
*/ attachTo(options) {
|
2943
2975
|
const resizer = new Resizer(options);
|
2944
2976
|
const plugins = this.editor.plugins;
|
2945
2977
|
resizer.attach();
|
@@ -2973,15 +3005,15 @@ function existsInDom(element) {
|
|
2973
3005
|
return resizer;
|
2974
3006
|
}
|
2975
3007
|
/**
|
2976
|
-
|
2977
|
-
|
2978
|
-
|
2979
|
-
|
3008
|
+
* Returns a resizer created for a given view element (widget element).
|
3009
|
+
*
|
3010
|
+
* @param viewElement View element associated with the resizer.
|
3011
|
+
*/ getResizerByViewElement(viewElement) {
|
2980
3012
|
return this._resizers.get(viewElement);
|
2981
3013
|
}
|
2982
3014
|
/**
|
2983
|
-
|
2984
|
-
|
3015
|
+
* Returns a resizer that contains a given resize handle.
|
3016
|
+
*/ _getResizerByHandle(domResizeHandle) {
|
2985
3017
|
for (const resizer of this._resizers.values()){
|
2986
3018
|
if (resizer.containsHandle(domResizeHandle)) {
|
2987
3019
|
return resizer;
|
@@ -2989,8 +3021,8 @@ function existsInDom(element) {
|
|
2989
3021
|
}
|
2990
3022
|
}
|
2991
3023
|
/**
|
2992
|
-
|
2993
|
-
|
3024
|
+
* @param domEventData Native DOM event.
|
3025
|
+
*/ _mouseDownListener(event, domEventData) {
|
2994
3026
|
const resizeHandle = domEventData.domTarget;
|
2995
3027
|
if (!Resizer.isResizeHandle(resizeHandle)) {
|
2996
3028
|
return;
|
@@ -3004,8 +3036,8 @@ function existsInDom(element) {
|
|
3004
3036
|
}
|
3005
3037
|
}
|
3006
3038
|
/**
|
3007
|
-
|
3008
|
-
|
3039
|
+
* @param domEventData Native DOM event.
|
3040
|
+
*/ _mouseMoveListener(event, domEventData) {
|
3009
3041
|
if (this._activeResizer) {
|
3010
3042
|
this._activeResizer.updateSize(domEventData);
|
3011
3043
|
}
|