@dangl/angular-material-shared 2.9.0-beta0037 → 2.9.0-beta0040

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 (175) hide show
  1. package/fesm2022/dangl-angular-material-shared-tiny-mce.mjs +29 -35
  2. package/fesm2022/dangl-angular-material-shared-tiny-mce.mjs.map +1 -1
  3. package/fesm2022/dangl-angular-material-shared.mjs +36 -51
  4. package/fesm2022/dangl-angular-material-shared.mjs.map +1 -1
  5. package/package.json +11 -10
  6. package/styles/material-theme.scss +1 -1
  7. package/styles/material-variables.scss +5 -5
  8. package/tinymce-assets/icons/default/icons.js +46 -9
  9. package/tinymce-assets/icons/default/icons.min.js +1 -1
  10. package/tinymce-assets/models/dom/model.js +8198 -7244
  11. package/tinymce-assets/models/dom/model.min.js +1 -4
  12. package/tinymce-assets/plugins/accordion/plugin.js +1174 -879
  13. package/tinymce-assets/plugins/accordion/plugin.min.js +1 -4
  14. package/tinymce-assets/plugins/advlist/plugin.js +412 -200
  15. package/tinymce-assets/plugins/advlist/plugin.min.js +1 -4
  16. package/tinymce-assets/plugins/anchor/plugin.js +189 -166
  17. package/tinymce-assets/plugins/anchor/plugin.min.js +1 -4
  18. package/tinymce-assets/plugins/autolink/plugin.js +310 -220
  19. package/tinymce-assets/plugins/autolink/plugin.min.js +1 -4
  20. package/tinymce-assets/plugins/autoresize/plugin.js +180 -149
  21. package/tinymce-assets/plugins/autoresize/plugin.min.js +1 -4
  22. package/tinymce-assets/plugins/autosave/plugin.js +208 -189
  23. package/tinymce-assets/plugins/autosave/plugin.min.js +1 -4
  24. package/tinymce-assets/plugins/charmap/plugin.js +905 -1566
  25. package/tinymce-assets/plugins/charmap/plugin.min.js +1 -4
  26. package/tinymce-assets/plugins/code/plugin.js +73 -61
  27. package/tinymce-assets/plugins/code/plugin.min.js +0 -3
  28. package/tinymce-assets/plugins/codesample/plugin.js +3593 -2402
  29. package/tinymce-assets/plugins/codesample/plugin.min.js +8 -3
  30. package/tinymce-assets/plugins/directionality/plugin.js +545 -304
  31. package/tinymce-assets/plugins/directionality/plugin.min.js +1 -4
  32. package/tinymce-assets/plugins/emoticons/js/emojiimages.min.js +0 -2
  33. package/tinymce-assets/plugins/emoticons/js/emojis.min.js +0 -1
  34. package/tinymce-assets/plugins/emoticons/plugin.js +702 -488
  35. package/tinymce-assets/plugins/emoticons/plugin.min.js +1 -4
  36. package/tinymce-assets/plugins/fullscreen/plugin.js +1409 -1049
  37. package/tinymce-assets/plugins/fullscreen/plugin.min.js +1 -4
  38. package/tinymce-assets/plugins/help/js/i18n/keynav/ar.js +4 -1
  39. package/tinymce-assets/plugins/help/js/i18n/keynav/bg_BG.js +4 -1
  40. package/tinymce-assets/plugins/help/js/i18n/keynav/ca.js +4 -1
  41. package/tinymce-assets/plugins/help/js/i18n/keynav/cs.js +4 -1
  42. package/tinymce-assets/plugins/help/js/i18n/keynav/da.js +4 -1
  43. package/tinymce-assets/plugins/help/js/i18n/keynav/de.js +4 -1
  44. package/tinymce-assets/plugins/help/js/i18n/keynav/el.js +4 -1
  45. package/tinymce-assets/plugins/help/js/i18n/keynav/en.js +4 -1
  46. package/tinymce-assets/plugins/help/js/i18n/keynav/es.js +4 -1
  47. package/tinymce-assets/plugins/help/js/i18n/keynav/eu.js +4 -1
  48. package/tinymce-assets/plugins/help/js/i18n/keynav/fa.js +4 -1
  49. package/tinymce-assets/plugins/help/js/i18n/keynav/fi.js +4 -1
  50. package/tinymce-assets/plugins/help/js/i18n/keynav/fr_FR.js +4 -1
  51. package/tinymce-assets/plugins/help/js/i18n/keynav/he_IL.js +4 -1
  52. package/tinymce-assets/plugins/help/js/i18n/keynav/hi.js +4 -1
  53. package/tinymce-assets/plugins/help/js/i18n/keynav/hr.js +4 -1
  54. package/tinymce-assets/plugins/help/js/i18n/keynav/hu_HU.js +4 -1
  55. package/tinymce-assets/plugins/help/js/i18n/keynav/id.js +4 -1
  56. package/tinymce-assets/plugins/help/js/i18n/keynav/it.js +4 -1
  57. package/tinymce-assets/plugins/help/js/i18n/keynav/ja.js +4 -1
  58. package/tinymce-assets/plugins/help/js/i18n/keynav/kk.js +4 -1
  59. package/tinymce-assets/plugins/help/js/i18n/keynav/ko_KR.js +4 -1
  60. package/tinymce-assets/plugins/help/js/i18n/keynav/ms.js +4 -1
  61. package/tinymce-assets/plugins/help/js/i18n/keynav/nb_NO.js +4 -1
  62. package/tinymce-assets/plugins/help/js/i18n/keynav/nl.js +4 -1
  63. package/tinymce-assets/plugins/help/js/i18n/keynav/pl.js +4 -1
  64. package/tinymce-assets/plugins/help/js/i18n/keynav/pt_BR.js +4 -1
  65. package/tinymce-assets/plugins/help/js/i18n/keynav/pt_PT.js +4 -1
  66. package/tinymce-assets/plugins/help/js/i18n/keynav/ro.js +4 -1
  67. package/tinymce-assets/plugins/help/js/i18n/keynav/ru.js +4 -1
  68. package/tinymce-assets/plugins/help/js/i18n/keynav/sk.js +4 -1
  69. package/tinymce-assets/plugins/help/js/i18n/keynav/sl_SI.js +5 -2
  70. package/tinymce-assets/plugins/help/js/i18n/keynav/sv_SE.js +4 -1
  71. package/tinymce-assets/plugins/help/js/i18n/keynav/th_TH.js +4 -1
  72. package/tinymce-assets/plugins/help/js/i18n/keynav/tr.js +4 -1
  73. package/tinymce-assets/plugins/help/js/i18n/keynav/uk.js +4 -1
  74. package/tinymce-assets/plugins/help/js/i18n/keynav/vi.js +4 -1
  75. package/tinymce-assets/plugins/help/js/i18n/keynav/zh_CN.js +8 -5
  76. package/tinymce-assets/plugins/help/js/i18n/keynav/zh_TW.js +4 -1
  77. package/tinymce-assets/plugins/help/plugin.js +739 -809
  78. package/tinymce-assets/plugins/help/plugin.min.js +1 -4
  79. package/tinymce-assets/plugins/image/plugin.js +1475 -1291
  80. package/tinymce-assets/plugins/image/plugin.min.js +1 -4
  81. package/tinymce-assets/plugins/importcss/plugin.js +328 -269
  82. package/tinymce-assets/plugins/importcss/plugin.min.js +1 -4
  83. package/tinymce-assets/plugins/insertdatetime/plugin.js +140 -141
  84. package/tinymce-assets/plugins/insertdatetime/plugin.min.js +1 -4
  85. package/tinymce-assets/plugins/link/plugin.js +1419 -1084
  86. package/tinymce-assets/plugins/link/plugin.min.js +1 -4
  87. package/tinymce-assets/plugins/lists/plugin.js +2177 -1805
  88. package/tinymce-assets/plugins/lists/plugin.min.js +1 -4
  89. package/tinymce-assets/plugins/media/plugin.js +1305 -1047
  90. package/tinymce-assets/plugins/media/plugin.min.js +1 -4
  91. package/tinymce-assets/plugins/nonbreaking/plugin.js +93 -88
  92. package/tinymce-assets/plugins/nonbreaking/plugin.min.js +0 -3
  93. package/tinymce-assets/plugins/pagebreak/plugin.js +91 -85
  94. package/tinymce-assets/plugins/pagebreak/plugin.min.js +0 -3
  95. package/tinymce-assets/plugins/preview/plugin.js +742 -74
  96. package/tinymce-assets/plugins/preview/plugin.min.js +1 -4
  97. package/tinymce-assets/plugins/quickbars/plugin.js +582 -375
  98. package/tinymce-assets/plugins/quickbars/plugin.min.js +1 -4
  99. package/tinymce-assets/plugins/save/plugin.js +100 -82
  100. package/tinymce-assets/plugins/save/plugin.min.js +1 -4
  101. package/tinymce-assets/plugins/searchreplace/plugin.js +1183 -906
  102. package/tinymce-assets/plugins/searchreplace/plugin.min.js +1 -4
  103. package/tinymce-assets/plugins/table/plugin.js +3651 -3094
  104. package/tinymce-assets/plugins/table/plugin.min.js +1 -4
  105. package/tinymce-assets/plugins/visualblocks/plugin.js +71 -63
  106. package/tinymce-assets/plugins/visualblocks/plugin.min.js +1 -4
  107. package/tinymce-assets/plugins/visualchars/plugin.js +685 -436
  108. package/tinymce-assets/plugins/visualchars/plugin.min.js +1 -4
  109. package/tinymce-assets/plugins/wordcount/plugin.js +382 -307
  110. package/tinymce-assets/plugins/wordcount/plugin.min.js +1 -4
  111. package/tinymce-assets/skins/content/dark/content.css +9 -0
  112. package/tinymce-assets/skins/content/dark/content.js +10 -2
  113. package/tinymce-assets/skins/content/dark/content.min.css +9 -0
  114. package/tinymce-assets/skins/content/default/content.css +9 -0
  115. package/tinymce-assets/skins/content/default/content.js +10 -2
  116. package/tinymce-assets/skins/content/default/content.min.css +9 -0
  117. package/tinymce-assets/skins/content/document/content.css +9 -0
  118. package/tinymce-assets/skins/content/document/content.js +10 -2
  119. package/tinymce-assets/skins/content/document/content.min.css +9 -0
  120. package/tinymce-assets/skins/content/tinymce-5/content.css +9 -0
  121. package/tinymce-assets/skins/content/tinymce-5/content.js +10 -2
  122. package/tinymce-assets/skins/content/tinymce-5/content.min.css +9 -0
  123. package/tinymce-assets/skins/content/tinymce-5-dark/content.css +9 -0
  124. package/tinymce-assets/skins/content/tinymce-5-dark/content.js +10 -2
  125. package/tinymce-assets/skins/content/tinymce-5-dark/content.min.css +9 -0
  126. package/tinymce-assets/skins/content/writer/content.css +9 -0
  127. package/tinymce-assets/skins/content/writer/content.js +10 -2
  128. package/tinymce-assets/skins/content/writer/content.min.css +9 -0
  129. package/tinymce-assets/skins/ui/oxide/content.css +157 -49
  130. package/tinymce-assets/skins/ui/oxide/content.inline.css +157 -49
  131. package/tinymce-assets/skins/ui/oxide/content.inline.js +10 -2
  132. package/tinymce-assets/skins/ui/oxide/content.inline.min.css +10 -1
  133. package/tinymce-assets/skins/ui/oxide/content.js +10 -2
  134. package/tinymce-assets/skins/ui/oxide/content.min.css +10 -1
  135. package/tinymce-assets/skins/ui/oxide/skin.css +1592 -214
  136. package/tinymce-assets/skins/ui/oxide/skin.js +1 -2
  137. package/tinymce-assets/skins/ui/oxide/skin.min.css +1 -1
  138. package/tinymce-assets/skins/ui/oxide/skin.shadowdom.js +1 -2
  139. package/tinymce-assets/skins/ui/oxide-dark/content.css +157 -42
  140. package/tinymce-assets/skins/ui/oxide-dark/content.inline.css +157 -49
  141. package/tinymce-assets/skins/ui/oxide-dark/content.inline.js +10 -2
  142. package/tinymce-assets/skins/ui/oxide-dark/content.inline.min.css +10 -1
  143. package/tinymce-assets/skins/ui/oxide-dark/content.js +10 -2
  144. package/tinymce-assets/skins/ui/oxide-dark/content.min.css +10 -1
  145. package/tinymce-assets/skins/ui/oxide-dark/skin.css +1595 -217
  146. package/tinymce-assets/skins/ui/oxide-dark/skin.js +1 -2
  147. package/tinymce-assets/skins/ui/oxide-dark/skin.min.css +1 -1
  148. package/tinymce-assets/skins/ui/oxide-dark/skin.shadowdom.js +1 -2
  149. package/tinymce-assets/skins/ui/tinymce-5/content.css +157 -49
  150. package/tinymce-assets/skins/ui/tinymce-5/content.inline.css +157 -49
  151. package/tinymce-assets/skins/ui/tinymce-5/content.inline.js +10 -2
  152. package/tinymce-assets/skins/ui/tinymce-5/content.inline.min.css +10 -1
  153. package/tinymce-assets/skins/ui/tinymce-5/content.js +10 -2
  154. package/tinymce-assets/skins/ui/tinymce-5/content.min.css +10 -1
  155. package/tinymce-assets/skins/ui/tinymce-5/skin.css +1606 -203
  156. package/tinymce-assets/skins/ui/tinymce-5/skin.js +1 -2
  157. package/tinymce-assets/skins/ui/tinymce-5/skin.min.css +1 -1
  158. package/tinymce-assets/skins/ui/tinymce-5/skin.shadowdom.js +1 -2
  159. package/tinymce-assets/skins/ui/tinymce-5-dark/content.css +157 -42
  160. package/tinymce-assets/skins/ui/tinymce-5-dark/content.inline.css +157 -49
  161. package/tinymce-assets/skins/ui/tinymce-5-dark/content.inline.js +10 -2
  162. package/tinymce-assets/skins/ui/tinymce-5-dark/content.inline.min.css +10 -1
  163. package/tinymce-assets/skins/ui/tinymce-5-dark/content.js +10 -2
  164. package/tinymce-assets/skins/ui/tinymce-5-dark/content.min.css +10 -1
  165. package/tinymce-assets/skins/ui/tinymce-5-dark/skin.css +1607 -204
  166. package/tinymce-assets/skins/ui/tinymce-5-dark/skin.js +1 -2
  167. package/tinymce-assets/skins/ui/tinymce-5-dark/skin.min.css +1 -1
  168. package/tinymce-assets/skins/ui/tinymce-5-dark/skin.shadowdom.js +1 -2
  169. package/tinymce-assets/themes/silver/theme.js +32786 -28738
  170. package/tinymce-assets/themes/silver/theme.min.js +1 -4
  171. package/types/dangl-angular-material-shared-tiny-mce.d.ts +12 -13
  172. package/types/dangl-angular-material-shared.d.ts +26 -26
  173. package/tinymce-assets/plugins/template/index.js +0 -7
  174. package/tinymce-assets/plugins/template/plugin.js +0 -567
  175. package/tinymce-assets/plugins/template/plugin.min.js +0 -4
@@ -1,360 +1,615 @@
1
1
  /**
2
- * TinyMCE version 6.8.3 (2024-02-08)
2
+ * TinyMCE version 7.9.3 (2026-05-19)
3
3
  */
4
4
 
5
5
  (function () {
6
6
  'use strict';
7
7
 
8
- const Cell = initial => {
9
- let value = initial;
10
- const get = () => {
11
- return value;
12
- };
13
- const set = v => {
14
- value = v;
15
- };
16
- return {
17
- get,
18
- set
19
- };
20
- };
21
-
22
- var global$3 = tinymce.util.Tools.resolve('tinymce.PluginManager');
23
-
8
+ /* eslint-disable @typescript-eslint/no-wrapper-object-types */
24
9
  const hasProto = (v, constructor, predicate) => {
25
- var _a;
26
- if (predicate(v, constructor.prototype)) {
27
- return true;
28
- } else {
29
- return ((_a = v.constructor) === null || _a === void 0 ? void 0 : _a.name) === constructor.name;
30
- }
10
+ var _a;
11
+ if (predicate(v, constructor.prototype)) {
12
+ return true;
13
+ }
14
+ else {
15
+ // String-based fallback time
16
+ return ((_a = v.constructor) === null || _a === void 0 ? void 0 : _a.name) === constructor.name;
17
+ }
31
18
  };
32
- const typeOf = x => {
33
- const t = typeof x;
34
- if (x === null) {
35
- return 'null';
36
- } else if (t === 'object' && Array.isArray(x)) {
37
- return 'array';
38
- } else if (t === 'object' && hasProto(x, String, (o, proto) => proto.isPrototypeOf(o))) {
39
- return 'string';
40
- } else {
41
- return t;
42
- }
19
+ const typeOf = (x) => {
20
+ const t = typeof x;
21
+ if (x === null) {
22
+ return 'null';
23
+ }
24
+ else if (t === 'object' && Array.isArray(x)) {
25
+ return 'array';
26
+ }
27
+ else if (t === 'object' && hasProto(x, String, (o, proto) => proto.isPrototypeOf(o))) {
28
+ return 'string';
29
+ }
30
+ else {
31
+ return t;
32
+ }
43
33
  };
44
- const isType$1 = type => value => typeOf(value) === type;
45
- const isSimpleType = type => value => typeof value === type;
34
+ const isType$1 = (type) => (value) => typeOf(value) === type;
35
+ const isSimpleType = (type) => (value) => typeof value === type;
46
36
  const isString = isType$1('string');
47
37
  const isArray = isType$1('array');
48
38
  const isBoolean = isSimpleType('boolean');
49
- const isNullable = a => a === null || a === undefined;
50
- const isNonNullable = a => !isNullable(a);
39
+ const isNullable = (a) => a === null || a === undefined;
40
+ const isNonNullable = (a) => !isNullable(a);
51
41
  const isNumber = isSimpleType('number');
52
42
 
53
- const noop = () => {
54
- };
55
- const constant = value => {
56
- return () => {
57
- return value;
58
- };
43
+ const noop = () => { };
44
+ const constant = (value) => {
45
+ return () => {
46
+ return value;
47
+ };
59
48
  };
60
49
  const always = constant(true);
61
50
 
62
- const punctuationStr = `[~\u2116|!-*+-\\/:;?@\\[-\`{}\u00A1\u00AB\u00B7\u00BB\u00BF;\u00B7\u055A-\u055F\u0589\u058A\u05BE\u05C0\u05C3\u05C6\u05F3\u05F4\u0609\u060A\u060C\u060D\u061B\u061E\u061F\u066A-\u066D\u06D4\u0700-\u070D\u07F7-\u07F9\u0830-\u083E\u085E\u0964\u0965\u0970\u0DF4\u0E4F\u0E5A\u0E5B\u0F04-\u0F12\u0F3A-\u0F3D\u0F85\u0FD0-\u0FD4\u0FD9\u0FDA\u104A-\u104F\u10FB\u1361-\u1368\u1400\u166D\u166E\u169B\u169C\u16EB-\u16ED\u1735\u1736\u17D4-\u17D6\u17D8-\u17DA\u1800-\u180A\u1944\u1945\u1A1E\u1A1F\u1AA0-\u1AA6\u1AA8-\u1AAD\u1B5A-\u1B60\u1BFC-\u1BFF\u1C3B-\u1C3F\u1C7E\u1C7F\u1CD3\u2010-\u2027\u2030-\u2043\u2045-\u2051\u2053-\u205E\u207D\u207E\u208D\u208E\u3008\u3009\u2768-\u2775\u27C5\u27C6\u27E6-\u27EF\u2983-\u2998\u29D8-\u29DB\u29FC\u29FD\u2CF9-\u2CFC\u2CFE\u2CFF\u2D70\u2E00-\u2E2E\u2E30\u2E31\u3001-\u3003\u3008-\u3011\u3014-\u301F\u3030\u303D\u30A0\u30FB\uA4FE\uA4FF\uA60D-\uA60F\uA673\uA67E\uA6F2-\uA6F7\uA874-\uA877\uA8CE\uA8CF\uA8F8-\uA8FA\uA92E\uA92F\uA95F\uA9C1-\uA9CD\uA9DE\uA9DF\uAA5C-\uAA5F\uAADE\uAADF\uABEB\uFD3E\uFD3F\uFE10-\uFE19\uFE30-\uFE52\uFE54-\uFE61\uFE63\uFE68\uFE6A\uFE6B\uFF01-\uFF03\uFF05-\uFF0A\uFF0C-\uFF0F\uFF1A\uFF1B\uFF1F\uFF20\uFF3B-\uFF3D\uFF3F\uFF5B\uFF5D\uFF5F-\uFF65]`;
63
-
64
- const punctuation$1 = constant(punctuationStr);
65
-
51
+ /**
52
+ * The `Optional` type represents a value (of any type) that potentially does
53
+ * not exist. Any `Optional<T>` can either be a `Some<T>` (in which case the
54
+ * value does exist) or a `None` (in which case the value does not exist). This
55
+ * module defines a whole lot of FP-inspired utility functions for dealing with
56
+ * `Optional` objects.
57
+ *
58
+ * Comparison with null or undefined:
59
+ * - We don't get fancy null coalescing operators with `Optional`
60
+ * - We do get fancy helper functions with `Optional`
61
+ * - `Optional` support nesting, and allow for the type to still be nullable (or
62
+ * another `Optional`)
63
+ * - There is no option to turn off strict-optional-checks like there is for
64
+ * strict-null-checks
65
+ */
66
66
  class Optional {
67
- constructor(tag, value) {
68
- this.tag = tag;
69
- this.value = value;
70
- }
71
- static some(value) {
72
- return new Optional(true, value);
73
- }
74
- static none() {
75
- return Optional.singletonNone;
76
- }
77
- fold(onNone, onSome) {
78
- if (this.tag) {
79
- return onSome(this.value);
80
- } else {
81
- return onNone();
67
+ // The internal representation has a `tag` and a `value`, but both are
68
+ // private: able to be console.logged, but not able to be accessed by code
69
+ constructor(tag, value) {
70
+ this.tag = tag;
71
+ this.value = value;
82
72
  }
83
- }
84
- isSome() {
85
- return this.tag;
86
- }
87
- isNone() {
88
- return !this.tag;
89
- }
90
- map(mapper) {
91
- if (this.tag) {
92
- return Optional.some(mapper(this.value));
93
- } else {
94
- return Optional.none();
73
+ // --- Identities ---
74
+ /**
75
+ * Creates a new `Optional<T>` that **does** contain a value.
76
+ */
77
+ static some(value) {
78
+ return new Optional(true, value);
95
79
  }
96
- }
97
- bind(binder) {
98
- if (this.tag) {
99
- return binder(this.value);
100
- } else {
101
- return Optional.none();
80
+ /**
81
+ * Create a new `Optional<T>` that **does not** contain a value. `T` can be
82
+ * any type because we don't actually have a `T`.
83
+ */
84
+ static none() {
85
+ return Optional.singletonNone;
102
86
  }
103
- }
104
- exists(predicate) {
105
- return this.tag && predicate(this.value);
106
- }
107
- forall(predicate) {
108
- return !this.tag || predicate(this.value);
109
- }
110
- filter(predicate) {
111
- if (!this.tag || predicate(this.value)) {
112
- return this;
113
- } else {
114
- return Optional.none();
87
+ /**
88
+ * Perform a transform on an `Optional` type. Regardless of whether this
89
+ * `Optional` contains a value or not, `fold` will return a value of type `U`.
90
+ * If this `Optional` does not contain a value, the `U` will be created by
91
+ * calling `onNone`. If this `Optional` does contain a value, the `U` will be
92
+ * created by calling `onSome`.
93
+ *
94
+ * For the FP enthusiasts in the room, this function:
95
+ * 1. Could be used to implement all of the functions below
96
+ * 2. Forms a catamorphism
97
+ */
98
+ fold(onNone, onSome) {
99
+ if (this.tag) {
100
+ return onSome(this.value);
101
+ }
102
+ else {
103
+ return onNone();
104
+ }
105
+ }
106
+ /**
107
+ * Determine if this `Optional` object contains a value.
108
+ */
109
+ isSome() {
110
+ return this.tag;
111
+ }
112
+ /**
113
+ * Determine if this `Optional` object **does not** contain a value.
114
+ */
115
+ isNone() {
116
+ return !this.tag;
117
+ }
118
+ // --- Functor (name stolen from Haskell / maths) ---
119
+ /**
120
+ * Perform a transform on an `Optional` object, **if** there is a value. If
121
+ * you provide a function to turn a T into a U, this is the function you use
122
+ * to turn an `Optional<T>` into an `Optional<U>`. If this **does** contain
123
+ * a value then the output will also contain a value (that value being the
124
+ * output of `mapper(this.value)`), and if this **does not** contain a value
125
+ * then neither will the output.
126
+ */
127
+ map(mapper) {
128
+ if (this.tag) {
129
+ return Optional.some(mapper(this.value));
130
+ }
131
+ else {
132
+ return Optional.none();
133
+ }
115
134
  }
116
- }
117
- getOr(replacement) {
118
- return this.tag ? this.value : replacement;
119
- }
120
- or(replacement) {
121
- return this.tag ? this : replacement;
122
- }
123
- getOrThunk(thunk) {
124
- return this.tag ? this.value : thunk();
125
- }
126
- orThunk(thunk) {
127
- return this.tag ? this : thunk();
128
- }
129
- getOrDie(message) {
130
- if (!this.tag) {
131
- throw new Error(message !== null && message !== void 0 ? message : 'Called getOrDie on None');
132
- } else {
133
- return this.value;
135
+ // --- Monad (name stolen from Haskell / maths) ---
136
+ /**
137
+ * Perform a transform on an `Optional` object, **if** there is a value.
138
+ * Unlike `map`, here the transform itself also returns an `Optional`.
139
+ */
140
+ bind(binder) {
141
+ if (this.tag) {
142
+ return binder(this.value);
143
+ }
144
+ else {
145
+ return Optional.none();
146
+ }
147
+ }
148
+ // --- Traversable (name stolen from Haskell / maths) ---
149
+ /**
150
+ * For a given predicate, this function finds out if there **exists** a value
151
+ * inside this `Optional` object that meets the predicate. In practice, this
152
+ * means that for `Optional`s that do not contain a value it returns false (as
153
+ * no predicate-meeting value exists).
154
+ */
155
+ exists(predicate) {
156
+ return this.tag && predicate(this.value);
157
+ }
158
+ /**
159
+ * For a given predicate, this function finds out if **all** the values inside
160
+ * this `Optional` object meet the predicate. In practice, this means that
161
+ * for `Optional`s that do not contain a value it returns true (as all 0
162
+ * objects do meet the predicate).
163
+ */
164
+ forall(predicate) {
165
+ return !this.tag || predicate(this.value);
166
+ }
167
+ filter(predicate) {
168
+ if (!this.tag || predicate(this.value)) {
169
+ return this;
170
+ }
171
+ else {
172
+ return Optional.none();
173
+ }
134
174
  }
135
- }
136
- static from(value) {
137
- return isNonNullable(value) ? Optional.some(value) : Optional.none();
138
- }
139
- getOrNull() {
140
- return this.tag ? this.value : null;
141
- }
142
- getOrUndefined() {
143
- return this.value;
144
- }
145
- each(worker) {
146
- if (this.tag) {
147
- worker(this.value);
175
+ // --- Getters ---
176
+ /**
177
+ * Get the value out of the inside of the `Optional` object, using a default
178
+ * `replacement` value if the provided `Optional` object does not contain a
179
+ * value.
180
+ */
181
+ getOr(replacement) {
182
+ return this.tag ? this.value : replacement;
183
+ }
184
+ /**
185
+ * Get the value out of the inside of the `Optional` object, using a default
186
+ * `replacement` value if the provided `Optional` object does not contain a
187
+ * value. Unlike `getOr`, in this method the `replacement` object is also
188
+ * `Optional` - meaning that this method will always return an `Optional`.
189
+ */
190
+ or(replacement) {
191
+ return this.tag ? this : replacement;
192
+ }
193
+ /**
194
+ * Get the value out of the inside of the `Optional` object, using a default
195
+ * `replacement` value if the provided `Optional` object does not contain a
196
+ * value. Unlike `getOr`, in this method the `replacement` value is
197
+ * "thunked" - that is to say that you don't pass a value to `getOrThunk`, you
198
+ * pass a function which (if called) will **return** the `value` you want to
199
+ * use.
200
+ */
201
+ getOrThunk(thunk) {
202
+ return this.tag ? this.value : thunk();
203
+ }
204
+ /**
205
+ * Get the value out of the inside of the `Optional` object, using a default
206
+ * `replacement` value if the provided Optional object does not contain a
207
+ * value.
208
+ *
209
+ * Unlike `or`, in this method the `replacement` value is "thunked" - that is
210
+ * to say that you don't pass a value to `orThunk`, you pass a function which
211
+ * (if called) will **return** the `value` you want to use.
212
+ *
213
+ * Unlike `getOrThunk`, in this method the `replacement` value is also
214
+ * `Optional`, meaning that this method will always return an `Optional`.
215
+ */
216
+ orThunk(thunk) {
217
+ return this.tag ? this : thunk();
218
+ }
219
+ /**
220
+ * Get the value out of the inside of the `Optional` object, throwing an
221
+ * exception if the provided `Optional` object does not contain a value.
222
+ *
223
+ * WARNING:
224
+ * You should only be using this function if you know that the `Optional`
225
+ * object **is not** empty (otherwise you're throwing exceptions in production
226
+ * code, which is bad).
227
+ *
228
+ * In tests this is more acceptable.
229
+ *
230
+ * Prefer other methods to this, such as `.each`.
231
+ */
232
+ getOrDie(message) {
233
+ if (!this.tag) {
234
+ throw new Error(message !== null && message !== void 0 ? message : 'Called getOrDie on None');
235
+ }
236
+ else {
237
+ return this.value;
238
+ }
239
+ }
240
+ // --- Interop with null and undefined ---
241
+ /**
242
+ * Creates an `Optional` value from a nullable (or undefined-able) input.
243
+ * Null, or undefined, is converted to `None`, and anything else is converted
244
+ * to `Some`.
245
+ */
246
+ static from(value) {
247
+ return isNonNullable(value) ? Optional.some(value) : Optional.none();
248
+ }
249
+ /**
250
+ * Converts an `Optional` to a nullable type, by getting the value if it
251
+ * exists, or returning `null` if it does not.
252
+ */
253
+ getOrNull() {
254
+ return this.tag ? this.value : null;
255
+ }
256
+ /**
257
+ * Converts an `Optional` to an undefined-able type, by getting the value if
258
+ * it exists, or returning `undefined` if it does not.
259
+ */
260
+ getOrUndefined() {
261
+ return this.value;
262
+ }
263
+ // --- Utilities ---
264
+ /**
265
+ * If the `Optional` contains a value, perform an action on that value.
266
+ * Unlike the rest of the methods on this type, `.each` has side-effects. If
267
+ * you want to transform an `Optional<T>` **into** something, then this is not
268
+ * the method for you. If you want to use an `Optional<T>` to **do**
269
+ * something, then this is the method for you - provided you're okay with not
270
+ * doing anything in the case where the `Optional` doesn't have a value inside
271
+ * it. If you're not sure whether your use-case fits into transforming
272
+ * **into** something or **doing** something, check whether it has a return
273
+ * value. If it does, you should be performing a transform.
274
+ */
275
+ each(worker) {
276
+ if (this.tag) {
277
+ worker(this.value);
278
+ }
279
+ }
280
+ /**
281
+ * Turn the `Optional` object into an array that contains all of the values
282
+ * stored inside the `Optional`. In practice, this means the output will have
283
+ * either 0 or 1 elements.
284
+ */
285
+ toArray() {
286
+ return this.tag ? [this.value] : [];
287
+ }
288
+ /**
289
+ * Turn the `Optional` object into a string for debugging or printing. Not
290
+ * recommended for production code, but good for debugging. Also note that
291
+ * these days an `Optional` object can be logged to the console directly, and
292
+ * its inner value (if it exists) will be visible.
293
+ */
294
+ toString() {
295
+ return this.tag ? `some(${this.value})` : 'none()';
148
296
  }
149
- }
150
- toArray() {
151
- return this.tag ? [this.value] : [];
152
- }
153
- toString() {
154
- return this.tag ? `some(${ this.value })` : 'none()';
155
- }
156
297
  }
298
+ // Sneaky optimisation: every instance of Optional.none is identical, so just
299
+ // reuse the same object
157
300
  Optional.singletonNone = new Optional(false);
158
301
 
159
- const punctuation = punctuation$1;
160
-
161
- var global$2 = tinymce.util.Tools.resolve('tinymce.Env');
162
-
163
- var global$1 = tinymce.util.Tools.resolve('tinymce.util.Tools');
164
-
302
+ /* eslint-disable @typescript-eslint/unbound-method */
165
303
  const nativeSlice = Array.prototype.slice;
166
304
  const nativePush = Array.prototype.push;
167
305
  const map = (xs, f) => {
168
- const len = xs.length;
169
- const r = new Array(len);
170
- for (let i = 0; i < len; i++) {
171
- const x = xs[i];
172
- r[i] = f(x, i);
173
- }
174
- return r;
306
+ // pre-allocating array size when it's guaranteed to be known
307
+ // http://jsperf.com/push-allocated-vs-dynamic/22
308
+ const len = xs.length;
309
+ const r = new Array(len);
310
+ for (let i = 0; i < len; i++) {
311
+ const x = xs[i];
312
+ r[i] = f(x, i);
313
+ }
314
+ return r;
175
315
  };
316
+ // Unwound implementing other functions in terms of each.
317
+ // The code size is roughly the same, and it should allow for better optimisation.
318
+ // const each = function<T, U>(xs: T[], f: (x: T, i?: number, xs?: T[]) => void): void {
176
319
  const each = (xs, f) => {
177
- for (let i = 0, len = xs.length; i < len; i++) {
178
- const x = xs[i];
179
- f(x, i);
180
- }
320
+ for (let i = 0, len = xs.length; i < len; i++) {
321
+ const x = xs[i];
322
+ f(x, i);
323
+ }
181
324
  };
182
325
  const eachr = (xs, f) => {
183
- for (let i = xs.length - 1; i >= 0; i--) {
184
- const x = xs[i];
185
- f(x, i);
186
- }
326
+ for (let i = xs.length - 1; i >= 0; i--) {
327
+ const x = xs[i];
328
+ f(x, i);
329
+ }
187
330
  };
331
+ /*
332
+ * Groups an array into contiguous arrays of like elements. Whether an element is like or not depends on f.
333
+ *
334
+ * f is a function that derives a value from an element - e.g. true or false, or a string.
335
+ * Elements are like if this function generates the same value for them (according to ===).
336
+ *
337
+ *
338
+ * Order of the elements is preserved. Arr.flatten() on the result will return the original list, as with Haskell groupBy function.
339
+ * For a good explanation, see the group function (which is a special case of groupBy)
340
+ * http://hackage.haskell.org/package/base-4.7.0.0/docs/Data-List.html#v:group
341
+ */
188
342
  const groupBy = (xs, f) => {
189
- if (xs.length === 0) {
190
- return [];
191
- } else {
192
- let wasType = f(xs[0]);
193
- const r = [];
194
- let group = [];
195
- for (let i = 0, len = xs.length; i < len; i++) {
196
- const x = xs[i];
197
- const type = f(x);
198
- if (type !== wasType) {
199
- r.push(group);
200
- group = [];
201
- }
202
- wasType = type;
203
- group.push(x);
343
+ if (xs.length === 0) {
344
+ return [];
204
345
  }
205
- if (group.length !== 0) {
206
- r.push(group);
346
+ else {
347
+ let wasType = f(xs[0]); // initial case for matching
348
+ const r = [];
349
+ let group = [];
350
+ for (let i = 0, len = xs.length; i < len; i++) {
351
+ const x = xs[i];
352
+ const type = f(x);
353
+ if (type !== wasType) {
354
+ r.push(group);
355
+ group = [];
356
+ }
357
+ wasType = type;
358
+ group.push(x);
359
+ }
360
+ if (group.length !== 0) {
361
+ r.push(group);
362
+ }
363
+ return r;
207
364
  }
208
- return r;
209
- }
210
365
  };
211
366
  const foldl = (xs, f, acc) => {
212
- each(xs, (x, i) => {
213
- acc = f(acc, x, i);
214
- });
215
- return acc;
367
+ each(xs, (x, i) => {
368
+ acc = f(acc, x, i);
369
+ });
370
+ return acc;
216
371
  };
217
- const flatten = xs => {
218
- const r = [];
219
- for (let i = 0, len = xs.length; i < len; ++i) {
220
- if (!isArray(xs[i])) {
221
- throw new Error('Arr.flatten item ' + i + ' was not an array, input: ' + xs);
372
+ const flatten = (xs) => {
373
+ // Note, this is possible because push supports multiple arguments:
374
+ // http://jsperf.com/concat-push/6
375
+ // Note that in the past, concat() would silently work (very slowly) for array-like objects.
376
+ // With this change it will throw an error.
377
+ const r = [];
378
+ for (let i = 0, len = xs.length; i < len; ++i) {
379
+ // Ensure that each value is an array itself
380
+ if (!isArray(xs[i])) {
381
+ throw new Error('Arr.flatten item ' + i + ' was not an array, input: ' + xs);
382
+ }
383
+ nativePush.apply(r, xs[i]);
222
384
  }
223
- nativePush.apply(r, xs[i]);
224
- }
225
- return r;
385
+ return r;
226
386
  };
227
387
  const bind = (xs, f) => flatten(map(xs, f));
228
388
  const sort = (xs, comparator) => {
229
- const copy = nativeSlice.call(xs, 0);
230
- copy.sort(comparator);
231
- return copy;
389
+ const copy = nativeSlice.call(xs, 0);
390
+ copy.sort(comparator);
391
+ return copy;
232
392
  };
233
393
 
394
+ // eslint-disable-next-line @typescript-eslint/unbound-method
234
395
  const hasOwnProperty = Object.hasOwnProperty;
235
396
  const has = (obj, key) => hasOwnProperty.call(obj, key);
236
397
 
237
- typeof window !== 'undefined' ? window : Function('return this;')();
398
+ const Cell = (initial) => {
399
+ let value = initial;
400
+ const get = () => {
401
+ return value;
402
+ };
403
+ const set = (v) => {
404
+ value = v;
405
+ };
406
+ return {
407
+ get,
408
+ set
409
+ };
410
+ };
238
411
 
239
- const DOCUMENT = 9;
240
- const DOCUMENT_FRAGMENT = 11;
241
- const ELEMENT = 1;
242
- const TEXT = 3;
412
+ const singleton = (doRevoke) => {
413
+ const subject = Cell(Optional.none());
414
+ const revoke = () => subject.get().each(doRevoke);
415
+ const clear = () => {
416
+ revoke();
417
+ subject.set(Optional.none());
418
+ };
419
+ const isSet = () => subject.get().isSome();
420
+ const get = () => subject.get();
421
+ const set = (s) => {
422
+ revoke();
423
+ subject.set(Optional.some(s));
424
+ };
425
+ return {
426
+ clear,
427
+ isSet,
428
+ get,
429
+ set
430
+ };
431
+ };
432
+ const value = () => {
433
+ const subject = singleton(noop);
434
+ const on = (f) => subject.get().each(f);
435
+ return {
436
+ ...subject,
437
+ on
438
+ };
439
+ };
243
440
 
244
- const type = element => element.dom.nodeType;
245
- const isType = t => element => type(element) === t;
246
- const isText$1 = isType(TEXT);
441
+ var global$3 = tinymce.util.Tools.resolve('tinymce.PluginManager');
247
442
 
248
- const rawSet = (dom, key, value) => {
249
- if (isString(value) || isBoolean(value) || isNumber(value)) {
250
- dom.setAttribute(key, value + '');
251
- } else {
252
- console.error('Invalid call to Attribute.set. Key ', key, ':: Value ', value, ':: Element ', dom);
253
- throw new Error('Attribute value was not simple');
254
- }
255
- };
256
- const set = (element, key, value) => {
257
- rawSet(element.dom, key, value);
443
+ /* eslint-disable max-len */
444
+ const punctuationStr = `[~№|!-*+-\\/:;?@\\[-\`{}\u00A1\u00AB\u00B7\u00BB\u00BF;\u00B7\u055A-\u055F\u0589\u058A\u05BE\u05C0\u05C3\u05C6\u05F3\u05F4\u0609\u060A\u060C\u060D\u061B\u061E\u061F\u066A-\u066D\u06D4\u0700-\u070D\u07F7-\u07F9\u0830-\u083E\u085E\u0964\u0965\u0970\u0DF4\u0E4F\u0E5A\u0E5B\u0F04-\u0F12\u0F3A-\u0F3D\u0F85\u0FD0-\u0FD4\u0FD9\u0FDA\u104A-\u104F\u10FB\u1361-\u1368\u1400\u166D\u166E\u169B\u169C\u16EB-\u16ED\u1735\u1736\u17D4-\u17D6\u17D8-\u17DA\u1800-\u180A\u1944\u1945\u1A1E\u1A1F\u1AA0-\u1AA6\u1AA8-\u1AAD\u1B5A-\u1B60\u1BFC-\u1BFF\u1C3B-\u1C3F\u1C7E\u1C7F\u1CD3\u2010-\u2027\u2030-\u2043\u2045-\u2051\u2053-\u205E\u207D\u207E\u208D\u208E\u3008\u3009\u2768-\u2775\u27C5\u27C6\u27E6-\u27EF\u2983-\u2998\u29D8-\u29DB\u29FC\u29FD\u2CF9-\u2CFC\u2CFE\u2CFF\u2D70\u2E00-\u2E2E\u2E30\u2E31\u3001-\u3003\u3008-\u3011\u3014-\u301F\u3030\u303D\u30A0\u30FB\uA4FE\uA4FF\uA60D-\uA60F\uA673\uA67E\uA6F2-\uA6F7\uA874-\uA877\uA8CE\uA8CF\uA8F8-\uA8FA\uA92E\uA92F\uA95F\uA9C1-\uA9CD\uA9DE\uA9DF\uAA5C-\uAA5F\uAADE\uAADF\uABEB\uFD3E\uFD3F\uFE10-\uFE19\uFE30-\uFE52\uFE54-\uFE61\uFE63\uFE68\uFE6A\uFE6B\uFF01-\uFF03\uFF05-\uFF0A\uFF0C-\uFF0F\uFF1A\uFF1B\uFF1F\uFF20\uFF3B-\uFF3D\uFF3F\uFF5B\uFF5D\uFF5F-\uFF65]`;
445
+
446
+ const punctuation$1 = constant(punctuationStr);
447
+
448
+ // tslint:disable-next-line:variable-name
449
+ const Custom = (regex, prefix, suffix, flags) => {
450
+ const term = () => {
451
+ return new RegExp(regex, flags.getOr('g'));
452
+ };
453
+ return {
454
+ term,
455
+ prefix,
456
+ suffix
457
+ };
258
458
  };
259
459
 
460
+ Custom;
461
+ const punctuation = punctuation$1;
462
+
463
+ var global$2 = tinymce.util.Tools.resolve('tinymce.Env');
464
+
465
+ var global$1 = tinymce.util.Tools.resolve('tinymce.util.Tools');
466
+
260
467
  const fromHtml = (html, scope) => {
261
- const doc = scope || document;
262
- const div = doc.createElement('div');
263
- div.innerHTML = html;
264
- if (!div.hasChildNodes() || div.childNodes.length > 1) {
265
- const message = 'HTML does not have a single root node';
266
- console.error(message, html);
267
- throw new Error(message);
268
- }
269
- return fromDom(div.childNodes[0]);
468
+ const doc = scope || document;
469
+ const div = doc.createElement('div');
470
+ div.innerHTML = html;
471
+ if (!div.hasChildNodes() || div.childNodes.length > 1) {
472
+ const message = 'HTML does not have a single root node';
473
+ // eslint-disable-next-line no-console
474
+ console.error(message, html);
475
+ throw new Error(message);
476
+ }
477
+ return fromDom(div.childNodes[0]);
270
478
  };
271
479
  const fromTag = (tag, scope) => {
272
- const doc = scope || document;
273
- const node = doc.createElement(tag);
274
- return fromDom(node);
480
+ const doc = scope || document;
481
+ const node = doc.createElement(tag);
482
+ return fromDom(node);
275
483
  };
276
484
  const fromText = (text, scope) => {
277
- const doc = scope || document;
278
- const node = doc.createTextNode(text);
279
- return fromDom(node);
485
+ const doc = scope || document;
486
+ const node = doc.createTextNode(text);
487
+ return fromDom(node);
280
488
  };
281
- const fromDom = node => {
282
- if (node === null || node === undefined) {
283
- throw new Error('Node cannot be null or undefined');
284
- }
285
- return { dom: node };
489
+ const fromDom = (node) => {
490
+ // TODO: Consider removing this check, but left atm for safety
491
+ if (node === null || node === undefined) {
492
+ throw new Error('Node cannot be null or undefined');
493
+ }
494
+ return {
495
+ dom: node
496
+ };
286
497
  };
287
498
  const fromPoint = (docElm, x, y) => Optional.from(docElm.dom.elementFromPoint(x, y)).map(fromDom);
499
+ // tslint:disable-next-line:variable-name
288
500
  const SugarElement = {
289
- fromHtml,
290
- fromTag,
291
- fromText,
292
- fromDom,
293
- fromPoint
501
+ fromHtml,
502
+ fromTag,
503
+ fromText,
504
+ fromDom,
505
+ fromPoint
294
506
  };
295
507
 
296
- const bypassSelector = dom => dom.nodeType !== ELEMENT && dom.nodeType !== DOCUMENT && dom.nodeType !== DOCUMENT_FRAGMENT || dom.childElementCount === 0;
508
+ const DOCUMENT = 9;
509
+ const DOCUMENT_FRAGMENT = 11;
510
+ const ELEMENT = 1;
511
+ const TEXT = 3;
512
+
513
+ const bypassSelector = (dom) =>
514
+ // Only elements, documents and shadow roots support querySelector
515
+ // shadow root element type is DOCUMENT_FRAGMENT
516
+ dom.nodeType !== ELEMENT && dom.nodeType !== DOCUMENT && dom.nodeType !== DOCUMENT_FRAGMENT ||
517
+ // IE fix for complex queries on empty nodes: http://jsfiddle.net/spyder/fv9ptr5L/
518
+ dom.childElementCount === 0;
297
519
  const all = (selector, scope) => {
298
- const base = scope === undefined ? document : scope.dom;
299
- return bypassSelector(base) ? [] : map(base.querySelectorAll(selector), SugarElement.fromDom);
520
+ const base = scope === undefined ? document : scope.dom;
521
+ return bypassSelector(base) ? [] : map(base.querySelectorAll(selector), SugarElement.fromDom);
522
+ };
523
+
524
+ /*
525
+ * Most of sand doesn't alter the methods on the object.
526
+ * We're making an exception for Node, because bitwise and is so easy to get wrong.
527
+ *
528
+ * Might be nice to ADT this at some point instead of having individual methods.
529
+ */
530
+ const compareDocumentPosition = (a, b, match) => {
531
+ // Returns: 0 if e1 and e2 are the same node, or a bitmask comparing the positions
532
+ // of nodes e1 and e2 in their documents. See the URL below for bitmask interpretation
533
+ // https://developer.mozilla.org/en-US/docs/Web/API/Node/compareDocumentPosition
534
+ // eslint-disable-next-line no-bitwise
535
+ return (a.compareDocumentPosition(b) & match) !== 0;
300
536
  };
537
+ const documentPositionPreceding = (a, b) => {
538
+ return compareDocumentPosition(a, b, Node.DOCUMENT_POSITION_PRECEDING);
539
+ };
540
+
541
+ const type = (element) => element.dom.nodeType;
542
+ const isType = (t) => (element) => type(element) === t;
543
+ const isText$1 = isType(TEXT);
301
544
 
302
- const parent = element => Optional.from(element.dom.parentNode).map(SugarElement.fromDom);
303
- const children = element => map(element.dom.childNodes, SugarElement.fromDom);
545
+ const parent = (element) => Optional.from(element.dom.parentNode).map(SugarElement.fromDom);
546
+ const children = (element) => map(element.dom.childNodes, SugarElement.fromDom);
304
547
  const spot = (element, offset) => ({
305
- element,
306
- offset
548
+ element,
549
+ offset
307
550
  });
308
551
  const leaf = (element, offset) => {
309
- const cs = children(element);
310
- return cs.length > 0 && offset < cs.length ? spot(cs[offset], 0) : spot(element, offset);
552
+ const cs = children(element);
553
+ return cs.length > 0 && offset < cs.length ? spot(cs[offset], 0) : spot(element, offset);
311
554
  };
312
555
 
313
556
  const before = (marker, element) => {
314
- const parent$1 = parent(marker);
315
- parent$1.each(v => {
316
- v.dom.insertBefore(element.dom, marker.dom);
317
- });
557
+ const parent$1 = parent(marker);
558
+ parent$1.each((v) => {
559
+ v.dom.insertBefore(element.dom, marker.dom);
560
+ });
318
561
  };
319
562
  const append = (parent, element) => {
320
- parent.dom.appendChild(element.dom);
563
+ parent.dom.appendChild(element.dom);
321
564
  };
322
565
  const wrap = (element, wrapper) => {
323
- before(element, wrapper);
324
- append(wrapper, element);
566
+ before(element, wrapper);
567
+ append(wrapper, element);
325
568
  };
326
569
 
327
- const NodeValue = (is, name) => {
328
- const get = element => {
329
- if (!is(element)) {
330
- throw new Error('Can only get ' + name + ' value of a ' + name + ' node');
570
+ const rawSet = (dom, key, value) => {
571
+ /*
572
+ * JQuery coerced everything to a string, and silently did nothing on text node/null/undefined.
573
+ *
574
+ * We fail on those invalid cases, only allowing numbers and booleans.
575
+ */
576
+ if (isString(value) || isBoolean(value) || isNumber(value)) {
577
+ dom.setAttribute(key, value + '');
331
578
  }
332
- return getOption(element).getOr('');
333
- };
334
- const getOption = element => is(element) ? Optional.from(element.dom.nodeValue) : Optional.none();
335
- const set = (element, value) => {
336
- if (!is(element)) {
337
- throw new Error('Can only set raw ' + name + ' value of a ' + name + ' node');
579
+ else {
580
+ // eslint-disable-next-line no-console
581
+ console.error('Invalid call to Attribute.set. Key ', key, ':: Value ', value, ':: Element ', dom);
582
+ throw new Error('Attribute value was not simple');
338
583
  }
339
- element.dom.nodeValue = value;
340
- };
341
- return {
342
- get,
343
- getOption,
344
- set
345
- };
346
584
  };
347
-
348
- const api = NodeValue(isText$1, 'text');
349
- const get$1 = element => api.get(element);
350
-
351
- const compareDocumentPosition = (a, b, match) => {
352
- return (a.compareDocumentPosition(b) & match) !== 0;
585
+ const set = (element, key, value) => {
586
+ rawSet(element.dom, key, value);
353
587
  };
354
- const documentPositionPreceding = (a, b) => {
355
- return compareDocumentPosition(a, b, Node.DOCUMENT_POSITION_PRECEDING);
588
+
589
+ const NodeValue = (is, name) => {
590
+ const get = (element) => {
591
+ if (!is(element)) {
592
+ throw new Error('Can only get ' + name + ' value of a ' + name + ' node');
593
+ }
594
+ return getOption(element).getOr('');
595
+ };
596
+ const getOption = (element) => is(element) ? Optional.from(element.dom.nodeValue) : Optional.none();
597
+ const set = (element, value) => {
598
+ if (!is(element)) {
599
+ throw new Error('Can only set raw ' + name + ' value of a ' + name + ' node');
600
+ }
601
+ element.dom.nodeValue = value;
602
+ };
603
+ return {
604
+ get,
605
+ getOption,
606
+ set
607
+ };
356
608
  };
357
609
 
610
+ const api = NodeValue(isText$1, 'text');
611
+ const get$1 = (element) => api.get(element);
612
+
358
613
  const descendants = (scope, selector) => all(selector, scope);
359
614
 
360
615
  var global = tinymce.util.Tools.resolve('tinymce.dom.TreeWalker');
@@ -364,730 +619,752 @@
364
619
  const isContentEditableTrueInCef = (dom, node) => dom.getContentEditable(node) === 'true' && node.parentNode && !dom.isEditable(node.parentNode);
365
620
  const isHidden = (dom, node) => !dom.isBlock(node) && has(dom.schema.getWhitespaceElements(), node.nodeName);
366
621
  const isBoundary = (dom, node) => isSimpleBoundary(dom, node) || isContentEditableFalse(dom, node) || isHidden(dom, node) || isContentEditableTrueInCef(dom, node);
367
- const isText = node => node.nodeType === 3;
622
+ const isText = (node) => node.nodeType === 3;
368
623
  const nuSection = () => ({
369
- sOffset: 0,
370
- fOffset: 0,
371
- elements: []
624
+ sOffset: 0,
625
+ fOffset: 0,
626
+ elements: []
372
627
  });
373
628
  const toLeaf = (node, offset) => leaf(SugarElement.fromDom(node), offset);
374
629
  const walk = (dom, walkerFn, startNode, callbacks, endNode, skipStart = true) => {
375
- let next = skipStart ? walkerFn(false) : startNode;
376
- while (next) {
377
- const isCefNode = isContentEditableFalse(dom, next);
378
- if (isCefNode || isHidden(dom, next)) {
379
- const stopWalking = isCefNode ? callbacks.cef(next) : callbacks.boundary(next);
380
- if (stopWalking) {
381
- break;
382
- } else {
383
- next = walkerFn(true);
384
- continue;
385
- }
386
- } else if (isSimpleBoundary(dom, next)) {
387
- if (callbacks.boundary(next)) {
388
- break;
389
- }
390
- } else if (isText(next)) {
391
- callbacks.text(next);
392
- }
393
- if (next === endNode) {
394
- break;
395
- } else {
396
- next = walkerFn(false);
630
+ let next = skipStart ? walkerFn(false) : startNode;
631
+ while (next) {
632
+ // Walk over content editable or hidden elements
633
+ const isCefNode = isContentEditableFalse(dom, next);
634
+ if (isCefNode || isHidden(dom, next)) {
635
+ const stopWalking = isCefNode ? callbacks.cef(next) : callbacks.boundary(next);
636
+ if (stopWalking) {
637
+ break;
638
+ }
639
+ else {
640
+ next = walkerFn(true);
641
+ continue;
642
+ }
643
+ }
644
+ else if (isSimpleBoundary(dom, next)) {
645
+ if (callbacks.boundary(next)) {
646
+ break;
647
+ }
648
+ }
649
+ else if (isText(next)) {
650
+ callbacks.text(next);
651
+ }
652
+ if (next === endNode) {
653
+ break;
654
+ }
655
+ else {
656
+ next = walkerFn(false);
657
+ }
397
658
  }
398
- }
399
659
  };
400
660
  const collectTextToBoundary = (dom, section, node, rootNode, forwards) => {
401
- var _a;
402
- if (isBoundary(dom, node)) {
403
- return;
404
- }
405
- const rootBlock = (_a = dom.getParent(rootNode, dom.isBlock)) !== null && _a !== void 0 ? _a : dom.getRoot();
406
- const walker = new global(node, rootBlock);
407
- const walkerFn = forwards ? walker.next.bind(walker) : walker.prev.bind(walker);
408
- walk(dom, walkerFn, node, {
409
- boundary: always,
410
- cef: always,
411
- text: next => {
412
- if (forwards) {
413
- section.fOffset += next.length;
414
- } else {
415
- section.sOffset += next.length;
416
- }
417
- section.elements.push(SugarElement.fromDom(next));
661
+ var _a;
662
+ // Don't bother collecting text nodes if we're already at a boundary
663
+ if (isBoundary(dom, node)) {
664
+ return;
418
665
  }
419
- });
666
+ const rootBlock = (_a = dom.getParent(rootNode, dom.isBlock)) !== null && _a !== void 0 ? _a : dom.getRoot();
667
+ const walker = new global(node, rootBlock);
668
+ const walkerFn = forwards ? walker.next.bind(walker) : walker.prev.bind(walker);
669
+ // Walk over and add text nodes to the section and increase the offsets
670
+ // so we know to ignore the additional text when matching
671
+ walk(dom, walkerFn, node, {
672
+ boundary: always,
673
+ cef: always,
674
+ text: (next) => {
675
+ if (forwards) {
676
+ section.fOffset += next.length;
677
+ }
678
+ else {
679
+ section.sOffset += next.length;
680
+ }
681
+ section.elements.push(SugarElement.fromDom(next));
682
+ }
683
+ });
420
684
  };
421
685
  const collect = (dom, rootNode, startNode, endNode, callbacks, skipStart = true) => {
422
- const walker = new global(startNode, rootNode);
423
- const sections = [];
424
- let current = nuSection();
425
- collectTextToBoundary(dom, current, startNode, rootNode, false);
426
- const finishSection = () => {
427
- if (current.elements.length > 0) {
428
- sections.push(current);
429
- current = nuSection();
430
- }
431
- return false;
432
- };
433
- walk(dom, walker.next.bind(walker), startNode, {
434
- boundary: finishSection,
435
- cef: node => {
436
- finishSection();
437
- if (callbacks) {
438
- sections.push(...callbacks.cef(node));
439
- }
440
- return false;
441
- },
442
- text: next => {
443
- current.elements.push(SugarElement.fromDom(next));
444
- if (callbacks) {
445
- callbacks.text(next, current);
446
- }
686
+ const walker = new global(startNode, rootNode);
687
+ const sections = [];
688
+ let current = nuSection();
689
+ // Find any text between the start node and the closest boundary
690
+ collectTextToBoundary(dom, current, startNode, rootNode, false);
691
+ const finishSection = () => {
692
+ if (current.elements.length > 0) {
693
+ sections.push(current);
694
+ current = nuSection();
695
+ }
696
+ return false;
697
+ };
698
+ // Collect all the text nodes in the specified range and create sections from the
699
+ // boundaries within the range
700
+ walk(dom, walker.next.bind(walker), startNode, {
701
+ boundary: finishSection,
702
+ cef: (node) => {
703
+ finishSection();
704
+ // Collect additional nested contenteditable true content
705
+ if (callbacks) {
706
+ sections.push(...callbacks.cef(node));
707
+ }
708
+ return false;
709
+ },
710
+ text: (next) => {
711
+ current.elements.push(SugarElement.fromDom(next));
712
+ if (callbacks) {
713
+ callbacks.text(next, current);
714
+ }
715
+ }
716
+ }, endNode, skipStart);
717
+ // Find any text between the end node and the closest boundary, then finalise the section
718
+ if (endNode) {
719
+ collectTextToBoundary(dom, current, endNode, rootNode, true);
447
720
  }
448
- }, endNode, skipStart);
449
- if (endNode) {
450
- collectTextToBoundary(dom, current, endNode, rootNode, true);
451
- }
452
- finishSection();
453
- return sections;
721
+ finishSection();
722
+ return sections;
454
723
  };
455
724
  const collectRangeSections = (dom, rng) => {
456
- const start = toLeaf(rng.startContainer, rng.startOffset);
457
- const startNode = start.element.dom;
458
- const end = toLeaf(rng.endContainer, rng.endOffset);
459
- const endNode = end.element.dom;
460
- return collect(dom, rng.commonAncestorContainer, startNode, endNode, {
461
- text: (node, section) => {
462
- if (node === endNode) {
463
- section.fOffset += node.length - end.offset;
464
- } else if (node === startNode) {
465
- section.sOffset += start.offset;
466
- }
467
- },
468
- cef: node => {
469
- const sections = bind(descendants(SugarElement.fromDom(node), '*[contenteditable=true]'), e => {
470
- const ceTrueNode = e.dom;
471
- return collect(dom, ceTrueNode, ceTrueNode);
472
- });
473
- return sort(sections, (a, b) => documentPositionPreceding(a.elements[0].dom, b.elements[0].dom) ? 1 : -1);
474
- }
475
- }, false);
725
+ const start = toLeaf(rng.startContainer, rng.startOffset);
726
+ const startNode = start.element.dom;
727
+ const end = toLeaf(rng.endContainer, rng.endOffset);
728
+ const endNode = end.element.dom;
729
+ return collect(dom, rng.commonAncestorContainer, startNode, endNode, {
730
+ text: (node, section) => {
731
+ // Set the start/end offset of the section
732
+ if (node === endNode) {
733
+ section.fOffset += node.length - end.offset;
734
+ }
735
+ else if (node === startNode) {
736
+ section.sOffset += start.offset;
737
+ }
738
+ },
739
+ cef: (node) => {
740
+ // Collect the sections and then order them appropriately, as nested sections maybe out of order
741
+ // TODO: See if we can improve this to avoid the sort overhead
742
+ const sections = bind(descendants(SugarElement.fromDom(node), '*[contenteditable=true]'), (e) => {
743
+ const ceTrueNode = e.dom;
744
+ return collect(dom, ceTrueNode, ceTrueNode);
745
+ });
746
+ return sort(sections, (a, b) => (documentPositionPreceding(a.elements[0].dom, b.elements[0].dom)) ? 1 : -1);
747
+ }
748
+ }, false);
476
749
  };
477
750
  const fromRng = (dom, rng) => rng.collapsed ? [] : collectRangeSections(dom, rng);
478
751
  const fromNode = (dom, node) => {
479
- const rng = dom.createRng();
480
- rng.selectNode(node);
481
- return fromRng(dom, rng);
752
+ const rng = dom.createRng();
753
+ rng.selectNode(node);
754
+ return fromRng(dom, rng);
482
755
  };
483
- const fromNodes = (dom, nodes) => bind(nodes, node => fromNode(dom, node));
756
+ const fromNodes = (dom, nodes) => bind(nodes, (node) => fromNode(dom, node));
484
757
 
485
758
  const find$2 = (text, pattern, start = 0, finish = text.length) => {
486
- const regex = pattern.regex;
487
- regex.lastIndex = start;
488
- const results = [];
489
- let match;
490
- while (match = regex.exec(text)) {
491
- const matchedText = match[pattern.matchIndex];
492
- const matchStart = match.index + match[0].indexOf(matchedText);
493
- const matchFinish = matchStart + matchedText.length;
494
- if (matchFinish > finish) {
495
- break;
759
+ const regex = pattern.regex;
760
+ regex.lastIndex = start;
761
+ const results = [];
762
+ let match;
763
+ while ((match = regex.exec(text))) {
764
+ const matchedText = match[pattern.matchIndex];
765
+ const matchStart = match.index + match[0].indexOf(matchedText);
766
+ const matchFinish = matchStart + matchedText.length;
767
+ // Stop finding matches if we've hit the finish mark
768
+ if (matchFinish > finish) {
769
+ break;
770
+ }
771
+ results.push({
772
+ start: matchStart,
773
+ finish: matchFinish
774
+ });
775
+ regex.lastIndex = matchFinish;
496
776
  }
497
- results.push({
498
- start: matchStart,
499
- finish: matchFinish
500
- });
501
- regex.lastIndex = matchFinish;
502
- }
503
- return results;
777
+ return results;
504
778
  };
505
779
  const extract = (elements, matches) => {
506
- const nodePositions = foldl(elements, (acc, element) => {
507
- const content = get$1(element);
508
- const start = acc.last;
509
- const finish = start + content.length;
510
- const positions = bind(matches, (match, matchIdx) => {
511
- if (match.start < finish && match.finish > start) {
512
- return [{
513
- element,
514
- start: Math.max(start, match.start) - start,
515
- finish: Math.min(finish, match.finish) - start,
516
- matchId: matchIdx
517
- }];
518
- } else {
519
- return [];
520
- }
521
- });
522
- return {
523
- results: acc.results.concat(positions),
524
- last: finish
525
- };
526
- }, {
527
- results: [],
528
- last: 0
529
- }).results;
530
- return groupBy(nodePositions, position => position.matchId);
780
+ // Walk over each text node and compare with the matches
781
+ const nodePositions = foldl(elements, (acc, element) => {
782
+ const content = get$1(element);
783
+ const start = acc.last;
784
+ const finish = start + content.length;
785
+ // Find positions for any matches in the current text node
786
+ const positions = bind(matches, (match, matchIdx) => {
787
+ // Check to see if the match overlaps with the text position
788
+ if (match.start < finish && match.finish > start) {
789
+ return [{
790
+ element,
791
+ start: Math.max(start, match.start) - start,
792
+ finish: Math.min(finish, match.finish) - start,
793
+ matchId: matchIdx
794
+ }];
795
+ }
796
+ else {
797
+ return [];
798
+ }
799
+ });
800
+ return {
801
+ results: acc.results.concat(positions),
802
+ last: finish
803
+ };
804
+ }, { results: [], last: 0 }).results;
805
+ // Group the positions by the match id
806
+ return groupBy(nodePositions, (position) => position.matchId);
531
807
  };
532
808
 
533
- const find$1 = (pattern, sections) => bind(sections, section => {
534
- const elements = section.elements;
535
- const content = map(elements, get$1).join('');
536
- const positions = find$2(content, pattern, section.sOffset, content.length - section.fOffset);
537
- return extract(elements, positions);
809
+ const find$1 = (pattern, sections) => bind(sections, (section) => {
810
+ const elements = section.elements;
811
+ const content = map(elements, get$1).join('');
812
+ const positions = find$2(content, pattern, section.sOffset, content.length - section.fOffset);
813
+ return extract(elements, positions);
538
814
  });
539
815
  const mark = (matches, replacementNode) => {
540
- eachr(matches, (match, idx) => {
541
- eachr(match, pos => {
542
- const wrapper = SugarElement.fromDom(replacementNode.cloneNode(false));
543
- set(wrapper, 'data-mce-index', idx);
544
- const textNode = pos.element.dom;
545
- if (textNode.length === pos.finish && pos.start === 0) {
546
- wrap(pos.element, wrapper);
547
- } else {
548
- if (textNode.length !== pos.finish) {
549
- textNode.splitText(pos.finish);
550
- }
551
- const matchNode = textNode.splitText(pos.start);
552
- wrap(SugarElement.fromDom(matchNode), wrapper);
553
- }
816
+ // Walk backwards and mark the positions
817
+ // Note: We need to walk backwards so the position indexes don't change
818
+ eachr(matches, (match, idx) => {
819
+ eachr(match, (pos) => {
820
+ const wrapper = SugarElement.fromDom(replacementNode.cloneNode(false));
821
+ set(wrapper, 'data-mce-index', idx);
822
+ const textNode = pos.element.dom;
823
+ if (textNode.length === pos.finish && pos.start === 0) {
824
+ wrap(pos.element, wrapper);
825
+ }
826
+ else {
827
+ if (textNode.length !== pos.finish) {
828
+ textNode.splitText(pos.finish);
829
+ }
830
+ const matchNode = textNode.splitText(pos.start);
831
+ wrap(SugarElement.fromDom(matchNode), wrapper);
832
+ }
833
+ });
554
834
  });
555
- });
556
835
  };
557
836
  const findAndMark = (dom, pattern, node, replacementNode) => {
558
- const textSections = fromNode(dom, node);
559
- const matches = find$1(pattern, textSections);
560
- mark(matches, replacementNode);
561
- return matches.length;
837
+ const textSections = fromNode(dom, node);
838
+ const matches = find$1(pattern, textSections);
839
+ mark(matches, replacementNode);
840
+ return matches.length;
562
841
  };
563
842
  const findAndMarkInSelection = (dom, pattern, selection, replacementNode) => {
564
- const bookmark = selection.getBookmark();
565
- const nodes = dom.select('td[data-mce-selected],th[data-mce-selected]');
566
- const textSections = nodes.length > 0 ? fromNodes(dom, nodes) : fromRng(dom, selection.getRng());
567
- const matches = find$1(pattern, textSections);
568
- mark(matches, replacementNode);
569
- selection.moveToBookmark(bookmark);
570
- return matches.length;
843
+ const bookmark = selection.getBookmark();
844
+ // Handle table cell selection as the table plugin enables
845
+ // you to fake select table cells and perform actions on them
846
+ const nodes = dom.select('td[data-mce-selected],th[data-mce-selected]');
847
+ const textSections = nodes.length > 0 ? fromNodes(dom, nodes) : fromRng(dom, selection.getRng());
848
+ // Find and mark matches
849
+ const matches = find$1(pattern, textSections);
850
+ mark(matches, replacementNode);
851
+ // Restore the selection
852
+ selection.moveToBookmark(bookmark);
853
+ return matches.length;
571
854
  };
572
855
 
573
- const getElmIndex = elm => {
574
- return elm.getAttribute('data-mce-index');
856
+ const getElmIndex = (elm) => {
857
+ return elm.getAttribute('data-mce-index');
575
858
  };
576
859
  const markAllMatches = (editor, currentSearchState, pattern, inSelection) => {
577
- const marker = editor.dom.create('span', { 'data-mce-bogus': 1 });
578
- marker.className = 'mce-match-marker';
579
- const node = editor.getBody();
580
- done(editor, currentSearchState, false);
581
- if (inSelection) {
582
- return findAndMarkInSelection(editor.dom, pattern, editor.selection, marker);
583
- } else {
584
- return findAndMark(editor.dom, pattern, node, marker);
585
- }
860
+ const marker = editor.dom.create('span', {
861
+ 'data-mce-bogus': 1
862
+ });
863
+ marker.className = 'mce-match-marker';
864
+ const node = editor.getBody();
865
+ done(editor, currentSearchState, false);
866
+ if (inSelection) {
867
+ return findAndMarkInSelection(editor.dom, pattern, editor.selection, marker);
868
+ }
869
+ else {
870
+ return findAndMark(editor.dom, pattern, node, marker);
871
+ }
586
872
  };
587
- const unwrap = node => {
588
- var _a;
589
- const parentNode = node.parentNode;
590
- if (node.firstChild) {
591
- parentNode.insertBefore(node.firstChild, node);
592
- }
593
- (_a = node.parentNode) === null || _a === void 0 ? void 0 : _a.removeChild(node);
873
+ const unwrap = (node) => {
874
+ var _a;
875
+ const parentNode = node.parentNode;
876
+ if (node.firstChild) {
877
+ parentNode.insertBefore(node.firstChild, node);
878
+ }
879
+ (_a = node.parentNode) === null || _a === void 0 ? void 0 : _a.removeChild(node);
594
880
  };
595
881
  const findSpansByIndex = (editor, index) => {
596
- const spans = [];
597
- const nodes = global$1.toArray(editor.getBody().getElementsByTagName('span'));
598
- if (nodes.length) {
599
- for (let i = 0; i < nodes.length; i++) {
600
- const nodeIndex = getElmIndex(nodes[i]);
601
- if (nodeIndex === null || !nodeIndex.length) {
602
- continue;
603
- }
604
- if (nodeIndex === index.toString()) {
605
- spans.push(nodes[i]);
606
- }
882
+ const spans = [];
883
+ const nodes = global$1.toArray(editor.getBody().getElementsByTagName('span'));
884
+ if (nodes.length) {
885
+ for (let i = 0; i < nodes.length; i++) {
886
+ const nodeIndex = getElmIndex(nodes[i]);
887
+ if (nodeIndex === null || !nodeIndex.length) {
888
+ continue;
889
+ }
890
+ if (nodeIndex === index.toString()) {
891
+ spans.push(nodes[i]);
892
+ }
893
+ }
607
894
  }
608
- }
609
- return spans;
895
+ return spans;
610
896
  };
611
897
  const moveSelection = (editor, currentSearchState, forward) => {
612
- const searchState = currentSearchState.get();
613
- let testIndex = searchState.index;
614
- const dom = editor.dom;
615
- if (forward) {
616
- if (testIndex + 1 === searchState.count) {
617
- testIndex = 0;
618
- } else {
619
- testIndex++;
898
+ const searchState = currentSearchState.get();
899
+ let testIndex = searchState.index;
900
+ const dom = editor.dom;
901
+ if (forward) {
902
+ if (testIndex + 1 === searchState.count) {
903
+ testIndex = 0;
904
+ }
905
+ else {
906
+ testIndex++;
907
+ }
620
908
  }
621
- } else {
622
- if (testIndex - 1 === -1) {
623
- testIndex = searchState.count - 1;
624
- } else {
625
- testIndex--;
909
+ else {
910
+ if (testIndex - 1 === -1) {
911
+ testIndex = searchState.count - 1;
912
+ }
913
+ else {
914
+ testIndex--;
915
+ }
626
916
  }
627
- }
628
- dom.removeClass(findSpansByIndex(editor, searchState.index), 'mce-match-marker-selected');
629
- const spans = findSpansByIndex(editor, testIndex);
630
- if (spans.length) {
631
- dom.addClass(findSpansByIndex(editor, testIndex), 'mce-match-marker-selected');
632
- editor.selection.scrollIntoView(spans[0]);
633
- return testIndex;
634
- }
635
- return -1;
917
+ dom.removeClass(findSpansByIndex(editor, searchState.index), 'mce-match-marker-selected');
918
+ const spans = findSpansByIndex(editor, testIndex);
919
+ if (spans.length) {
920
+ dom.addClass(findSpansByIndex(editor, testIndex), 'mce-match-marker-selected');
921
+ editor.selection.scrollIntoView(spans[0]);
922
+ return testIndex;
923
+ }
924
+ return -1;
636
925
  };
637
926
  const removeNode = (dom, node) => {
638
- const parent = node.parentNode;
639
- dom.remove(node);
640
- if (parent && dom.isEmpty(parent)) {
641
- dom.remove(parent);
642
- }
927
+ const parent = node.parentNode;
928
+ dom.remove(node);
929
+ if (parent && dom.isEmpty(parent)) {
930
+ dom.remove(parent);
931
+ }
643
932
  };
644
933
  const escapeSearchText = (text, wholeWord) => {
645
- const escapedText = text.replace(/[\-\[\]\/\{\}\(\)\*\+\?\.\\\^\$\|]/g, '\\$&').replace(/\s/g, '[^\\S\\r\\n\\uFEFF]');
646
- const wordRegex = '(' + escapedText + ')';
647
- return wholeWord ? `(?:^|\\s|${ punctuation() })` + wordRegex + `(?=$|\\s|${ punctuation() })` : wordRegex;
934
+ const escapedText = text.replace(/[\-\[\]\/\{\}\(\)\*\+\?\.\\\^\$\|]/g, '\\$&').replace(/\s/g, '[^\\S\\r\\n\\uFEFF]');
935
+ const wordRegex = '(' + escapedText + ')';
936
+ return wholeWord ? `(?:^|\\s|${punctuation()})` + wordRegex + `(?=$|\\s|${punctuation()})` : wordRegex;
648
937
  };
649
938
  const find = (editor, currentSearchState, text, matchCase, wholeWord, inSelection) => {
650
- const selection = editor.selection;
651
- const escapedText = escapeSearchText(text, wholeWord);
652
- const isForwardSelection = selection.isForward();
653
- const pattern = {
654
- regex: new RegExp(escapedText, matchCase ? 'g' : 'gi'),
655
- matchIndex: 1
656
- };
657
- const count = markAllMatches(editor, currentSearchState, pattern, inSelection);
658
- if (global$2.browser.isSafari()) {
659
- selection.setRng(selection.getRng(), isForwardSelection);
660
- }
661
- if (count) {
662
- const newIndex = moveSelection(editor, currentSearchState, true);
663
- currentSearchState.set({
664
- index: newIndex,
665
- count,
666
- text,
667
- matchCase,
668
- wholeWord,
669
- inSelection
670
- });
671
- }
672
- return count;
939
+ const selection = editor.selection;
940
+ const escapedText = escapeSearchText(text, wholeWord);
941
+ const isForwardSelection = selection.isForward();
942
+ const pattern = {
943
+ regex: new RegExp(escapedText, matchCase ? 'g' : 'gi'),
944
+ matchIndex: 1
945
+ };
946
+ const count = markAllMatches(editor, currentSearchState, pattern, inSelection);
947
+ // Safari has a bug whereby splitting text nodes breaks the selection (which is done when marking matches).
948
+ // As such we need to manually reset it after doing a find action. See https://bugs.webkit.org/show_bug.cgi?id=230594
949
+ if (global$2.browser.isSafari()) {
950
+ selection.setRng(selection.getRng(), isForwardSelection);
951
+ }
952
+ if (count) {
953
+ const newIndex = moveSelection(editor, currentSearchState, true);
954
+ currentSearchState.set({
955
+ index: newIndex,
956
+ count,
957
+ text,
958
+ matchCase,
959
+ wholeWord,
960
+ inSelection
961
+ });
962
+ }
963
+ return count;
673
964
  };
674
965
  const next = (editor, currentSearchState) => {
675
- const index = moveSelection(editor, currentSearchState, true);
676
- currentSearchState.set({
677
- ...currentSearchState.get(),
678
- index
679
- });
966
+ const index = moveSelection(editor, currentSearchState, true);
967
+ currentSearchState.set({ ...currentSearchState.get(), index });
680
968
  };
681
969
  const prev = (editor, currentSearchState) => {
682
- const index = moveSelection(editor, currentSearchState, false);
683
- currentSearchState.set({
684
- ...currentSearchState.get(),
685
- index
686
- });
970
+ const index = moveSelection(editor, currentSearchState, false);
971
+ currentSearchState.set({ ...currentSearchState.get(), index });
687
972
  };
688
- const isMatchSpan = node => {
689
- const matchIndex = getElmIndex(node);
690
- return matchIndex !== null && matchIndex.length > 0;
973
+ const isMatchSpan = (node) => {
974
+ const matchIndex = getElmIndex(node);
975
+ return matchIndex !== null && matchIndex.length > 0;
691
976
  };
692
977
  const replace = (editor, currentSearchState, text, forward, all) => {
693
- const searchState = currentSearchState.get();
694
- const currentIndex = searchState.index;
695
- let currentMatchIndex, nextIndex = currentIndex;
696
- forward = forward !== false;
697
- const node = editor.getBody();
698
- const nodes = global$1.grep(global$1.toArray(node.getElementsByTagName('span')), isMatchSpan);
699
- for (let i = 0; i < nodes.length; i++) {
700
- const nodeIndex = getElmIndex(nodes[i]);
701
- let matchIndex = currentMatchIndex = parseInt(nodeIndex, 10);
702
- if (all || matchIndex === searchState.index) {
703
- if (text.length) {
704
- nodes[i].innerText = text;
705
- unwrap(nodes[i]);
706
- } else {
707
- removeNode(editor.dom, nodes[i]);
708
- }
709
- while (nodes[++i]) {
710
- matchIndex = parseInt(getElmIndex(nodes[i]), 10);
711
- if (matchIndex === currentMatchIndex) {
712
- removeNode(editor.dom, nodes[i]);
713
- } else {
714
- i--;
715
- break;
978
+ const searchState = currentSearchState.get();
979
+ const currentIndex = searchState.index;
980
+ let currentMatchIndex, nextIndex = currentIndex;
981
+ forward = forward !== false;
982
+ const node = editor.getBody();
983
+ const nodes = global$1.grep(global$1.toArray(node.getElementsByTagName('span')), isMatchSpan);
984
+ for (let i = 0; i < nodes.length; i++) {
985
+ const nodeIndex = getElmIndex(nodes[i]);
986
+ let matchIndex = currentMatchIndex = parseInt(nodeIndex, 10);
987
+ if (all || matchIndex === searchState.index) {
988
+ if (text.length) {
989
+ nodes[i].innerText = text;
990
+ unwrap(nodes[i]);
991
+ }
992
+ else {
993
+ removeNode(editor.dom, nodes[i]);
994
+ }
995
+ while (nodes[++i]) {
996
+ matchIndex = parseInt(getElmIndex(nodes[i]), 10);
997
+ if (matchIndex === currentMatchIndex) {
998
+ removeNode(editor.dom, nodes[i]);
999
+ }
1000
+ else {
1001
+ i--;
1002
+ break;
1003
+ }
1004
+ }
1005
+ if (forward) {
1006
+ nextIndex--;
1007
+ }
1008
+ }
1009
+ else if (currentMatchIndex > currentIndex) {
1010
+ nodes[i].setAttribute('data-mce-index', String(currentMatchIndex - 1));
716
1011
  }
717
- }
718
- if (forward) {
719
- nextIndex--;
720
- }
721
- } else if (currentMatchIndex > currentIndex) {
722
- nodes[i].setAttribute('data-mce-index', String(currentMatchIndex - 1));
723
1012
  }
724
- }
725
- currentSearchState.set({
726
- ...searchState,
727
- count: all ? 0 : searchState.count - 1,
728
- index: nextIndex
729
- });
730
- if (forward) {
731
- next(editor, currentSearchState);
732
- } else {
733
- prev(editor, currentSearchState);
734
- }
735
- return !all && currentSearchState.get().count > 0;
1013
+ currentSearchState.set({
1014
+ ...searchState,
1015
+ count: all ? 0 : searchState.count - 1,
1016
+ index: nextIndex
1017
+ });
1018
+ if (forward) {
1019
+ next(editor, currentSearchState);
1020
+ }
1021
+ else {
1022
+ prev(editor, currentSearchState);
1023
+ }
1024
+ return !all && currentSearchState.get().count > 0;
736
1025
  };
737
1026
  const done = (editor, currentSearchState, keepEditorSelection) => {
738
- let startContainer;
739
- let endContainer;
740
- const searchState = currentSearchState.get();
741
- const nodes = global$1.toArray(editor.getBody().getElementsByTagName('span'));
742
- for (let i = 0; i < nodes.length; i++) {
743
- const nodeIndex = getElmIndex(nodes[i]);
744
- if (nodeIndex !== null && nodeIndex.length) {
745
- if (nodeIndex === searchState.index.toString()) {
746
- if (!startContainer) {
747
- startContainer = nodes[i].firstChild;
1027
+ let startContainer;
1028
+ let endContainer;
1029
+ const searchState = currentSearchState.get();
1030
+ const nodes = global$1.toArray(editor.getBody().getElementsByTagName('span'));
1031
+ for (let i = 0; i < nodes.length; i++) {
1032
+ const nodeIndex = getElmIndex(nodes[i]);
1033
+ if (nodeIndex !== null && nodeIndex.length) {
1034
+ if (nodeIndex === searchState.index.toString()) {
1035
+ // Note: The first child of the span node will be the highlighted text node
1036
+ if (!startContainer) {
1037
+ startContainer = nodes[i].firstChild;
1038
+ }
1039
+ endContainer = nodes[i].firstChild;
1040
+ }
1041
+ unwrap(nodes[i]);
1042
+ }
1043
+ }
1044
+ // Reset the search state
1045
+ currentSearchState.set({
1046
+ ...searchState,
1047
+ index: -1,
1048
+ count: 0,
1049
+ text: ''
1050
+ });
1051
+ if (startContainer && endContainer) {
1052
+ const rng = editor.dom.createRng();
1053
+ rng.setStart(startContainer, 0);
1054
+ rng.setEnd(endContainer, endContainer.data.length);
1055
+ if (keepEditorSelection !== false) {
1056
+ editor.selection.setRng(rng);
748
1057
  }
749
- endContainer = nodes[i].firstChild;
750
- }
751
- unwrap(nodes[i]);
1058
+ return rng;
752
1059
  }
753
- }
754
- currentSearchState.set({
755
- ...searchState,
756
- index: -1,
757
- count: 0,
758
- text: ''
759
- });
760
- if (startContainer && endContainer) {
761
- const rng = editor.dom.createRng();
762
- rng.setStart(startContainer, 0);
763
- rng.setEnd(endContainer, endContainer.data.length);
764
- if (keepEditorSelection !== false) {
765
- editor.selection.setRng(rng);
1060
+ else {
1061
+ return undefined;
766
1062
  }
767
- return rng;
768
- } else {
769
- return undefined;
770
- }
771
1063
  };
772
1064
  const hasNext = (editor, currentSearchState) => currentSearchState.get().count > 1;
773
1065
  const hasPrev = (editor, currentSearchState) => currentSearchState.get().count > 1;
774
1066
 
775
1067
  const get = (editor, currentState) => {
776
- const done$1 = keepEditorSelection => {
777
- return done(editor, currentState, keepEditorSelection);
778
- };
779
- const find$1 = (text, matchCase, wholeWord, inSelection = false) => {
780
- return find(editor, currentState, text, matchCase, wholeWord, inSelection);
781
- };
782
- const next$1 = () => {
783
- return next(editor, currentState);
784
- };
785
- const prev$1 = () => {
786
- return prev(editor, currentState);
787
- };
788
- const replace$1 = (text, forward, all) => {
789
- return replace(editor, currentState, text, forward, all);
790
- };
791
- return {
792
- done: done$1,
793
- find: find$1,
794
- next: next$1,
795
- prev: prev$1,
796
- replace: replace$1
797
- };
798
- };
799
-
800
- const singleton = doRevoke => {
801
- const subject = Cell(Optional.none());
802
- const revoke = () => subject.get().each(doRevoke);
803
- const clear = () => {
804
- revoke();
805
- subject.set(Optional.none());
806
- };
807
- const isSet = () => subject.get().isSome();
808
- const get = () => subject.get();
809
- const set = s => {
810
- revoke();
811
- subject.set(Optional.some(s));
812
- };
813
- return {
814
- clear,
815
- isSet,
816
- get,
817
- set
818
- };
819
- };
820
- const value = () => {
821
- const subject = singleton(noop);
822
- const on = f => subject.get().each(f);
823
- return {
824
- ...subject,
825
- on
826
- };
1068
+ const done$1 = (keepEditorSelection) => {
1069
+ return done(editor, currentState, keepEditorSelection);
1070
+ };
1071
+ const find$1 = (text, matchCase, wholeWord, inSelection = false) => {
1072
+ return find(editor, currentState, text, matchCase, wholeWord, inSelection);
1073
+ };
1074
+ const next$1 = () => {
1075
+ return next(editor, currentState);
1076
+ };
1077
+ const prev$1 = () => {
1078
+ return prev(editor, currentState);
1079
+ };
1080
+ const replace$1 = (text, forward, all) => {
1081
+ return replace(editor, currentState, text, forward, all);
1082
+ };
1083
+ return {
1084
+ done: done$1,
1085
+ find: find$1,
1086
+ next: next$1,
1087
+ prev: prev$1,
1088
+ replace: replace$1
1089
+ };
827
1090
  };
828
1091
 
829
1092
  const open = (editor, currentSearchState) => {
830
- const dialogApi = value();
831
- editor.undoManager.add();
832
- const selectedText = global$1.trim(editor.selection.getContent({ format: 'text' }));
833
- const updateButtonStates = api => {
834
- api.setEnabled('next', hasNext(editor, currentSearchState));
835
- api.setEnabled('prev', hasPrev(editor, currentSearchState));
836
- };
837
- const updateSearchState = api => {
838
- const data = api.getData();
839
- const current = currentSearchState.get();
840
- currentSearchState.set({
841
- ...current,
842
- matchCase: data.matchcase,
843
- wholeWord: data.wholewords,
844
- inSelection: data.inselection
845
- });
846
- };
847
- const disableAll = (api, disable) => {
848
- const buttons = [
849
- 'replace',
850
- 'replaceall',
851
- 'prev',
852
- 'next'
853
- ];
854
- const toggle = name => api.setEnabled(name, !disable);
855
- each(buttons, toggle);
856
- };
857
- const toggleNotFoundAlert = (isVisible, api) => {
858
- api.redial(getDialogSpec(isVisible, api.getData()));
859
- };
860
- const focusButtonIfRequired = (api, name) => {
861
- if (global$2.browser.isSafari() && global$2.deviceType.isTouch() && (name === 'find' || name === 'replace' || name === 'replaceall')) {
862
- api.focus(name);
863
- }
864
- };
865
- const reset = api => {
866
- done(editor, currentSearchState, false);
867
- disableAll(api, true);
868
- updateButtonStates(api);
869
- };
870
- const doFind = api => {
871
- const data = api.getData();
872
- const last = currentSearchState.get();
873
- if (!data.findtext.length) {
874
- reset(api);
875
- return;
876
- }
877
- if (last.text === data.findtext && last.matchCase === data.matchcase && last.wholeWord === data.wholewords) {
878
- next(editor, currentSearchState);
879
- } else {
880
- const count = find(editor, currentSearchState, data.findtext, data.matchcase, data.wholewords, data.inselection);
881
- if (count <= 0) {
882
- toggleNotFoundAlert(true, api);
883
- }
884
- disableAll(api, count === 0);
885
- }
886
- updateButtonStates(api);
887
- };
888
- const initialState = currentSearchState.get();
889
- const initialData = {
890
- findtext: selectedText,
891
- replacetext: '',
892
- wholewords: initialState.wholeWord,
893
- matchcase: initialState.matchCase,
894
- inselection: initialState.inSelection
895
- };
896
- const getPanelItems = error => {
897
- const items = [
898
- {
899
- type: 'bar',
900
- items: [
901
- {
902
- type: 'input',
903
- name: 'findtext',
904
- placeholder: 'Find',
905
- maximized: true,
906
- inputMode: 'search'
907
- },
908
- {
909
- type: 'button',
910
- name: 'prev',
911
- text: 'Previous',
912
- icon: 'action-prev',
913
- enabled: false,
914
- borderless: true
915
- },
916
- {
917
- type: 'button',
918
- name: 'next',
919
- text: 'Next',
920
- icon: 'action-next',
921
- enabled: false,
922
- borderless: true
923
- }
924
- ]
925
- },
926
- {
927
- type: 'input',
928
- name: 'replacetext',
929
- placeholder: 'Replace with',
930
- inputMode: 'search'
931
- }
932
- ];
933
- if (error) {
934
- items.push({
935
- type: 'alertbanner',
936
- level: 'error',
937
- text: 'Could not find the specified string.',
938
- icon: 'warning'
939
- });
940
- }
941
- return items;
942
- };
943
- const getDialogSpec = (showNoMatchesAlertBanner, initialData) => ({
944
- title: 'Find and Replace',
945
- size: 'normal',
946
- body: {
947
- type: 'panel',
948
- items: getPanelItems(showNoMatchesAlertBanner)
949
- },
950
- buttons: [
951
- {
952
- type: 'menu',
953
- name: 'options',
954
- icon: 'preferences',
955
- tooltip: 'Preferences',
956
- align: 'start',
957
- items: [
958
- {
959
- type: 'togglemenuitem',
960
- name: 'matchcase',
961
- text: 'Match case'
962
- },
963
- {
964
- type: 'togglemenuitem',
965
- name: 'wholewords',
966
- text: 'Find whole words only'
967
- },
968
- {
969
- type: 'togglemenuitem',
970
- name: 'inselection',
971
- text: 'Find in selection'
972
- }
973
- ]
974
- },
975
- {
976
- type: 'custom',
977
- name: 'find',
978
- text: 'Find',
979
- primary: true
980
- },
981
- {
982
- type: 'custom',
983
- name: 'replace',
984
- text: 'Replace',
985
- enabled: false
986
- },
987
- {
988
- type: 'custom',
989
- name: 'replaceall',
990
- text: 'Replace all',
991
- enabled: false
992
- }
993
- ],
994
- initialData,
995
- onChange: (api, details) => {
996
- if (showNoMatchesAlertBanner) {
997
- toggleNotFoundAlert(false, api);
998
- }
999
- if (details.name === 'findtext' && currentSearchState.get().count > 0) {
1000
- reset(api);
1001
- }
1002
- },
1003
- onAction: (api, details) => {
1004
- const data = api.getData();
1005
- switch (details.name) {
1006
- case 'find':
1007
- doFind(api);
1008
- break;
1009
- case 'replace':
1010
- if (!replace(editor, currentSearchState, data.replacetext)) {
1011
- reset(api);
1012
- } else {
1013
- updateButtonStates(api);
1093
+ const dialogApi = value();
1094
+ editor.undoManager.add();
1095
+ const selectedText = global$1.trim(editor.selection.getContent({ format: 'text' }));
1096
+ const updateButtonStates = (api) => {
1097
+ api.setEnabled('next', hasNext(editor, currentSearchState));
1098
+ api.setEnabled('prev', hasPrev(editor, currentSearchState));
1099
+ };
1100
+ const updateSearchState = (api) => {
1101
+ const data = api.getData();
1102
+ const current = currentSearchState.get();
1103
+ currentSearchState.set({
1104
+ ...current,
1105
+ matchCase: data.matchcase,
1106
+ wholeWord: data.wholewords,
1107
+ inSelection: data.inselection
1108
+ });
1109
+ };
1110
+ const disableAll = (api, disable) => {
1111
+ const buttons = ['replace', 'replaceall', 'prev', 'next'];
1112
+ const toggle = (name) => api.setEnabled(name, !disable);
1113
+ each(buttons, toggle);
1114
+ };
1115
+ const toggleNotFoundAlert = (isVisible, api) => {
1116
+ api.redial(getDialogSpec(isVisible, api.getData()));
1117
+ };
1118
+ // Temporarily workaround for iOS/iPadOS dialog placement to hide the keyboard
1119
+ // TODO: Remove in 5.2 once iOS fixed positioning is fixed. See TINY-4441
1120
+ const focusButtonIfRequired = (api, name) => {
1121
+ if (global$2.browser.isSafari() && global$2.deviceType.isTouch() && (name === 'find' || name === 'replace' || name === 'replaceall')) {
1122
+ api.focus(name);
1014
1123
  }
1015
- break;
1016
- case 'replaceall':
1017
- replace(editor, currentSearchState, data.replacetext, true, true);
1018
- reset(api);
1019
- break;
1020
- case 'prev':
1021
- prev(editor, currentSearchState);
1124
+ };
1125
+ const reset = (api) => {
1126
+ // Clean up the markers if required
1127
+ done(editor, currentSearchState, false);
1128
+ // Disable the buttons
1129
+ disableAll(api, true);
1022
1130
  updateButtonStates(api);
1023
- break;
1024
- case 'next':
1025
- next(editor, currentSearchState);
1131
+ };
1132
+ const doFind = (api) => {
1133
+ const data = api.getData();
1134
+ const last = currentSearchState.get();
1135
+ if (!data.findtext.length) {
1136
+ reset(api);
1137
+ return;
1138
+ }
1139
+ // Same search text, so treat the find as a next click instead
1140
+ if (last.text === data.findtext && last.matchCase === data.matchcase && last.wholeWord === data.wholewords) {
1141
+ next(editor, currentSearchState);
1142
+ }
1143
+ else {
1144
+ // Find new matches
1145
+ const count = find(editor, currentSearchState, data.findtext, data.matchcase, data.wholewords, data.inselection);
1146
+ if (count <= 0) {
1147
+ toggleNotFoundAlert(true, api);
1148
+ }
1149
+ disableAll(api, count === 0);
1150
+ }
1026
1151
  updateButtonStates(api);
1027
- break;
1028
- case 'matchcase':
1029
- case 'wholewords':
1030
- case 'inselection':
1031
- toggleNotFoundAlert(false, api);
1032
- updateSearchState(api);
1033
- reset(api);
1034
- break;
1035
- }
1036
- focusButtonIfRequired(api, details.name);
1037
- },
1038
- onSubmit: api => {
1039
- doFind(api);
1040
- focusButtonIfRequired(api, 'find');
1041
- },
1042
- onClose: () => {
1043
- editor.focus();
1044
- done(editor, currentSearchState);
1045
- editor.undoManager.add();
1046
- }
1047
- });
1048
- dialogApi.set(editor.windowManager.open(getDialogSpec(false, initialData), { inline: 'toolbar' }));
1152
+ };
1153
+ const initialState = currentSearchState.get();
1154
+ const initialData = {
1155
+ findtext: selectedText,
1156
+ replacetext: '',
1157
+ wholewords: initialState.wholeWord,
1158
+ matchcase: initialState.matchCase,
1159
+ inselection: initialState.inSelection
1160
+ };
1161
+ const getPanelItems = (error) => {
1162
+ const items = [
1163
+ {
1164
+ type: 'label',
1165
+ label: 'Find',
1166
+ for: 'findtext',
1167
+ items: [
1168
+ {
1169
+ type: 'bar',
1170
+ items: [
1171
+ {
1172
+ type: 'input',
1173
+ name: 'findtext',
1174
+ maximized: true,
1175
+ inputMode: 'search'
1176
+ },
1177
+ {
1178
+ type: 'button',
1179
+ name: 'prev',
1180
+ text: 'Previous',
1181
+ icon: 'action-prev',
1182
+ enabled: false,
1183
+ borderless: true
1184
+ },
1185
+ {
1186
+ type: 'button',
1187
+ name: 'next',
1188
+ text: 'Next',
1189
+ icon: 'action-next',
1190
+ enabled: false,
1191
+ borderless: true
1192
+ }
1193
+ ]
1194
+ }
1195
+ ]
1196
+ },
1197
+ {
1198
+ type: 'input',
1199
+ name: 'replacetext',
1200
+ label: 'Replace with',
1201
+ inputMode: 'search'
1202
+ },
1203
+ ];
1204
+ if (error) {
1205
+ items.push({
1206
+ type: 'alertbanner',
1207
+ level: 'error',
1208
+ text: 'Could not find the specified string.',
1209
+ icon: 'warning',
1210
+ });
1211
+ }
1212
+ return items;
1213
+ };
1214
+ const getDialogSpec = (showNoMatchesAlertBanner, initialData) => ({
1215
+ title: 'Find and Replace',
1216
+ size: 'normal',
1217
+ body: {
1218
+ type: 'panel',
1219
+ items: getPanelItems(showNoMatchesAlertBanner)
1220
+ },
1221
+ buttons: [
1222
+ {
1223
+ type: 'menu',
1224
+ name: 'options',
1225
+ icon: 'preferences',
1226
+ tooltip: 'Preferences',
1227
+ align: 'start',
1228
+ items: [
1229
+ {
1230
+ type: 'togglemenuitem',
1231
+ name: 'matchcase',
1232
+ text: 'Match case'
1233
+ }, {
1234
+ type: 'togglemenuitem',
1235
+ name: 'wholewords',
1236
+ text: 'Find whole words only'
1237
+ },
1238
+ {
1239
+ type: 'togglemenuitem',
1240
+ name: 'inselection',
1241
+ text: 'Find in selection'
1242
+ }
1243
+ ]
1244
+ },
1245
+ {
1246
+ type: 'custom',
1247
+ name: 'find',
1248
+ text: 'Find',
1249
+ primary: true
1250
+ },
1251
+ {
1252
+ type: 'custom',
1253
+ name: 'replace',
1254
+ text: 'Replace',
1255
+ enabled: false
1256
+ },
1257
+ {
1258
+ type: 'custom',
1259
+ name: 'replaceall',
1260
+ text: 'Replace all',
1261
+ enabled: false,
1262
+ }
1263
+ ],
1264
+ initialData,
1265
+ onChange: (api, details) => {
1266
+ if (showNoMatchesAlertBanner) {
1267
+ toggleNotFoundAlert(false, api);
1268
+ }
1269
+ if (details.name === 'findtext' && currentSearchState.get().count > 0) {
1270
+ reset(api);
1271
+ }
1272
+ },
1273
+ onAction: (api, details) => {
1274
+ const data = api.getData();
1275
+ switch (details.name) {
1276
+ case 'find':
1277
+ doFind(api);
1278
+ break;
1279
+ case 'replace':
1280
+ if (!replace(editor, currentSearchState, data.replacetext)) {
1281
+ reset(api);
1282
+ }
1283
+ else {
1284
+ updateButtonStates(api);
1285
+ }
1286
+ break;
1287
+ case 'replaceall':
1288
+ replace(editor, currentSearchState, data.replacetext, true, true);
1289
+ reset(api);
1290
+ break;
1291
+ case 'prev':
1292
+ prev(editor, currentSearchState);
1293
+ updateButtonStates(api);
1294
+ break;
1295
+ case 'next':
1296
+ next(editor, currentSearchState);
1297
+ updateButtonStates(api);
1298
+ break;
1299
+ case 'matchcase':
1300
+ case 'wholewords':
1301
+ case 'inselection':
1302
+ toggleNotFoundAlert(false, api);
1303
+ updateSearchState(api);
1304
+ reset(api);
1305
+ break;
1306
+ }
1307
+ focusButtonIfRequired(api, details.name);
1308
+ },
1309
+ onSubmit: (api) => {
1310
+ doFind(api);
1311
+ focusButtonIfRequired(api, 'find');
1312
+ },
1313
+ onClose: () => {
1314
+ editor.focus();
1315
+ done(editor, currentSearchState);
1316
+ editor.undoManager.add();
1317
+ }
1318
+ });
1319
+ dialogApi.set(editor.windowManager.open(getDialogSpec(false, initialData), { inline: 'toolbar' }));
1049
1320
  };
1050
1321
 
1051
1322
  const register$1 = (editor, currentSearchState) => {
1052
- editor.addCommand('SearchReplace', () => {
1053
- open(editor, currentSearchState);
1054
- });
1323
+ editor.addCommand('SearchReplace', () => {
1324
+ open(editor, currentSearchState);
1325
+ });
1055
1326
  };
1056
1327
 
1057
1328
  const showDialog = (editor, currentSearchState) => () => {
1058
- open(editor, currentSearchState);
1329
+ open(editor, currentSearchState);
1059
1330
  };
1060
1331
  const register = (editor, currentSearchState) => {
1061
- editor.ui.registry.addMenuItem('searchreplace', {
1062
- text: 'Find and replace...',
1063
- shortcut: 'Meta+F',
1064
- onAction: showDialog(editor, currentSearchState),
1065
- icon: 'search'
1066
- });
1067
- editor.ui.registry.addButton('searchreplace', {
1068
- tooltip: 'Find and replace',
1069
- onAction: showDialog(editor, currentSearchState),
1070
- icon: 'search'
1071
- });
1072
- editor.shortcuts.add('Meta+F', '', showDialog(editor, currentSearchState));
1332
+ editor.ui.registry.addMenuItem('searchreplace', {
1333
+ text: 'Find and replace...',
1334
+ shortcut: 'Meta+F',
1335
+ onAction: showDialog(editor, currentSearchState),
1336
+ icon: 'search'
1337
+ });
1338
+ editor.ui.registry.addButton('searchreplace', {
1339
+ tooltip: 'Find and replace',
1340
+ onAction: showDialog(editor, currentSearchState),
1341
+ icon: 'search',
1342
+ shortcut: 'Meta+F'
1343
+ });
1344
+ editor.shortcuts.add('Meta+F', '', showDialog(editor, currentSearchState));
1073
1345
  };
1074
1346
 
1075
1347
  var Plugin = () => {
1076
- global$3.add('searchreplace', editor => {
1077
- const currentSearchState = Cell({
1078
- index: -1,
1079
- count: 0,
1080
- text: '',
1081
- matchCase: false,
1082
- wholeWord: false,
1083
- inSelection: false
1348
+ global$3.add('searchreplace', (editor) => {
1349
+ const currentSearchState = Cell({
1350
+ index: -1,
1351
+ count: 0,
1352
+ text: '',
1353
+ matchCase: false,
1354
+ wholeWord: false,
1355
+ inSelection: false
1356
+ });
1357
+ register$1(editor, currentSearchState);
1358
+ register(editor, currentSearchState);
1359
+ return get(editor, currentSearchState);
1084
1360
  });
1085
- register$1(editor, currentSearchState);
1086
- register(editor, currentSearchState);
1087
- return get(editor, currentSearchState);
1088
- });
1089
1361
  };
1090
1362
 
1091
1363
  Plugin();
1364
+ /** *****
1365
+ * DO NOT EXPORT ANYTHING
1366
+ *
1367
+ * IF YOU DO ROLLUP WILL LEAVE A GLOBAL ON THE PAGE
1368
+ *******/
1092
1369
 
1093
1370
  })();