qms-angular 1.0.30 → 1.0.31
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.
- package/bundles/qms-angular.umd.js +902 -496
- package/bundles/qms-angular.umd.js.map +1 -1
- package/esm2015/lib/components/breadcrumb/breadcrumb.js +39 -41
- package/esm2015/lib/components/breadcrumb/enum/dropdown-node-width.enum.js +6 -0
- package/esm2015/lib/components/button/button-toggle.js +1 -1
- package/esm2015/lib/components/dialog/constant.js +4 -2
- package/esm2015/lib/components/dialog/dialog.js +4 -4
- package/esm2015/lib/components/related/common/data-type.enum.js +2 -2
- package/esm2015/lib/components/related/common/qms-icon.const.js +21 -1
- package/esm2015/lib/components/related/common/tree.function.js +10 -5
- package/esm2015/lib/components/related/list-other-related/list-related.component.js +6 -2
- package/esm2015/lib/components/related/model/popup-data.model.js +2 -1
- package/esm2015/lib/components/related/model/related-data.model.js +1 -1
- package/esm2015/lib/components/related/model/tree-config.model.js +1 -1
- package/esm2015/lib/components/related/model/tree-node.model.js +1 -1
- package/esm2015/lib/components/related/popup/related-popup.component.js +179 -12
- package/esm2015/lib/components/related/related.module.js +7 -5
- package/esm2015/lib/components/related/risk/analysis/analysis.component.js +1 -1
- package/esm2015/lib/components/related/service/related-global.service.js +5 -1
- package/esm2015/lib/components/related/tree/tree.component.js +30 -7
- package/esm2015/lib/components/table/table-action.js +2 -2
- package/esm2015/lib/directives/scrollbar/scrollbar.directive.js +8 -2
- package/esm2015/lib/model/en.js +7 -2
- package/esm2015/lib/model/no.js +7 -2
- package/esm2015/lib/qms-ckeditor-components/common/constants/ckeditorEvent.constant.js +3 -1
- package/esm2015/lib/qms-ckeditor-components/common/models/qms-ckeditor-data.model.js +1 -1
- package/esm2015/lib/qms-ckeditor-components/common/models/qms-ckeditor-input.model.js +2 -1
- package/esm2015/lib/qms-ckeditor-components/common/module/confirm/qms-ckeditor-confirm.component.js +1 -1
- package/esm2015/lib/qms-ckeditor-components/components/qms-ckeditor-link/attachments/link-attachment.component.js +1 -1
- package/esm2015/lib/qms-ckeditor-components/components/qms-ckeditor-link/qms-ckeditor-link.component.js +1 -1
- package/esm2015/lib/qms-ckeditor-components/components/qms-ckeditor-load-template/qms-ckeditor-load-template.component.js +1 -1
- package/esm2015/lib/qms-ckeditor-components/components/qms-ckeditor-relation/qmsckeditor-related.component.js +1 -1
- package/esm2015/lib/qms-ckeditor-components/components/qms-ckeditor-template/qms-ckeditor-template.component.js +1 -1
- package/esm2015/lib/qms-ckeditor-components/components/qms-ckeditor-tooltip/qms-ckeditor-tooltip.component.js +76 -0
- package/esm2015/lib/qms-ckeditor-components/models/qms-ckeditor-tooltip.model.js +7 -0
- package/esm2015/lib/qms-ckeditor-components/qms-ckeditor.component.js +51 -2
- package/esm2015/lib/qms-ckeditor-components/qms-ckeditor.module.js +4 -2
- package/esm2015/qms-angular.js +3 -1
- package/fesm2015/qms-angular.js +864 -476
- package/fesm2015/qms-angular.js.map +1 -1
- package/lib/components/breadcrumb/breadcrumb.d.ts +1 -0
- package/lib/components/breadcrumb/enum/dropdown-node-width.enum.d.ts +4 -0
- package/lib/components/related/common/data-type.enum.d.ts +1 -1
- package/lib/components/related/common/qms-icon.const.d.ts +4 -0
- package/lib/components/related/list-other-related/list-related.component.d.ts +1 -0
- package/lib/components/related/model/popup-data.model.d.ts +1 -0
- package/lib/components/related/model/related-data.model.d.ts +4 -0
- package/lib/components/related/model/tree-config.model.d.ts +1 -0
- package/lib/components/related/model/tree-node.model.d.ts +1 -0
- package/lib/components/related/popup/related-popup.component.d.ts +18 -0
- package/lib/components/related/service/related-global.service.d.ts +2 -0
- package/lib/components/related/tree/tree.component.d.ts +7 -1
- package/lib/directives/scrollbar/scrollbar.directive.d.ts +1 -0
- package/lib/model/en.d.ts +6 -1
- package/lib/model/no.d.ts +6 -1
- package/lib/qms-ckeditor-components/common/constants/ckeditorEvent.constant.d.ts +2 -0
- package/lib/qms-ckeditor-components/common/models/qms-ckeditor-data.model.d.ts +1 -0
- package/lib/qms-ckeditor-components/common/models/qms-ckeditor-input.model.d.ts +1 -0
- package/lib/qms-ckeditor-components/components/qms-ckeditor-tooltip/qms-ckeditor-tooltip.component.d.ts +36 -0
- package/lib/qms-ckeditor-components/models/qms-ckeditor-tooltip.model.d.ts +6 -0
- package/lib/qms-ckeditor-components/qms-ckeditor.component.d.ts +6 -0
- package/package.json +1 -1
- package/qms-angular.d.ts +2 -0
- package/qms-angular.metadata.json +1 -1
- package/src/assets/qms-ckeditor-plugin/build/ckeditor.js +2 -1
- package/src/assets/qms-ckeditor-plugin/build/ckeditor.js.map +1 -1
- package/src/assets/qms-ckeditor-plugin/package-lock.json +852 -2063
- package/src/assets/qms-ckeditor-plugin/package.json +25 -19
- package/src/assets/qms-ckeditor-plugin/src/ckeditor.js +10 -2
- package/src/assets/qms-ckeditor-plugin/src/plugins/ckeditor5-find-and-replace/src/findandreplace.js +132 -0
- package/src/assets/qms-ckeditor-plugin/src/plugins/ckeditor5-find-and-replace/src/findandreplaceediting.js +315 -0
- package/src/assets/qms-ckeditor-plugin/src/plugins/ckeditor5-find-and-replace/src/findandreplaceui.js +223 -0
- package/src/assets/qms-ckeditor-plugin/src/plugins/ckeditor5-find-and-replace/src/findcommand.js +90 -0
- package/src/assets/qms-ckeditor-plugin/src/plugins/ckeditor5-find-and-replace/src/findnextcommand.js +62 -0
- package/src/assets/qms-ckeditor-plugin/src/plugins/ckeditor5-find-and-replace/src/findpreviouscommand.js +28 -0
- package/src/assets/qms-ckeditor-plugin/src/plugins/ckeditor5-find-and-replace/src/index.js +10 -0
- package/src/assets/qms-ckeditor-plugin/src/plugins/ckeditor5-find-and-replace/src/replaceallcommand.js +54 -0
- package/src/assets/qms-ckeditor-plugin/src/plugins/ckeditor5-find-and-replace/src/replacecommand.js +66 -0
- package/src/assets/qms-ckeditor-plugin/src/plugins/ckeditor5-find-and-replace/src/ui/checkboxview.js +212 -0
- package/src/assets/qms-ckeditor-plugin/src/plugins/ckeditor5-find-and-replace/src/ui/findandreplaceformview.js +546 -0
- package/src/assets/qms-ckeditor-plugin/src/plugins/ckeditor5-find-and-replace/src/utils.js +158 -0
- package/src/assets/qms-ckeditor-plugin/src/plugins/ckeditor5-find-and-replace/theme/findandreplace.css +13 -0
- package/src/assets/qms-ckeditor-plugin/src/plugins/ckeditor5-find-and-replace/theme/findandreplaceform.css +226 -0
- package/src/assets/qms-ckeditor-plugin/src/plugins/ckeditor5-find-and-replace/theme/icons/find-replace.svg +1 -0
- package/src/assets/qms-ckeditor-plugin/src/plugins/ckeditor5-special-characters/src/specialcharacters.js +4 -4
- package/src/assets/qms-ckeditor-plugin/src/plugins/ckeditor5-special-characters/src/specialcharactersarrows.js +1 -1
- package/src/assets/qms-ckeditor-plugin/src/plugins/ckeditor5-special-characters/src/specialcharacterscurrency.js +1 -1
- package/src/assets/qms-ckeditor-plugin/src/plugins/ckeditor5-special-characters/src/specialcharactersessentials.js +1 -1
- package/src/assets/qms-ckeditor-plugin/src/plugins/ckeditor5-special-characters/src/specialcharacterslatin.js +1 -1
- package/src/assets/qms-ckeditor-plugin/src/plugins/ckeditor5-special-characters/src/specialcharactersmathematical.js +1 -1
- package/src/assets/qms-ckeditor-plugin/src/plugins/ckeditor5-special-characters/src/specialcharacterstext.js +1 -1
- package/src/assets/qms-ckeditor-plugin/src/plugins/ckeditor5-special-characters/src/ui/charactergridview.js +1 -1
- package/src/assets/qms-ckeditor-plugin/src/plugins/ckeditor5-special-characters/src/ui/characterinfoview.js +1 -1
- package/src/assets/qms-ckeditor-plugin/src/plugins/ckeditor5-special-characters/src/ui/specialcharactersnavigationview.js +2 -2
- package/src/assets/qms-ckeditor-plugin/src/plugins/common/qmsCKEditorConstant.js +4 -0
- package/src/assets/qms-ckeditor-plugin/src/plugins/common/qmsCKEditorService.js +10 -0
- package/src/assets/qms-ckeditor-plugin/src/plugins/tooltip/inserttooltipcommand.js +98 -0
- package/src/assets/qms-ckeditor-plugin/src/plugins/tooltip/removetooltipcommand.js +41 -0
- package/src/assets/qms-ckeditor-plugin/src/plugins/tooltip/tooltip.js +14 -0
- package/src/assets/qms-ckeditor-plugin/src/plugins/tooltip/tooltipediting.js +280 -0
- package/src/assets/qms-ckeditor-plugin/src/plugins/tooltip/tooltipui.js +203 -0
- package/src/assets/qms-ckeditor-plugin/src/plugins/tooltip/ui/actionsview.js +95 -0
- package/src/assets/qms-ckeditor-plugin/src/plugins/tooltip/utils.js +70 -0
- package/src/assets/qms-ckeditor-plugin/src/themes/icons/information.svg +50 -0
- package/src/assets/qms-ckeditor-plugin/src/themes/tyles/tooltip.css +74 -0
- package/src/lib/components/breadcrumb/breadcrumb.scss +9 -0
- package/src/lib/components/button/button-toggle.scss +25 -1
- package/src/lib/components/dialog/dialog.scss +9 -0
- package/src/lib/components/related/popup/related-popup.component.scss +46 -0
- package/src/lib/components/table/table.scss +5 -27
- package/src/lib/qms-ckeditor-components/components/qms-ckeditor-tooltip/qms-ckeditor-tooltip.component.scss +11 -0
- package/src/lib/qms-ckeditor-components/qms-ckeditor.component.scss +29 -1
- package/src/lib/qms-ckeditor-components/styles/_modules.scss +6 -0
- package/src/themes/core/_form.scss +4 -0
- package/src/themes/core/_input.scss +8 -0
- package/src/themes/core/_scrollbar.scss +9 -2
- package/src/themes/core/_styles.scss +5 -0
- package/src/themes/core/_tab.scss +272 -6
@@ -0,0 +1,280 @@
|
|
1
|
+
import Plugin from '@ckeditor/ckeditor5-core/src/plugin';
|
2
|
+
import '../../themes/tyles/tooltip.css';
|
3
|
+
import { TOOLTIP_CUSTOM_PROPERTY, TOOLTIP_ATTRIBUTE, INSERT_TOOLTIP_COMMAND, REMOVE_TOOLTIP_COMMAND, isTyping, shouldCopyAttributes} from './utils';
|
4
|
+
import InsertTooltipCommand from './inserttooltipcommand';
|
5
|
+
import RemoveTooltipCommand from './removetooltipcommand';
|
6
|
+
import {MouseObserver} from '@ckeditor/ckeditor5-engine';
|
7
|
+
import { keyCodes } from '@ckeditor/ckeditor5-utils';
|
8
|
+
import { Input, TwoStepCaretMovement, findAttributeRange } from '@ckeditor/ckeditor5-typing';
|
9
|
+
import { ClipboardPipeline } from '@ckeditor/ckeditor5-clipboard';
|
10
|
+
|
11
|
+
export default class TooltipEditing extends Plugin {
|
12
|
+
|
13
|
+
static get pluginName() {
|
14
|
+
return 'TooltipEditing';
|
15
|
+
}
|
16
|
+
|
17
|
+
static get requires() {
|
18
|
+
// Clipboard is required for handling cut and paste events while typing over the tooltip.
|
19
|
+
return [ TwoStepCaretMovement, Input, ClipboardPipeline ];
|
20
|
+
}
|
21
|
+
|
22
|
+
init() {
|
23
|
+
const editor = this.editor;
|
24
|
+
|
25
|
+
editor.model.schema.extend('$text', { allowAttributes: TOOLTIP_ATTRIBUTE });
|
26
|
+
editor.conversion.for('upcast').elementToAttribute({
|
27
|
+
view: {
|
28
|
+
name: 'span',
|
29
|
+
attributes: {
|
30
|
+
tooltip: true
|
31
|
+
}
|
32
|
+
},
|
33
|
+
model: {
|
34
|
+
key: TOOLTIP_ATTRIBUTE,
|
35
|
+
value: viewElement => viewElement.getAttribute(TOOLTIP_ATTRIBUTE)
|
36
|
+
}
|
37
|
+
});
|
38
|
+
|
39
|
+
editor.conversion.for('downcast').attributeToElement({
|
40
|
+
model: TOOLTIP_ATTRIBUTE,
|
41
|
+
view: (modelAttributeValue, { writer: viewWriter }) =>{
|
42
|
+
const attributes = { class: 'np-tooltip'};
|
43
|
+
attributes[TOOLTIP_ATTRIBUTE] = modelAttributeValue;
|
44
|
+
|
45
|
+
const tooltipElement = viewWriter.createAttributeElement('span', attributes);
|
46
|
+
viewWriter.setCustomProperty(TOOLTIP_CUSTOM_PROPERTY, true, tooltipElement);
|
47
|
+
return tooltipElement;
|
48
|
+
}
|
49
|
+
});
|
50
|
+
|
51
|
+
editor.commands.add(INSERT_TOOLTIP_COMMAND, new InsertTooltipCommand(editor));
|
52
|
+
editor.commands.add(REMOVE_TOOLTIP_COMMAND, new RemoveTooltipCommand(editor));
|
53
|
+
|
54
|
+
// Enable two-step caret movement for `data-tooltip` attribute.
|
55
|
+
const twoStepCaretMovementPlugin = editor.plugins.get(TwoStepCaretMovement);
|
56
|
+
twoStepCaretMovementPlugin.registerAttribute(TOOLTIP_ATTRIBUTE);
|
57
|
+
|
58
|
+
// Change the attributes of the selection in certain situations after the link was inserted into the document.
|
59
|
+
this._enableInsertContentSelectionAttributesFixer();
|
60
|
+
|
61
|
+
// Handle a click at the beginning/end of a tooltip element.
|
62
|
+
this._enableClickingAtBeginingOrEndTooltip();
|
63
|
+
|
64
|
+
// Handle typing over the tooltip element.
|
65
|
+
this._enableTypingOverTooltip();
|
66
|
+
|
67
|
+
// Handle removing the content after the tooltip element.
|
68
|
+
this._handleDeleteContent();
|
69
|
+
}
|
70
|
+
|
71
|
+
_enableInsertContentSelectionAttributesFixer() {
|
72
|
+
const editor = this.editor;
|
73
|
+
const model = editor.model;
|
74
|
+
const selection = model.document.selection;
|
75
|
+
|
76
|
+
this.listenTo(model, 'insertContent', () => {
|
77
|
+
const nodeBefore = selection.anchor.nodeBefore;
|
78
|
+
const nodeAfter = selection.anchor.nodeAfter;
|
79
|
+
|
80
|
+
if (!selection.hasAttribute(TOOLTIP_ATTRIBUTE)) {
|
81
|
+
return;
|
82
|
+
}
|
83
|
+
|
84
|
+
if (!nodeBefore) {
|
85
|
+
return;
|
86
|
+
}
|
87
|
+
|
88
|
+
if (!nodeBefore.hasAttribute(TOOLTIP_ATTRIBUTE)) {
|
89
|
+
return;
|
90
|
+
}
|
91
|
+
|
92
|
+
if (nodeAfter && nodeAfter.hasAttribute(TOOLTIP_ATTRIBUTE)) {
|
93
|
+
return;
|
94
|
+
}
|
95
|
+
//console.log('_enableInsertContentSelectionAttributesFixer==>insertContent==>writer.removeSelectionAttribute(TOOLTIP_ATTRIBUTE)');
|
96
|
+
|
97
|
+
model.change(writer => {
|
98
|
+
writer.removeSelectionAttribute(TOOLTIP_ATTRIBUTE);
|
99
|
+
});
|
100
|
+
}, { priority: 'low' });
|
101
|
+
}
|
102
|
+
|
103
|
+
_enableTypingOverTooltip() {
|
104
|
+
const editor = this.editor;
|
105
|
+
const view = editor.editing.view;
|
106
|
+
|
107
|
+
// Selection attributes when started typing over the tooltip.
|
108
|
+
let selectionAttributes;
|
109
|
+
|
110
|
+
// Whether pressed `Backspace` or `Delete`. If so, attributes should not be preserved.
|
111
|
+
let deletedContent;
|
112
|
+
|
113
|
+
// Detect pressing `Backspace` / `Delete`.
|
114
|
+
|
115
|
+
this.listenTo(view.document, 'delete', () => {
|
116
|
+
deletedContent = true;
|
117
|
+
}, { priority: 'high' });
|
118
|
+
|
119
|
+
// Listening to `model#deleteContent` allows detecting whether selected content was the tooltip.
|
120
|
+
// If so, before removing the element, we will copy its attributes.
|
121
|
+
this.listenTo(editor.model, 'deleteContent', () => {
|
122
|
+
const selection = editor.model.document.selection;
|
123
|
+
|
124
|
+
// Copy attributes only if anything is selected.
|
125
|
+
if (selection.isCollapsed) {
|
126
|
+
return;
|
127
|
+
}
|
128
|
+
|
129
|
+
// When the content was deleted, do not preserve attributes.
|
130
|
+
if (deletedContent) {
|
131
|
+
deletedContent = false;
|
132
|
+
return;
|
133
|
+
}
|
134
|
+
|
135
|
+
// Enabled only when typing.
|
136
|
+
if (!isTyping(editor)) {
|
137
|
+
return;
|
138
|
+
}
|
139
|
+
|
140
|
+
if (shouldCopyAttributes(editor.model)) {
|
141
|
+
selectionAttributes = selection.getAttributes();
|
142
|
+
}
|
143
|
+
}, { priority: 'high' });
|
144
|
+
|
145
|
+
// Listening to `model#insertContent` allows detecting the content insertion.
|
146
|
+
// We want to apply attributes that were removed while typing over the tooltip.
|
147
|
+
this.listenTo(editor.model, 'insertContent', (evt, [ element ]) => {
|
148
|
+
deletedContent = false;
|
149
|
+
//console.log('_enableTypingOverTooltip==>insertContent==>isTyping(editor): ' + isTyping(editor));
|
150
|
+
|
151
|
+
// Enabled only when typing.
|
152
|
+
if (!isTyping(editor)) {
|
153
|
+
return;
|
154
|
+
}
|
155
|
+
|
156
|
+
if (!selectionAttributes) {
|
157
|
+
return;
|
158
|
+
}
|
159
|
+
//console.log('_enableTypingOverTooltip==>insertContent==>selectionAttributes: ');
|
160
|
+
//console.log(selectionAttributes);
|
161
|
+
|
162
|
+
editor.model.change(writer => {
|
163
|
+
for (const [ attribute, value ] of selectionAttributes) {
|
164
|
+
writer.setAttribute(attribute, value, element);
|
165
|
+
}
|
166
|
+
});
|
167
|
+
|
168
|
+
selectionAttributes = null;
|
169
|
+
}, { priority: 'high' });
|
170
|
+
}
|
171
|
+
|
172
|
+
_enableClickingAtBeginingOrEndTooltip() {
|
173
|
+
const editor = this.editor;
|
174
|
+
const selection = editor.model.document.selection;
|
175
|
+
editor.editing.view.addObserver(MouseObserver);
|
176
|
+
let clicked = false;
|
177
|
+
|
178
|
+
// Detect the click.
|
179
|
+
this.listenTo(editor.editing.view.document, 'mousedown', () => {
|
180
|
+
clicked = true;
|
181
|
+
});
|
182
|
+
|
183
|
+
// When the selection has changed...
|
184
|
+
this.listenTo(editor.editing.view.document, 'selectionChange', () => {
|
185
|
+
|
186
|
+
if (!clicked) {
|
187
|
+
return;
|
188
|
+
}
|
189
|
+
|
190
|
+
// ...and it was caused by the click...
|
191
|
+
clicked = false;
|
192
|
+
|
193
|
+
// ...and no text is selected...
|
194
|
+
if (!selection.isCollapsed) {
|
195
|
+
return;
|
196
|
+
}
|
197
|
+
|
198
|
+
//console.log('_enableClickingAtBeginingOrEndTooltip==>selectionChange==>selection.hasAttribute(TOOLTIP_ATTRIBUTE): ' + selection.hasAttribute(TOOLTIP_ATTRIBUTE));
|
199
|
+
// ...and clicked text is the tooltip...
|
200
|
+
if (!selection.hasAttribute(TOOLTIP_ATTRIBUTE)) {
|
201
|
+
return;
|
202
|
+
}
|
203
|
+
|
204
|
+
const position = selection.getFirstPosition();
|
205
|
+
const selectedRange = findAttributeRange(position, TOOLTIP_ATTRIBUTE, selection.getAttribute(TOOLTIP_ATTRIBUTE), editor.model);
|
206
|
+
|
207
|
+
// ...check whether clicked start/end boundary of the tooltip.
|
208
|
+
// If so, remove the `tooltip` attribute.
|
209
|
+
const isTouching = position.isTouching(selectedRange.start) || position.isTouching(selectedRange.end);
|
210
|
+
//console.log('_enableClickingAtBeginingOrEndTooltip==>selectionChange==>isTouching: ' + isTouching);
|
211
|
+
if (isTouching) {
|
212
|
+
editor.model.change(writer => {
|
213
|
+
writer.removeSelectionAttribute(TOOLTIP_ATTRIBUTE);
|
214
|
+
});
|
215
|
+
}
|
216
|
+
});
|
217
|
+
}
|
218
|
+
|
219
|
+
_handleDeleteContent() {
|
220
|
+
const editor = this.editor;
|
221
|
+
const model = editor.model;
|
222
|
+
const selection = model.document.selection;
|
223
|
+
const view = editor.editing.view;
|
224
|
+
|
225
|
+
// A flag whether attributes `tooltip` attribute should be preserved.
|
226
|
+
let shouldPreserveAttributes = false;
|
227
|
+
|
228
|
+
// A flag whether the `Backspace` key was pressed.
|
229
|
+
let hasBackspacePressed = false;
|
230
|
+
|
231
|
+
// Detect pressing `Backspace`.
|
232
|
+
this.listenTo(view.document, 'delete', (evt, data) => {
|
233
|
+
hasBackspacePressed = data.domEvent.keyCode === keyCodes.backspace;
|
234
|
+
}, { priority: 'high' });
|
235
|
+
|
236
|
+
// Before removing the content, check whether the selection is inside a tooltip or at the end of tooltip but with 2-SCM enabled.
|
237
|
+
// If so, we want to preserve tooltip attributes.
|
238
|
+
this.listenTo(model, 'deleteContent', () => {
|
239
|
+
// Reset the state.
|
240
|
+
shouldPreserveAttributes = false;
|
241
|
+
|
242
|
+
const position = selection.getFirstPosition();
|
243
|
+
const tooltip = selection.getAttribute(TOOLTIP_ATTRIBUTE);
|
244
|
+
|
245
|
+
if (!tooltip) {
|
246
|
+
return;
|
247
|
+
}
|
248
|
+
|
249
|
+
const selectedRange = findAttributeRange(position, TOOLTIP_ATTRIBUTE, tooltip, model);
|
250
|
+
|
251
|
+
// Preserve `tooltip` attribute if the selection is in the middle of the tooltip or
|
252
|
+
// the selection is at the end of the tooltip and 2-SCM is activated.
|
253
|
+
shouldPreserveAttributes = selectedRange.containsPosition(position) || selectedRange.end.isEqual(position);
|
254
|
+
}, { priority: 'high' });
|
255
|
+
|
256
|
+
// After removing the content, check whether the current selection should preserve the `tooltip` attribute.
|
257
|
+
this.listenTo(model, 'deleteContent', () => {
|
258
|
+
// If didn't press `Backspace`.
|
259
|
+
if (!hasBackspacePressed) {
|
260
|
+
return;
|
261
|
+
}
|
262
|
+
|
263
|
+
//console.log('_handleDeleteContent==>deleteContent==>shouldPreserveAttributes: ' + shouldPreserveAttributes);
|
264
|
+
|
265
|
+
hasBackspacePressed = false;
|
266
|
+
|
267
|
+
// Disable the mechanism if inside a tooltip (`<$text url="foo">F[]oo</$text>` or <$text url="foo">Foo[]</$text>`).
|
268
|
+
if (shouldPreserveAttributes) {
|
269
|
+
return;
|
270
|
+
}
|
271
|
+
|
272
|
+
// Use `model.enqueueChange()` in order to execute the callback at the end of the changes process.
|
273
|
+
editor.model.enqueueChange(writer => {
|
274
|
+
writer.removeSelectionAttribute(TOOLTIP_ATTRIBUTE);
|
275
|
+
});
|
276
|
+
}, { priority: 'low' });
|
277
|
+
}
|
278
|
+
|
279
|
+
}
|
280
|
+
|
@@ -0,0 +1,203 @@
|
|
1
|
+
|
2
|
+
import Plugin from '@ckeditor/ckeditor5-core/src/plugin';
|
3
|
+
import informationIcon from '../../themes/icons/information.svg';
|
4
|
+
import * as QMSCKEditorConstant from '../common/qmsCKEditorConstant';
|
5
|
+
import * as QMSCKEditorService from '../common/qmsCKEditorService';
|
6
|
+
import ActionsView from './ui/actionsview';
|
7
|
+
import { ClickObserver } from '@ckeditor/ckeditor5-engine';
|
8
|
+
import { ButtonView, ContextualBalloon, clickOutsideHandler } from '@ckeditor/ckeditor5-ui';
|
9
|
+
import { TOOLTIP_ATTRIBUTE, findTooltipElementAncestor, getSelectionParent, INSERT_TOOLTIP_COMMAND, REMOVE_TOOLTIP_COMMAND} from './utils';
|
10
|
+
|
11
|
+
export default class TooltipUI extends Plugin {
|
12
|
+
static get requires() {
|
13
|
+
return [ContextualBalloon];
|
14
|
+
}
|
15
|
+
|
16
|
+
static get pluginName() {
|
17
|
+
return 'TooltipUI';
|
18
|
+
}
|
19
|
+
|
20
|
+
get _isVisible() {
|
21
|
+
return this._balloon.visibleView === this._actionView;
|
22
|
+
}
|
23
|
+
|
24
|
+
get _isInBalloon() {
|
25
|
+
return this._balloon.hasView(this._actionView);
|
26
|
+
}
|
27
|
+
|
28
|
+
init() {
|
29
|
+
const editor = this.editor;
|
30
|
+
const t = editor.t;
|
31
|
+
const view = editor.editing.view;
|
32
|
+
|
33
|
+
view.addObserver(ClickObserver);
|
34
|
+
this._createActionsView();
|
35
|
+
|
36
|
+
editor.ui.componentFactory.add('tooltip', locale => {
|
37
|
+
const buttonView = new ButtonView(locale);
|
38
|
+
|
39
|
+
buttonView.set({
|
40
|
+
label: t('Tooltip'),
|
41
|
+
icon: informationIcon,
|
42
|
+
withText: true,
|
43
|
+
tooltip: true
|
44
|
+
});
|
45
|
+
|
46
|
+
// Bind button to the command.
|
47
|
+
const insertTooltipCommand = editor.commands.get(INSERT_TOOLTIP_COMMAND);
|
48
|
+
buttonView.bind('isEnabled').to(insertTooltipCommand, 'isEnabled' );
|
49
|
+
buttonView.bind('isOn').to(insertTooltipCommand, 'value', value => !!value );
|
50
|
+
|
51
|
+
buttonView.on('execute', () => {
|
52
|
+
editor.execute(INSERT_TOOLTIP_COMMAND);
|
53
|
+
});
|
54
|
+
|
55
|
+
return buttonView;
|
56
|
+
});
|
57
|
+
}
|
58
|
+
|
59
|
+
destroy() {
|
60
|
+
super.destroy();
|
61
|
+
this._actionView.destroy();
|
62
|
+
}
|
63
|
+
|
64
|
+
_createActionsView() {
|
65
|
+
const editor = this.editor;
|
66
|
+
const view = editor.editing.view;
|
67
|
+
const viewDocument = view.document;
|
68
|
+
this._balloon = this.editor.plugins.get('ContextualBalloon');
|
69
|
+
this._actionView = new ActionsView(editor.locale);
|
70
|
+
|
71
|
+
const insertTooltipCommand = editor.commands.get(INSERT_TOOLTIP_COMMAND);
|
72
|
+
const removeTooltipCommand = editor.commands.get(REMOVE_TOOLTIP_COMMAND);
|
73
|
+
|
74
|
+
this._actionView.bind(TOOLTIP_ATTRIBUTE).to( insertTooltipCommand, 'value');
|
75
|
+
this._actionView.editButtonView.bind('isEnabled').to(insertTooltipCommand);
|
76
|
+
this._actionView.removeButtonView.bind('isEnabled').to(removeTooltipCommand);
|
77
|
+
|
78
|
+
this.listenTo(this._actionView, 'edit', () => {
|
79
|
+
const tooltip = { text: '', content: '' };
|
80
|
+
const selectedElement = this._getSelectedTooltipElement();
|
81
|
+
if(selectedElement){
|
82
|
+
tooltip.content = selectedElement.getAttribute(TOOLTIP_ATTRIBUTE);
|
83
|
+
if(selectedElement.childCount > 0){
|
84
|
+
tooltip.text = selectedElement.getChild(0).data;
|
85
|
+
}
|
86
|
+
}
|
87
|
+
QMSCKEditorService.tooltipNotify(tooltip);
|
88
|
+
window[QMSCKEditorConstant.QMSCK_TOOLTIP_IS_PROCESSING] = false;
|
89
|
+
this._hideActionsView(true);
|
90
|
+
});
|
91
|
+
|
92
|
+
this.listenTo(this._actionView, 'remove', () => {
|
93
|
+
editor.execute(REMOVE_TOOLTIP_COMMAND);
|
94
|
+
this._hideActionsView(true);
|
95
|
+
});
|
96
|
+
|
97
|
+
this._actionView.keystrokes.set('Esc', (data, cancel) => {
|
98
|
+
this._hideActionsView(true);
|
99
|
+
cancel();
|
100
|
+
});
|
101
|
+
|
102
|
+
this.listenTo(viewDocument, 'click', () => {
|
103
|
+
const selectedElement = this._getSelectedTooltipElement();
|
104
|
+
if (!!selectedElement) {
|
105
|
+
// Then show panel but keep focus inside editor editable.
|
106
|
+
this._showActionsView();
|
107
|
+
}
|
108
|
+
});
|
109
|
+
|
110
|
+
// Close on click outside of balloon panel element.
|
111
|
+
clickOutsideHandler({
|
112
|
+
emitter: this._actionView,
|
113
|
+
activator: () => this._isVisible,
|
114
|
+
contextElements: [ this._balloon.view.element ],
|
115
|
+
callback: () => this._hideActionsView()
|
116
|
+
});
|
117
|
+
}
|
118
|
+
|
119
|
+
_showActionsView() {
|
120
|
+
if (this._isVisible) {
|
121
|
+
return;
|
122
|
+
}
|
123
|
+
const editor = this.editor;
|
124
|
+
const viewDocument = editor.editing.view.document;
|
125
|
+
//const command = editor.commands.get('imageTextAlternative');
|
126
|
+
//const labeledInput = this._actionView.labeledInput;
|
127
|
+
|
128
|
+
if (!this._isInBalloon) {
|
129
|
+
this._balloon.add({
|
130
|
+
view: this._actionView,
|
131
|
+
position: this._getBalloonPositionData()
|
132
|
+
});
|
133
|
+
}
|
134
|
+
|
135
|
+
// Reposition the balloon or hide the form if an tooltip is no longer selected.
|
136
|
+
const prevSelectedElement = this._getSelectedTooltipElement();
|
137
|
+
const prevSelectionParent = getSelectionParent(viewDocument);
|
138
|
+
|
139
|
+
this.listenTo(editor.ui, 'update', () => {
|
140
|
+
const selectedElement = this._getSelectedTooltipElement();
|
141
|
+
const selectionParent = getSelectionParent(viewDocument);
|
142
|
+
|
143
|
+
if ((prevSelectedElement && !selectedElement) || (!prevSelectedElement && selectionParent !== prevSelectionParent)) {
|
144
|
+
this._hideActionsView(true);
|
145
|
+
}
|
146
|
+
else if (this._isVisible)
|
147
|
+
{
|
148
|
+
this._balloon.updatePosition(this._getBalloonPositionData());
|
149
|
+
}
|
150
|
+
});
|
151
|
+
}
|
152
|
+
|
153
|
+
_getBalloonPositionData() {
|
154
|
+
const editingView = this.editor.editing.view;
|
155
|
+
const selectedElement = this._getSelectedTooltipElement();
|
156
|
+
return {
|
157
|
+
target: editingView.domConverter.viewToDom(selectedElement)
|
158
|
+
};
|
159
|
+
}
|
160
|
+
|
161
|
+
_hideActionsView(focusEditable) {
|
162
|
+
if (!this._isInBalloon) {
|
163
|
+
return;
|
164
|
+
}
|
165
|
+
|
166
|
+
if (this._actionView.focusTracker.isFocused) {
|
167
|
+
this._actionView.removeButtonView.focus();
|
168
|
+
}
|
169
|
+
this.stopListening(this.editor.ui, 'update');
|
170
|
+
this._balloon.remove(this._actionView);
|
171
|
+
|
172
|
+
if (focusEditable) {
|
173
|
+
this.editor.editing.view.focus();
|
174
|
+
}
|
175
|
+
}
|
176
|
+
|
177
|
+
_getSelectedTooltipElement() {
|
178
|
+
const view = this.editor.editing.view;
|
179
|
+
const selection = view.document.selection;
|
180
|
+
if (selection.isCollapsed) {
|
181
|
+
return findTooltipElementAncestor(selection.getFirstPosition());
|
182
|
+
}
|
183
|
+
else {
|
184
|
+
// The range for fully selected link is usually anchored in adjacent text nodes.
|
185
|
+
// Trim it to get closer to the actual link element.
|
186
|
+
const range = selection.getFirstRange().getTrimmed();
|
187
|
+
const startTooltip = findTooltipElementAncestor(range.start);
|
188
|
+
const endTooltip = findTooltipElementAncestor(range.end);
|
189
|
+
if (!startTooltip || startTooltip != endTooltip) {
|
190
|
+
return null;
|
191
|
+
}
|
192
|
+
|
193
|
+
// Check if the link element is fully selected.
|
194
|
+
if (view.createRangeIn(startTooltip).getTrimmed().isEqual(range)) {
|
195
|
+
return startTooltip;
|
196
|
+
}
|
197
|
+
else {
|
198
|
+
return null;
|
199
|
+
}
|
200
|
+
}
|
201
|
+
}
|
202
|
+
}
|
203
|
+
|
@@ -0,0 +1,95 @@
|
|
1
|
+
import { ButtonView, View, ViewCollection, FocusCycler } from '@ckeditor/ckeditor5-ui';
|
2
|
+
import { FocusTracker, KeystrokeHandler } from '@ckeditor/ckeditor5-utils';
|
3
|
+
import { icons } from '@ckeditor/ckeditor5-core';
|
4
|
+
import '@ckeditor/ckeditor5-ui/theme/components/responsive-form/responsiveform.css';
|
5
|
+
import '../../../themes/tyles/linkactions.css';
|
6
|
+
import { TOOLTIP_ATTRIBUTE } from '../utils';
|
7
|
+
export default class ActionsView extends View {
|
8
|
+
constructor( locale ) {
|
9
|
+
super( locale );
|
10
|
+
|
11
|
+
const t = locale.t;
|
12
|
+
|
13
|
+
this.focusTracker = new FocusTracker();
|
14
|
+
|
15
|
+
this.keystrokes = new KeystrokeHandler();
|
16
|
+
|
17
|
+
this.removeButtonView = this._createButton(t('Remove tooltip'), icons.eraser, 'remove');
|
18
|
+
|
19
|
+
this.editButtonView = this._createButton(t('Edit tooltip'), icons.pencil, 'edit');
|
20
|
+
|
21
|
+
this.set(TOOLTIP_ATTRIBUTE);
|
22
|
+
|
23
|
+
this._focusables = new ViewCollection();
|
24
|
+
|
25
|
+
this._focusCycler = new FocusCycler( {
|
26
|
+
focusables: this._focusables,
|
27
|
+
focusTracker: this.focusTracker,
|
28
|
+
keystrokeHandler: this.keystrokes,
|
29
|
+
actions: {
|
30
|
+
// Navigate fields backwards using the Shift + Tab keystroke.
|
31
|
+
focusPrevious: 'shift + tab',
|
32
|
+
// Navigate fields forwards using the Tab key.
|
33
|
+
focusNext: 'tab'
|
34
|
+
}
|
35
|
+
} );
|
36
|
+
|
37
|
+
this.setTemplate( {
|
38
|
+
tag: 'div',
|
39
|
+
|
40
|
+
attributes: {
|
41
|
+
class: [
|
42
|
+
'ck',
|
43
|
+
'ck-link-actions',
|
44
|
+
'ck-responsive-form'
|
45
|
+
],
|
46
|
+
// https://github.com/ckeditor/ckeditor5-link/issues/90
|
47
|
+
tabindex: '-1'
|
48
|
+
},
|
49
|
+
|
50
|
+
children: [
|
51
|
+
this.editButtonView,
|
52
|
+
this.removeButtonView
|
53
|
+
]
|
54
|
+
} );
|
55
|
+
}
|
56
|
+
|
57
|
+
render() {
|
58
|
+
super.render();
|
59
|
+
|
60
|
+
const childViews = [
|
61
|
+
this.editButtonView,
|
62
|
+
this.removeButtonView
|
63
|
+
];
|
64
|
+
|
65
|
+
childViews.forEach( v => {
|
66
|
+
// Register the view as focusable.
|
67
|
+
this._focusables.add( v );
|
68
|
+
|
69
|
+
// Register the view in the focus tracker.
|
70
|
+
this.focusTracker.add( v.element );
|
71
|
+
} );
|
72
|
+
|
73
|
+
// Start listening for the keystrokes coming from #element.
|
74
|
+
this.keystrokes.listenTo( this.element );
|
75
|
+
}
|
76
|
+
|
77
|
+
focus() {
|
78
|
+
this._focusCycler.focusFirst();
|
79
|
+
}
|
80
|
+
|
81
|
+
_createButton( label, icon, eventName ) {
|
82
|
+
const button = new ButtonView( this.locale );
|
83
|
+
|
84
|
+
button.set( {
|
85
|
+
label,
|
86
|
+
icon,
|
87
|
+
tooltip: true
|
88
|
+
} );
|
89
|
+
|
90
|
+
button.delegate('execute').to(this, eventName);
|
91
|
+
|
92
|
+
return button;
|
93
|
+
}
|
94
|
+
}
|
95
|
+
|
@@ -0,0 +1,70 @@
|
|
1
|
+
|
2
|
+
export const TOOLTIP_CUSTOM_PROPERTY = 'tooltip';
|
3
|
+
export const TOOLTIP_ATTRIBUTE = 'data-tooltip';
|
4
|
+
export const INSERT_TOOLTIP_COMMAND = 'inserttooltip';
|
5
|
+
export const REMOVE_TOOLTIP_COMMAND = 'removetooltip';
|
6
|
+
|
7
|
+
export function isTooltipElement(node) {
|
8
|
+
return node.is('attributeElement') && !!node.getCustomProperty(TOOLTIP_CUSTOM_PROPERTY);
|
9
|
+
}
|
10
|
+
|
11
|
+
export function findTooltipElementAncestor(position) {
|
12
|
+
return position.getAncestors().find(ancestor => isTooltipElement(ancestor));
|
13
|
+
}
|
14
|
+
|
15
|
+
export function isTooltipAllowed(element, schema) {
|
16
|
+
if (!element) {
|
17
|
+
return false;
|
18
|
+
}
|
19
|
+
return element.is('element', 'span') && schema.checkAttribute('span', TOOLTIP_ATTRIBUTE);
|
20
|
+
}
|
21
|
+
|
22
|
+
export function getSelectionParent(viewDocument) {
|
23
|
+
return viewDocument.selection.focus.getAncestors()
|
24
|
+
.reverse()
|
25
|
+
.find(node => node.is('element'));
|
26
|
+
}
|
27
|
+
|
28
|
+
export function isTyping(editor) {
|
29
|
+
const input = editor.plugins.get('Input');
|
30
|
+
return input.isInput(editor.model.change(writer => writer.batch));
|
31
|
+
}
|
32
|
+
|
33
|
+
|
34
|
+
export function shouldCopyAttributes(model) {
|
35
|
+
const selection = model.document.selection;
|
36
|
+
const firstPosition = selection.getFirstPosition();
|
37
|
+
const lastPosition = selection.getLastPosition();
|
38
|
+
const nodeAtFirstPosition = firstPosition.nodeAfter;
|
39
|
+
|
40
|
+
// The text tooltip node does not exist...
|
41
|
+
if (!nodeAtFirstPosition) {
|
42
|
+
return false;
|
43
|
+
}
|
44
|
+
|
45
|
+
// ...or it isn't the text node...
|
46
|
+
if (!nodeAtFirstPosition.is('$text')) {
|
47
|
+
return false;
|
48
|
+
}
|
49
|
+
|
50
|
+
// ...or isn't the tooltip.
|
51
|
+
if (!nodeAtFirstPosition.hasAttribute(TOOLTIP_ATTRIBUTE)) {
|
52
|
+
return false;
|
53
|
+
}
|
54
|
+
|
55
|
+
// `textNode` = the position is inside the tooltip element.
|
56
|
+
// `nodeBefore` = the position is at the end of the tooltip element.
|
57
|
+
const nodeAtLastPosition = lastPosition.textNode || lastPosition.nodeBefore;
|
58
|
+
|
59
|
+
// If both references the same node selection contains a single text node.
|
60
|
+
if (nodeAtFirstPosition === nodeAtLastPosition) {
|
61
|
+
return true;
|
62
|
+
}
|
63
|
+
|
64
|
+
// If nodes are not equal, maybe the tooltip nodes has defined additional attributes inside.
|
65
|
+
// First, we need to find the entire tooltip range.
|
66
|
+
const tooltipRange = findAttributeRange(firstPosition, TOOLTIP_ATTRIBUTE, nodeAtFirstPosition.getAttribute(TOOLTIP_ATTRIBUTE), model);
|
67
|
+
|
68
|
+
// Then we can check whether selected range is inside the found tooltip range. If so, attributes should be preserved.
|
69
|
+
return tooltipRange.containsRange(model.createRange(firstPosition, lastPosition) , true);
|
70
|
+
}
|
@@ -0,0 +1,50 @@
|
|
1
|
+
<?xml version="1.0" encoding="iso-8859-1"?>
|
2
|
+
<!-- Generator: Adobe Illustrator 19.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
|
3
|
+
<svg version="1.1" id="Capa_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
|
4
|
+
viewBox="0 0 512 512" style="enable-background:new 0 0 512 512;" xml:space="preserve">
|
5
|
+
<g>
|
6
|
+
<g>
|
7
|
+
<g>
|
8
|
+
<path d="M256,85.333c-23.531,0-42.667,19.135-42.667,42.667s19.135,42.667,42.667,42.667s42.667-19.135,42.667-42.667
|
9
|
+
S279.531,85.333,256,85.333z M256,149.333c-11.76,0-21.333-9.573-21.333-21.333s9.573-21.333,21.333-21.333
|
10
|
+
s21.333,9.573,21.333,21.333S267.76,149.333,256,149.333z"/>
|
11
|
+
<path d="M288,192h-85.333c-5.896,0-10.667,4.771-10.667,10.667v42.667c0,5.896,4.771,10.667,10.667,10.667h10.667v160
|
12
|
+
c0,5.896,4.771,10.667,10.667,10.667h64c5.896,0,10.667-4.771,10.667-10.667V202.667C298.667,196.771,293.896,192,288,192z
|
13
|
+
M277.333,405.333h-42.667v-160c0-5.896-4.771-10.667-10.667-10.667h-10.667v-21.333h64V405.333z"/>
|
14
|
+
<path d="M256,0C114.844,0,0,114.844,0,256s114.844,256,256,256s256-114.844,256-256S397.156,0,256,0z M256,490.667
|
15
|
+
C126.604,490.667,21.333,385.396,21.333,256S126.604,21.333,256,21.333S490.667,126.604,490.667,256S385.396,490.667,256,490.667
|
16
|
+
z"/>
|
17
|
+
</g>
|
18
|
+
</g>
|
19
|
+
</g>
|
20
|
+
<g>
|
21
|
+
</g>
|
22
|
+
<g>
|
23
|
+
</g>
|
24
|
+
<g>
|
25
|
+
</g>
|
26
|
+
<g>
|
27
|
+
</g>
|
28
|
+
<g>
|
29
|
+
</g>
|
30
|
+
<g>
|
31
|
+
</g>
|
32
|
+
<g>
|
33
|
+
</g>
|
34
|
+
<g>
|
35
|
+
</g>
|
36
|
+
<g>
|
37
|
+
</g>
|
38
|
+
<g>
|
39
|
+
</g>
|
40
|
+
<g>
|
41
|
+
</g>
|
42
|
+
<g>
|
43
|
+
</g>
|
44
|
+
<g>
|
45
|
+
</g>
|
46
|
+
<g>
|
47
|
+
</g>
|
48
|
+
<g>
|
49
|
+
</g>
|
50
|
+
</svg>
|