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.
Files changed (118) hide show
  1. package/bundles/qms-angular.umd.js +902 -496
  2. package/bundles/qms-angular.umd.js.map +1 -1
  3. package/esm2015/lib/components/breadcrumb/breadcrumb.js +39 -41
  4. package/esm2015/lib/components/breadcrumb/enum/dropdown-node-width.enum.js +6 -0
  5. package/esm2015/lib/components/button/button-toggle.js +1 -1
  6. package/esm2015/lib/components/dialog/constant.js +4 -2
  7. package/esm2015/lib/components/dialog/dialog.js +4 -4
  8. package/esm2015/lib/components/related/common/data-type.enum.js +2 -2
  9. package/esm2015/lib/components/related/common/qms-icon.const.js +21 -1
  10. package/esm2015/lib/components/related/common/tree.function.js +10 -5
  11. package/esm2015/lib/components/related/list-other-related/list-related.component.js +6 -2
  12. package/esm2015/lib/components/related/model/popup-data.model.js +2 -1
  13. package/esm2015/lib/components/related/model/related-data.model.js +1 -1
  14. package/esm2015/lib/components/related/model/tree-config.model.js +1 -1
  15. package/esm2015/lib/components/related/model/tree-node.model.js +1 -1
  16. package/esm2015/lib/components/related/popup/related-popup.component.js +179 -12
  17. package/esm2015/lib/components/related/related.module.js +7 -5
  18. package/esm2015/lib/components/related/risk/analysis/analysis.component.js +1 -1
  19. package/esm2015/lib/components/related/service/related-global.service.js +5 -1
  20. package/esm2015/lib/components/related/tree/tree.component.js +30 -7
  21. package/esm2015/lib/components/table/table-action.js +2 -2
  22. package/esm2015/lib/directives/scrollbar/scrollbar.directive.js +8 -2
  23. package/esm2015/lib/model/en.js +7 -2
  24. package/esm2015/lib/model/no.js +7 -2
  25. package/esm2015/lib/qms-ckeditor-components/common/constants/ckeditorEvent.constant.js +3 -1
  26. package/esm2015/lib/qms-ckeditor-components/common/models/qms-ckeditor-data.model.js +1 -1
  27. package/esm2015/lib/qms-ckeditor-components/common/models/qms-ckeditor-input.model.js +2 -1
  28. package/esm2015/lib/qms-ckeditor-components/common/module/confirm/qms-ckeditor-confirm.component.js +1 -1
  29. package/esm2015/lib/qms-ckeditor-components/components/qms-ckeditor-link/attachments/link-attachment.component.js +1 -1
  30. package/esm2015/lib/qms-ckeditor-components/components/qms-ckeditor-link/qms-ckeditor-link.component.js +1 -1
  31. package/esm2015/lib/qms-ckeditor-components/components/qms-ckeditor-load-template/qms-ckeditor-load-template.component.js +1 -1
  32. package/esm2015/lib/qms-ckeditor-components/components/qms-ckeditor-relation/qmsckeditor-related.component.js +1 -1
  33. package/esm2015/lib/qms-ckeditor-components/components/qms-ckeditor-template/qms-ckeditor-template.component.js +1 -1
  34. package/esm2015/lib/qms-ckeditor-components/components/qms-ckeditor-tooltip/qms-ckeditor-tooltip.component.js +76 -0
  35. package/esm2015/lib/qms-ckeditor-components/models/qms-ckeditor-tooltip.model.js +7 -0
  36. package/esm2015/lib/qms-ckeditor-components/qms-ckeditor.component.js +51 -2
  37. package/esm2015/lib/qms-ckeditor-components/qms-ckeditor.module.js +4 -2
  38. package/esm2015/qms-angular.js +3 -1
  39. package/fesm2015/qms-angular.js +864 -476
  40. package/fesm2015/qms-angular.js.map +1 -1
  41. package/lib/components/breadcrumb/breadcrumb.d.ts +1 -0
  42. package/lib/components/breadcrumb/enum/dropdown-node-width.enum.d.ts +4 -0
  43. package/lib/components/related/common/data-type.enum.d.ts +1 -1
  44. package/lib/components/related/common/qms-icon.const.d.ts +4 -0
  45. package/lib/components/related/list-other-related/list-related.component.d.ts +1 -0
  46. package/lib/components/related/model/popup-data.model.d.ts +1 -0
  47. package/lib/components/related/model/related-data.model.d.ts +4 -0
  48. package/lib/components/related/model/tree-config.model.d.ts +1 -0
  49. package/lib/components/related/model/tree-node.model.d.ts +1 -0
  50. package/lib/components/related/popup/related-popup.component.d.ts +18 -0
  51. package/lib/components/related/service/related-global.service.d.ts +2 -0
  52. package/lib/components/related/tree/tree.component.d.ts +7 -1
  53. package/lib/directives/scrollbar/scrollbar.directive.d.ts +1 -0
  54. package/lib/model/en.d.ts +6 -1
  55. package/lib/model/no.d.ts +6 -1
  56. package/lib/qms-ckeditor-components/common/constants/ckeditorEvent.constant.d.ts +2 -0
  57. package/lib/qms-ckeditor-components/common/models/qms-ckeditor-data.model.d.ts +1 -0
  58. package/lib/qms-ckeditor-components/common/models/qms-ckeditor-input.model.d.ts +1 -0
  59. package/lib/qms-ckeditor-components/components/qms-ckeditor-tooltip/qms-ckeditor-tooltip.component.d.ts +36 -0
  60. package/lib/qms-ckeditor-components/models/qms-ckeditor-tooltip.model.d.ts +6 -0
  61. package/lib/qms-ckeditor-components/qms-ckeditor.component.d.ts +6 -0
  62. package/package.json +1 -1
  63. package/qms-angular.d.ts +2 -0
  64. package/qms-angular.metadata.json +1 -1
  65. package/src/assets/qms-ckeditor-plugin/build/ckeditor.js +2 -1
  66. package/src/assets/qms-ckeditor-plugin/build/ckeditor.js.map +1 -1
  67. package/src/assets/qms-ckeditor-plugin/package-lock.json +852 -2063
  68. package/src/assets/qms-ckeditor-plugin/package.json +25 -19
  69. package/src/assets/qms-ckeditor-plugin/src/ckeditor.js +10 -2
  70. package/src/assets/qms-ckeditor-plugin/src/plugins/ckeditor5-find-and-replace/src/findandreplace.js +132 -0
  71. package/src/assets/qms-ckeditor-plugin/src/plugins/ckeditor5-find-and-replace/src/findandreplaceediting.js +315 -0
  72. package/src/assets/qms-ckeditor-plugin/src/plugins/ckeditor5-find-and-replace/src/findandreplaceui.js +223 -0
  73. package/src/assets/qms-ckeditor-plugin/src/plugins/ckeditor5-find-and-replace/src/findcommand.js +90 -0
  74. package/src/assets/qms-ckeditor-plugin/src/plugins/ckeditor5-find-and-replace/src/findnextcommand.js +62 -0
  75. package/src/assets/qms-ckeditor-plugin/src/plugins/ckeditor5-find-and-replace/src/findpreviouscommand.js +28 -0
  76. package/src/assets/qms-ckeditor-plugin/src/plugins/ckeditor5-find-and-replace/src/index.js +10 -0
  77. package/src/assets/qms-ckeditor-plugin/src/plugins/ckeditor5-find-and-replace/src/replaceallcommand.js +54 -0
  78. package/src/assets/qms-ckeditor-plugin/src/plugins/ckeditor5-find-and-replace/src/replacecommand.js +66 -0
  79. package/src/assets/qms-ckeditor-plugin/src/plugins/ckeditor5-find-and-replace/src/ui/checkboxview.js +212 -0
  80. package/src/assets/qms-ckeditor-plugin/src/plugins/ckeditor5-find-and-replace/src/ui/findandreplaceformview.js +546 -0
  81. package/src/assets/qms-ckeditor-plugin/src/plugins/ckeditor5-find-and-replace/src/utils.js +158 -0
  82. package/src/assets/qms-ckeditor-plugin/src/plugins/ckeditor5-find-and-replace/theme/findandreplace.css +13 -0
  83. package/src/assets/qms-ckeditor-plugin/src/plugins/ckeditor5-find-and-replace/theme/findandreplaceform.css +226 -0
  84. package/src/assets/qms-ckeditor-plugin/src/plugins/ckeditor5-find-and-replace/theme/icons/find-replace.svg +1 -0
  85. package/src/assets/qms-ckeditor-plugin/src/plugins/ckeditor5-special-characters/src/specialcharacters.js +4 -4
  86. package/src/assets/qms-ckeditor-plugin/src/plugins/ckeditor5-special-characters/src/specialcharactersarrows.js +1 -1
  87. package/src/assets/qms-ckeditor-plugin/src/plugins/ckeditor5-special-characters/src/specialcharacterscurrency.js +1 -1
  88. package/src/assets/qms-ckeditor-plugin/src/plugins/ckeditor5-special-characters/src/specialcharactersessentials.js +1 -1
  89. package/src/assets/qms-ckeditor-plugin/src/plugins/ckeditor5-special-characters/src/specialcharacterslatin.js +1 -1
  90. package/src/assets/qms-ckeditor-plugin/src/plugins/ckeditor5-special-characters/src/specialcharactersmathematical.js +1 -1
  91. package/src/assets/qms-ckeditor-plugin/src/plugins/ckeditor5-special-characters/src/specialcharacterstext.js +1 -1
  92. package/src/assets/qms-ckeditor-plugin/src/plugins/ckeditor5-special-characters/src/ui/charactergridview.js +1 -1
  93. package/src/assets/qms-ckeditor-plugin/src/plugins/ckeditor5-special-characters/src/ui/characterinfoview.js +1 -1
  94. package/src/assets/qms-ckeditor-plugin/src/plugins/ckeditor5-special-characters/src/ui/specialcharactersnavigationview.js +2 -2
  95. package/src/assets/qms-ckeditor-plugin/src/plugins/common/qmsCKEditorConstant.js +4 -0
  96. package/src/assets/qms-ckeditor-plugin/src/plugins/common/qmsCKEditorService.js +10 -0
  97. package/src/assets/qms-ckeditor-plugin/src/plugins/tooltip/inserttooltipcommand.js +98 -0
  98. package/src/assets/qms-ckeditor-plugin/src/plugins/tooltip/removetooltipcommand.js +41 -0
  99. package/src/assets/qms-ckeditor-plugin/src/plugins/tooltip/tooltip.js +14 -0
  100. package/src/assets/qms-ckeditor-plugin/src/plugins/tooltip/tooltipediting.js +280 -0
  101. package/src/assets/qms-ckeditor-plugin/src/plugins/tooltip/tooltipui.js +203 -0
  102. package/src/assets/qms-ckeditor-plugin/src/plugins/tooltip/ui/actionsview.js +95 -0
  103. package/src/assets/qms-ckeditor-plugin/src/plugins/tooltip/utils.js +70 -0
  104. package/src/assets/qms-ckeditor-plugin/src/themes/icons/information.svg +50 -0
  105. package/src/assets/qms-ckeditor-plugin/src/themes/tyles/tooltip.css +74 -0
  106. package/src/lib/components/breadcrumb/breadcrumb.scss +9 -0
  107. package/src/lib/components/button/button-toggle.scss +25 -1
  108. package/src/lib/components/dialog/dialog.scss +9 -0
  109. package/src/lib/components/related/popup/related-popup.component.scss +46 -0
  110. package/src/lib/components/table/table.scss +5 -27
  111. package/src/lib/qms-ckeditor-components/components/qms-ckeditor-tooltip/qms-ckeditor-tooltip.component.scss +11 -0
  112. package/src/lib/qms-ckeditor-components/qms-ckeditor.component.scss +29 -1
  113. package/src/lib/qms-ckeditor-components/styles/_modules.scss +6 -0
  114. package/src/themes/core/_form.scss +4 -0
  115. package/src/themes/core/_input.scss +8 -0
  116. package/src/themes/core/_scrollbar.scss +9 -2
  117. package/src/themes/core/_styles.scss +5 -0
  118. package/src/themes/core/_tab.scss +272 -6
@@ -0,0 +1,546 @@
1
+ /**
2
+ * @license Copyright (c) 2003-2021, CKSource - Frederico Knabben. All rights reserved.
3
+ * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
4
+ */
5
+
6
+ /**
7
+ * @module find-and-replace/ui/findandreplaceformview
8
+ */
9
+
10
+ import { ButtonView, FocusCycler, LabeledFieldView, createLabeledInputText, View, submitHandler, ViewCollection } from '@ckeditor/ckeditor5-ui';
11
+ import { FocusTracker, KeystrokeHandler, uid } from '@ckeditor/ckeditor5-utils';
12
+
13
+ // See: #8833.
14
+ // eslint-disable-next-line ckeditor5-rules/ckeditor-imports
15
+ import '@ckeditor/ckeditor5-ui/theme/components/responsive-form/responsiveform.css';
16
+ import '../../theme/findandreplaceform.css';
17
+ // eslint-disable-next-line ckeditor5-rules/ckeditor-imports
18
+ import findArrowIcon from '@ckeditor/ckeditor5-ui/theme/icons/dropdown-arrow.svg';
19
+ import CheckboxView from '../ui/checkboxview';
20
+
21
+ /**
22
+ * The find and replace form view controller class.
23
+ *
24
+ * See {@link module:find-and-replace/ui/findandreplaceformview~FindAndReplaceFormView}.
25
+ *
26
+ * @extends module:ui/view~View
27
+ */
28
+ export default class FindAndReplaceFormView extends View {
29
+ constructor( locale ) {
30
+ super( locale );
31
+
32
+ const t = locale.t;
33
+
34
+ /**
35
+ * Indicates that the form is in active searching state.
36
+ *
37
+ * @readonly
38
+ * @observable
39
+ * @member {Boolean} #isSearching
40
+ */
41
+ this.set( 'isSearching' );
42
+ this.set( 'searchText', '' );
43
+ this.set( 'replaceText', '' );
44
+
45
+ /**
46
+ * Stores the number of matched search results.
47
+ *
48
+ * @readonly
49
+ * @observable
50
+ * @member {Number} #matchCount
51
+ */
52
+ this.set( 'matchCount', null );
53
+
54
+ /**
55
+ * The offset of currently highlighted search result in {@link #matchCount matched results}.
56
+ *
57
+ * @readonly
58
+ * @observable
59
+ * @member {Number|null} #highlightOffset
60
+ */
61
+ this.set( 'highlightOffset', null );
62
+
63
+ /**
64
+ * Whether the search results counter should be visible.
65
+ *
66
+ * @private
67
+ * @readonly
68
+ * @observable
69
+ * @member {Boolean} #isCounterHidden
70
+ */
71
+ this.set( 'isCounterHidden', true );
72
+
73
+ /**
74
+ * The find in text input view that stores the searched string.
75
+ *
76
+ * @member {module:ui/labeledfield/labeledfieldview~LabeledFieldView}
77
+ */
78
+ this.findInputView = this._createInputField( t( 'Find in text…' ) );
79
+
80
+ /**
81
+ * The find button view that initializes the search process.
82
+ *
83
+ * @member {module:ui/button/buttonview~ButtonView}
84
+ */
85
+ this.findButtonView = this._createButton( t( 'Find' ), 'ck-button-find' );
86
+ this.findButtonView.on( 'execute', () => {
87
+ this.fire( 'findNext', {
88
+ searchText: this.searchText,
89
+ matchCase: this.matchCaseView.isChecked,
90
+ wholeWords: this.matchWholeWordsView.isChecked
91
+ } );
92
+ } );
93
+
94
+ /**
95
+ * The find previous button view.
96
+ *
97
+ * @member {module:ui/button/buttonview~ButtonView}
98
+ */
99
+ this.findPrevButtonView = this._createButton( t( 'Previous result' ), 'ck-button-prev', findArrowIcon, false );
100
+ this.findPrevButtonView.on( 'execute', () => {
101
+ this.fire( 'findPrevious' );
102
+ } );
103
+
104
+ /**
105
+ * The find next button view.
106
+ *
107
+ * @member {module:ui/button/buttonview~ButtonView}
108
+ */
109
+ this.findNextButtonView = this._createButton( t( 'Next result' ), 'ck-button-next', findArrowIcon, false );
110
+ this.findNextButtonView.on( 'execute', () => {
111
+ this.fire( 'findNext' );
112
+ } );
113
+
114
+ /**
115
+ * The replace button view.
116
+ *
117
+ * @member {module:ui/button/buttonview~ButtonView}
118
+ */
119
+ this.replaceButtonView = this._createButton( t( 'Replace' ), 'ck-button-replace' );
120
+ this.replaceButtonView.on( 'execute', () => {
121
+ this.fire( 'replace', { searchText: this.searchText, replaceText: this.replaceText } );
122
+ } );
123
+
124
+ /**
125
+ * The replace all button view.
126
+ *
127
+ * @member {module:ui/button/buttonview~ButtonView}
128
+ */
129
+ this.replaceAllButtonView = this._createButton( t( 'Replace all' ), 'ck-button-replaceall' );
130
+ this.replaceAllButtonView.on( 'execute', () => {
131
+ this.fire( 'replaceAll', { searchText: this.searchText, replaceText: this.replaceText } );
132
+ } );
133
+
134
+ /**
135
+ * The match case checkbox view.
136
+ *
137
+ * @member {module:find-and-replace/ui/checkboxview~CheckboxView}
138
+ */
139
+ this.matchCaseView = this._createCheckbox( t( 'Match case' ) );
140
+
141
+ /**
142
+ * The whole words only checkbox view.
143
+ *
144
+ * @member {module:find-and-replace/ui/checkboxview~CheckboxView}
145
+ */
146
+ this.matchWholeWordsView = this._createCheckbox( t( 'Whole words only' ) );
147
+
148
+ /**
149
+ * The replace input view.
150
+ *
151
+ * @member {module:ui/labeledfield/labeledfieldview~LabeledFieldView}
152
+ */
153
+ this.replaceInputView = this._createInputField( t( 'Replace with…' ) );
154
+
155
+ /**
156
+ * Stores gathered views related to find functionality of the feature.
157
+ *
158
+ * @member {module:ui/view~View}
159
+ */
160
+ this.findView = this._createFindView();
161
+
162
+ /**
163
+ * Stores gathered views related to replace functionality of the feature.
164
+ *
165
+ * @member {module:ui/view~View}
166
+ */
167
+ this.replaceView = this._createReplaceView();
168
+
169
+ /**
170
+ * Tracks information about the DOM focus in the form.
171
+ *
172
+ * @readonly
173
+ * @member {module:utils/focustracker~FocusTracker}
174
+ */
175
+ this.focusTracker = new FocusTracker();
176
+
177
+ /**
178
+ * An instance of the {@link module:utils/keystrokehandler~KeystrokeHandler}.
179
+ *
180
+ * @readonly
181
+ * @member {module:utils/keystrokehandler~KeystrokeHandler}
182
+ */
183
+ this.keystrokes = new KeystrokeHandler();
184
+
185
+ /**
186
+ * A collection of views that can be focused in the form.
187
+ *
188
+ * @readonly
189
+ * @protected
190
+ * @member {module:ui/viewcollection~ViewCollection}
191
+ */
192
+ this._focusables = new ViewCollection();
193
+
194
+ /**
195
+ * Helps cycling over {@link #_focusables} in the form.
196
+ *
197
+ * @readonly
198
+ * @protected
199
+ * @member {module:ui/focuscycler~FocusCycler}
200
+ */
201
+ this._focusCycler = new FocusCycler( {
202
+ focusables: this._focusables,
203
+ focusTracker: this.focusTracker,
204
+ keystrokeHandler: this.keystrokes,
205
+ actions: {
206
+ // Navigate form fields backwards using the <kbd>Shift</kbd> + <kbd>Tab</kbd> keystroke.
207
+ focusPrevious: 'shift + tab',
208
+
209
+ // Navigate form fields forwards using the <kbd>Tab</kbd> key.
210
+ focusNext: 'tab'
211
+ }
212
+ } );
213
+
214
+ this.bind( 'searchText' ).to( this.findInputView.fieldView, 'value' );
215
+ this.findButtonView.bind( 'isEnabled' ).to( this.findInputView.fieldView, 'isEmpty', value => !value );
216
+ this.bind( 'replaceText' ).to( this.replaceInputView.fieldView, 'value' );
217
+ this.replaceButtonView.bind( 'isEnabled' ).to( this, 'isSearching' );
218
+ this.replaceAllButtonView.bind( 'isEnabled' ).to( this, 'isSearching' );
219
+
220
+ this.bind( 'isCounterHidden' ).to( this, 'matchCount', this, 'highlightOffset', ( matchCount, highlightOffset ) => {
221
+ return matchCount === null || matchCount === 0 ||
222
+ highlightOffset === null || highlightOffset === 0;
223
+ } );
224
+
225
+ this.setTemplate( {
226
+ tag: 'form',
227
+
228
+ attributes: {
229
+ class: [
230
+ 'ck',
231
+ 'ck-find-and-replace-form'
232
+ ]
233
+ },
234
+
235
+ children: [
236
+ this.findView,
237
+ this.replaceView
238
+ ]
239
+ } );
240
+ }
241
+
242
+ render() {
243
+ super.render();
244
+
245
+ submitHandler( {
246
+ view: this
247
+ } );
248
+
249
+ const childViews = [
250
+ this.findInputView,
251
+ this.matchCaseView,
252
+ this.matchWholeWordsView,
253
+ this.findButtonView,
254
+ this.findPrevButtonView,
255
+ this.findNextButtonView,
256
+ this.replaceInputView,
257
+ this.replaceAllButtonView,
258
+ this.replaceButtonView
259
+ ];
260
+
261
+ childViews.forEach( v => {
262
+ // Register the view as focusable.
263
+ this._focusables.add( v );
264
+
265
+ // Register the view in the focus tracker.
266
+ this.focusTracker.add( v.element );
267
+ } );
268
+
269
+ // Start listening for the keystrokes coming from #element.
270
+ this.keystrokes.listenTo( this.element );
271
+
272
+ const stopPropagation = data => data.stopPropagation();
273
+ const stopPropagationAndPreventDefault = data => {
274
+ data.stopPropagation();
275
+ data.preventDefault();
276
+ };
277
+
278
+ this.keystrokes.set( 'f3', event => {
279
+ stopPropagationAndPreventDefault( event );
280
+
281
+ this.findNextButtonView.fire( 'execute' );
282
+ } );
283
+
284
+ this.keystrokes.set( 'shift+f3', event => {
285
+ stopPropagationAndPreventDefault( event );
286
+
287
+ this.findPrevButtonView.fire( 'execute' );
288
+ } );
289
+
290
+ this.keystrokes.set( 'enter', event => {
291
+ // @todo: this is a bit workaroundish way to handle enter, we should work on views rather than raw DOM elements.
292
+ const target = event.target;
293
+
294
+ if ( target.classList.contains( 'ck-input-text' ) ) {
295
+ if (
296
+ target.parentElement.parentElement.parentElement.classList.contains( 'ck-find-form__wrapper' ) &&
297
+ this.findButtonView.isEnabled
298
+ ) {
299
+ this.findButtonView.fire( 'execute' );
300
+ stopPropagationAndPreventDefault( event );
301
+ } else if (
302
+ target.parentElement.parentElement.parentElement.classList.contains( 'ck-replace-form__wrapper' ) &&
303
+ this.replaceButtonView.isEnabled
304
+ ) {
305
+ this.replaceButtonView.fire( 'execute' );
306
+ stopPropagationAndPreventDefault( event );
307
+ }
308
+ }
309
+ } );
310
+
311
+ // Since the form is in the dropdown panel which is a child of the toolbar, the toolbar's
312
+ // keystroke handler would take over the key management in the URL input.
313
+ // We need to prevent this ASAP. Otherwise, the basic caret movement using the arrow keys will be impossible.
314
+ this.keystrokes.set( 'arrowright', stopPropagation );
315
+ this.keystrokes.set( 'arrowleft', stopPropagation );
316
+ this.keystrokes.set( 'arrowup', stopPropagation );
317
+ this.keystrokes.set( 'arrowdown', stopPropagation );
318
+
319
+ // Intercept the `selectstart` event, which is blocked by default because of the default behavior
320
+ // of the DropdownView#panelView.
321
+ this.listenTo( this.findInputView.element, 'selectstart', ( evt, domEvt ) => {
322
+ domEvt.stopPropagation();
323
+ }, { priority: 'high' } );
324
+ this.listenTo( this.replaceInputView.element, 'selectstart', ( evt, domEvt ) => {
325
+ domEvt.stopPropagation();
326
+ }, { priority: 'high' } );
327
+ }
328
+
329
+ /**
330
+ * Focuses the fist {@link #_focusables} in the form.
331
+ */
332
+ focus() {
333
+ this._focusCycler.focusFirst();
334
+ }
335
+
336
+ /**
337
+ * A collection of views for the 'find' functionality of the feature
338
+ *
339
+ * @private
340
+ * @return {module:ui/view~View} The find view instance.
341
+ */
342
+
343
+ _createFindView() {
344
+ const findView = new View();
345
+
346
+ const bind = this.bindTemplate;
347
+ const t = this.locale.t;
348
+
349
+ findView.setTemplate( {
350
+ tag: 'div',
351
+ attributes: {
352
+ class: [
353
+ 'ck',
354
+ 'ck-find-form__wrapper',
355
+ 'ck-responsive-form',
356
+ bind.if( 'isSearching', 'ck-is-searching' )
357
+ ],
358
+ tabindex: '-1'
359
+ },
360
+ children: [
361
+ this.findInputView,
362
+ { tag: 'span',
363
+ attributes: {
364
+ class: [
365
+ 'ck-results-counter',
366
+ bind.if( 'isCounterHidden', 'ck-hidden' )
367
+ ]
368
+ },
369
+ children: [
370
+ {
371
+ text: bind.to( 'highlightOffset' )
372
+ },
373
+ t( ' of ' ),
374
+ {
375
+ text: bind.to( 'matchCount' )
376
+ }
377
+ ]
378
+ },
379
+ {
380
+ tag: 'div',
381
+ attributes: {
382
+ class: [ 'ck-find-checkboxes' ]
383
+ },
384
+ children: [
385
+ this.matchCaseView,
386
+ this.matchWholeWordsView
387
+ ]
388
+ },
389
+ {
390
+ tag: 'div',
391
+ attributes: {
392
+ class: [
393
+ 'ck-find-buttons'
394
+ ]
395
+ },
396
+ children: [
397
+ this.findButtonView,
398
+ this.findPrevButtonView,
399
+ this.findNextButtonView
400
+ ]
401
+ }
402
+ ]
403
+ } );
404
+
405
+ return findView;
406
+ }
407
+
408
+ /**
409
+ * A collection of views for the 'replace' functionality of the feature
410
+ *
411
+ * @private
412
+ * @returns {module:ui/view~View} The replace view instance.
413
+ */
414
+ _createReplaceView() {
415
+ const replaceView = new View();
416
+ const bind = this.bindTemplate;
417
+
418
+ replaceView.setTemplate( {
419
+ tag: 'div',
420
+ attributes: {
421
+ class: [
422
+ 'ck',
423
+ 'ck-replace-form__wrapper',
424
+ 'ck-responsive-form',
425
+ bind.if( 'isSearching', 'ck-is-searching' )
426
+ ],
427
+ tabindex: '-1'
428
+ },
429
+ children: [
430
+ this.replaceInputView,
431
+ {
432
+ tag: 'div',
433
+ attributes: {
434
+ class: [
435
+ 'ck-replace-buttons'
436
+ ]
437
+ },
438
+ children: [
439
+ this.replaceAllButtonView,
440
+ this.replaceButtonView
441
+ ]
442
+ }
443
+ ]
444
+ } );
445
+ return replaceView;
446
+ }
447
+
448
+ /**
449
+ * Creates a labeled input view.
450
+ *
451
+ * @private
452
+ * @param {String} infoText The input label.
453
+ * @returns {module:ui/labeledfield/labeledfieldview~LabeledFieldView} The labeled input view instance.
454
+ */
455
+ _createInputField( infoText ) {
456
+ const labeledInput = new LabeledFieldView( this.locale, createLabeledInputText );
457
+ const inputField = labeledInput.fieldView;
458
+
459
+ // @todo: this looks like an upstream UI bug (the fact that InputTextView#value does not get updated).
460
+ inputField.on( 'input', () => {
461
+ inputField.value = inputField.element.value;
462
+ } );
463
+
464
+ labeledInput.label = infoText;
465
+ labeledInput.render();
466
+
467
+ return labeledInput;
468
+ }
469
+
470
+ /**
471
+ * Creates a button view.
472
+ *
473
+ * @private
474
+ * @param {String} label The button label.
475
+ * @param {String} className The individual button CSS class name.
476
+ * @param {String} icon An SVG image of icon to be used in button.
477
+ * @param {Boolean} withText Whether the text should be shown.
478
+ * @returns {module:ui/button/buttonview~ButtonView} The button view instance.
479
+ */
480
+ _createButton( label, className, icon, withText = true ) {
481
+ const button = new ButtonView( this.locale );
482
+
483
+ button.set( {
484
+ label,
485
+ icon,
486
+ withText
487
+ } );
488
+
489
+ button.extendTemplate( {
490
+ attributes: {
491
+ class: className
492
+ }
493
+ } );
494
+
495
+ return button;
496
+ }
497
+
498
+ /**
499
+ * Creates a view for the checkboxes.
500
+ *
501
+ * @private
502
+ * @param {String} label The checkbox label.
503
+ * @returns {module:ui/view~View} The checkbox view instance.
504
+ */
505
+ _createCheckbox( label ) {
506
+ const checkboxView = new CheckboxView( this.locale );
507
+
508
+ checkboxView.set( {
509
+ isVisible: true,
510
+ tooltip: true,
511
+ class: 'ck-find-checkboxes__box',
512
+ id: uid(),
513
+ label
514
+ } );
515
+
516
+ return checkboxView;
517
+ }
518
+ }
519
+
520
+ /**
521
+ * Fired when the find next button ({@link #findNextButtonView}) is triggered .
522
+ *
523
+ * @event findNext
524
+ * @param {String} searchText Search text.
525
+ */
526
+
527
+ /**
528
+ * Fired when the find previous button ({@link #findPrevButtonView}) is triggered.
529
+ *
530
+ * @event findPrevious
531
+ * @param {String} searchText Search text.
532
+ */
533
+
534
+ /**
535
+ * Fired when the replace button ({@link #replaceButtonView}) is triggered.
536
+ *
537
+ * @event replace
538
+ * @param {String} replaceText Replacement text.
539
+ */
540
+
541
+ /**
542
+ * Fired when the replaceAll button ({@link #replaceAllButtonView}) is triggered.
543
+ *
544
+ * @event replaceAll
545
+ * @param {String} replaceText Replacement text.
546
+ */
@@ -0,0 +1,158 @@
1
+ /**
2
+ * @license Copyright (c) 2003-2021, CKSource - Frederico Knabben. All rights reserved.
3
+ * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
4
+ */
5
+
6
+ /**
7
+ * @module find-and-replace
8
+ */
9
+
10
+ import { uid, Collection } from '@ckeditor/ckeditor5-utils';
11
+ import { escapeRegExp } from 'lodash-es';
12
+
13
+ /**
14
+ * Executes findCallback and updates search results list.
15
+ *
16
+ * @param {module:engine/model/range~Range} range
17
+ * @param {module:engine/model/model~Model} model
18
+ * @param {Function} findCallback
19
+ * @param {module:utils/collection~Collection} [startResults] An optional collection of find matches that the function should
20
+ * starts with. This would be a collection returned by a previous `updateFindResultFromRange()` call.
21
+ * @returns {module:utils/collection~Collection} A collection of objects describing find match.
22
+ *
23
+ * An example structure:
24
+ *
25
+ * ```js
26
+ * {
27
+ * id: resultId,
28
+ * label: foundItem.label,
29
+ * marker
30
+ * }
31
+ * ```
32
+ */
33
+ export function updateFindResultFromRange( range, model, findCallback, startResults ) {
34
+ const results = startResults || new Collection();
35
+
36
+ [ ...range ].forEach( ( { type, item } ) => {
37
+ if ( type === 'elementStart' ) {
38
+ if ( model.schema.checkChild( item, '$text' ) ) {
39
+ const foundItems = findCallback( {
40
+ item,
41
+ text: rangeToText( model.createRangeIn( item ) )
42
+ } );
43
+
44
+ if ( !foundItems ) {
45
+ return;
46
+ }
47
+
48
+ foundItems.forEach( foundItem => {
49
+ model.change( writer => {
50
+ const resultId = `findResult:${ uid() }`;
51
+ const marker = writer.addMarker( resultId, {
52
+ usingOperation: false,
53
+ affectsData: false,
54
+ range: writer.createRange(
55
+ writer.createPositionAt( item, foundItem.start ),
56
+ writer.createPositionAt( item, foundItem.end )
57
+ )
58
+ } );
59
+
60
+ const index = findInsertIndex( results, marker );
61
+
62
+ results.add(
63
+ {
64
+ id: resultId,
65
+ label: foundItem.label,
66
+ marker
67
+ },
68
+ index
69
+ );
70
+ } );
71
+ } );
72
+ }
73
+ }
74
+ } );
75
+
76
+ return results;
77
+ }
78
+
79
+ /**
80
+ * Returns text representation of a range. The returned text length should be the same as range length.
81
+ * In order to achieve this this function will:
82
+ * - replace inline elements (text-line) as new line character ("\n").
83
+ * - @todo: check unicode characters
84
+ */
85
+ export function rangeToText( range ) {
86
+ return Array.from( range.getItems() ).reduce( ( rangeText, node ) => {
87
+ // Trim text to a last occurrence of an inline element and update range start.
88
+ if ( !( node.is( 'text' ) || node.is( 'textProxy' ) ) ) {
89
+ // Editor has only one inline element defined in schema: `<softBreak>` which is treated as new line character in blocks.
90
+ // Special handling might be needed for other inline elements (inline widgets).
91
+ return `${ rangeText }\n`;
92
+ }
93
+
94
+ return rangeText + node.data;
95
+ }, '' );
96
+ }
97
+
98
+ function findInsertIndex( resultsList, markerToInsert ) {
99
+ const result = resultsList.find( ( { marker } ) => {
100
+ return markerToInsert.getStart().isBefore( marker.getStart() );
101
+ } );
102
+
103
+ return result ? resultsList.getIndex( result ) : resultsList.length;
104
+ }
105
+
106
+ function regexpMatchToFindResult( matchResult ) {
107
+ // In case of match words option the matching results contain indices so that we work on
108
+ // offset where a subject match group was (as opposed to working on entire matched string).
109
+ if ( matchResult.indices ) {
110
+ return {
111
+ label: matchResult[ 1 ],
112
+ start: matchResult.indices[ 1 ][ 0 ],
113
+ end: matchResult.indices[ 1 ][ 1 ]
114
+ };
115
+ } else {
116
+ return {
117
+ label: matchResult[ 1 ],
118
+ start: matchResult.index,
119
+ end: matchResult.index + matchResult[ 1 ].length
120
+ };
121
+ }
122
+ }
123
+
124
+ /**
125
+ *
126
+ * @param {String} searchTerm
127
+ * @param {Object} [options]
128
+ * @param {Boolean} [options.matchCase=false] If set to `true` letter casing will be ignored.
129
+ * @param {Boolean} [options.wholeWords=false] If set to `true` only whole words that match `callbackOrText` will be matched.
130
+ * @returns {Function}
131
+ */
132
+ export function findByTextCallback( searchTerm, options ) {
133
+ let flags = 'gu';
134
+
135
+ if ( !options.matchCase ) {
136
+ flags += 'i';
137
+ }
138
+
139
+ let regExpQuery = `(${ escapeRegExp( searchTerm ) })`;
140
+
141
+ if ( options.wholeWords ) {
142
+ flags += 'd'; // Special groups so that regexp indices are available.
143
+
144
+ const nonLetterGroup = '[^a-zA-Z\u00C0-\u024F\u1E00-\u1EFF]';
145
+
146
+ regExpQuery = `(?:^|${ nonLetterGroup }|_)` + regExpQuery + `(?:_|${ nonLetterGroup }|$)`;
147
+ }
148
+
149
+ const regExp = new RegExp( regExpQuery, flags );
150
+
151
+ function findCallback( { text } ) {
152
+ const matches = [ ...text.matchAll( regExp ) ];
153
+
154
+ return matches.map( regexpMatchToFindResult );
155
+ }
156
+
157
+ return findCallback;
158
+ }
@@ -0,0 +1,13 @@
1
+ /*
2
+ * Copyright (c) 2003-2021, CKSource - Frederico Knabben. All rights reserved.
3
+ * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
4
+ */
5
+
6
+ .ck-find-result {
7
+ background: hsl(58, 100%, 50%);
8
+ color: var(--ck-color-text);
9
+ }
10
+
11
+ .ck-find-result_selected {
12
+ background: hsl(52, 100%, 50%);
13
+ }