@dangl/angular-material-shared 2.9.0-beta0047 → 2.9.0-beta0048

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 (165) hide show
  1. package/package.json +1 -1
  2. package/tinymce-assets/icons/default/icons.js +9 -46
  3. package/tinymce-assets/icons/default/icons.min.js +1 -1
  4. package/tinymce-assets/models/dom/model.js +7239 -8193
  5. package/tinymce-assets/models/dom/model.min.js +1 -1
  6. package/tinymce-assets/plugins/accordion/plugin.js +879 -1174
  7. package/tinymce-assets/plugins/accordion/plugin.min.js +5 -1
  8. package/tinymce-assets/plugins/advlist/plugin.js +200 -412
  9. package/tinymce-assets/plugins/advlist/plugin.min.js +5 -1
  10. package/tinymce-assets/plugins/anchor/plugin.js +166 -189
  11. package/tinymce-assets/plugins/anchor/plugin.min.js +5 -1
  12. package/tinymce-assets/plugins/autolink/plugin.js +220 -310
  13. package/tinymce-assets/plugins/autolink/plugin.min.js +5 -1
  14. package/tinymce-assets/plugins/autoresize/plugin.js +149 -180
  15. package/tinymce-assets/plugins/autoresize/plugin.min.js +5 -1
  16. package/tinymce-assets/plugins/autosave/plugin.js +189 -208
  17. package/tinymce-assets/plugins/autosave/plugin.min.js +5 -1
  18. package/tinymce-assets/plugins/charmap/plugin.js +1566 -905
  19. package/tinymce-assets/plugins/charmap/plugin.min.js +5 -1
  20. package/tinymce-assets/plugins/code/plugin.js +61 -73
  21. package/tinymce-assets/plugins/code/plugin.min.js +4 -0
  22. package/tinymce-assets/plugins/codesample/plugin.js +2409 -3592
  23. package/tinymce-assets/plugins/codesample/plugin.min.js +12 -8
  24. package/tinymce-assets/plugins/directionality/plugin.js +304 -545
  25. package/tinymce-assets/plugins/directionality/plugin.min.js +5 -1
  26. package/tinymce-assets/plugins/emoticons/plugin.js +488 -702
  27. package/tinymce-assets/plugins/emoticons/plugin.min.js +5 -1
  28. package/tinymce-assets/plugins/fullscreen/plugin.js +1049 -1409
  29. package/tinymce-assets/plugins/fullscreen/plugin.min.js +5 -1
  30. package/tinymce-assets/plugins/help/js/i18n/keynav/ar.js +1 -4
  31. package/tinymce-assets/plugins/help/js/i18n/keynav/bg_BG.js +1 -4
  32. package/tinymce-assets/plugins/help/js/i18n/keynav/ca.js +1 -4
  33. package/tinymce-assets/plugins/help/js/i18n/keynav/cs.js +1 -4
  34. package/tinymce-assets/plugins/help/js/i18n/keynav/da.js +1 -4
  35. package/tinymce-assets/plugins/help/js/i18n/keynav/de.js +1 -4
  36. package/tinymce-assets/plugins/help/js/i18n/keynav/el.js +1 -4
  37. package/tinymce-assets/plugins/help/js/i18n/keynav/en.js +1 -4
  38. package/tinymce-assets/plugins/help/js/i18n/keynav/es.js +1 -4
  39. package/tinymce-assets/plugins/help/js/i18n/keynav/eu.js +1 -4
  40. package/tinymce-assets/plugins/help/js/i18n/keynav/fa.js +1 -4
  41. package/tinymce-assets/plugins/help/js/i18n/keynav/fi.js +1 -4
  42. package/tinymce-assets/plugins/help/js/i18n/keynav/fr_FR.js +1 -4
  43. package/tinymce-assets/plugins/help/js/i18n/keynav/he_IL.js +1 -4
  44. package/tinymce-assets/plugins/help/js/i18n/keynav/hi.js +1 -4
  45. package/tinymce-assets/plugins/help/js/i18n/keynav/hr.js +1 -4
  46. package/tinymce-assets/plugins/help/js/i18n/keynav/hu_HU.js +1 -4
  47. package/tinymce-assets/plugins/help/js/i18n/keynav/id.js +1 -4
  48. package/tinymce-assets/plugins/help/js/i18n/keynav/it.js +1 -4
  49. package/tinymce-assets/plugins/help/js/i18n/keynav/ja.js +1 -4
  50. package/tinymce-assets/plugins/help/js/i18n/keynav/kk.js +1 -4
  51. package/tinymce-assets/plugins/help/js/i18n/keynav/ko_KR.js +1 -4
  52. package/tinymce-assets/plugins/help/js/i18n/keynav/ms.js +1 -4
  53. package/tinymce-assets/plugins/help/js/i18n/keynav/nb_NO.js +1 -4
  54. package/tinymce-assets/plugins/help/js/i18n/keynav/nl.js +1 -4
  55. package/tinymce-assets/plugins/help/js/i18n/keynav/pl.js +1 -4
  56. package/tinymce-assets/plugins/help/js/i18n/keynav/pt_BR.js +1 -4
  57. package/tinymce-assets/plugins/help/js/i18n/keynav/pt_PT.js +1 -4
  58. package/tinymce-assets/plugins/help/js/i18n/keynav/ro.js +1 -4
  59. package/tinymce-assets/plugins/help/js/i18n/keynav/ru.js +1 -4
  60. package/tinymce-assets/plugins/help/js/i18n/keynav/sk.js +1 -4
  61. package/tinymce-assets/plugins/help/js/i18n/keynav/sl_SI.js +2 -5
  62. package/tinymce-assets/plugins/help/js/i18n/keynav/sv_SE.js +1 -4
  63. package/tinymce-assets/plugins/help/js/i18n/keynav/th_TH.js +1 -4
  64. package/tinymce-assets/plugins/help/js/i18n/keynav/tr.js +1 -4
  65. package/tinymce-assets/plugins/help/js/i18n/keynav/uk.js +1 -4
  66. package/tinymce-assets/plugins/help/js/i18n/keynav/vi.js +1 -4
  67. package/tinymce-assets/plugins/help/js/i18n/keynav/zh_CN.js +5 -8
  68. package/tinymce-assets/plugins/help/js/i18n/keynav/zh_TW.js +1 -4
  69. package/tinymce-assets/plugins/help/plugin.js +809 -739
  70. package/tinymce-assets/plugins/help/plugin.min.js +5 -1
  71. package/tinymce-assets/plugins/image/plugin.js +1291 -1475
  72. package/tinymce-assets/plugins/image/plugin.min.js +5 -1
  73. package/tinymce-assets/plugins/importcss/plugin.js +269 -328
  74. package/tinymce-assets/plugins/importcss/plugin.min.js +5 -1
  75. package/tinymce-assets/plugins/insertdatetime/plugin.js +141 -140
  76. package/tinymce-assets/plugins/insertdatetime/plugin.min.js +5 -1
  77. package/tinymce-assets/plugins/link/plugin.js +1084 -1419
  78. package/tinymce-assets/plugins/link/plugin.min.js +5 -1
  79. package/tinymce-assets/plugins/lists/plugin.js +1805 -2177
  80. package/tinymce-assets/plugins/lists/plugin.min.js +5 -1
  81. package/tinymce-assets/plugins/media/plugin.js +1047 -1305
  82. package/tinymce-assets/plugins/media/plugin.min.js +5 -1
  83. package/tinymce-assets/plugins/nonbreaking/plugin.js +88 -93
  84. package/tinymce-assets/plugins/nonbreaking/plugin.min.js +4 -0
  85. package/tinymce-assets/plugins/pagebreak/plugin.js +85 -91
  86. package/tinymce-assets/plugins/pagebreak/plugin.min.js +4 -0
  87. package/tinymce-assets/plugins/preview/plugin.js +74 -742
  88. package/tinymce-assets/plugins/preview/plugin.min.js +5 -1
  89. package/tinymce-assets/plugins/quickbars/plugin.js +375 -582
  90. package/tinymce-assets/plugins/quickbars/plugin.min.js +5 -1
  91. package/tinymce-assets/plugins/save/plugin.js +82 -100
  92. package/tinymce-assets/plugins/save/plugin.min.js +5 -1
  93. package/tinymce-assets/plugins/searchreplace/plugin.js +906 -1183
  94. package/tinymce-assets/plugins/searchreplace/plugin.min.js +5 -1
  95. package/tinymce-assets/plugins/table/plugin.js +3094 -3651
  96. package/tinymce-assets/plugins/table/plugin.min.js +5 -1
  97. package/tinymce-assets/plugins/template/index.js +7 -0
  98. package/tinymce-assets/plugins/template/plugin.js +567 -0
  99. package/tinymce-assets/plugins/template/plugin.min.js +5 -0
  100. package/tinymce-assets/plugins/visualblocks/plugin.js +63 -71
  101. package/tinymce-assets/plugins/visualblocks/plugin.min.js +5 -1
  102. package/tinymce-assets/plugins/visualchars/plugin.js +436 -685
  103. package/tinymce-assets/plugins/visualchars/plugin.min.js +5 -1
  104. package/tinymce-assets/plugins/wordcount/plugin.js +307 -382
  105. package/tinymce-assets/plugins/wordcount/plugin.min.js +5 -1
  106. package/tinymce-assets/skins/content/dark/content.css +4 -0
  107. package/tinymce-assets/skins/content/dark/content.js +6 -1
  108. package/tinymce-assets/skins/content/dark/content.min.css +4 -0
  109. package/tinymce-assets/skins/content/default/content.css +4 -0
  110. package/tinymce-assets/skins/content/default/content.js +6 -1
  111. package/tinymce-assets/skins/content/default/content.min.css +4 -0
  112. package/tinymce-assets/skins/content/document/content.css +4 -0
  113. package/tinymce-assets/skins/content/document/content.js +6 -1
  114. package/tinymce-assets/skins/content/document/content.min.css +4 -0
  115. package/tinymce-assets/skins/content/tinymce-5/content.css +4 -0
  116. package/tinymce-assets/skins/content/tinymce-5/content.js +6 -1
  117. package/tinymce-assets/skins/content/tinymce-5/content.min.css +4 -0
  118. package/tinymce-assets/skins/content/tinymce-5-dark/content.css +4 -0
  119. package/tinymce-assets/skins/content/tinymce-5-dark/content.js +6 -1
  120. package/tinymce-assets/skins/content/tinymce-5-dark/content.min.css +4 -0
  121. package/tinymce-assets/skins/content/writer/content.css +4 -0
  122. package/tinymce-assets/skins/content/writer/content.js +6 -1
  123. package/tinymce-assets/skins/content/writer/content.min.css +4 -0
  124. package/tinymce-assets/skins/ui/oxide/content.css +53 -148
  125. package/tinymce-assets/skins/ui/oxide/content.inline.css +53 -148
  126. package/tinymce-assets/skins/ui/oxide/content.inline.js +6 -1
  127. package/tinymce-assets/skins/ui/oxide/content.inline.min.css +5 -1
  128. package/tinymce-assets/skins/ui/oxide/content.js +6 -1
  129. package/tinymce-assets/skins/ui/oxide/content.min.css +5 -1
  130. package/tinymce-assets/skins/ui/oxide/skin.css +207 -1585
  131. package/tinymce-assets/skins/ui/oxide/skin.js +2 -1
  132. package/tinymce-assets/skins/ui/oxide/skin.min.css +1 -1
  133. package/tinymce-assets/skins/ui/oxide/skin.shadowdom.js +2 -1
  134. package/tinymce-assets/skins/ui/oxide-dark/content.css +46 -148
  135. package/tinymce-assets/skins/ui/oxide-dark/content.inline.css +53 -148
  136. package/tinymce-assets/skins/ui/oxide-dark/content.inline.js +6 -1
  137. package/tinymce-assets/skins/ui/oxide-dark/content.inline.min.css +5 -1
  138. package/tinymce-assets/skins/ui/oxide-dark/content.js +6 -1
  139. package/tinymce-assets/skins/ui/oxide-dark/content.min.css +5 -1
  140. package/tinymce-assets/skins/ui/oxide-dark/skin.css +219 -1597
  141. package/tinymce-assets/skins/ui/oxide-dark/skin.js +2 -1
  142. package/tinymce-assets/skins/ui/oxide-dark/skin.min.css +1 -1
  143. package/tinymce-assets/skins/ui/oxide-dark/skin.shadowdom.js +2 -1
  144. package/tinymce-assets/skins/ui/tinymce-5/content.css +53 -148
  145. package/tinymce-assets/skins/ui/tinymce-5/content.inline.css +53 -148
  146. package/tinymce-assets/skins/ui/tinymce-5/content.inline.js +6 -1
  147. package/tinymce-assets/skins/ui/tinymce-5/content.inline.min.css +5 -1
  148. package/tinymce-assets/skins/ui/tinymce-5/content.js +6 -1
  149. package/tinymce-assets/skins/ui/tinymce-5/content.min.css +5 -1
  150. package/tinymce-assets/skins/ui/tinymce-5/skin.css +194 -1597
  151. package/tinymce-assets/skins/ui/tinymce-5/skin.js +2 -1
  152. package/tinymce-assets/skins/ui/tinymce-5/skin.min.css +1 -1
  153. package/tinymce-assets/skins/ui/tinymce-5/skin.shadowdom.js +2 -1
  154. package/tinymce-assets/skins/ui/tinymce-5-dark/content.css +46 -148
  155. package/tinymce-assets/skins/ui/tinymce-5-dark/content.inline.css +53 -148
  156. package/tinymce-assets/skins/ui/tinymce-5-dark/content.inline.js +6 -1
  157. package/tinymce-assets/skins/ui/tinymce-5-dark/content.inline.min.css +5 -1
  158. package/tinymce-assets/skins/ui/tinymce-5-dark/content.js +6 -1
  159. package/tinymce-assets/skins/ui/tinymce-5-dark/content.min.css +5 -1
  160. package/tinymce-assets/skins/ui/tinymce-5-dark/skin.css +202 -1605
  161. package/tinymce-assets/skins/ui/tinymce-5-dark/skin.js +2 -1
  162. package/tinymce-assets/skins/ui/tinymce-5-dark/skin.min.css +1 -1
  163. package/tinymce-assets/skins/ui/tinymce-5-dark/skin.shadowdom.js +2 -1
  164. package/tinymce-assets/themes/silver/theme.js +28439 -32466
  165. package/tinymce-assets/themes/silver/theme.min.js +1 -1
@@ -1,5 +1,5 @@
1
1
  /**
2
- * TinyMCE version 7.9.3 (2026-05-19)
2
+ * TinyMCE version 6.8.6 (TBD)
3
3
  */
4
4
 
5
5
  (function () {
@@ -7,548 +7,278 @@
7
7
 
8
8
  var global$5 = tinymce.util.Tools.resolve('tinymce.PluginManager');
9
9
 
10
- /* eslint-disable @typescript-eslint/no-wrapper-object-types */
11
10
  const hasProto = (v, constructor, predicate) => {
12
- var _a;
13
- if (predicate(v, constructor.prototype)) {
14
- return true;
15
- }
16
- else {
17
- // String-based fallback time
18
- return ((_a = v.constructor) === null || _a === void 0 ? void 0 : _a.name) === constructor.name;
19
- }
20
- };
21
- const typeOf = (x) => {
22
- const t = typeof x;
23
- if (x === null) {
24
- return 'null';
25
- }
26
- else if (t === 'object' && Array.isArray(x)) {
27
- return 'array';
28
- }
29
- else if (t === 'object' && hasProto(x, String, (o, proto) => proto.isPrototypeOf(o))) {
30
- return 'string';
31
- }
32
- else {
33
- return t;
34
- }
11
+ var _a;
12
+ if (predicate(v, constructor.prototype)) {
13
+ return true;
14
+ } else {
15
+ return ((_a = v.constructor) === null || _a === void 0 ? void 0 : _a.name) === constructor.name;
16
+ }
17
+ };
18
+ const typeOf = x => {
19
+ const t = typeof x;
20
+ if (x === null) {
21
+ return 'null';
22
+ } else if (t === 'object' && Array.isArray(x)) {
23
+ return 'array';
24
+ } else if (t === 'object' && hasProto(x, String, (o, proto) => proto.isPrototypeOf(o))) {
25
+ return 'string';
26
+ } else {
27
+ return t;
28
+ }
35
29
  };
36
- const isType = (type) => (value) => typeOf(value) === type;
37
- const isSimpleType = (type) => (value) => typeof value === type;
38
- const eq = (t) => (a) => t === a;
30
+ const isType = type => value => typeOf(value) === type;
31
+ const isSimpleType = type => value => typeof value === type;
32
+ const eq = t => a => t === a;
39
33
  const isString = isType('string');
40
34
  const isObject = isType('object');
41
35
  const isArray = isType('array');
42
36
  const isNull = eq(null);
43
37
  const isBoolean = isSimpleType('boolean');
44
- const isNullable = (a) => a === null || a === undefined;
45
- const isNonNullable = (a) => !isNullable(a);
38
+ const isNullable = a => a === null || a === undefined;
39
+ const isNonNullable = a => !isNullable(a);
46
40
  const isFunction = isSimpleType('function');
47
41
  const isArrayOf = (value, pred) => {
48
- if (isArray(value)) {
49
- for (let i = 0, len = value.length; i < len; ++i) {
50
- if (!(pred(value[i]))) {
51
- return false;
52
- }
53
- }
54
- return true;
42
+ if (isArray(value)) {
43
+ for (let i = 0, len = value.length; i < len; ++i) {
44
+ if (!pred(value[i])) {
45
+ return false;
46
+ }
55
47
  }
56
- return false;
48
+ return true;
49
+ }
50
+ return false;
57
51
  };
58
52
 
59
- const noop = () => { };
60
- const constant = (value) => {
61
- return () => {
62
- return value;
63
- };
53
+ const noop = () => {
54
+ };
55
+ const constant = value => {
56
+ return () => {
57
+ return value;
58
+ };
64
59
  };
65
60
  const tripleEquals = (a, b) => {
66
- return a === b;
61
+ return a === b;
67
62
  };
68
63
 
69
- /**
70
- * The `Optional` type represents a value (of any type) that potentially does
71
- * not exist. Any `Optional<T>` can either be a `Some<T>` (in which case the
72
- * value does exist) or a `None` (in which case the value does not exist). This
73
- * module defines a whole lot of FP-inspired utility functions for dealing with
74
- * `Optional` objects.
75
- *
76
- * Comparison with null or undefined:
77
- * - We don't get fancy null coalescing operators with `Optional`
78
- * - We do get fancy helper functions with `Optional`
79
- * - `Optional` support nesting, and allow for the type to still be nullable (or
80
- * another `Optional`)
81
- * - There is no option to turn off strict-optional-checks like there is for
82
- * strict-null-checks
83
- */
84
64
  class Optional {
85
- // The internal representation has a `tag` and a `value`, but both are
86
- // private: able to be console.logged, but not able to be accessed by code
87
- constructor(tag, value) {
88
- this.tag = tag;
89
- this.value = value;
90
- }
91
- // --- Identities ---
92
- /**
93
- * Creates a new `Optional<T>` that **does** contain a value.
94
- */
95
- static some(value) {
96
- return new Optional(true, value);
97
- }
98
- /**
99
- * Create a new `Optional<T>` that **does not** contain a value. `T` can be
100
- * any type because we don't actually have a `T`.
101
- */
102
- static none() {
103
- return Optional.singletonNone;
104
- }
105
- /**
106
- * Perform a transform on an `Optional` type. Regardless of whether this
107
- * `Optional` contains a value or not, `fold` will return a value of type `U`.
108
- * If this `Optional` does not contain a value, the `U` will be created by
109
- * calling `onNone`. If this `Optional` does contain a value, the `U` will be
110
- * created by calling `onSome`.
111
- *
112
- * For the FP enthusiasts in the room, this function:
113
- * 1. Could be used to implement all of the functions below
114
- * 2. Forms a catamorphism
115
- */
116
- fold(onNone, onSome) {
117
- if (this.tag) {
118
- return onSome(this.value);
119
- }
120
- else {
121
- return onNone();
122
- }
123
- }
124
- /**
125
- * Determine if this `Optional` object contains a value.
126
- */
127
- isSome() {
128
- return this.tag;
129
- }
130
- /**
131
- * Determine if this `Optional` object **does not** contain a value.
132
- */
133
- isNone() {
134
- return !this.tag;
135
- }
136
- // --- Functor (name stolen from Haskell / maths) ---
137
- /**
138
- * Perform a transform on an `Optional` object, **if** there is a value. If
139
- * you provide a function to turn a T into a U, this is the function you use
140
- * to turn an `Optional<T>` into an `Optional<U>`. If this **does** contain
141
- * a value then the output will also contain a value (that value being the
142
- * output of `mapper(this.value)`), and if this **does not** contain a value
143
- * then neither will the output.
144
- */
145
- map(mapper) {
146
- if (this.tag) {
147
- return Optional.some(mapper(this.value));
148
- }
149
- else {
150
- return Optional.none();
151
- }
152
- }
153
- // --- Monad (name stolen from Haskell / maths) ---
154
- /**
155
- * Perform a transform on an `Optional` object, **if** there is a value.
156
- * Unlike `map`, here the transform itself also returns an `Optional`.
157
- */
158
- bind(binder) {
159
- if (this.tag) {
160
- return binder(this.value);
161
- }
162
- else {
163
- return Optional.none();
164
- }
165
- }
166
- // --- Traversable (name stolen from Haskell / maths) ---
167
- /**
168
- * For a given predicate, this function finds out if there **exists** a value
169
- * inside this `Optional` object that meets the predicate. In practice, this
170
- * means that for `Optional`s that do not contain a value it returns false (as
171
- * no predicate-meeting value exists).
172
- */
173
- exists(predicate) {
174
- return this.tag && predicate(this.value);
175
- }
176
- /**
177
- * For a given predicate, this function finds out if **all** the values inside
178
- * this `Optional` object meet the predicate. In practice, this means that
179
- * for `Optional`s that do not contain a value it returns true (as all 0
180
- * objects do meet the predicate).
181
- */
182
- forall(predicate) {
183
- return !this.tag || predicate(this.value);
184
- }
185
- filter(predicate) {
186
- if (!this.tag || predicate(this.value)) {
187
- return this;
188
- }
189
- else {
190
- return Optional.none();
191
- }
192
- }
193
- // --- Getters ---
194
- /**
195
- * Get the value out of the inside of the `Optional` object, using a default
196
- * `replacement` value if the provided `Optional` object does not contain a
197
- * value.
198
- */
199
- getOr(replacement) {
200
- return this.tag ? this.value : replacement;
201
- }
202
- /**
203
- * Get the value out of the inside of the `Optional` object, using a default
204
- * `replacement` value if the provided `Optional` object does not contain a
205
- * value. Unlike `getOr`, in this method the `replacement` object is also
206
- * `Optional` - meaning that this method will always return an `Optional`.
207
- */
208
- or(replacement) {
209
- return this.tag ? this : replacement;
210
- }
211
- /**
212
- * Get the value out of the inside of the `Optional` object, using a default
213
- * `replacement` value if the provided `Optional` object does not contain a
214
- * value. Unlike `getOr`, in this method the `replacement` value is
215
- * "thunked" - that is to say that you don't pass a value to `getOrThunk`, you
216
- * pass a function which (if called) will **return** the `value` you want to
217
- * use.
218
- */
219
- getOrThunk(thunk) {
220
- return this.tag ? this.value : thunk();
221
- }
222
- /**
223
- * Get the value out of the inside of the `Optional` object, using a default
224
- * `replacement` value if the provided Optional object does not contain a
225
- * value.
226
- *
227
- * Unlike `or`, in this method the `replacement` value is "thunked" - that is
228
- * to say that you don't pass a value to `orThunk`, you pass a function which
229
- * (if called) will **return** the `value` you want to use.
230
- *
231
- * Unlike `getOrThunk`, in this method the `replacement` value is also
232
- * `Optional`, meaning that this method will always return an `Optional`.
233
- */
234
- orThunk(thunk) {
235
- return this.tag ? this : thunk();
236
- }
237
- /**
238
- * Get the value out of the inside of the `Optional` object, throwing an
239
- * exception if the provided `Optional` object does not contain a value.
240
- *
241
- * WARNING:
242
- * You should only be using this function if you know that the `Optional`
243
- * object **is not** empty (otherwise you're throwing exceptions in production
244
- * code, which is bad).
245
- *
246
- * In tests this is more acceptable.
247
- *
248
- * Prefer other methods to this, such as `.each`.
249
- */
250
- getOrDie(message) {
251
- if (!this.tag) {
252
- throw new Error(message !== null && message !== void 0 ? message : 'Called getOrDie on None');
253
- }
254
- else {
255
- return this.value;
256
- }
257
- }
258
- // --- Interop with null and undefined ---
259
- /**
260
- * Creates an `Optional` value from a nullable (or undefined-able) input.
261
- * Null, or undefined, is converted to `None`, and anything else is converted
262
- * to `Some`.
263
- */
264
- static from(value) {
265
- return isNonNullable(value) ? Optional.some(value) : Optional.none();
266
- }
267
- /**
268
- * Converts an `Optional` to a nullable type, by getting the value if it
269
- * exists, or returning `null` if it does not.
270
- */
271
- getOrNull() {
272
- return this.tag ? this.value : null;
273
- }
274
- /**
275
- * Converts an `Optional` to an undefined-able type, by getting the value if
276
- * it exists, or returning `undefined` if it does not.
277
- */
278
- getOrUndefined() {
279
- return this.value;
280
- }
281
- // --- Utilities ---
282
- /**
283
- * If the `Optional` contains a value, perform an action on that value.
284
- * Unlike the rest of the methods on this type, `.each` has side-effects. If
285
- * you want to transform an `Optional<T>` **into** something, then this is not
286
- * the method for you. If you want to use an `Optional<T>` to **do**
287
- * something, then this is the method for you - provided you're okay with not
288
- * doing anything in the case where the `Optional` doesn't have a value inside
289
- * it. If you're not sure whether your use-case fits into transforming
290
- * **into** something or **doing** something, check whether it has a return
291
- * value. If it does, you should be performing a transform.
292
- */
293
- each(worker) {
294
- if (this.tag) {
295
- worker(this.value);
296
- }
297
- }
298
- /**
299
- * Turn the `Optional` object into an array that contains all of the values
300
- * stored inside the `Optional`. In practice, this means the output will have
301
- * either 0 or 1 elements.
302
- */
303
- toArray() {
304
- return this.tag ? [this.value] : [];
305
- }
306
- /**
307
- * Turn the `Optional` object into a string for debugging or printing. Not
308
- * recommended for production code, but good for debugging. Also note that
309
- * these days an `Optional` object can be logged to the console directly, and
310
- * its inner value (if it exists) will be visible.
311
- */
312
- toString() {
313
- return this.tag ? `some(${this.value})` : 'none()';
314
- }
65
+ constructor(tag, value) {
66
+ this.tag = tag;
67
+ this.value = value;
68
+ }
69
+ static some(value) {
70
+ return new Optional(true, value);
71
+ }
72
+ static none() {
73
+ return Optional.singletonNone;
74
+ }
75
+ fold(onNone, onSome) {
76
+ if (this.tag) {
77
+ return onSome(this.value);
78
+ } else {
79
+ return onNone();
80
+ }
81
+ }
82
+ isSome() {
83
+ return this.tag;
84
+ }
85
+ isNone() {
86
+ return !this.tag;
87
+ }
88
+ map(mapper) {
89
+ if (this.tag) {
90
+ return Optional.some(mapper(this.value));
91
+ } else {
92
+ return Optional.none();
93
+ }
94
+ }
95
+ bind(binder) {
96
+ if (this.tag) {
97
+ return binder(this.value);
98
+ } else {
99
+ return Optional.none();
100
+ }
101
+ }
102
+ exists(predicate) {
103
+ return this.tag && predicate(this.value);
104
+ }
105
+ forall(predicate) {
106
+ return !this.tag || predicate(this.value);
107
+ }
108
+ filter(predicate) {
109
+ if (!this.tag || predicate(this.value)) {
110
+ return this;
111
+ } else {
112
+ return Optional.none();
113
+ }
114
+ }
115
+ getOr(replacement) {
116
+ return this.tag ? this.value : replacement;
117
+ }
118
+ or(replacement) {
119
+ return this.tag ? this : replacement;
120
+ }
121
+ getOrThunk(thunk) {
122
+ return this.tag ? this.value : thunk();
123
+ }
124
+ orThunk(thunk) {
125
+ return this.tag ? this : thunk();
126
+ }
127
+ getOrDie(message) {
128
+ if (!this.tag) {
129
+ throw new Error(message !== null && message !== void 0 ? message : 'Called getOrDie on None');
130
+ } else {
131
+ return this.value;
132
+ }
133
+ }
134
+ static from(value) {
135
+ return isNonNullable(value) ? Optional.some(value) : Optional.none();
136
+ }
137
+ getOrNull() {
138
+ return this.tag ? this.value : null;
139
+ }
140
+ getOrUndefined() {
141
+ return this.value;
142
+ }
143
+ each(worker) {
144
+ if (this.tag) {
145
+ worker(this.value);
146
+ }
147
+ }
148
+ toArray() {
149
+ return this.tag ? [this.value] : [];
150
+ }
151
+ toString() {
152
+ return this.tag ? `some(${ this.value })` : 'none()';
153
+ }
315
154
  }
316
- // Sneaky optimisation: every instance of Optional.none is identical, so just
317
- // reuse the same object
318
155
  Optional.singletonNone = new Optional(false);
319
156
 
320
- /* eslint-disable @typescript-eslint/unbound-method */
321
- const nativeSlice = Array.prototype.slice;
322
157
  const nativeIndexOf = Array.prototype.indexOf;
323
158
  const nativePush = Array.prototype.push;
324
- /* eslint-enable */
325
159
  const rawIndexOf = (ts, t) => nativeIndexOf.call(ts, t);
326
160
  const contains = (xs, x) => rawIndexOf(xs, x) > -1;
327
161
  const map = (xs, f) => {
328
- // pre-allocating array size when it's guaranteed to be known
329
- // http://jsperf.com/push-allocated-vs-dynamic/22
330
- const len = xs.length;
331
- const r = new Array(len);
332
- for (let i = 0; i < len; i++) {
333
- const x = xs[i];
334
- r[i] = f(x, i);
335
- }
336
- return r;
162
+ const len = xs.length;
163
+ const r = new Array(len);
164
+ for (let i = 0; i < len; i++) {
165
+ const x = xs[i];
166
+ r[i] = f(x, i);
167
+ }
168
+ return r;
337
169
  };
338
- // Unwound implementing other functions in terms of each.
339
- // The code size is roughly the same, and it should allow for better optimisation.
340
- // const each = function<T, U>(xs: T[], f: (x: T, i?: number, xs?: T[]) => void): void {
341
170
  const each$1 = (xs, f) => {
342
- for (let i = 0, len = xs.length; i < len; i++) {
343
- const x = xs[i];
344
- f(x, i);
345
- }
171
+ for (let i = 0, len = xs.length; i < len; i++) {
172
+ const x = xs[i];
173
+ f(x, i);
174
+ }
346
175
  };
347
176
  const foldl = (xs, f, acc) => {
348
- each$1(xs, (x, i) => {
349
- acc = f(acc, x, i);
350
- });
351
- return acc;
177
+ each$1(xs, (x, i) => {
178
+ acc = f(acc, x, i);
179
+ });
180
+ return acc;
352
181
  };
353
- const flatten = (xs) => {
354
- // Note, this is possible because push supports multiple arguments:
355
- // http://jsperf.com/concat-push/6
356
- // Note that in the past, concat() would silently work (very slowly) for array-like objects.
357
- // With this change it will throw an error.
358
- const r = [];
359
- for (let i = 0, len = xs.length; i < len; ++i) {
360
- // Ensure that each value is an array itself
361
- if (!isArray(xs[i])) {
362
- throw new Error('Arr.flatten item ' + i + ' was not an array, input: ' + xs);
363
- }
364
- nativePush.apply(r, xs[i]);
182
+ const flatten = xs => {
183
+ const r = [];
184
+ for (let i = 0, len = xs.length; i < len; ++i) {
185
+ if (!isArray(xs[i])) {
186
+ throw new Error('Arr.flatten item ' + i + ' was not an array, input: ' + xs);
365
187
  }
366
- return r;
188
+ nativePush.apply(r, xs[i]);
189
+ }
190
+ return r;
367
191
  };
368
192
  const bind = (xs, f) => flatten(map(xs, f));
369
- isFunction(Array.from) ? Array.from : (x) => nativeSlice.call(x);
370
193
  const findMap = (arr, f) => {
371
- for (let i = 0; i < arr.length; i++) {
372
- const r = f(arr[i], i);
373
- if (r.isSome()) {
374
- return r;
375
- }
194
+ for (let i = 0; i < arr.length; i++) {
195
+ const r = f(arr[i], i);
196
+ if (r.isSome()) {
197
+ return r;
376
198
  }
377
- return Optional.none();
378
- };
379
-
380
- // There are many variations of Object iteration that are faster than the 'for-in' style:
381
- // http://jsperf.com/object-keys-iteration/107
382
- //
383
- // Use the native keys if it is available (IE9+), otherwise fall back to manually filtering
384
- const keys = Object.keys;
385
- // eslint-disable-next-line @typescript-eslint/unbound-method
386
- const hasOwnProperty = Object.hasOwnProperty;
387
- const each = (obj, f) => {
388
- const props = keys(obj);
389
- for (let k = 0, len = props.length; k < len; k++) {
390
- const i = props[k];
391
- const x = obj[i];
392
- f(x, i);
393
- }
394
- };
395
- const objAcc = (r) => (x, i) => {
396
- r[i] = x;
199
+ }
200
+ return Optional.none();
397
201
  };
398
- const internalFilter = (obj, pred, onTrue, onFalse) => {
399
- each(obj, (x, i) => {
400
- (pred(x, i) ? onTrue : onFalse)(x, i);
401
- });
402
- };
403
- const filter = (obj, pred) => {
404
- const t = {};
405
- internalFilter(obj, pred, objAcc(t), noop);
406
- return t;
407
- };
408
- const has = (obj, key) => hasOwnProperty.call(obj, key);
409
- const hasNonNullableKey = (obj, key) => has(obj, key) && obj[key] !== undefined && obj[key] !== null;
410
202
 
411
- const Cell = (initial) => {
412
- let value = initial;
413
- const get = () => {
414
- return value;
415
- };
416
- const set = (v) => {
417
- value = v;
418
- };
419
- return {
420
- get,
421
- set
422
- };
203
+ const is = (lhs, rhs, comparator = tripleEquals) => lhs.exists(left => comparator(left, rhs));
204
+ const cat = arr => {
205
+ const r = [];
206
+ const push = x => {
207
+ r.push(x);
208
+ };
209
+ for (let i = 0; i < arr.length; i++) {
210
+ arr[i].each(push);
211
+ }
212
+ return r;
423
213
  };
424
-
425
- /**
426
- * **Is** the value stored inside this Optional object equal to `rhs`?
427
- */
428
- const is = (lhs, rhs, comparator = tripleEquals) => lhs.exists((left) => comparator(left, rhs));
429
- const cat = (arr) => {
430
- const r = [];
431
- const push = (x) => {
432
- r.push(x);
433
- };
434
- for (let i = 0; i < arr.length; i++) {
435
- arr[i].each(push);
436
- }
437
- return r;
438
- };
439
- // This can help with type inference, by specifying the type param on the none case, so the caller doesn't have to.
440
214
  const someIf = (b, a) => b ? Optional.some(a) : Optional.none();
441
215
 
442
- const singleton = (doRevoke) => {
443
- const subject = Cell(Optional.none());
444
- const revoke = () => subject.get().each(doRevoke);
445
- const clear = () => {
446
- revoke();
447
- subject.set(Optional.none());
448
- };
449
- const isSet = () => subject.get().isSome();
450
- const get = () => subject.get();
451
- const set = (s) => {
452
- revoke();
453
- subject.set(Optional.some(s));
454
- };
455
- return {
456
- clear,
457
- isSet,
458
- get,
459
- set
460
- };
461
- };
462
- const value = () => {
463
- const subject = singleton(noop);
464
- const on = (f) => subject.get().each(f);
465
- return {
466
- ...subject,
467
- on
468
- };
469
- };
470
-
471
- const removeFromStart = (str, numChars) => {
472
- return str.substring(numChars);
473
- };
474
-
475
- const checkRange = (str, substr, start) => substr === '' || str.length >= substr.length && str.substr(start, start + substr.length) === substr;
476
- const removeLeading = (str, prefix) => {
477
- return startsWith(str, prefix) ? removeFromStart(str, prefix.length) : str;
478
- };
479
- /** Does 'str' start with 'prefix'?
480
- * Note: all strings start with the empty string.
481
- * More formally, for all strings x, startsWith(x, "").
482
- * This is so that for all strings x and y, startsWith(y + x, y)
483
- */
484
- const startsWith = (str, prefix) => {
485
- return checkRange(str, prefix, 0);
486
- };
487
-
488
- const option = (name) => (editor) => editor.options.get(name);
489
- const register$1 = (editor) => {
490
- const registerOption = editor.options.register;
491
- registerOption('link_assume_external_targets', {
492
- processor: (value) => {
493
- const valid = isString(value) || isBoolean(value);
494
- if (valid) {
495
- if (value === true) {
496
- return { value: 1 /* AssumeExternalTargets.WARN */, valid };
497
- }
498
- else if (value === "http" /* AssumeExternalTargets.ALWAYS_HTTP */ || value === "https" /* AssumeExternalTargets.ALWAYS_HTTPS */) {
499
- return { value, valid };
500
- }
501
- else {
502
- return { value: 0 /* AssumeExternalTargets.OFF */, valid };
503
- }
504
- }
505
- else {
506
- return { valid: false, message: 'Must be a string or a boolean.' };
507
- }
508
- },
509
- default: false
510
- });
511
- registerOption('link_context_toolbar', {
512
- processor: 'boolean',
513
- default: false
514
- });
515
- registerOption('link_list', {
516
- processor: (value) => isString(value) || isFunction(value) || isArrayOf(value, isObject)
517
- });
518
- registerOption('link_default_target', {
519
- processor: 'string'
520
- });
521
- registerOption('link_default_protocol', {
522
- processor: 'string',
523
- default: 'https'
524
- });
525
- registerOption('link_target_list', {
526
- processor: (value) => isBoolean(value) || isArrayOf(value, isObject),
527
- default: true
528
- });
529
- registerOption('link_rel_list', {
530
- processor: 'object[]',
531
- default: []
532
- });
533
- registerOption('link_class_list', {
534
- processor: 'object[]',
535
- default: []
536
- });
537
- registerOption('link_title', {
538
- processor: 'boolean',
539
- default: true
540
- });
541
- registerOption('allow_unsafe_link_target', {
542
- processor: 'boolean',
543
- default: false
544
- });
545
- registerOption('link_quicklink', {
546
- processor: 'boolean',
547
- default: false
548
- });
549
- registerOption('link_attributes_postprocess', {
550
- processor: 'function',
551
- });
216
+ const option = name => editor => editor.options.get(name);
217
+ const register$1 = editor => {
218
+ const registerOption = editor.options.register;
219
+ registerOption('link_assume_external_targets', {
220
+ processor: value => {
221
+ const valid = isString(value) || isBoolean(value);
222
+ if (valid) {
223
+ if (value === true) {
224
+ return {
225
+ value: 1,
226
+ valid
227
+ };
228
+ } else if (value === 'http' || value === 'https') {
229
+ return {
230
+ value,
231
+ valid
232
+ };
233
+ } else {
234
+ return {
235
+ value: 0,
236
+ valid
237
+ };
238
+ }
239
+ } else {
240
+ return {
241
+ valid: false,
242
+ message: 'Must be a string or a boolean.'
243
+ };
244
+ }
245
+ },
246
+ default: false
247
+ });
248
+ registerOption('link_context_toolbar', {
249
+ processor: 'boolean',
250
+ default: false
251
+ });
252
+ registerOption('link_list', { processor: value => isString(value) || isFunction(value) || isArrayOf(value, isObject) });
253
+ registerOption('link_default_target', { processor: 'string' });
254
+ registerOption('link_default_protocol', {
255
+ processor: 'string',
256
+ default: 'https'
257
+ });
258
+ registerOption('link_target_list', {
259
+ processor: value => isBoolean(value) || isArrayOf(value, isObject),
260
+ default: true
261
+ });
262
+ registerOption('link_rel_list', {
263
+ processor: 'object[]',
264
+ default: []
265
+ });
266
+ registerOption('link_class_list', {
267
+ processor: 'object[]',
268
+ default: []
269
+ });
270
+ registerOption('link_title', {
271
+ processor: 'boolean',
272
+ default: true
273
+ });
274
+ registerOption('allow_unsafe_link_target', {
275
+ processor: 'boolean',
276
+ default: false
277
+ });
278
+ registerOption('link_quicklink', {
279
+ processor: 'boolean',
280
+ default: false
281
+ });
552
282
  };
553
283
  const assumeExternalTargets = option('link_assume_external_targets');
554
284
  const hasContextToolbar = option('link_context_toolbar');
@@ -561,1017 +291,952 @@
561
291
  const shouldShowLinkTitle = option('link_title');
562
292
  const allowUnsafeLinkTarget = option('allow_unsafe_link_target');
563
293
  const useQuickLink = option('link_quicklink');
564
- const attributesPostProcess = option('link_attributes_postprocess');
565
294
 
566
- var global$4 = tinymce.util.Tools.resolve('tinymce.util.URI');
295
+ var global$4 = tinymce.util.Tools.resolve('tinymce.util.Tools');
296
+
297
+ const getValue = item => isString(item.value) ? item.value : '';
298
+ const getText = item => {
299
+ if (isString(item.text)) {
300
+ return item.text;
301
+ } else if (isString(item.title)) {
302
+ return item.title;
303
+ } else {
304
+ return '';
305
+ }
306
+ };
307
+ const sanitizeList = (list, extractValue) => {
308
+ const out = [];
309
+ global$4.each(list, item => {
310
+ const text = getText(item);
311
+ if (item.menu !== undefined) {
312
+ const items = sanitizeList(item.menu, extractValue);
313
+ out.push({
314
+ text,
315
+ items
316
+ });
317
+ } else {
318
+ const value = extractValue(item);
319
+ out.push({
320
+ text,
321
+ value
322
+ });
323
+ }
324
+ });
325
+ return out;
326
+ };
327
+ const sanitizeWith = (extracter = getValue) => list => Optional.from(list).map(list => sanitizeList(list, extracter));
328
+ const sanitize = list => sanitizeWith(getValue)(list);
329
+ const createUi = (name, label) => items => ({
330
+ name,
331
+ type: 'listbox',
332
+ label,
333
+ items
334
+ });
335
+ const ListOptions = {
336
+ sanitize,
337
+ sanitizeWith,
338
+ createUi,
339
+ getValue
340
+ };
341
+
342
+ const keys = Object.keys;
343
+ const hasOwnProperty = Object.hasOwnProperty;
344
+ const each = (obj, f) => {
345
+ const props = keys(obj);
346
+ for (let k = 0, len = props.length; k < len; k++) {
347
+ const i = props[k];
348
+ const x = obj[i];
349
+ f(x, i);
350
+ }
351
+ };
352
+ const objAcc = r => (x, i) => {
353
+ r[i] = x;
354
+ };
355
+ const internalFilter = (obj, pred, onTrue, onFalse) => {
356
+ each(obj, (x, i) => {
357
+ (pred(x, i) ? onTrue : onFalse)(x, i);
358
+ });
359
+ };
360
+ const filter = (obj, pred) => {
361
+ const t = {};
362
+ internalFilter(obj, pred, objAcc(t), noop);
363
+ return t;
364
+ };
365
+ const has = (obj, key) => hasOwnProperty.call(obj, key);
366
+ const hasNonNullableKey = (obj, key) => has(obj, key) && obj[key] !== undefined && obj[key] !== null;
567
367
 
568
368
  var global$3 = tinymce.util.Tools.resolve('tinymce.dom.TreeWalker');
569
369
 
570
- var global$2 = tinymce.util.Tools.resolve('tinymce.util.Tools');
370
+ var global$2 = tinymce.util.Tools.resolve('tinymce.util.URI');
571
371
 
572
- const isAnchor = (elm) => isNonNullable(elm) && elm.nodeName.toLowerCase() === 'a';
573
- const isLink = (elm) => isAnchor(elm) && !!getHref(elm);
372
+ const isAnchor = elm => isNonNullable(elm) && elm.nodeName.toLowerCase() === 'a';
373
+ const isLink = elm => isAnchor(elm) && !!getHref(elm);
574
374
  const collectNodesInRange = (rng, predicate) => {
575
- if (rng.collapsed) {
576
- return [];
577
- }
578
- else {
579
- const contents = rng.cloneContents();
580
- const firstChild = contents.firstChild;
581
- const walker = new global$3(firstChild, contents);
582
- const elements = [];
583
- let current = firstChild;
584
- do {
585
- if (predicate(current)) {
586
- elements.push(current);
587
- }
588
- } while ((current = walker.next()));
589
- return elements;
590
- }
591
- };
592
- const hasProtocol = (url) => /^\w+:/i.test(url);
593
- const getHref = (elm) => {
594
- var _a, _b;
595
- // Returns the real href value not the resolved a.href value
596
- return (_b = (_a = elm.getAttribute('data-mce-href')) !== null && _a !== void 0 ? _a : elm.getAttribute('href')) !== null && _b !== void 0 ? _b : '';
375
+ if (rng.collapsed) {
376
+ return [];
377
+ } else {
378
+ const contents = rng.cloneContents();
379
+ const firstChild = contents.firstChild;
380
+ const walker = new global$3(firstChild, contents);
381
+ const elements = [];
382
+ let current = firstChild;
383
+ do {
384
+ if (predicate(current)) {
385
+ elements.push(current);
386
+ }
387
+ } while (current = walker.next());
388
+ return elements;
389
+ }
390
+ };
391
+ const hasProtocol = url => /^\w+:/i.test(url);
392
+ const getHref = elm => {
393
+ var _a, _b;
394
+ return (_b = (_a = elm.getAttribute('data-mce-href')) !== null && _a !== void 0 ? _a : elm.getAttribute('href')) !== null && _b !== void 0 ? _b : '';
597
395
  };
598
396
  const applyRelTargetRules = (rel, isUnsafe) => {
599
- const rules = ['noopener'];
600
- const rels = rel ? rel.split(/\s+/) : [];
601
- const toString = (rels) => global$2.trim(rels.sort().join(' '));
602
- const addTargetRules = (rels) => {
603
- rels = removeTargetRules(rels);
604
- return rels.length > 0 ? rels.concat(rules) : rules;
605
- };
606
- const removeTargetRules = (rels) => rels.filter((val) => global$2.inArray(rules, val) === -1);
607
- const newRels = isUnsafe ? addTargetRules(rels) : removeTargetRules(rels);
608
- return newRels.length > 0 ? toString(newRels) : '';
609
- };
610
- const trimCaretContainers = (text) => text.replace(/\uFEFF/g, '');
397
+ const rules = ['noopener'];
398
+ const rels = rel ? rel.split(/\s+/) : [];
399
+ const toString = rels => global$4.trim(rels.sort().join(' '));
400
+ const addTargetRules = rels => {
401
+ rels = removeTargetRules(rels);
402
+ return rels.length > 0 ? rels.concat(rules) : rules;
403
+ };
404
+ const removeTargetRules = rels => rels.filter(val => global$4.inArray(rules, val) === -1);
405
+ const newRels = isUnsafe ? addTargetRules(rels) : removeTargetRules(rels);
406
+ return newRels.length > 0 ? toString(newRels) : '';
407
+ };
408
+ const trimCaretContainers = text => text.replace(/\uFEFF/g, '');
611
409
  const getAnchorElement = (editor, selectedElm) => {
612
- selectedElm = selectedElm || getLinksInSelection(editor.selection.getRng())[0] || editor.selection.getNode();
613
- if (isImageFigure(selectedElm)) {
614
- // for an image contained in a figure we look for a link inside the selected element
615
- return Optional.from(editor.dom.select('a[href]', selectedElm)[0]);
616
- }
617
- else {
618
- return Optional.from(editor.dom.getParent(selectedElm, 'a[href]'));
619
- }
410
+ selectedElm = selectedElm || getLinksInSelection(editor.selection.getRng())[0] || editor.selection.getNode();
411
+ if (isImageFigure(selectedElm)) {
412
+ return Optional.from(editor.dom.select('a[href]', selectedElm)[0]);
413
+ } else {
414
+ return Optional.from(editor.dom.getParent(selectedElm, 'a[href]'));
415
+ }
620
416
  };
621
417
  const isInAnchor = (editor, selectedElm) => getAnchorElement(editor, selectedElm).isSome();
622
418
  const getAnchorText = (selection, anchorElm) => {
623
- const text = anchorElm.fold(() => selection.getContent({ format: 'text' }), (anchorElm) => anchorElm.innerText || anchorElm.textContent || '');
624
- return trimCaretContainers(text);
625
- };
626
- const getLinksInSelection = (rng) => collectNodesInRange(rng, isLink);
627
- const getLinks$1 = (elements) => global$2.grep(elements, isLink);
628
- const hasLinks = (elements) => getLinks$1(elements).length > 0;
629
- const hasLinksInSelection = (rng) => getLinksInSelection(rng).length > 0;
630
- const isOnlyTextSelected = (editor) => {
631
- // Allow anchor and inline text elements to be in the selection but nothing else
632
- const inlineTextElements = editor.schema.getTextInlineElements();
633
- const isElement = (elm) => elm.nodeType === 1 && !isAnchor(elm) && !has(inlineTextElements, elm.nodeName.toLowerCase());
634
- // If selection is inside a block anchor then always treat it as non text only
635
- const isInBlockAnchor = getAnchorElement(editor).exists((anchor) => anchor.hasAttribute('data-mce-block'));
636
- if (isInBlockAnchor) {
637
- return false;
638
- }
639
- const rng = editor.selection.getRng();
640
- if (!rng.collapsed) {
641
- // Collect all non inline text elements in the range and make sure no elements were found
642
- const elements = collectNodesInRange(rng, isElement);
643
- return elements.length === 0;
644
- }
645
- else {
646
- return true;
647
- }
648
- };
649
- const isImageFigure = (elm) => isNonNullable(elm) && elm.nodeName === 'FIGURE' && /\bimage\b/i.test(elm.className);
650
-
651
- const getLinkAttrs = (data) => {
652
- const attrs = ['title', 'rel', 'class', 'target'];
653
- return foldl(attrs, (acc, key) => {
654
- data[key].each((value) => {
655
- // If dealing with an empty string, then treat that as being null so the attribute is removed
656
- acc[key] = value.length > 0 ? value : null;
657
- });
658
- return acc;
659
- }, {
660
- href: data.href
419
+ const text = anchorElm.fold(() => selection.getContent({ format: 'text' }), anchorElm => anchorElm.innerText || anchorElm.textContent || '');
420
+ return trimCaretContainers(text);
421
+ };
422
+ const getLinksInSelection = rng => collectNodesInRange(rng, isLink);
423
+ const getLinks$1 = elements => global$4.grep(elements, isLink);
424
+ const hasLinks = elements => getLinks$1(elements).length > 0;
425
+ const hasLinksInSelection = rng => getLinksInSelection(rng).length > 0;
426
+ const isOnlyTextSelected = editor => {
427
+ const inlineTextElements = editor.schema.getTextInlineElements();
428
+ const isElement = elm => elm.nodeType === 1 && !isAnchor(elm) && !has(inlineTextElements, elm.nodeName.toLowerCase());
429
+ const isInBlockAnchor = getAnchorElement(editor).exists(anchor => anchor.hasAttribute('data-mce-block'));
430
+ if (isInBlockAnchor) {
431
+ return false;
432
+ }
433
+ const rng = editor.selection.getRng();
434
+ if (!rng.collapsed) {
435
+ const elements = collectNodesInRange(rng, isElement);
436
+ return elements.length === 0;
437
+ } else {
438
+ return true;
439
+ }
440
+ };
441
+ const isImageFigure = elm => isNonNullable(elm) && elm.nodeName === 'FIGURE' && /\bimage\b/i.test(elm.className);
442
+ const getLinkAttrs = data => {
443
+ const attrs = [
444
+ 'title',
445
+ 'rel',
446
+ 'class',
447
+ 'target'
448
+ ];
449
+ return foldl(attrs, (acc, key) => {
450
+ data[key].each(value => {
451
+ acc[key] = value.length > 0 ? value : null;
661
452
  });
453
+ return acc;
454
+ }, { href: data.href });
662
455
  };
663
456
  const handleExternalTargets = (href, assumeExternalTargets) => {
664
- if ((assumeExternalTargets === "http" /* AssumeExternalTargets.ALWAYS_HTTP */
665
- || assumeExternalTargets === "https" /* AssumeExternalTargets.ALWAYS_HTTPS */)
666
- && !hasProtocol(href)) {
667
- return assumeExternalTargets + '://' + href;
668
- }
669
- return href;
457
+ if ((assumeExternalTargets === 'http' || assumeExternalTargets === 'https') && !hasProtocol(href)) {
458
+ return assumeExternalTargets + '://' + href;
459
+ }
460
+ return href;
670
461
  };
671
462
  const applyLinkOverrides = (editor, linkAttrs) => {
672
- const newLinkAttrs = { ...linkAttrs };
673
- if (getRelList(editor).length === 0 && !allowUnsafeLinkTarget(editor)) {
674
- const newRel = applyRelTargetRules(newLinkAttrs.rel, newLinkAttrs.target === '_blank');
675
- newLinkAttrs.rel = newRel ? newRel : null;
676
- }
677
- if (Optional.from(newLinkAttrs.target).isNone() && getTargetList(editor) === false) {
678
- newLinkAttrs.target = getDefaultLinkTarget(editor);
679
- }
680
- newLinkAttrs.href = handleExternalTargets(newLinkAttrs.href, assumeExternalTargets(editor));
681
- return newLinkAttrs;
463
+ const newLinkAttrs = { ...linkAttrs };
464
+ if (getRelList(editor).length === 0 && !allowUnsafeLinkTarget(editor)) {
465
+ const newRel = applyRelTargetRules(newLinkAttrs.rel, newLinkAttrs.target === '_blank');
466
+ newLinkAttrs.rel = newRel ? newRel : null;
467
+ }
468
+ if (Optional.from(newLinkAttrs.target).isNone() && getTargetList(editor) === false) {
469
+ newLinkAttrs.target = getDefaultLinkTarget(editor);
470
+ }
471
+ newLinkAttrs.href = handleExternalTargets(newLinkAttrs.href, assumeExternalTargets(editor));
472
+ return newLinkAttrs;
682
473
  };
683
474
  const updateLink = (editor, anchorElm, text, linkAttrs) => {
684
- // If we have text, then update the anchor elements text content
685
- text.each((text) => {
686
- if (has(anchorElm, 'innerText')) {
687
- anchorElm.innerText = text;
688
- }
689
- else {
690
- anchorElm.textContent = text;
691
- }
692
- });
693
- editor.dom.setAttribs(anchorElm, linkAttrs);
694
- // Move the cursor behind the updated link, so the user can go on typing.
695
- const rng = editor.dom.createRng();
696
- rng.setStartAfter(anchorElm);
697
- rng.setEndAfter(anchorElm);
698
- editor.selection.setRng(rng);
699
- };
700
- const createLink = (editor, selectedElm, text, linkAttrs) => {
701
- const dom = editor.dom;
702
- if (isImageFigure(selectedElm)) {
703
- linkImageFigure(dom, selectedElm, linkAttrs);
704
- }
705
- else {
706
- text.fold(() => {
707
- editor.execCommand('mceInsertLink', false, linkAttrs);
708
- // Now the newly inserted link is selected. Move the cursor behind the new link, so the user can go on typing.
709
- const end = editor.selection.getEnd();
710
- const rng = dom.createRng();
711
- rng.setStartAfter(end);
712
- rng.setEndAfter(end);
713
- editor.selection.setRng(rng);
714
- }, (text) => {
715
- editor.insertContent(dom.createHTML('a', linkAttrs, dom.encode(text)));
716
- });
475
+ text.each(text => {
476
+ if (has(anchorElm, 'innerText')) {
477
+ anchorElm.innerText = text;
478
+ } else {
479
+ anchorElm.textContent = text;
717
480
  }
481
+ });
482
+ editor.dom.setAttribs(anchorElm, linkAttrs);
483
+ editor.selection.select(anchorElm);
718
484
  };
719
- const linkDomMutation = (editor, attachState, data) => {
720
- const selectedElm = editor.selection.getNode();
721
- const anchorElm = getAnchorElement(editor, selectedElm);
722
- const linkAttrs = applyLinkOverrides(editor, getLinkAttrs(data));
723
- const attributesPostProcess$1 = attributesPostProcess(editor);
724
- if (isNonNullable(attributesPostProcess$1)) {
725
- attributesPostProcess$1(linkAttrs);
726
- }
727
- editor.undoManager.transact(() => {
728
- if (data.href === attachState.href) {
729
- attachState.attach();
730
- }
731
- anchorElm.fold(() => {
732
- createLink(editor, selectedElm, data.text, linkAttrs);
733
- }, (elm) => {
734
- editor.focus();
735
- updateLink(editor, elm, data.text, linkAttrs);
736
- });
485
+ const createLink = (editor, selectedElm, text, linkAttrs) => {
486
+ const dom = editor.dom;
487
+ if (isImageFigure(selectedElm)) {
488
+ linkImageFigure(dom, selectedElm, linkAttrs);
489
+ } else {
490
+ text.fold(() => {
491
+ editor.execCommand('mceInsertLink', false, linkAttrs);
492
+ }, text => {
493
+ editor.insertContent(dom.createHTML('a', linkAttrs, dom.encode(text)));
737
494
  });
495
+ }
738
496
  };
739
- const unlinkSelection = (editor) => {
740
- const dom = editor.dom, selection = editor.selection;
741
- const bookmark = selection.getBookmark();
742
- const rng = selection.getRng().cloneRange();
743
- // Extend the selection out to the entire anchor element
744
- const startAnchorElm = dom.getParent(rng.startContainer, 'a[href]', editor.getBody());
745
- const endAnchorElm = dom.getParent(rng.endContainer, 'a[href]', editor.getBody());
746
- if (startAnchorElm) {
747
- rng.setStartBefore(startAnchorElm);
748
- }
749
- if (endAnchorElm) {
750
- rng.setEndAfter(endAnchorElm);
751
- }
752
- selection.setRng(rng);
753
- // Remove the link
754
- editor.execCommand('unlink');
755
- selection.moveToBookmark(bookmark);
756
- };
757
- const unlinkDomMutation = (editor) => {
758
- editor.undoManager.transact(() => {
759
- const node = editor.selection.getNode();
760
- if (isImageFigure(node)) {
761
- unlinkImageFigure(editor, node);
762
- }
763
- else {
764
- unlinkSelection(editor);
765
- }
766
- editor.focus();
497
+ const linkDomMutation = (editor, attachState, data) => {
498
+ const selectedElm = editor.selection.getNode();
499
+ const anchorElm = getAnchorElement(editor, selectedElm);
500
+ const linkAttrs = applyLinkOverrides(editor, getLinkAttrs(data));
501
+ editor.undoManager.transact(() => {
502
+ if (data.href === attachState.href) {
503
+ attachState.attach();
504
+ }
505
+ anchorElm.fold(() => {
506
+ createLink(editor, selectedElm, data.text, linkAttrs);
507
+ }, elm => {
508
+ editor.focus();
509
+ updateLink(editor, elm, data.text, linkAttrs);
767
510
  });
768
- };
769
- /*
770
- * RTC uses unwrapped options.
771
- *
772
- * To best simulate this, we unwrap to null and filter out empty values.
773
- */
774
- const unwrapOptions = (data) => {
775
- const { class: cls, href, rel, target, text, title } = data;
776
- return filter({
777
- class: cls.getOrNull(),
778
- href,
779
- rel: rel.getOrNull(),
780
- target: target.getOrNull(),
781
- text: text.getOrNull(),
782
- title: title.getOrNull()
783
- }, (v, _k) => isNull(v) === false);
511
+ });
512
+ };
513
+ const unlinkSelection = editor => {
514
+ const dom = editor.dom, selection = editor.selection;
515
+ const bookmark = selection.getBookmark();
516
+ const rng = selection.getRng().cloneRange();
517
+ const startAnchorElm = dom.getParent(rng.startContainer, 'a[href]', editor.getBody());
518
+ const endAnchorElm = dom.getParent(rng.endContainer, 'a[href]', editor.getBody());
519
+ if (startAnchorElm) {
520
+ rng.setStartBefore(startAnchorElm);
521
+ }
522
+ if (endAnchorElm) {
523
+ rng.setEndAfter(endAnchorElm);
524
+ }
525
+ selection.setRng(rng);
526
+ editor.execCommand('unlink');
527
+ selection.moveToBookmark(bookmark);
528
+ };
529
+ const unlinkDomMutation = editor => {
530
+ editor.undoManager.transact(() => {
531
+ const node = editor.selection.getNode();
532
+ if (isImageFigure(node)) {
533
+ unlinkImageFigure(editor, node);
534
+ } else {
535
+ unlinkSelection(editor);
536
+ }
537
+ editor.focus();
538
+ });
539
+ };
540
+ const unwrapOptions = data => {
541
+ const {
542
+ class: cls,
543
+ href,
544
+ rel,
545
+ target,
546
+ text,
547
+ title
548
+ } = data;
549
+ return filter({
550
+ class: cls.getOrNull(),
551
+ href,
552
+ rel: rel.getOrNull(),
553
+ target: target.getOrNull(),
554
+ text: text.getOrNull(),
555
+ title: title.getOrNull()
556
+ }, (v, _k) => isNull(v) === false);
784
557
  };
785
558
  const sanitizeData = (editor, data) => {
786
- const getOption = editor.options.get;
787
- const uriOptions = {
788
- allow_html_data_urls: getOption('allow_html_data_urls'),
789
- allow_script_urls: getOption('allow_script_urls'),
790
- allow_svg_data_urls: getOption('allow_svg_data_urls')
791
- };
792
- // Sanitize the URL
793
- const href = data.href;
794
- return {
795
- ...data,
796
- href: global$4.isDomSafe(href, 'a', uriOptions) ? href : ''
797
- };
559
+ const getOption = editor.options.get;
560
+ const uriOptions = {
561
+ allow_html_data_urls: getOption('allow_html_data_urls'),
562
+ allow_script_urls: getOption('allow_script_urls'),
563
+ allow_svg_data_urls: getOption('allow_svg_data_urls')
564
+ };
565
+ const href = data.href;
566
+ return {
567
+ ...data,
568
+ href: global$2.isDomSafe(href, 'a', uriOptions) ? href : ''
569
+ };
798
570
  };
799
571
  const link = (editor, attachState, data) => {
800
- const sanitizedData = sanitizeData(editor, data);
801
- editor.hasPlugin('rtc', true) ? editor.execCommand('createlink', false, unwrapOptions(sanitizedData)) : linkDomMutation(editor, attachState, sanitizedData);
572
+ const sanitizedData = sanitizeData(editor, data);
573
+ editor.hasPlugin('rtc', true) ? editor.execCommand('createlink', false, unwrapOptions(sanitizedData)) : linkDomMutation(editor, attachState, sanitizedData);
802
574
  };
803
- const unlink = (editor) => {
804
- editor.hasPlugin('rtc', true) ? editor.execCommand('unlink') : unlinkDomMutation(editor);
575
+ const unlink = editor => {
576
+ editor.hasPlugin('rtc', true) ? editor.execCommand('unlink') : unlinkDomMutation(editor);
805
577
  };
806
578
  const unlinkImageFigure = (editor, fig) => {
807
- var _a;
808
- const img = editor.dom.select('img', fig)[0];
809
- if (img) {
810
- const a = editor.dom.getParents(img, 'a[href]', fig)[0];
811
- if (a) {
812
- (_a = a.parentNode) === null || _a === void 0 ? void 0 : _a.insertBefore(img, a);
813
- editor.dom.remove(a);
814
- }
579
+ var _a;
580
+ const img = editor.dom.select('img', fig)[0];
581
+ if (img) {
582
+ const a = editor.dom.getParents(img, 'a[href]', fig)[0];
583
+ if (a) {
584
+ (_a = a.parentNode) === null || _a === void 0 ? void 0 : _a.insertBefore(img, a);
585
+ editor.dom.remove(a);
815
586
  }
587
+ }
816
588
  };
817
589
  const linkImageFigure = (dom, fig, attrs) => {
818
- var _a;
819
- const img = dom.select('img', fig)[0];
820
- if (img) {
821
- const a = dom.create('a', attrs);
822
- (_a = img.parentNode) === null || _a === void 0 ? void 0 : _a.insertBefore(a, img);
823
- a.appendChild(img);
824
- }
825
- };
826
-
827
- const getValue = (item) => isString(item.value) ? item.value : '';
828
- const getText = (item) => {
829
- if (isString(item.text)) {
830
- return item.text;
831
- }
832
- else if (isString(item.title)) {
833
- return item.title;
834
- }
835
- else {
836
- return '';
837
- }
838
- };
839
- const sanitizeList = (list, extractValue) => {
840
- const out = [];
841
- global$2.each(list, (item) => {
842
- const text = getText(item);
843
- if (item.menu !== undefined) {
844
- const items = sanitizeList(item.menu, extractValue);
845
- out.push({ text, items }); // list group
846
- }
847
- else {
848
- const value = extractValue(item);
849
- out.push({ text, value }); // list value
850
- }
851
- });
852
- return out;
853
- };
854
- const sanitizeWith = (extracter = getValue) => (list) => Optional.from(list).map((list) => sanitizeList(list, extracter));
855
- const sanitize = (list) => sanitizeWith(getValue)(list);
856
- // NOTE: May need to care about flattening.
857
- const createUi = (name, label) => (items) => ({
858
- name,
859
- type: 'listbox',
860
- label,
861
- items
862
- });
863
- const ListOptions = {
864
- sanitize,
865
- sanitizeWith,
866
- createUi,
867
- getValue
590
+ var _a;
591
+ const img = dom.select('img', fig)[0];
592
+ if (img) {
593
+ const a = dom.create('a', attrs);
594
+ (_a = img.parentNode) === null || _a === void 0 ? void 0 : _a.insertBefore(a, img);
595
+ a.appendChild(img);
596
+ }
868
597
  };
869
598
 
870
- const isListGroup = (item) => hasNonNullableKey(item, 'items');
871
- const findTextByValue = (value, catalog) => findMap(catalog, (item) => {
872
- if (isListGroup(item)) {
873
- return findTextByValue(value, item.items);
874
- }
875
- else {
876
- return someIf(item.value === value, item);
877
- }
599
+ const isListGroup = item => hasNonNullableKey(item, 'items');
600
+ const findTextByValue = (value, catalog) => findMap(catalog, item => {
601
+ if (isListGroup(item)) {
602
+ return findTextByValue(value, item.items);
603
+ } else {
604
+ return someIf(item.value === value, item);
605
+ }
878
606
  });
879
607
  const getDelta = (persistentText, fieldName, catalog, data) => {
880
- const value = data[fieldName];
881
- const hasPersistentText = persistentText.length > 0;
882
- return value !== undefined ? findTextByValue(value, catalog).map((i) => ({
883
- url: {
884
- value: i.value,
885
- meta: {
886
- text: hasPersistentText ? persistentText : i.text,
887
- attach: noop
888
- }
889
- },
890
- text: hasPersistentText ? persistentText : i.text
891
- })) : Optional.none();
608
+ const value = data[fieldName];
609
+ const hasPersistentText = persistentText.length > 0;
610
+ return value !== undefined ? findTextByValue(value, catalog).map(i => ({
611
+ url: {
612
+ value: i.value,
613
+ meta: {
614
+ text: hasPersistentText ? persistentText : i.text,
615
+ attach: noop
616
+ }
617
+ },
618
+ text: hasPersistentText ? persistentText : i.text
619
+ })) : Optional.none();
892
620
  };
893
621
  const findCatalog = (catalogs, fieldName) => {
894
- if (fieldName === 'link') {
895
- return catalogs.link;
896
- }
897
- else if (fieldName === 'anchor') {
898
- return catalogs.anchor;
899
- }
900
- else {
901
- return Optional.none();
902
- }
622
+ if (fieldName === 'link') {
623
+ return catalogs.link;
624
+ } else if (fieldName === 'anchor') {
625
+ return catalogs.anchor;
626
+ } else {
627
+ return Optional.none();
628
+ }
903
629
  };
904
630
  const init = (initialData, linkCatalog) => {
905
- const persistentData = {
906
- text: initialData.text,
907
- title: initialData.title
908
- };
909
- const getTitleFromUrlChange = (url) => { var _a; return someIf(persistentData.title.length <= 0, Optional.from((_a = url.meta) === null || _a === void 0 ? void 0 : _a.title).getOr('')); };
910
- const getTextFromUrlChange = (url) => { var _a; return someIf(persistentData.text.length <= 0, Optional.from((_a = url.meta) === null || _a === void 0 ? void 0 : _a.text).getOr(url.value)); };
911
- const onUrlChange = (data) => {
912
- const text = getTextFromUrlChange(data.url);
913
- const title = getTitleFromUrlChange(data.url);
914
- // We are going to change the text/title because it has not been manually entered by the user.
915
- if (text.isSome() || title.isSome()) {
916
- return Optional.some({
917
- ...text.map((text) => ({ text })).getOr({}),
918
- ...title.map((title) => ({ title })).getOr({})
919
- });
920
- }
921
- else {
922
- return Optional.none();
923
- }
924
- };
925
- const onCatalogChange = (data, change) => {
926
- const catalog = findCatalog(linkCatalog, change).getOr([]);
927
- return getDelta(persistentData.text, change, catalog, data);
928
- };
929
- const onChange = (getData, change) => {
930
- const name = change.name;
931
- if (name === 'url') {
932
- return onUrlChange(getData());
933
- }
934
- else if (contains(['anchor', 'link'], name)) {
935
- return onCatalogChange(getData(), name);
936
- }
937
- else if (name === 'text' || name === 'title') {
938
- // Update the persistent text/title state, as a user has input custom text
939
- persistentData[name] = getData()[name];
940
- return Optional.none();
941
- }
942
- else {
943
- return Optional.none();
944
- }
945
- };
946
- return {
947
- onChange
948
- };
631
+ const persistentData = {
632
+ text: initialData.text,
633
+ title: initialData.title
634
+ };
635
+ const getTitleFromUrlChange = url => {
636
+ var _a;
637
+ return someIf(persistentData.title.length <= 0, Optional.from((_a = url.meta) === null || _a === void 0 ? void 0 : _a.title).getOr(''));
638
+ };
639
+ const getTextFromUrlChange = url => {
640
+ var _a;
641
+ return someIf(persistentData.text.length <= 0, Optional.from((_a = url.meta) === null || _a === void 0 ? void 0 : _a.text).getOr(url.value));
642
+ };
643
+ const onUrlChange = data => {
644
+ const text = getTextFromUrlChange(data.url);
645
+ const title = getTitleFromUrlChange(data.url);
646
+ if (text.isSome() || title.isSome()) {
647
+ return Optional.some({
648
+ ...text.map(text => ({ text })).getOr({}),
649
+ ...title.map(title => ({ title })).getOr({})
650
+ });
651
+ } else {
652
+ return Optional.none();
653
+ }
654
+ };
655
+ const onCatalogChange = (data, change) => {
656
+ const catalog = findCatalog(linkCatalog, change).getOr([]);
657
+ return getDelta(persistentData.text, change, catalog, data);
658
+ };
659
+ const onChange = (getData, change) => {
660
+ const name = change.name;
661
+ if (name === 'url') {
662
+ return onUrlChange(getData());
663
+ } else if (contains([
664
+ 'anchor',
665
+ 'link'
666
+ ], name)) {
667
+ return onCatalogChange(getData(), name);
668
+ } else if (name === 'text' || name === 'title') {
669
+ persistentData[name] = getData()[name];
670
+ return Optional.none();
671
+ } else {
672
+ return Optional.none();
673
+ }
674
+ };
675
+ return { onChange };
949
676
  };
950
677
  const DialogChanges = {
951
- init,
952
- getDelta
678
+ init,
679
+ getDelta
953
680
  };
954
681
 
955
682
  var global$1 = tinymce.util.Tools.resolve('tinymce.util.Delay');
956
683
 
957
- // Delay confirm since onSubmit will move focus
958
684
  const delayedConfirm = (editor, message, callback) => {
959
- const rng = editor.selection.getRng();
960
- global$1.setEditorTimeout(editor, () => {
961
- editor.windowManager.confirm(message, (state) => {
962
- editor.selection.setRng(rng);
963
- callback(state);
964
- });
965
- });
966
- };
967
- const tryEmailTransform = (data) => {
968
- const url = data.href;
969
- const suggestMailTo = url.indexOf('@') > 0 && url.indexOf('/') === -1 && url.indexOf('mailto:') === -1;
970
- return suggestMailTo ? Optional.some({
971
- message: 'The URL you entered seems to be an email address. Do you want to add the required mailto: prefix?',
972
- preprocess: (oldData) => ({ ...oldData, href: 'mailto:' + url })
973
- }) : Optional.none();
974
- };
975
- const tryProtocolTransform = (assumeExternalTargets, defaultLinkProtocol) => (data) => {
976
- const url = data.href;
977
- const suggestProtocol = (assumeExternalTargets === 1 /* AssumeExternalTargets.WARN */ && !hasProtocol(url) ||
978
- assumeExternalTargets === 0 /* AssumeExternalTargets.OFF */ && /^\s*www(\.|\d\.)/i.test(url));
979
- return suggestProtocol ? Optional.some({
980
- message: `The URL you entered seems to be an external link. Do you want to add the required ${defaultLinkProtocol}:// prefix?`,
981
- preprocess: (oldData) => ({ ...oldData, href: defaultLinkProtocol + '://' + url })
982
- }) : Optional.none();
983
- };
984
- const preprocess = (editor, data) => findMap([tryEmailTransform, tryProtocolTransform(assumeExternalTargets(editor), getDefaultLinkProtocol(editor))], (f) => f(data)).fold(() => Promise.resolve(data), (transform) => new Promise((callback) => {
985
- delayedConfirm(editor, transform.message, (state) => {
986
- callback(state ? transform.preprocess(data) : data);
685
+ const rng = editor.selection.getRng();
686
+ global$1.setEditorTimeout(editor, () => {
687
+ editor.windowManager.confirm(message, state => {
688
+ editor.selection.setRng(rng);
689
+ callback(state);
987
690
  });
691
+ });
692
+ };
693
+ const tryEmailTransform = data => {
694
+ const url = data.href;
695
+ const suggestMailTo = url.indexOf('@') > 0 && url.indexOf('/') === -1 && url.indexOf('mailto:') === -1;
696
+ return suggestMailTo ? Optional.some({
697
+ message: 'The URL you entered seems to be an email address. Do you want to add the required mailto: prefix?',
698
+ preprocess: oldData => ({
699
+ ...oldData,
700
+ href: 'mailto:' + url
701
+ })
702
+ }) : Optional.none();
703
+ };
704
+ const tryProtocolTransform = (assumeExternalTargets, defaultLinkProtocol) => data => {
705
+ const url = data.href;
706
+ const suggestProtocol = assumeExternalTargets === 1 && !hasProtocol(url) || assumeExternalTargets === 0 && /^\s*www(\.|\d\.)/i.test(url);
707
+ return suggestProtocol ? Optional.some({
708
+ message: `The URL you entered seems to be an external link. Do you want to add the required ${ defaultLinkProtocol }:// prefix?`,
709
+ preprocess: oldData => ({
710
+ ...oldData,
711
+ href: defaultLinkProtocol + '://' + url
712
+ })
713
+ }) : Optional.none();
714
+ };
715
+ const preprocess = (editor, data) => findMap([
716
+ tryEmailTransform,
717
+ tryProtocolTransform(assumeExternalTargets(editor), getDefaultLinkProtocol(editor))
718
+ ], f => f(data)).fold(() => Promise.resolve(data), transform => new Promise(callback => {
719
+ delayedConfirm(editor, transform.message, state => {
720
+ callback(state ? transform.preprocess(data) : data);
721
+ });
988
722
  }));
989
- const DialogConfirms = {
990
- preprocess
991
- };
723
+ const DialogConfirms = { preprocess };
992
724
 
993
- // NOTE: you currently need anchors in the content for this field to appear
994
- const getAnchors = (editor) => {
995
- const anchorNodes = editor.dom.select('a:not([href])');
996
- const anchors = bind(anchorNodes, (anchor) => {
997
- const id = anchor.name || anchor.id;
998
- return id ? [{ text: id, value: '#' + id }] : [];
999
- });
1000
- return anchors.length > 0 ? Optional.some([{ text: 'None', value: '' }].concat(anchors)) : Optional.none();
1001
- };
1002
- const AnchorListOptions = {
1003
- getAnchors
1004
- };
725
+ const getAnchors = editor => {
726
+ const anchorNodes = editor.dom.select('a:not([href])');
727
+ const anchors = bind(anchorNodes, anchor => {
728
+ const id = anchor.name || anchor.id;
729
+ return id ? [{
730
+ text: id,
731
+ value: '#' + id
732
+ }] : [];
733
+ });
734
+ return anchors.length > 0 ? Optional.some([{
735
+ text: 'None',
736
+ value: ''
737
+ }].concat(anchors)) : Optional.none();
738
+ };
739
+ const AnchorListOptions = { getAnchors };
1005
740
 
1006
- // Looks like tinymce currently renders menus, but doesn't
1007
- // let you choose from one.
1008
- const getClasses = (editor) => {
1009
- const list = getLinkClassList(editor);
1010
- if (list.length > 0) {
1011
- return ListOptions.sanitize(list);
1012
- }
1013
- return Optional.none();
1014
- };
1015
- const ClassListOptions = {
1016
- getClasses
1017
- };
741
+ const getClasses = editor => {
742
+ const list = getLinkClassList(editor);
743
+ if (list.length > 0) {
744
+ return ListOptions.sanitize(list);
745
+ }
746
+ return Optional.none();
747
+ };
748
+ const ClassListOptions = { getClasses };
1018
749
 
1019
- const parseJson = (text) => {
1020
- // Do some proper modelling.
1021
- try {
1022
- return Optional.some(JSON.parse(text));
1023
- }
1024
- catch (_a) {
1025
- return Optional.none();
1026
- }
1027
- };
1028
- const getLinks = (editor) => {
1029
- const extractor = (item) => editor.convertURL(item.value || item.url || '', 'href');
1030
- const linkList = getLinkList(editor);
1031
- return new Promise((resolve) => {
1032
- // TODO - better handling of failure
1033
- if (isString(linkList)) {
1034
- fetch(linkList)
1035
- .then((res) => res.ok ? res.text().then(parseJson) : Promise.reject())
1036
- .then(resolve, () => resolve(Optional.none()));
1037
- }
1038
- else if (isFunction(linkList)) {
1039
- linkList((output) => resolve(Optional.some(output)));
1040
- }
1041
- else {
1042
- resolve(Optional.from(linkList));
1043
- }
1044
- }).then((optItems) => optItems.bind(ListOptions.sanitizeWith(extractor)).map((items) => {
1045
- if (items.length > 0) {
1046
- const noneItem = [{ text: 'None', value: '' }];
1047
- return noneItem.concat(items);
1048
- }
1049
- else {
1050
- return items;
1051
- }
1052
- }));
1053
- };
1054
- const LinkListOptions = {
1055
- getLinks
1056
- };
750
+ const parseJson = text => {
751
+ try {
752
+ return Optional.some(JSON.parse(text));
753
+ } catch (err) {
754
+ return Optional.none();
755
+ }
756
+ };
757
+ const getLinks = editor => {
758
+ const extractor = item => editor.convertURL(item.value || item.url || '', 'href');
759
+ const linkList = getLinkList(editor);
760
+ return new Promise(resolve => {
761
+ if (isString(linkList)) {
762
+ fetch(linkList).then(res => res.ok ? res.text().then(parseJson) : Promise.reject()).then(resolve, () => resolve(Optional.none()));
763
+ } else if (isFunction(linkList)) {
764
+ linkList(output => resolve(Optional.some(output)));
765
+ } else {
766
+ resolve(Optional.from(linkList));
767
+ }
768
+ }).then(optItems => optItems.bind(ListOptions.sanitizeWith(extractor)).map(items => {
769
+ if (items.length > 0) {
770
+ const noneItem = [{
771
+ text: 'None',
772
+ value: ''
773
+ }];
774
+ return noneItem.concat(items);
775
+ } else {
776
+ return items;
777
+ }
778
+ }));
779
+ };
780
+ const LinkListOptions = { getLinks };
1057
781
 
1058
782
  const getRels = (editor, initialTarget) => {
1059
- const list = getRelList(editor);
1060
- if (list.length > 0) {
1061
- const isTargetBlank = is(initialTarget, '_blank');
1062
- const enforceSafe = allowUnsafeLinkTarget(editor) === false;
1063
- const safeRelExtractor = (item) => applyRelTargetRules(ListOptions.getValue(item), isTargetBlank);
1064
- const sanitizer = enforceSafe ? ListOptions.sanitizeWith(safeRelExtractor) : ListOptions.sanitize;
1065
- return sanitizer(list);
1066
- }
1067
- return Optional.none();
1068
- };
1069
- const RelOptions = {
1070
- getRels
1071
- };
783
+ const list = getRelList(editor);
784
+ if (list.length > 0) {
785
+ const isTargetBlank = is(initialTarget, '_blank');
786
+ const enforceSafe = allowUnsafeLinkTarget(editor) === false;
787
+ const safeRelExtractor = item => applyRelTargetRules(ListOptions.getValue(item), isTargetBlank);
788
+ const sanitizer = enforceSafe ? ListOptions.sanitizeWith(safeRelExtractor) : ListOptions.sanitize;
789
+ return sanitizer(list);
790
+ }
791
+ return Optional.none();
792
+ };
793
+ const RelOptions = { getRels };
1072
794
 
1073
- // In current tinymce, targets can be nested menus.
1074
- // Do we really want to support that?
1075
795
  const fallbacks = [
1076
- { text: 'Current window', value: '' },
1077
- { text: 'New window', value: '_blank' }
796
+ {
797
+ text: 'Current window',
798
+ value: ''
799
+ },
800
+ {
801
+ text: 'New window',
802
+ value: '_blank'
803
+ }
1078
804
  ];
1079
- const getTargets = (editor) => {
1080
- const list = getTargetList(editor);
1081
- if (isArray(list)) {
1082
- return ListOptions.sanitize(list).orThunk(() => Optional.some(fallbacks));
1083
- }
1084
- else if (list === false) {
1085
- return Optional.none();
1086
- }
1087
- return Optional.some(fallbacks);
1088
- };
1089
- const TargetOptions = {
1090
- getTargets
805
+ const getTargets = editor => {
806
+ const list = getTargetList(editor);
807
+ if (isArray(list)) {
808
+ return ListOptions.sanitize(list).orThunk(() => Optional.some(fallbacks));
809
+ } else if (list === false) {
810
+ return Optional.none();
811
+ }
812
+ return Optional.some(fallbacks);
1091
813
  };
814
+ const TargetOptions = { getTargets };
1092
815
 
1093
816
  const nonEmptyAttr = (dom, elem, name) => {
1094
- const val = dom.getAttrib(elem, name);
1095
- return val !== null && val.length > 0 ? Optional.some(val) : Optional.none();
817
+ const val = dom.getAttrib(elem, name);
818
+ return val !== null && val.length > 0 ? Optional.some(val) : Optional.none();
1096
819
  };
1097
820
  const extractFromAnchor = (editor, anchor) => {
1098
- const dom = editor.dom;
1099
- const onlyText = isOnlyTextSelected(editor);
1100
- const text = onlyText ? Optional.some(getAnchorText(editor.selection, anchor)) : Optional.none();
1101
- const url = anchor.bind((anchorElm) => Optional.from(dom.getAttrib(anchorElm, 'href')));
1102
- const target = anchor.bind((anchorElm) => Optional.from(dom.getAttrib(anchorElm, 'target')));
1103
- const rel = anchor.bind((anchorElm) => nonEmptyAttr(dom, anchorElm, 'rel'));
1104
- const linkClass = anchor.bind((anchorElm) => nonEmptyAttr(dom, anchorElm, 'class'));
1105
- const title = anchor.bind((anchorElm) => nonEmptyAttr(dom, anchorElm, 'title'));
1106
- return {
1107
- url,
1108
- text,
1109
- title,
1110
- target,
1111
- rel,
1112
- linkClass
1113
- };
1114
- };
1115
- const collect = (editor, linkNode) => LinkListOptions.getLinks(editor).then((links) => {
1116
- const anchor = extractFromAnchor(editor, linkNode);
1117
- return {
1118
- anchor,
1119
- catalogs: {
1120
- targets: TargetOptions.getTargets(editor),
1121
- // This should be initial target. Is anchor.target that?
1122
- rels: RelOptions.getRels(editor, anchor.target),
1123
- classes: ClassListOptions.getClasses(editor),
1124
- anchor: AnchorListOptions.getAnchors(editor),
1125
- link: links
1126
- },
1127
- optNode: linkNode,
1128
- flags: {
1129
- titleEnabled: shouldShowLinkTitle(editor)
1130
- }
1131
- };
821
+ const dom = editor.dom;
822
+ const onlyText = isOnlyTextSelected(editor);
823
+ const text = onlyText ? Optional.some(getAnchorText(editor.selection, anchor)) : Optional.none();
824
+ const url = anchor.bind(anchorElm => Optional.from(dom.getAttrib(anchorElm, 'href')));
825
+ const target = anchor.bind(anchorElm => Optional.from(dom.getAttrib(anchorElm, 'target')));
826
+ const rel = anchor.bind(anchorElm => nonEmptyAttr(dom, anchorElm, 'rel'));
827
+ const linkClass = anchor.bind(anchorElm => nonEmptyAttr(dom, anchorElm, 'class'));
828
+ const title = anchor.bind(anchorElm => nonEmptyAttr(dom, anchorElm, 'title'));
829
+ return {
830
+ url,
831
+ text,
832
+ title,
833
+ target,
834
+ rel,
835
+ linkClass
836
+ };
837
+ };
838
+ const collect = (editor, linkNode) => LinkListOptions.getLinks(editor).then(links => {
839
+ const anchor = extractFromAnchor(editor, linkNode);
840
+ return {
841
+ anchor,
842
+ catalogs: {
843
+ targets: TargetOptions.getTargets(editor),
844
+ rels: RelOptions.getRels(editor, anchor.target),
845
+ classes: ClassListOptions.getClasses(editor),
846
+ anchor: AnchorListOptions.getAnchors(editor),
847
+ link: links
848
+ },
849
+ optNode: linkNode,
850
+ flags: { titleEnabled: shouldShowLinkTitle(editor) }
851
+ };
1132
852
  });
1133
- const DialogInfo = {
1134
- collect
1135
- };
853
+ const DialogInfo = { collect };
1136
854
 
1137
- const handleSubmit = (editor, info) => (api) => {
1138
- const data = api.getData();
1139
- if (!data.url.value) {
1140
- unlink(editor);
1141
- // Temporary fix. TODO: TINY-2811
1142
- api.close();
1143
- return;
1144
- }
1145
- // Check if a key is defined, meaning it was a field in the dialog. If it is,
1146
- // then check if it's changed and return none if nothing has changed.
1147
- const getChangedValue = (key) => Optional.from(data[key]).filter((value) => !is(info.anchor[key], value));
1148
- const changedData = {
1149
- href: data.url.value,
1150
- text: getChangedValue('text'),
1151
- target: getChangedValue('target'),
1152
- rel: getChangedValue('rel'),
1153
- class: getChangedValue('linkClass'),
1154
- title: getChangedValue('title')
1155
- };
1156
- const attachState = {
1157
- href: data.url.value,
1158
- attach: data.url.meta !== undefined && data.url.meta.attach ? data.url.meta.attach : noop
1159
- };
1160
- // eslint-disable-next-line @typescript-eslint/no-floating-promises
1161
- DialogConfirms.preprocess(editor, changedData).then((pData) => {
1162
- link(editor, attachState, pData);
1163
- });
855
+ const handleSubmit = (editor, info) => api => {
856
+ const data = api.getData();
857
+ if (!data.url.value) {
858
+ unlink(editor);
1164
859
  api.close();
1165
- };
1166
- const collectData = (editor) => {
1167
- const anchorNode = getAnchorElement(editor);
1168
- return DialogInfo.collect(editor, anchorNode);
860
+ return;
861
+ }
862
+ const getChangedValue = key => Optional.from(data[key]).filter(value => !is(info.anchor[key], value));
863
+ const changedData = {
864
+ href: data.url.value,
865
+ text: getChangedValue('text'),
866
+ target: getChangedValue('target'),
867
+ rel: getChangedValue('rel'),
868
+ class: getChangedValue('linkClass'),
869
+ title: getChangedValue('title')
870
+ };
871
+ const attachState = {
872
+ href: data.url.value,
873
+ attach: data.url.meta !== undefined && data.url.meta.attach ? data.url.meta.attach : noop
874
+ };
875
+ DialogConfirms.preprocess(editor, changedData).then(pData => {
876
+ link(editor, attachState, pData);
877
+ });
878
+ api.close();
879
+ };
880
+ const collectData = editor => {
881
+ const anchorNode = getAnchorElement(editor);
882
+ return DialogInfo.collect(editor, anchorNode);
1169
883
  };
1170
884
  const getInitialData = (info, defaultTarget) => {
1171
- const anchor = info.anchor;
1172
- const url = anchor.url.getOr('');
1173
- return {
1174
- url: {
1175
- value: url,
1176
- meta: {
1177
- original: {
1178
- value: url
1179
- }
1180
- }
1181
- },
1182
- text: anchor.text.getOr(''),
1183
- title: anchor.title.getOr(''),
1184
- anchor: url,
1185
- link: url,
1186
- rel: anchor.rel.getOr(''),
1187
- target: anchor.target.or(defaultTarget).getOr(''),
1188
- linkClass: anchor.linkClass.getOr('')
1189
- };
885
+ const anchor = info.anchor;
886
+ const url = anchor.url.getOr('');
887
+ return {
888
+ url: {
889
+ value: url,
890
+ meta: { original: { value: url } }
891
+ },
892
+ text: anchor.text.getOr(''),
893
+ title: anchor.title.getOr(''),
894
+ anchor: url,
895
+ link: url,
896
+ rel: anchor.rel.getOr(''),
897
+ target: anchor.target.or(defaultTarget).getOr(''),
898
+ linkClass: anchor.linkClass.getOr('')
899
+ };
1190
900
  };
1191
901
  const makeDialog = (settings, onSubmit, editor) => {
1192
- const urlInput = [
1193
- {
1194
- name: 'url',
1195
- type: 'urlinput',
1196
- filetype: 'file',
1197
- label: 'URL',
1198
- picker_text: 'Browse links'
1199
- }
1200
- ];
1201
- const displayText = settings.anchor.text.map(() => ({
1202
- name: 'text',
1203
- type: 'input',
1204
- label: 'Text to display'
1205
- })).toArray();
1206
- const titleText = settings.flags.titleEnabled ? [
1207
- {
1208
- name: 'title',
1209
- type: 'input',
1210
- label: 'Title'
1211
- }
1212
- ] : [];
1213
- const defaultTarget = Optional.from(getDefaultLinkTarget(editor));
1214
- const initialData = getInitialData(settings, defaultTarget);
1215
- const catalogs = settings.catalogs;
1216
- const dialogDelta = DialogChanges.init(initialData, catalogs);
1217
- const body = {
1218
- type: 'panel',
1219
- items: flatten([
1220
- urlInput,
1221
- displayText,
1222
- titleText,
1223
- cat([
1224
- catalogs.anchor.map(ListOptions.createUi('anchor', 'Anchors')),
1225
- catalogs.rels.map(ListOptions.createUi('rel', 'Rel')),
1226
- catalogs.targets.map(ListOptions.createUi('target', 'Open link in...')),
1227
- catalogs.link.map(ListOptions.createUi('link', 'Link list')),
1228
- catalogs.classes.map(ListOptions.createUi('linkClass', 'Class'))
1229
- ])
1230
- ])
1231
- };
1232
- return {
1233
- title: 'Insert/Edit Link',
1234
- size: 'normal',
1235
- body,
1236
- buttons: [
1237
- {
1238
- type: 'cancel',
1239
- name: 'cancel',
1240
- text: 'Cancel'
1241
- },
1242
- {
1243
- type: 'submit',
1244
- name: 'save',
1245
- text: 'Save',
1246
- primary: true
1247
- }
1248
- ],
1249
- initialData,
1250
- onChange: (api, { name }) => {
1251
- dialogDelta.onChange(api.getData, { name }).each((newData) => {
1252
- api.setData(newData);
1253
- });
1254
- },
1255
- onSubmit
1256
- };
1257
- };
1258
- const open = (editor) => {
1259
- const data = collectData(editor);
1260
- // eslint-disable-next-line @typescript-eslint/no-floating-promises
1261
- data.then((info) => {
1262
- const onSubmit = handleSubmit(editor, info);
1263
- return makeDialog(info, onSubmit, editor);
1264
- }).then((spec) => {
1265
- editor.windowManager.open(spec);
1266
- });
1267
- };
1268
-
1269
- const register = (editor) => {
1270
- editor.addCommand('mceLink', (_ui, value) => {
1271
- if ((value === null || value === void 0 ? void 0 : value.dialog) === true || !useQuickLink(editor)) {
1272
- open(editor);
1273
- }
1274
- else {
1275
- editor.dispatch('contexttoolbar-show', {
1276
- toolbarKey: 'quicklink'
1277
- });
1278
- }
1279
- });
902
+ const urlInput = [{
903
+ name: 'url',
904
+ type: 'urlinput',
905
+ filetype: 'file',
906
+ label: 'URL',
907
+ picker_text: 'Browse links'
908
+ }];
909
+ const displayText = settings.anchor.text.map(() => ({
910
+ name: 'text',
911
+ type: 'input',
912
+ label: 'Text to display'
913
+ })).toArray();
914
+ const titleText = settings.flags.titleEnabled ? [{
915
+ name: 'title',
916
+ type: 'input',
917
+ label: 'Title'
918
+ }] : [];
919
+ const defaultTarget = Optional.from(getDefaultLinkTarget(editor));
920
+ const initialData = getInitialData(settings, defaultTarget);
921
+ const catalogs = settings.catalogs;
922
+ const dialogDelta = DialogChanges.init(initialData, catalogs);
923
+ const body = {
924
+ type: 'panel',
925
+ items: flatten([
926
+ urlInput,
927
+ displayText,
928
+ titleText,
929
+ cat([
930
+ catalogs.anchor.map(ListOptions.createUi('anchor', 'Anchors')),
931
+ catalogs.rels.map(ListOptions.createUi('rel', 'Rel')),
932
+ catalogs.targets.map(ListOptions.createUi('target', 'Open link in...')),
933
+ catalogs.link.map(ListOptions.createUi('link', 'Link list')),
934
+ catalogs.classes.map(ListOptions.createUi('linkClass', 'Class'))
935
+ ])
936
+ ])
937
+ };
938
+ return {
939
+ title: 'Insert/Edit Link',
940
+ size: 'normal',
941
+ body,
942
+ buttons: [
943
+ {
944
+ type: 'cancel',
945
+ name: 'cancel',
946
+ text: 'Cancel'
947
+ },
948
+ {
949
+ type: 'submit',
950
+ name: 'save',
951
+ text: 'Save',
952
+ primary: true
953
+ }
954
+ ],
955
+ initialData,
956
+ onChange: (api, {name}) => {
957
+ dialogDelta.onChange(api.getData, { name }).each(newData => {
958
+ api.setData(newData);
959
+ });
960
+ },
961
+ onSubmit
962
+ };
963
+ };
964
+ const open$1 = editor => {
965
+ const data = collectData(editor);
966
+ data.then(info => {
967
+ const onSubmit = handleSubmit(editor, info);
968
+ return makeDialog(info, onSubmit, editor);
969
+ }).then(spec => {
970
+ editor.windowManager.open(spec);
971
+ });
1280
972
  };
1281
973
 
1282
- const setup$2 = (editor) => {
1283
- editor.addShortcut('Meta+K', '', () => {
1284
- editor.execCommand('mceLink');
1285
- });
974
+ const register = editor => {
975
+ editor.addCommand('mceLink', (_ui, value) => {
976
+ if ((value === null || value === void 0 ? void 0 : value.dialog) === true || !useQuickLink(editor)) {
977
+ open$1(editor);
978
+ } else {
979
+ editor.dispatch('contexttoolbar-show', { toolbarKey: 'quicklink' });
980
+ }
981
+ });
1286
982
  };
1287
983
 
1288
984
  var global = tinymce.util.Tools.resolve('tinymce.util.VK');
1289
985
 
1290
986
  const appendClickRemove = (link, evt) => {
1291
- document.body.appendChild(link);
1292
- link.dispatchEvent(evt);
1293
- document.body.removeChild(link);
1294
- };
1295
- const openLink = (url) => {
1296
- const link = document.createElement('a');
1297
- link.target = '_blank';
1298
- link.href = url;
1299
- link.rel = 'noreferrer noopener';
1300
- const evt = new MouseEvent('click', {
1301
- bubbles: true,
1302
- cancelable: true,
1303
- view: window
1304
- });
1305
- document.dispatchEvent(evt);
1306
- appendClickRemove(link, evt);
987
+ document.body.appendChild(link);
988
+ link.dispatchEvent(evt);
989
+ document.body.removeChild(link);
990
+ };
991
+ const open = url => {
992
+ const link = document.createElement('a');
993
+ link.target = '_blank';
994
+ link.href = url;
995
+ link.rel = 'noreferrer noopener';
996
+ const evt = document.createEvent('MouseEvents');
997
+ evt.initMouseEvent('click', true, true, window, 0, 0, 0, 0, 0, false, false, false, false, 0, null);
998
+ appendClickRemove(link, evt);
1307
999
  };
1308
- const hasOnlyAltModifier = (e) => {
1309
- return e.altKey === true && e.shiftKey === false && e.ctrlKey === false && e.metaKey === false;
1000
+
1001
+ const getLink = (editor, elm) => editor.dom.getParent(elm, 'a[href]');
1002
+ const getSelectedLink = editor => getLink(editor, editor.selection.getStart());
1003
+ const hasOnlyAltModifier = e => {
1004
+ return e.altKey === true && e.shiftKey === false && e.ctrlKey === false && e.metaKey === false;
1310
1005
  };
1311
1006
  const gotoLink = (editor, a) => {
1312
- if (a) {
1313
- const href = getHref(a);
1314
- if (/^#/.test(href)) {
1315
- const targetEl = editor.dom.select(`${href},[name="${removeLeading(href, '#')}"]`);
1316
- if (targetEl.length) {
1317
- editor.selection.scrollIntoView(targetEl[0], true);
1318
- }
1319
- }
1320
- else {
1321
- openLink(a.href);
1322
- }
1323
- }
1007
+ if (a) {
1008
+ const href = getHref(a);
1009
+ if (/^#/.test(href)) {
1010
+ const targetEl = editor.dom.select(href);
1011
+ if (targetEl.length) {
1012
+ editor.selection.scrollIntoView(targetEl[0], true);
1013
+ }
1014
+ } else {
1015
+ open(a.href);
1016
+ }
1017
+ }
1018
+ };
1019
+ const openDialog = editor => () => {
1020
+ editor.execCommand('mceLink', false, { dialog: true });
1021
+ };
1022
+ const gotoSelectedLink = editor => () => {
1023
+ gotoLink(editor, getSelectedLink(editor));
1024
+ };
1025
+ const setupGotoLinks = editor => {
1026
+ editor.on('click', e => {
1027
+ const link = getLink(editor, e.target);
1028
+ if (link && global.metaKeyPressed(e)) {
1029
+ e.preventDefault();
1030
+ gotoLink(editor, link);
1031
+ }
1032
+ });
1033
+ editor.on('keydown', e => {
1034
+ if (!e.isDefaultPrevented() && e.keyCode === 13 && hasOnlyAltModifier(e)) {
1035
+ const link = getSelectedLink(editor);
1036
+ if (link) {
1037
+ e.preventDefault();
1038
+ gotoLink(editor, link);
1039
+ }
1040
+ }
1041
+ });
1324
1042
  };
1325
- const isSelectionOnImageWithEmbeddedLink = (editor) => {
1326
- const rng = editor.selection.getRng();
1327
- const node = rng.startContainer;
1328
- // Handle a case where an image embedded with a link is selected
1329
- return isLink(node) && rng.startContainer === rng.endContainer && editor.dom.select('img', node).length === 1;
1330
- };
1331
- const getLinkFromElement = (editor, element) => {
1332
- const links = getLinks$1(editor.dom.getParents(element));
1333
- return someIf(links.length === 1, links[0]);
1334
- };
1335
- const getLinkInSelection = (editor) => {
1336
- const links = getLinksInSelection(editor.selection.getRng());
1337
- return someIf(links.length > 0, links[0]).or(getLinkFromElement(editor, editor.selection.getNode()));
1338
- };
1339
- const getLinkFromSelection = (editor) => editor.selection.isCollapsed() || isSelectionOnImageWithEmbeddedLink(editor)
1340
- ? getLinkFromElement(editor, editor.selection.getStart())
1341
- : getLinkInSelection(editor);
1342
- const setup$1 = (editor) => {
1343
- const selectedLink = value();
1344
- const getSelectedLink = () => selectedLink.get().or(getLinkFromSelection(editor));
1345
- const gotoSelectedLink = () => getSelectedLink().each((link) => gotoLink(editor, link));
1346
- editor.on('contextmenu', (e) => {
1347
- getLinkFromElement(editor, e.target).each(selectedLink.set);
1348
- });
1349
- editor.on('SelectionChange', () => {
1350
- if (!selectedLink.isSet()) {
1351
- getLinkFromSelection(editor).each(selectedLink.set);
1352
- }
1353
- });
1354
- editor.on('click', (e) => {
1355
- selectedLink.clear();
1356
- const links = getLinks$1(editor.dom.getParents(e.target));
1357
- if (links.length === 1 && global.metaKeyPressed(e)) {
1358
- e.preventDefault();
1359
- gotoLink(editor, links[0]);
1360
- }
1361
- });
1362
- editor.on('keydown', (e) => {
1363
- selectedLink.clear();
1364
- if (!e.isDefaultPrevented() && e.keyCode === 13 && hasOnlyAltModifier(e)) {
1365
- getSelectedLink().each((link) => {
1366
- e.preventDefault();
1367
- gotoLink(editor, link);
1368
- });
1369
- }
1370
- });
1371
- return {
1372
- gotoSelectedLink
1373
- };
1043
+ const toggleState = (editor, toggler) => {
1044
+ editor.on('NodeChange', toggler);
1045
+ return () => editor.off('NodeChange', toggler);
1046
+ };
1047
+ const toggleLinkState = editor => api => {
1048
+ const updateState = () => {
1049
+ api.setActive(!editor.mode.isReadOnly() && isInAnchor(editor, editor.selection.getNode()));
1050
+ api.setEnabled(editor.selection.isEditable());
1051
+ };
1052
+ updateState();
1053
+ return toggleState(editor, updateState);
1054
+ };
1055
+ const toggleLinkMenuState = editor => api => {
1056
+ const updateState = () => {
1057
+ api.setEnabled(editor.selection.isEditable());
1058
+ };
1059
+ updateState();
1060
+ return toggleState(editor, updateState);
1061
+ };
1062
+ const hasExactlyOneLinkInSelection = editor => {
1063
+ const links = editor.selection.isCollapsed() ? getLinks$1(editor.dom.getParents(editor.selection.getStart())) : getLinksInSelection(editor.selection.getRng());
1064
+ return links.length === 1;
1065
+ };
1066
+ const toggleGotoLinkState = editor => api => {
1067
+ const updateState = () => api.setEnabled(hasExactlyOneLinkInSelection(editor));
1068
+ updateState();
1069
+ return toggleState(editor, updateState);
1070
+ };
1071
+ const toggleUnlinkState = editor => api => {
1072
+ const hasLinks$1 = parents => hasLinks(parents) || hasLinksInSelection(editor.selection.getRng());
1073
+ const parents = editor.dom.getParents(editor.selection.getStart());
1074
+ const updateEnabled = parents => {
1075
+ api.setEnabled(hasLinks$1(parents) && editor.selection.isEditable());
1076
+ };
1077
+ updateEnabled(parents);
1078
+ return toggleState(editor, e => updateEnabled(e.parents));
1374
1079
  };
1375
1080
 
1376
- const openDialog = (editor) => () => {
1377
- editor.execCommand('mceLink', false, { dialog: true });
1081
+ const setup = editor => {
1082
+ editor.addShortcut('Meta+K', '', () => {
1083
+ editor.execCommand('mceLink');
1084
+ });
1378
1085
  };
1379
- const toggleState = (editor, toggler) => {
1380
- editor.on('NodeChange', toggler);
1381
- return () => editor.off('NodeChange', toggler);
1382
- };
1383
- const toggleLinkState = (editor) => (api) => {
1384
- const updateState = () => {
1385
- api.setActive(!editor.mode.isReadOnly() && isInAnchor(editor, editor.selection.getNode()));
1386
- api.setEnabled(editor.selection.isEditable());
1387
- };
1388
- updateState();
1389
- return toggleState(editor, updateState);
1390
- };
1391
- const toggleLinkMenuState = (editor) => (api) => {
1392
- const updateState = () => {
1393
- api.setEnabled(editor.selection.isEditable());
1394
- };
1395
- updateState();
1396
- return toggleState(editor, updateState);
1397
- };
1398
- const toggleRequiresLinkState = (editor) => (api) => {
1399
- const hasLinks$1 = (parents) => hasLinks(parents) || hasLinksInSelection(editor.selection.getRng());
1400
- const parents = editor.dom.getParents(editor.selection.getStart());
1401
- const updateEnabled = (parents) => {
1402
- api.setEnabled(hasLinks$1(parents) && editor.selection.isEditable());
1403
- };
1404
- updateEnabled(parents);
1405
- return toggleState(editor, (e) => updateEnabled(e.parents));
1406
- };
1407
- const setupButtons = (editor, openLink) => {
1408
- editor.ui.registry.addToggleButton('link', {
1086
+
1087
+ const setupButtons = editor => {
1088
+ editor.ui.registry.addToggleButton('link', {
1089
+ icon: 'link',
1090
+ tooltip: 'Insert/edit link',
1091
+ onAction: openDialog(editor),
1092
+ onSetup: toggleLinkState(editor)
1093
+ });
1094
+ editor.ui.registry.addButton('openlink', {
1095
+ icon: 'new-tab',
1096
+ tooltip: 'Open link',
1097
+ onAction: gotoSelectedLink(editor),
1098
+ onSetup: toggleGotoLinkState(editor)
1099
+ });
1100
+ editor.ui.registry.addButton('unlink', {
1101
+ icon: 'unlink',
1102
+ tooltip: 'Remove link',
1103
+ onAction: () => unlink(editor),
1104
+ onSetup: toggleUnlinkState(editor)
1105
+ });
1106
+ };
1107
+ const setupMenuItems = editor => {
1108
+ editor.ui.registry.addMenuItem('openlink', {
1109
+ text: 'Open link',
1110
+ icon: 'new-tab',
1111
+ onAction: gotoSelectedLink(editor),
1112
+ onSetup: toggleGotoLinkState(editor)
1113
+ });
1114
+ editor.ui.registry.addMenuItem('link', {
1115
+ icon: 'link',
1116
+ text: 'Link...',
1117
+ shortcut: 'Meta+K',
1118
+ onSetup: toggleLinkMenuState(editor),
1119
+ onAction: openDialog(editor)
1120
+ });
1121
+ editor.ui.registry.addMenuItem('unlink', {
1122
+ icon: 'unlink',
1123
+ text: 'Remove link',
1124
+ onAction: () => unlink(editor),
1125
+ onSetup: toggleUnlinkState(editor)
1126
+ });
1127
+ };
1128
+ const setupContextMenu = editor => {
1129
+ const inLink = 'link unlink openlink';
1130
+ const noLink = 'link';
1131
+ editor.ui.registry.addContextMenu('link', {
1132
+ update: element => {
1133
+ const isEditable = editor.dom.isEditable(element);
1134
+ if (!isEditable) {
1135
+ return '';
1136
+ }
1137
+ return hasLinks(editor.dom.getParents(element, 'a')) ? inLink : noLink;
1138
+ }
1139
+ });
1140
+ };
1141
+ const setupContextToolbars = editor => {
1142
+ const collapseSelectionToEnd = editor => {
1143
+ editor.selection.collapse(false);
1144
+ };
1145
+ const onSetupLink = buttonApi => {
1146
+ const node = editor.selection.getNode();
1147
+ buttonApi.setEnabled(isInAnchor(editor, node));
1148
+ return noop;
1149
+ };
1150
+ const getLinkText = value => {
1151
+ const anchor = getAnchorElement(editor);
1152
+ const onlyText = isOnlyTextSelected(editor);
1153
+ if (anchor.isNone() && onlyText) {
1154
+ const text = getAnchorText(editor.selection, anchor);
1155
+ return someIf(text.length === 0, value);
1156
+ } else {
1157
+ return Optional.none();
1158
+ }
1159
+ };
1160
+ editor.ui.registry.addContextForm('quicklink', {
1161
+ launch: {
1162
+ type: 'contextformtogglebutton',
1163
+ icon: 'link',
1164
+ tooltip: 'Link',
1165
+ onSetup: toggleLinkState(editor)
1166
+ },
1167
+ label: 'Link',
1168
+ predicate: node => hasContextToolbar(editor) && isInAnchor(editor, node),
1169
+ initValue: () => {
1170
+ const elm = getAnchorElement(editor);
1171
+ return elm.fold(constant(''), getHref);
1172
+ },
1173
+ commands: [
1174
+ {
1175
+ type: 'contextformtogglebutton',
1409
1176
  icon: 'link',
1410
- tooltip: 'Insert/edit link',
1411
- shortcut: 'Meta+K',
1412
- onAction: openDialog(editor),
1413
- onSetup: toggleLinkState(editor)
1414
- });
1415
- editor.ui.registry.addButton('openlink', {
1416
- icon: 'new-tab',
1417
- tooltip: 'Open link',
1418
- onAction: openLink.gotoSelectedLink,
1419
- onSetup: toggleRequiresLinkState(editor)
1420
- });
1421
- editor.ui.registry.addButton('unlink', {
1177
+ tooltip: 'Link',
1178
+ primary: true,
1179
+ onSetup: buttonApi => {
1180
+ const node = editor.selection.getNode();
1181
+ buttonApi.setActive(isInAnchor(editor, node));
1182
+ return toggleLinkState(editor)(buttonApi);
1183
+ },
1184
+ onAction: formApi => {
1185
+ const value = formApi.getValue();
1186
+ const text = getLinkText(value);
1187
+ const attachState = {
1188
+ href: value,
1189
+ attach: noop
1190
+ };
1191
+ link(editor, attachState, {
1192
+ href: value,
1193
+ text,
1194
+ title: Optional.none(),
1195
+ rel: Optional.none(),
1196
+ target: Optional.none(),
1197
+ class: Optional.none()
1198
+ });
1199
+ collapseSelectionToEnd(editor);
1200
+ formApi.hide();
1201
+ }
1202
+ },
1203
+ {
1204
+ type: 'contextformbutton',
1422
1205
  icon: 'unlink',
1423
1206
  tooltip: 'Remove link',
1424
- onAction: () => unlink(editor),
1425
- onSetup: toggleRequiresLinkState(editor)
1426
- });
1427
- };
1428
- const setupMenuItems = (editor, openLink) => {
1429
- editor.ui.registry.addMenuItem('openlink', {
1430
- text: 'Open link',
1431
- icon: 'new-tab',
1432
- onAction: openLink.gotoSelectedLink,
1433
- onSetup: toggleRequiresLinkState(editor)
1434
- });
1435
- editor.ui.registry.addMenuItem('link', {
1436
- icon: 'link',
1437
- text: 'Link...',
1438
- shortcut: 'Meta+K',
1439
- onAction: openDialog(editor),
1440
- onSetup: toggleLinkMenuState(editor)
1441
- });
1442
- editor.ui.registry.addMenuItem('unlink', {
1443
- icon: 'unlink',
1444
- text: 'Remove link',
1445
- onAction: () => unlink(editor),
1446
- onSetup: toggleRequiresLinkState(editor)
1447
- });
1448
- };
1449
- const setupContextMenu = (editor) => {
1450
- const inLink = 'link unlink openlink';
1451
- const noLink = 'link';
1452
- editor.ui.registry.addContextMenu('link', {
1453
- update: (element) => {
1454
- const isEditable = editor.dom.isEditable(element);
1455
- if (!isEditable) {
1456
- return '';
1457
- }
1458
- return hasLinks(editor.dom.getParents(element, 'a')) ? inLink : noLink;
1207
+ onSetup: onSetupLink,
1208
+ onAction: formApi => {
1209
+ unlink(editor);
1210
+ formApi.hide();
1459
1211
  }
1460
- });
1461
- };
1462
- const setupContextToolbars = (editor, openLink) => {
1463
- const collapseSelectionToEnd = (editor) => {
1464
- editor.selection.collapse(false);
1465
- };
1466
- const onSetupLink = (buttonApi) => {
1467
- const node = editor.selection.getNode();
1468
- buttonApi.setEnabled(isInAnchor(editor, node) && editor.selection.isEditable());
1469
- return noop;
1470
- };
1471
- /**
1472
- * if we're editing a link, don't change the text.
1473
- * if anything other than text is selected, don't change the text.
1474
- * TINY-9593: If there is a text selection return `Optional.none`
1475
- * because `mceInsertLink` command will handle the selection.
1476
- */
1477
- const getLinkText = (value) => {
1478
- const anchor = getAnchorElement(editor);
1479
- const onlyText = isOnlyTextSelected(editor);
1480
- if (anchor.isNone() && onlyText) {
1481
- const text = getAnchorText(editor.selection, anchor);
1482
- return someIf(text.length === 0, value);
1483
- }
1484
- else {
1485
- return Optional.none();
1212
+ },
1213
+ {
1214
+ type: 'contextformbutton',
1215
+ icon: 'new-tab',
1216
+ tooltip: 'Open link',
1217
+ onSetup: onSetupLink,
1218
+ onAction: formApi => {
1219
+ gotoSelectedLink(editor)();
1220
+ formApi.hide();
1486
1221
  }
1487
- };
1488
- editor.ui.registry.addContextForm('quicklink', {
1489
- launch: {
1490
- type: 'contextformtogglebutton',
1491
- icon: 'link',
1492
- tooltip: 'Link',
1493
- onSetup: toggleLinkState(editor)
1494
- },
1495
- label: 'Link',
1496
- predicate: (node) => hasContextToolbar(editor) && isInAnchor(editor, node),
1497
- initValue: () => {
1498
- const elm = getAnchorElement(editor);
1499
- return elm.fold(constant(''), getHref);
1500
- },
1501
- commands: [
1502
- {
1503
- type: 'contextformtogglebutton',
1504
- icon: 'link',
1505
- tooltip: 'Link',
1506
- primary: true,
1507
- onSetup: (buttonApi) => {
1508
- const node = editor.selection.getNode();
1509
- // TODO: Make a test for this later.
1510
- buttonApi.setActive(isInAnchor(editor, node));
1511
- return toggleLinkState(editor)(buttonApi);
1512
- },
1513
- onAction: (formApi) => {
1514
- const value = formApi.getValue();
1515
- const text = getLinkText(value);
1516
- const attachState = { href: value, attach: noop };
1517
- link(editor, attachState, {
1518
- href: value,
1519
- text,
1520
- title: Optional.none(),
1521
- rel: Optional.none(),
1522
- target: Optional.from(getDefaultLinkTarget(editor)),
1523
- class: Optional.none()
1524
- });
1525
- collapseSelectionToEnd(editor);
1526
- formApi.hide();
1527
- }
1528
- },
1529
- {
1530
- type: 'contextformbutton',
1531
- icon: 'unlink',
1532
- tooltip: 'Remove link',
1533
- onSetup: onSetupLink,
1534
- // TODO: The original inlite action was quite complex. Are we missing something with this?
1535
- onAction: (formApi) => {
1536
- unlink(editor);
1537
- formApi.hide();
1538
- }
1539
- },
1540
- {
1541
- type: 'contextformbutton',
1542
- icon: 'new-tab',
1543
- tooltip: 'Open link',
1544
- onSetup: onSetupLink,
1545
- onAction: (formApi) => {
1546
- openLink.gotoSelectedLink();
1547
- formApi.hide();
1548
- }
1549
- }
1550
- ]
1551
- });
1552
- };
1553
- const setup = (editor) => {
1554
- const openLink = setup$1(editor);
1555
- setupButtons(editor, openLink);
1556
- setupMenuItems(editor, openLink);
1557
- setupContextMenu(editor);
1558
- setupContextToolbars(editor, openLink);
1222
+ }
1223
+ ]
1224
+ });
1559
1225
  };
1560
1226
 
1561
1227
  var Plugin = () => {
1562
- global$5.add('link', (editor) => {
1563
- register$1(editor);
1564
- register(editor);
1565
- setup(editor);
1566
- setup$2(editor);
1567
- });
1228
+ global$5.add('link', editor => {
1229
+ register$1(editor);
1230
+ setupButtons(editor);
1231
+ setupMenuItems(editor);
1232
+ setupContextMenu(editor);
1233
+ setupContextToolbars(editor);
1234
+ setupGotoLinks(editor);
1235
+ register(editor);
1236
+ setup(editor);
1237
+ });
1568
1238
  };
1569
1239
 
1570
1240
  Plugin();
1571
- /** *****
1572
- * DO NOT EXPORT ANYTHING
1573
- *
1574
- * IF YOU DO ROLLUP WILL LEAVE A GLOBAL ON THE PAGE
1575
- *******/
1576
1241
 
1577
1242
  })();