@ckeditor/ckeditor5-find-and-replace 41.1.0 → 41.3.0-alpha.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (133) hide show
  1. package/build/find-and-replace.js +2 -2
  2. package/build/translations/af.js +1 -1
  3. package/build/translations/ar.js +1 -1
  4. package/build/translations/bg.js +1 -1
  5. package/build/translations/bn.js +1 -1
  6. package/build/translations/bs.js +1 -1
  7. package/build/translations/ca.js +1 -1
  8. package/build/translations/cs.js +1 -1
  9. package/build/translations/da.js +1 -1
  10. package/build/translations/de.js +1 -1
  11. package/build/translations/el.js +1 -1
  12. package/build/translations/en-au.js +1 -1
  13. package/build/translations/es.js +1 -1
  14. package/build/translations/et.js +1 -1
  15. package/build/translations/fa.js +1 -1
  16. package/build/translations/fi.js +1 -1
  17. package/build/translations/fr.js +1 -1
  18. package/build/translations/gl.js +1 -1
  19. package/build/translations/he.js +1 -1
  20. package/build/translations/hi.js +1 -1
  21. package/build/translations/hr.js +1 -1
  22. package/build/translations/hu.js +1 -1
  23. package/build/translations/id.js +1 -1
  24. package/build/translations/it.js +1 -1
  25. package/build/translations/ja.js +1 -1
  26. package/build/translations/jv.js +1 -1
  27. package/build/translations/ko.js +1 -1
  28. package/build/translations/lt.js +1 -1
  29. package/build/translations/lv.js +1 -1
  30. package/build/translations/ms.js +1 -1
  31. package/build/translations/nl.js +1 -1
  32. package/build/translations/no.js +1 -1
  33. package/build/translations/pl.js +1 -1
  34. package/build/translations/pt-br.js +1 -1
  35. package/build/translations/pt.js +1 -1
  36. package/build/translations/ro.js +1 -1
  37. package/build/translations/ru.js +1 -1
  38. package/build/translations/sk.js +1 -1
  39. package/build/translations/sr-latn.js +1 -1
  40. package/build/translations/sr.js +1 -1
  41. package/build/translations/sv.js +1 -1
  42. package/build/translations/th.js +1 -1
  43. package/build/translations/tr.js +1 -1
  44. package/build/translations/tt.js +1 -1
  45. package/build/translations/ug.js +1 -1
  46. package/build/translations/uk.js +1 -1
  47. package/build/translations/ur.js +1 -1
  48. package/build/translations/vi.js +1 -1
  49. package/build/translations/zh-cn.js +1 -1
  50. package/build/translations/zh.js +1 -1
  51. package/dist/content-index.css +4 -0
  52. package/dist/editor-index.css +20 -0
  53. package/dist/index.css +38 -0
  54. package/dist/index.css.map +1 -0
  55. package/dist/index.js +1493 -0
  56. package/dist/index.js.map +1 -0
  57. package/dist/types/augmentation.d.ts +20 -0
  58. package/dist/types/findandreplace.d.ts +42 -0
  59. package/dist/types/findandreplaceconfig.d.ts +31 -0
  60. package/dist/types/findandreplaceediting.d.ts +63 -0
  61. package/dist/types/findandreplacestate.d.ts +95 -0
  62. package/dist/types/findandreplaceui.d.ts +67 -0
  63. package/dist/types/findandreplaceutils.d.ts +67 -0
  64. package/dist/types/findcommand.d.ts +48 -0
  65. package/dist/types/findnextcommand.d.ts +35 -0
  66. package/dist/types/findpreviouscommand.d.ts +19 -0
  67. package/dist/types/index.d.ts +18 -0
  68. package/dist/types/replaceallcommand.d.ts +35 -0
  69. package/dist/types/replacecommand.d.ts +22 -0
  70. package/dist/types/replacecommandbase.d.ts +31 -0
  71. package/dist/types/ui/findandreplaceformview.d.ts +309 -0
  72. package/lang/contexts.json +2 -1
  73. package/lang/translations/af.po +4 -0
  74. package/lang/translations/ar.po +4 -0
  75. package/lang/translations/bg.po +4 -0
  76. package/lang/translations/bn.po +4 -0
  77. package/lang/translations/bs.po +4 -0
  78. package/lang/translations/ca.po +4 -0
  79. package/lang/translations/cs.po +4 -0
  80. package/lang/translations/da.po +4 -0
  81. package/lang/translations/de.po +4 -0
  82. package/lang/translations/el.po +4 -0
  83. package/lang/translations/en-au.po +4 -0
  84. package/lang/translations/en.po +4 -0
  85. package/lang/translations/es.po +4 -0
  86. package/lang/translations/et.po +4 -0
  87. package/lang/translations/fa.po +4 -0
  88. package/lang/translations/fi.po +4 -0
  89. package/lang/translations/fr.po +4 -0
  90. package/lang/translations/gl.po +4 -0
  91. package/lang/translations/he.po +5 -1
  92. package/lang/translations/hi.po +4 -0
  93. package/lang/translations/hr.po +4 -0
  94. package/lang/translations/hu.po +4 -0
  95. package/lang/translations/id.po +4 -0
  96. package/lang/translations/it.po +4 -0
  97. package/lang/translations/ja.po +4 -0
  98. package/lang/translations/jv.po +4 -0
  99. package/lang/translations/ko.po +4 -0
  100. package/lang/translations/lt.po +4 -0
  101. package/lang/translations/lv.po +4 -0
  102. package/lang/translations/ms.po +4 -0
  103. package/lang/translations/nl.po +4 -0
  104. package/lang/translations/no.po +4 -0
  105. package/lang/translations/pl.po +4 -0
  106. package/lang/translations/pt-br.po +4 -0
  107. package/lang/translations/pt.po +6 -2
  108. package/lang/translations/ro.po +4 -0
  109. package/lang/translations/ru.po +4 -0
  110. package/lang/translations/sk.po +4 -0
  111. package/lang/translations/sr-latn.po +4 -0
  112. package/lang/translations/sr.po +4 -0
  113. package/lang/translations/sv.po +4 -0
  114. package/lang/translations/th.po +4 -0
  115. package/lang/translations/tr.po +4 -0
  116. package/lang/translations/tt.po +4 -0
  117. package/lang/translations/ug.po +4 -0
  118. package/lang/translations/uk.po +4 -0
  119. package/lang/translations/ur.po +4 -0
  120. package/lang/translations/vi.po +4 -0
  121. package/lang/translations/zh-cn.po +4 -0
  122. package/lang/translations/zh.po +4 -0
  123. package/package.json +4 -3
  124. package/src/findandreplace.js +4 -4
  125. package/src/findandreplaceediting.d.ts +14 -14
  126. package/src/findandreplaceediting.js +86 -60
  127. package/src/findandreplacestate.d.ts +27 -1
  128. package/src/findandreplacestate.js +20 -0
  129. package/src/findandreplaceui.js +11 -10
  130. package/src/findandreplaceutils.js +13 -5
  131. package/src/findcommand.d.ts +10 -13
  132. package/src/findcommand.js +6 -0
  133. package/src/index.d.ts +1 -1
@@ -35,7 +35,7 @@ msgstr "Resultado anterior"
35
35
 
36
36
  msgctxt "The label for the previous result button in the find and replace dropdown."
37
37
  msgid "Next result"
38
- msgstr "Próximo resultado"
38
+ msgstr "Resultado seguinte"
39
39
 
40
40
  msgctxt "The label for the (single) replace action button in the find and replace dropdown."
41
41
  msgid "Replace"
@@ -55,7 +55,7 @@ msgstr "Apenas palavras inteiras"
55
55
 
56
56
  msgctxt "The label for the text replacement in the find and replace dropdown."
57
57
  msgid "Replace with…"
58
- msgstr "Substituir com..."
58
+ msgstr "Substituir por..."
59
59
 
60
60
  msgctxt "An error text displayed when user attempted to find an empty text."
61
61
  msgid "Text to find must not be empty."
@@ -68,3 +68,7 @@ msgstr "Dica: Encontre algum texto primeiro para poder substituí-lo."
68
68
  msgctxt "The label and the tooltip of the options dropdown button in the find and replace form."
69
69
  msgid "Advanced options"
70
70
  msgstr "Opções avançadas"
71
+
72
+ msgctxt "Keystroke description for assistive technologies: keystroke for opening the find and replace UI."
73
+ msgid "Find in the document"
74
+ msgstr "Localizar no documento"
@@ -68,3 +68,7 @@ msgstr "Sfat: Mai întâi găsiți textul pentru a-l înlocui."
68
68
  msgctxt "The label and the tooltip of the options dropdown button in the find and replace form."
69
69
  msgid "Advanced options"
70
70
  msgstr "Opțiuni avansate"
71
+
72
+ msgctxt "Keystroke description for assistive technologies: keystroke for opening the find and replace UI."
73
+ msgid "Find in the document"
74
+ msgstr "Căutare în document"
@@ -68,3 +68,7 @@ msgstr "Совет: сначала найдите текст, чтобы зам
68
68
  msgctxt "The label and the tooltip of the options dropdown button in the find and replace form."
69
69
  msgid "Advanced options"
70
70
  msgstr "Дополнительные параметры"
71
+
72
+ msgctxt "Keystroke description for assistive technologies: keystroke for opening the find and replace UI."
73
+ msgid "Find in the document"
74
+ msgstr "Найти в документе"
@@ -68,3 +68,7 @@ msgstr "Tip: Najskôr vyhľadajte text, ktorý následne môžete nahradiť."
68
68
  msgctxt "The label and the tooltip of the options dropdown button in the find and replace form."
69
69
  msgid "Advanced options"
70
70
  msgstr "Pokročilé nastavenia"
71
+
72
+ msgctxt "Keystroke description for assistive technologies: keystroke for opening the find and replace UI."
73
+ msgid "Find in the document"
74
+ msgstr "Nájsť v dokumente"
@@ -68,3 +68,7 @@ msgstr "Savet: Prvo pronađjite neki tekst da biste ga zamenili."
68
68
  msgctxt "The label and the tooltip of the options dropdown button in the find and replace form."
69
69
  msgid "Advanced options"
70
70
  msgstr ""
71
+
72
+ msgctxt "Keystroke description for assistive technologies: keystroke for opening the find and replace UI."
73
+ msgid "Find in the document"
74
+ msgstr ""
@@ -68,3 +68,7 @@ msgstr "Савет: Прво пронађите неки текст да бис
68
68
  msgctxt "The label and the tooltip of the options dropdown button in the find and replace form."
69
69
  msgid "Advanced options"
70
70
  msgstr "Napredne opcije"
71
+
72
+ msgctxt "Keystroke description for assistive technologies: keystroke for opening the find and replace UI."
73
+ msgid "Find in the document"
74
+ msgstr "Nađi u dokumentu"
@@ -68,3 +68,7 @@ msgstr "Tips: Hitta någon text först för att ersätta den."
68
68
  msgctxt "The label and the tooltip of the options dropdown button in the find and replace form."
69
69
  msgid "Advanced options"
70
70
  msgstr "Avancerade alternativ"
71
+
72
+ msgctxt "Keystroke description for assistive technologies: keystroke for opening the find and replace UI."
73
+ msgid "Find in the document"
74
+ msgstr "Hitta i dokumentet"
@@ -68,3 +68,7 @@ msgstr "เคล็ดลับ: ค้นหาข้อความบาง
68
68
  msgctxt "The label and the tooltip of the options dropdown button in the find and replace form."
69
69
  msgid "Advanced options"
70
70
  msgstr "ตัวเลือกขั้นสูง"
71
+
72
+ msgctxt "Keystroke description for assistive technologies: keystroke for opening the find and replace UI."
73
+ msgid "Find in the document"
74
+ msgstr "ค้นหาในเอกสาร"
@@ -68,3 +68,7 @@ msgstr "İpucu: Değiştirmek için önce bir metin bul."
68
68
  msgctxt "The label and the tooltip of the options dropdown button in the find and replace form."
69
69
  msgid "Advanced options"
70
70
  msgstr "Gelişmiş seçenekler"
71
+
72
+ msgctxt "Keystroke description for assistive technologies: keystroke for opening the find and replace UI."
73
+ msgid "Find in the document"
74
+ msgstr "Belgede bul"
@@ -68,3 +68,7 @@ msgstr ""
68
68
  msgctxt "The label and the tooltip of the options dropdown button in the find and replace form."
69
69
  msgid "Advanced options"
70
70
  msgstr ""
71
+
72
+ msgctxt "Keystroke description for assistive technologies: keystroke for opening the find and replace UI."
73
+ msgid "Find in the document"
74
+ msgstr ""
@@ -68,3 +68,7 @@ msgstr "ئەسكەرتىش: ئاۋال ئىزدەپ ئاندىن ئالماشت
68
68
  msgctxt "The label and the tooltip of the options dropdown button in the find and replace form."
69
69
  msgid "Advanced options"
70
70
  msgstr ""
71
+
72
+ msgctxt "Keystroke description for assistive technologies: keystroke for opening the find and replace UI."
73
+ msgid "Find in the document"
74
+ msgstr ""
@@ -68,3 +68,7 @@ msgstr "Порада: спочатку знайдіть текст, щоб за
68
68
  msgctxt "The label and the tooltip of the options dropdown button in the find and replace form."
69
69
  msgid "Advanced options"
70
70
  msgstr "Розширені опції"
71
+
72
+ msgctxt "Keystroke description for assistive technologies: keystroke for opening the find and replace UI."
73
+ msgid "Find in the document"
74
+ msgstr "Пошук в документі"
@@ -68,3 +68,7 @@ msgstr "نکتہ: تبدیل کرنے کے لیے پہلے متن کو تلاش
68
68
  msgctxt "The label and the tooltip of the options dropdown button in the find and replace form."
69
69
  msgid "Advanced options"
70
70
  msgstr ""
71
+
72
+ msgctxt "Keystroke description for assistive technologies: keystroke for opening the find and replace UI."
73
+ msgid "Find in the document"
74
+ msgstr ""
@@ -68,3 +68,7 @@ msgstr "Mẹo: Tìm một đoạn văn bản trước để thay thế."
68
68
  msgctxt "The label and the tooltip of the options dropdown button in the find and replace form."
69
69
  msgid "Advanced options"
70
70
  msgstr "Tùy chọn nâng cao"
71
+
72
+ msgctxt "Keystroke description for assistive technologies: keystroke for opening the find and replace UI."
73
+ msgid "Find in the document"
74
+ msgstr "Tìm trong tài liệu"
@@ -68,3 +68,7 @@ msgstr "提示:先查找文本再替换"
68
68
  msgctxt "The label and the tooltip of the options dropdown button in the find and replace form."
69
69
  msgid "Advanced options"
70
70
  msgstr "高级选项"
71
+
72
+ msgctxt "Keystroke description for assistive technologies: keystroke for opening the find and replace UI."
73
+ msgid "Find in the document"
74
+ msgstr "在文档中查找"
@@ -68,3 +68,7 @@ msgstr "提示:先查找字串再取代"
68
68
  msgctxt "The label and the tooltip of the options dropdown button in the find and replace form."
69
69
  msgid "Advanced options"
70
70
  msgstr "進階選項"
71
+
72
+ msgctxt "Keystroke description for assistive technologies: keystroke for opening the find and replace UI."
73
+ msgid "Find in the document"
74
+ msgstr "在文件中尋找"
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ckeditor/ckeditor5-find-and-replace",
3
- "version": "41.1.0",
3
+ "version": "41.3.0-alpha.0",
4
4
  "description": "Find and replace feature for CKEditor 5.",
5
5
  "keywords": [
6
6
  "ckeditor",
@@ -13,8 +13,8 @@
13
13
  "type": "module",
14
14
  "main": "src/index.js",
15
15
  "dependencies": {
16
- "@ckeditor/ckeditor5-ui": "41.1.0",
17
- "ckeditor5": "41.1.0",
16
+ "@ckeditor/ckeditor5-ui": "41.3.0-alpha.0",
17
+ "ckeditor5": "41.3.0-alpha.0",
18
18
  "lodash-es": "4.17.21"
19
19
  },
20
20
  "author": "CKSource (http://cksource.com/)",
@@ -27,6 +27,7 @@
27
27
  "directory": "packages/ckeditor5-find-and-replace"
28
28
  },
29
29
  "files": [
30
+ "dist",
30
31
  "lang",
31
32
  "src/**/*.js",
32
33
  "src/**/*.d.ts",
@@ -42,7 +42,7 @@ export default class FindAndReplace extends Plugin {
42
42
  // Data is contained only for the "find" button.
43
43
  if (data) {
44
44
  state.searchText = data.searchText;
45
- this.editor.execute('find', data.searchText, data);
45
+ findAndReplaceEditing.find(data.searchText, data);
46
46
  }
47
47
  else {
48
48
  // Find next arrow button press.
@@ -51,7 +51,7 @@ export default class FindAndReplace extends Plugin {
51
51
  });
52
52
  ui.on('findPrevious', (event, data) => {
53
53
  if (data && state.searchText !== data.searchText) {
54
- this.editor.execute('find', data.searchText);
54
+ findAndReplaceEditing.find(data.searchText);
55
55
  }
56
56
  else {
57
57
  // Subsequent calls.
@@ -60,7 +60,7 @@ export default class FindAndReplace extends Plugin {
60
60
  });
61
61
  ui.on('replace', (event, data) => {
62
62
  if (state.searchText !== data.searchText) {
63
- this.editor.execute('find', data.searchText);
63
+ findAndReplaceEditing.find(data.searchText);
64
64
  }
65
65
  const highlightedResult = state.highlightedResult;
66
66
  if (highlightedResult) {
@@ -70,7 +70,7 @@ export default class FindAndReplace extends Plugin {
70
70
  ui.on('replaceAll', (event, data) => {
71
71
  // The state hadn't been yet built for this search text.
72
72
  if (state.searchText !== data.searchText) {
73
- this.editor.execute('find', data.searchText);
73
+ findAndReplaceEditing.find(data.searchText);
74
74
  }
75
75
  this.editor.execute('replaceAll', data.replaceText, state.results);
76
76
  });
@@ -6,9 +6,9 @@
6
6
  * @module find-and-replace/findandreplaceediting
7
7
  */
8
8
  import { Plugin } from 'ckeditor5/src/core.js';
9
- import type { Item } from 'ckeditor5/src/engine.js';
10
9
  import { type Collection } from 'ckeditor5/src/utils.js';
11
- import FindAndReplaceState from './findandreplacestate.js';
10
+ import { type FindAttributes } from './findcommand.js';
11
+ import FindAndReplaceState, { type FindCallback } from './findandreplacestate.js';
12
12
  import FindAndReplaceUtils from './findandreplaceutils.js';
13
13
  import type { ResultType } from './findandreplace.js';
14
14
  import '../theme/findandreplace.css';
@@ -25,18 +25,17 @@ export default class FindAndReplaceEditing extends Plugin {
25
25
  */
26
26
  static get pluginName(): "FindAndReplaceEditing";
27
27
  /**
28
- * The collection of currently highlighted search results.
29
- *
30
- * @private
31
- * @member {module:utils/collection~Collection} #_activeResults
28
+ * An object storing the find and replace state within a given editor instance.
32
29
  */
33
- private _activeResults?;
30
+ state?: FindAndReplaceState;
34
31
  /**
35
- * An object storing the find and replace state within a given editor instance.
32
+ * A flag that indicates that the user has started a search and the editor is listening for changes
33
+ * to the text on which it will perform an automatic search. Among other things, the mode is activated
34
+ * when the user first clicks 'Find' button and then later deactivated when the modal or search dropdown is closed.
36
35
  *
37
- * @member {module:find-and-replace/findandreplacestate~FindAndReplaceState} #state
36
+ * @internal
38
37
  */
39
- state?: FindAndReplaceState;
38
+ _isSearchActive: boolean;
40
39
  /**
41
40
  * @inheritDoc
42
41
  */
@@ -44,10 +43,7 @@ export default class FindAndReplaceEditing extends Plugin {
44
43
  /**
45
44
  * Initiate a search.
46
45
  */
47
- find(callbackOrText: string | (({ item, text }: {
48
- item: Item;
49
- text: string;
50
- }) => Array<ResultType>)): Collection<ResultType>;
46
+ find(callbackOrText: string | FindCallback, findAttributes?: FindAttributes): Collection<ResultType>;
51
47
  /**
52
48
  * Stops active results from updating, and clears out the results.
53
49
  */
@@ -60,4 +56,8 @@ export default class FindAndReplaceEditing extends Plugin {
60
56
  * Sets up the marker downcast converters for search results highlighting.
61
57
  */
62
58
  private _defineConverters;
59
+ /**
60
+ * Reacts to document changes in order to update search list.
61
+ */
62
+ private _onDocumentChange;
63
63
  }
@@ -18,56 +18,82 @@ import { debounce } from 'lodash-es';
18
18
  import '../theme/findandreplace.css';
19
19
  const HIGHLIGHT_CLASS = 'ck-find-result_selected';
20
20
  /**
21
- * Reacts to document changes in order to update search list.
21
+ * Implements the editing part for find and replace plugin. For example conversion, commands etc.
22
22
  */
23
- function onDocumentChange(results, editor, searchCallback) {
24
- const changedNodes = new Set();
25
- const removedMarkers = new Set();
26
- const model = editor.model;
27
- const changes = model.document.differ.getChanges();
28
- // Get nodes in which changes happened to re-run a search callback on them.
29
- changes.forEach(change => {
30
- if (change.name === '$text' || model.schema.isInline(change.position.nodeAfter)) {
31
- changedNodes.add(change.position.parent);
32
- [...model.markers.getMarkersAtPosition(change.position)].forEach(markerAtChange => {
33
- removedMarkers.add(markerAtChange.name);
23
+ export default class FindAndReplaceEditing extends Plugin {
24
+ constructor() {
25
+ super(...arguments);
26
+ /**
27
+ * Reacts to document changes in order to update search list.
28
+ */
29
+ this._onDocumentChange = () => {
30
+ const changedNodes = new Set();
31
+ const removedMarkers = new Set();
32
+ const model = this.editor.model;
33
+ const { results } = this.state;
34
+ const changes = model.document.differ.getChanges();
35
+ const changedMarkers = model.document.differ.getChangedMarkers();
36
+ // Get nodes in which changes happened to re-run a search callback on them.
37
+ changes.forEach(change => {
38
+ if (!change.position) {
39
+ return;
40
+ }
41
+ if (change.name === '$text' || (change.position.nodeAfter && model.schema.isInline(change.position.nodeAfter))) {
42
+ changedNodes.add(change.position.parent);
43
+ [...model.markers.getMarkersAtPosition(change.position)].forEach(markerAtChange => {
44
+ removedMarkers.add(markerAtChange.name);
45
+ });
46
+ }
47
+ else if (change.type === 'insert' && change.position.nodeAfter) {
48
+ changedNodes.add(change.position.nodeAfter);
49
+ }
50
+ });
51
+ // Get markers from removed nodes also.
52
+ changedMarkers.forEach(({ name, data: { newRange } }) => {
53
+ if (newRange && newRange.start.root.rootName === '$graveyard') {
54
+ removedMarkers.add(name);
55
+ }
56
+ });
57
+ // Get markers from the updated nodes and remove all (search will be re-run on these nodes).
58
+ changedNodes.forEach(node => {
59
+ const markersInNode = [...model.markers.getMarkersIntersectingRange(model.createRangeIn(node))];
60
+ markersInNode.forEach(marker => removedMarkers.add(marker.name));
34
61
  });
35
- }
36
- else if (change.type === 'insert') {
37
- changedNodes.add(change.position.nodeAfter);
38
- }
39
- });
40
- // Get markers from removed nodes also.
41
- model.document.differ.getChangedMarkers().forEach(({ name, data: { newRange } }) => {
42
- if (newRange && newRange.start.root.rootName === '$graveyard') {
43
- removedMarkers.add(name);
44
- }
45
- });
46
- // Get markers from the updated nodes and remove all (search will be re-run on these nodes).
47
- changedNodes.forEach(node => {
48
- const markersInNode = [...model.markers.getMarkersIntersectingRange(model.createRangeIn(node))];
49
- markersInNode.forEach(marker => removedMarkers.add(marker.name));
50
- });
51
- // Remove results & markers from the changed part of content.
52
- model.change(writer => {
53
- removedMarkers.forEach(markerName => {
54
- // Remove the result first - in order to prevent rendering a removed marker.
55
- if (results.has(markerName)) {
62
+ // Remove results from the changed part of content.
63
+ removedMarkers.forEach(markerName => {
64
+ if (!results.has(markerName)) {
65
+ return;
66
+ }
67
+ if (results.get(markerName) === this.state.highlightedResult) {
68
+ this.state.highlightedResult = null;
69
+ }
56
70
  results.remove(markerName);
71
+ });
72
+ // Run search callback again on updated nodes.
73
+ const changedSearchResults = [];
74
+ const findAndReplaceUtils = this.editor.plugins.get('FindAndReplaceUtils');
75
+ changedNodes.forEach(nodeToCheck => {
76
+ const changedNodeSearchResults = findAndReplaceUtils.updateFindResultFromRange(model.createRangeOn(nodeToCheck), model, this.state.lastSearchCallback, results);
77
+ changedSearchResults.push(...changedNodeSearchResults);
78
+ });
79
+ changedMarkers.forEach(markerToCheck => {
80
+ // Handle search result highlight update when T&C plugin is active.
81
+ // Lookup is performed only on newly inserted markers.
82
+ if (markerToCheck.data.newRange) {
83
+ const changedNodeSearchResults = findAndReplaceUtils.updateFindResultFromRange(markerToCheck.data.newRange, model, this.state.lastSearchCallback, results);
84
+ changedSearchResults.push(...changedNodeSearchResults);
85
+ }
86
+ });
87
+ if (!this.state.highlightedResult && changedSearchResults.length) {
88
+ // If there are found phrases but none is selected, select the first one.
89
+ this.state.highlightedResult = changedSearchResults[0];
57
90
  }
58
- writer.removeMarker(markerName);
59
- });
60
- });
61
- // Run search callback again on updated nodes.
62
- changedNodes.forEach(nodeToCheck => {
63
- const findAndReplaceUtils = editor.plugins.get('FindAndReplaceUtils');
64
- findAndReplaceUtils.updateFindResultFromRange(model.createRangeOn(nodeToCheck), model, searchCallback, results);
65
- });
66
- }
67
- /**
68
- * Implements the editing part for find and replace plugin. For example conversion, commands etc.
69
- */
70
- export default class FindAndReplaceEditing extends Plugin {
91
+ else {
92
+ // If there is already highlight item then refresh highlight offset after appending new items.
93
+ this.state.refreshHighlightOffset();
94
+ }
95
+ };
96
+ }
71
97
  /**
72
98
  * @inheritDoc
73
99
  */
@@ -84,8 +110,8 @@ export default class FindAndReplaceEditing extends Plugin {
84
110
  * @inheritDoc
85
111
  */
86
112
  init() {
87
- this._activeResults = null;
88
113
  this.state = new FindAndReplaceState(this.editor.model);
114
+ this.set('_isSearchActive', false);
89
115
  this._defineConverters();
90
116
  this._defineCommands();
91
117
  this.listenTo(this.state, 'change:highlightedResult', (eventInfo, name, newValue, oldValue) => {
@@ -125,29 +151,29 @@ export default class FindAndReplaceEditing extends Plugin {
125
151
  // It's possible that the editor will get destroyed before debounced call kicks in.
126
152
  // This would result with accessing a view three that is no longer in DOM.
127
153
  this.listenTo(this.editor, 'destroy', debouncedScrollListener.cancel);
154
+ this.on('change:_isSearchActive', (evt, name, isSearchActive) => {
155
+ if (isSearchActive) {
156
+ this.listenTo(this.editor.model.document, 'change:data', this._onDocumentChange);
157
+ }
158
+ else {
159
+ this.stopListening(this.editor.model.document, 'change:data', this._onDocumentChange);
160
+ }
161
+ });
128
162
  }
129
163
  /**
130
164
  * Initiate a search.
131
165
  */
132
- find(callbackOrText) {
133
- const { editor } = this;
134
- const { model } = editor;
135
- const { findCallback, results } = editor.execute('find', callbackOrText);
136
- this._activeResults = results;
137
- // @todo: handle this listener, another copy is in findcommand.js file.
138
- this.listenTo(model.document, 'change:data', () => onDocumentChange(this._activeResults, editor, findCallback));
139
- return this._activeResults;
166
+ find(callbackOrText, findAttributes) {
167
+ this._isSearchActive = true;
168
+ this.editor.execute('find', callbackOrText, findAttributes);
169
+ return this.state.results;
140
170
  }
141
171
  /**
142
172
  * Stops active results from updating, and clears out the results.
143
173
  */
144
174
  stop() {
145
- if (!this._activeResults) {
146
- return;
147
- }
148
- this.stopListening(this.editor.model.document);
149
175
  this.state.clear(this.editor.model);
150
- this._activeResults = null;
176
+ this._isSearchActive = false;
151
177
  }
152
178
  /**
153
179
  * Sets up the commands.
@@ -5,7 +5,7 @@
5
5
  /**
6
6
  * @module find-and-replace/findandreplacestate
7
7
  */
8
- import type { Model } from 'ckeditor5/src/engine.js';
8
+ import type { Model, Item } from 'ckeditor5/src/engine.js';
9
9
  import { Collection } from 'ckeditor5/src/utils.js';
10
10
  import type { ResultType } from './findandreplace.js';
11
11
  declare const FindAndReplaceState_base: {
@@ -29,6 +29,13 @@ export default class FindAndReplaceState extends FindAndReplaceState_base {
29
29
  * @observable
30
30
  */
31
31
  highlightedResult: ResultType | null;
32
+ /**
33
+ * Currently highlighted search result offset in {@link #results matched results}.
34
+ *
35
+ * @readonly
36
+ * @observable
37
+ */
38
+ highlightedOffset: number;
32
39
  /**
33
40
  * Searched text value.
34
41
  *
@@ -36,6 +43,14 @@ export default class FindAndReplaceState extends FindAndReplaceState_base {
36
43
  * @observable
37
44
  */
38
45
  searchText: string;
46
+ /**
47
+ * The most recent search callback used by the feature to find matches.
48
+ * It is used to re-run the search when user modifies the editor content.
49
+ *
50
+ * @readonly
51
+ * @observable
52
+ */
53
+ lastSearchCallback: FindCallback | null;
39
54
  /**
40
55
  * Replace text value.
41
56
  *
@@ -65,5 +80,16 @@ export default class FindAndReplaceState extends FindAndReplaceState_base {
65
80
  * Cleans the state up and removes markers from the model.
66
81
  */
67
82
  clear(model: Model): void;
83
+ /**
84
+ * Refreshes the highlight result offset based on it's index within the result list.
85
+ */
86
+ refreshHighlightOffset(): void;
68
87
  }
88
+ /**
89
+ * The callback function used to find matches in the document.
90
+ */
91
+ export type FindCallback = (({ item, text }: {
92
+ item: Item;
93
+ text: string;
94
+ }) => Array<ResultType>);
69
95
  export {};
@@ -14,8 +14,10 @@ export default class FindAndReplaceState extends ObservableMixin() {
14
14
  super();
15
15
  this.set('results', new Collection());
16
16
  this.set('highlightedResult', null);
17
+ this.set('highlightedOffset', 0);
17
18
  this.set('searchText', '');
18
19
  this.set('replaceText', '');
20
+ this.set('lastSearchCallback', null);
19
21
  this.set('matchCase', false);
20
22
  this.set('matchWholeWords', false);
21
23
  this.results.on('change', (eventInfo, { removed, index }) => {
@@ -37,6 +39,9 @@ export default class FindAndReplaceState extends ObservableMixin() {
37
39
  }
38
40
  }
39
41
  });
42
+ this.on('change:highlightedResult', () => {
43
+ this.refreshHighlightOffset();
44
+ });
40
45
  }
41
46
  /**
42
47
  * Cleans the state up and removes markers from the model.
@@ -57,4 +62,19 @@ export default class FindAndReplaceState extends ObservableMixin() {
57
62
  });
58
63
  this.results.clear();
59
64
  }
65
+ /**
66
+ * Refreshes the highlight result offset based on it's index within the result list.
67
+ */
68
+ refreshHighlightOffset() {
69
+ const { highlightedResult, results } = this;
70
+ const sortMapping = { before: -1, same: 0, after: 1, different: 1 };
71
+ if (highlightedResult) {
72
+ this.highlightedOffset = Array.from(results)
73
+ .sort((a, b) => sortMapping[a.marker.getStart().compareWith(b.marker.getStart())])
74
+ .indexOf(highlightedResult) + 1;
75
+ }
76
+ else {
77
+ this.highlightedOffset = 0;
78
+ }
79
+ }
60
80
  }
@@ -43,6 +43,7 @@ export default class FindAndReplaceUI extends Plugin {
43
43
  const editor = this.editor;
44
44
  const isUiUsingDropdown = editor.config.get('findAndReplace.uiType') === 'dropdown';
45
45
  const findCommand = editor.commands.get('find');
46
+ const t = this.editor.t;
46
47
  // Register the toolbar component: dropdown or button (that opens a dialog).
47
48
  editor.ui.componentFactory.add('findAndReplace', () => {
48
49
  let view;
@@ -82,6 +83,15 @@ export default class FindAndReplaceUI extends Plugin {
82
83
  });
83
84
  return view;
84
85
  });
86
+ // Add the information about the keystroke to the accessibility database.
87
+ editor.accessibility.addKeystrokeInfos({
88
+ keystrokes: [
89
+ {
90
+ label: t('Find in the document'),
91
+ keystroke: 'CTRL+F'
92
+ }
93
+ ]
94
+ });
85
95
  }
86
96
  /**
87
97
  * Creates a dropdown containing the find and replace form.
@@ -176,16 +186,7 @@ export default class FindAndReplaceUI extends Plugin {
176
186
  const commands = editor.commands;
177
187
  const findAndReplaceEditing = this.editor.plugins.get('FindAndReplaceEditing');
178
188
  const editingState = findAndReplaceEditing.state;
179
- const sortMapping = { before: -1, same: 0, after: 1, different: 1 };
180
- // Let the form know which result is being highlighted.
181
- formView.bind('highlightOffset').to(editingState, 'highlightedResult', highlightedResult => {
182
- if (!highlightedResult) {
183
- return 0;
184
- }
185
- return Array.from(editingState.results)
186
- .sort((a, b) => sortMapping[a.marker.getStart().compareWith(b.marker.getStart())])
187
- .indexOf(highlightedResult) + 1;
188
- });
189
+ formView.bind('highlightOffset').to(editingState, 'highlightedOffset');
189
190
  // Let the form know how many results were found in total.
190
191
  formView.listenTo(editingState.results, 'change', () => {
191
192
  formView.matchCount = editingState.results.length;
@@ -37,6 +37,12 @@ export default class FindAndReplaceUtils extends Plugin {
37
37
  */
38
38
  updateFindResultFromRange(range, model, findCallback, startResults) {
39
39
  const results = startResults || new Collection();
40
+ const checkIfResultAlreadyOnList = (marker) => results.find(markerItem => {
41
+ const { marker: resultsMarker } = markerItem;
42
+ const resultRange = resultsMarker.getRange();
43
+ const markerRange = marker.getRange();
44
+ return resultRange.isEqual(markerRange);
45
+ });
40
46
  model.change(writer => {
41
47
  [...range].forEach(({ type, item }) => {
42
48
  if (type === 'elementStart') {
@@ -56,11 +62,13 @@ export default class FindAndReplaceUtils extends Plugin {
56
62
  range: writer.createRange(writer.createPositionAt(item, foundItem.start), writer.createPositionAt(item, foundItem.end))
57
63
  });
58
64
  const index = findInsertIndex(results, marker);
59
- results.add({
60
- id: resultId,
61
- label: foundItem.label,
62
- marker
63
- }, index);
65
+ if (!checkIfResultAlreadyOnList(marker)) {
66
+ results.add({
67
+ id: resultId,
68
+ label: foundItem.label,
69
+ marker
70
+ }, index);
71
+ }
64
72
  });
65
73
  }
66
74
  }