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

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (175) hide show
  1. package/fesm2022/dangl-angular-material-shared-tiny-mce.mjs +29 -35
  2. package/fesm2022/dangl-angular-material-shared-tiny-mce.mjs.map +1 -1
  3. package/fesm2022/dangl-angular-material-shared.mjs +36 -51
  4. package/fesm2022/dangl-angular-material-shared.mjs.map +1 -1
  5. package/package.json +11 -10
  6. package/styles/material-theme.scss +1 -1
  7. package/styles/material-variables.scss +5 -5
  8. package/tinymce-assets/icons/default/icons.js +46 -9
  9. package/tinymce-assets/icons/default/icons.min.js +1 -1
  10. package/tinymce-assets/models/dom/model.js +8198 -7244
  11. package/tinymce-assets/models/dom/model.min.js +1 -4
  12. package/tinymce-assets/plugins/accordion/plugin.js +1174 -879
  13. package/tinymce-assets/plugins/accordion/plugin.min.js +1 -4
  14. package/tinymce-assets/plugins/advlist/plugin.js +412 -200
  15. package/tinymce-assets/plugins/advlist/plugin.min.js +1 -4
  16. package/tinymce-assets/plugins/anchor/plugin.js +189 -166
  17. package/tinymce-assets/plugins/anchor/plugin.min.js +1 -4
  18. package/tinymce-assets/plugins/autolink/plugin.js +310 -220
  19. package/tinymce-assets/plugins/autolink/plugin.min.js +1 -4
  20. package/tinymce-assets/plugins/autoresize/plugin.js +180 -149
  21. package/tinymce-assets/plugins/autoresize/plugin.min.js +1 -4
  22. package/tinymce-assets/plugins/autosave/plugin.js +208 -189
  23. package/tinymce-assets/plugins/autosave/plugin.min.js +1 -4
  24. package/tinymce-assets/plugins/charmap/plugin.js +905 -1566
  25. package/tinymce-assets/plugins/charmap/plugin.min.js +1 -4
  26. package/tinymce-assets/plugins/code/plugin.js +73 -61
  27. package/tinymce-assets/plugins/code/plugin.min.js +0 -3
  28. package/tinymce-assets/plugins/codesample/plugin.js +3593 -2402
  29. package/tinymce-assets/plugins/codesample/plugin.min.js +8 -3
  30. package/tinymce-assets/plugins/directionality/plugin.js +545 -304
  31. package/tinymce-assets/plugins/directionality/plugin.min.js +1 -4
  32. package/tinymce-assets/plugins/emoticons/js/emojiimages.min.js +0 -2
  33. package/tinymce-assets/plugins/emoticons/js/emojis.min.js +0 -1
  34. package/tinymce-assets/plugins/emoticons/plugin.js +702 -488
  35. package/tinymce-assets/plugins/emoticons/plugin.min.js +1 -4
  36. package/tinymce-assets/plugins/fullscreen/plugin.js +1409 -1049
  37. package/tinymce-assets/plugins/fullscreen/plugin.min.js +1 -4
  38. package/tinymce-assets/plugins/help/js/i18n/keynav/ar.js +4 -1
  39. package/tinymce-assets/plugins/help/js/i18n/keynav/bg_BG.js +4 -1
  40. package/tinymce-assets/plugins/help/js/i18n/keynav/ca.js +4 -1
  41. package/tinymce-assets/plugins/help/js/i18n/keynav/cs.js +4 -1
  42. package/tinymce-assets/plugins/help/js/i18n/keynav/da.js +4 -1
  43. package/tinymce-assets/plugins/help/js/i18n/keynav/de.js +4 -1
  44. package/tinymce-assets/plugins/help/js/i18n/keynav/el.js +4 -1
  45. package/tinymce-assets/plugins/help/js/i18n/keynav/en.js +4 -1
  46. package/tinymce-assets/plugins/help/js/i18n/keynav/es.js +4 -1
  47. package/tinymce-assets/plugins/help/js/i18n/keynav/eu.js +4 -1
  48. package/tinymce-assets/plugins/help/js/i18n/keynav/fa.js +4 -1
  49. package/tinymce-assets/plugins/help/js/i18n/keynav/fi.js +4 -1
  50. package/tinymce-assets/plugins/help/js/i18n/keynav/fr_FR.js +4 -1
  51. package/tinymce-assets/plugins/help/js/i18n/keynav/he_IL.js +4 -1
  52. package/tinymce-assets/plugins/help/js/i18n/keynav/hi.js +4 -1
  53. package/tinymce-assets/plugins/help/js/i18n/keynav/hr.js +4 -1
  54. package/tinymce-assets/plugins/help/js/i18n/keynav/hu_HU.js +4 -1
  55. package/tinymce-assets/plugins/help/js/i18n/keynav/id.js +4 -1
  56. package/tinymce-assets/plugins/help/js/i18n/keynav/it.js +4 -1
  57. package/tinymce-assets/plugins/help/js/i18n/keynav/ja.js +4 -1
  58. package/tinymce-assets/plugins/help/js/i18n/keynav/kk.js +4 -1
  59. package/tinymce-assets/plugins/help/js/i18n/keynav/ko_KR.js +4 -1
  60. package/tinymce-assets/plugins/help/js/i18n/keynav/ms.js +4 -1
  61. package/tinymce-assets/plugins/help/js/i18n/keynav/nb_NO.js +4 -1
  62. package/tinymce-assets/plugins/help/js/i18n/keynav/nl.js +4 -1
  63. package/tinymce-assets/plugins/help/js/i18n/keynav/pl.js +4 -1
  64. package/tinymce-assets/plugins/help/js/i18n/keynav/pt_BR.js +4 -1
  65. package/tinymce-assets/plugins/help/js/i18n/keynav/pt_PT.js +4 -1
  66. package/tinymce-assets/plugins/help/js/i18n/keynav/ro.js +4 -1
  67. package/tinymce-assets/plugins/help/js/i18n/keynav/ru.js +4 -1
  68. package/tinymce-assets/plugins/help/js/i18n/keynav/sk.js +4 -1
  69. package/tinymce-assets/plugins/help/js/i18n/keynav/sl_SI.js +5 -2
  70. package/tinymce-assets/plugins/help/js/i18n/keynav/sv_SE.js +4 -1
  71. package/tinymce-assets/plugins/help/js/i18n/keynav/th_TH.js +4 -1
  72. package/tinymce-assets/plugins/help/js/i18n/keynav/tr.js +4 -1
  73. package/tinymce-assets/plugins/help/js/i18n/keynav/uk.js +4 -1
  74. package/tinymce-assets/plugins/help/js/i18n/keynav/vi.js +4 -1
  75. package/tinymce-assets/plugins/help/js/i18n/keynav/zh_CN.js +8 -5
  76. package/tinymce-assets/plugins/help/js/i18n/keynav/zh_TW.js +4 -1
  77. package/tinymce-assets/plugins/help/plugin.js +739 -809
  78. package/tinymce-assets/plugins/help/plugin.min.js +1 -4
  79. package/tinymce-assets/plugins/image/plugin.js +1475 -1291
  80. package/tinymce-assets/plugins/image/plugin.min.js +1 -4
  81. package/tinymce-assets/plugins/importcss/plugin.js +328 -269
  82. package/tinymce-assets/plugins/importcss/plugin.min.js +1 -4
  83. package/tinymce-assets/plugins/insertdatetime/plugin.js +140 -141
  84. package/tinymce-assets/plugins/insertdatetime/plugin.min.js +1 -4
  85. package/tinymce-assets/plugins/link/plugin.js +1419 -1084
  86. package/tinymce-assets/plugins/link/plugin.min.js +1 -4
  87. package/tinymce-assets/plugins/lists/plugin.js +2177 -1805
  88. package/tinymce-assets/plugins/lists/plugin.min.js +1 -4
  89. package/tinymce-assets/plugins/media/plugin.js +1305 -1047
  90. package/tinymce-assets/plugins/media/plugin.min.js +1 -4
  91. package/tinymce-assets/plugins/nonbreaking/plugin.js +93 -88
  92. package/tinymce-assets/plugins/nonbreaking/plugin.min.js +0 -3
  93. package/tinymce-assets/plugins/pagebreak/plugin.js +91 -85
  94. package/tinymce-assets/plugins/pagebreak/plugin.min.js +0 -3
  95. package/tinymce-assets/plugins/preview/plugin.js +742 -74
  96. package/tinymce-assets/plugins/preview/plugin.min.js +1 -4
  97. package/tinymce-assets/plugins/quickbars/plugin.js +582 -375
  98. package/tinymce-assets/plugins/quickbars/plugin.min.js +1 -4
  99. package/tinymce-assets/plugins/save/plugin.js +100 -82
  100. package/tinymce-assets/plugins/save/plugin.min.js +1 -4
  101. package/tinymce-assets/plugins/searchreplace/plugin.js +1183 -906
  102. package/tinymce-assets/plugins/searchreplace/plugin.min.js +1 -4
  103. package/tinymce-assets/plugins/table/plugin.js +3651 -3094
  104. package/tinymce-assets/plugins/table/plugin.min.js +1 -4
  105. package/tinymce-assets/plugins/visualblocks/plugin.js +71 -63
  106. package/tinymce-assets/plugins/visualblocks/plugin.min.js +1 -4
  107. package/tinymce-assets/plugins/visualchars/plugin.js +685 -436
  108. package/tinymce-assets/plugins/visualchars/plugin.min.js +1 -4
  109. package/tinymce-assets/plugins/wordcount/plugin.js +382 -307
  110. package/tinymce-assets/plugins/wordcount/plugin.min.js +1 -4
  111. package/tinymce-assets/skins/content/dark/content.css +9 -0
  112. package/tinymce-assets/skins/content/dark/content.js +10 -2
  113. package/tinymce-assets/skins/content/dark/content.min.css +9 -0
  114. package/tinymce-assets/skins/content/default/content.css +9 -0
  115. package/tinymce-assets/skins/content/default/content.js +10 -2
  116. package/tinymce-assets/skins/content/default/content.min.css +9 -0
  117. package/tinymce-assets/skins/content/document/content.css +9 -0
  118. package/tinymce-assets/skins/content/document/content.js +10 -2
  119. package/tinymce-assets/skins/content/document/content.min.css +9 -0
  120. package/tinymce-assets/skins/content/tinymce-5/content.css +9 -0
  121. package/tinymce-assets/skins/content/tinymce-5/content.js +10 -2
  122. package/tinymce-assets/skins/content/tinymce-5/content.min.css +9 -0
  123. package/tinymce-assets/skins/content/tinymce-5-dark/content.css +9 -0
  124. package/tinymce-assets/skins/content/tinymce-5-dark/content.js +10 -2
  125. package/tinymce-assets/skins/content/tinymce-5-dark/content.min.css +9 -0
  126. package/tinymce-assets/skins/content/writer/content.css +9 -0
  127. package/tinymce-assets/skins/content/writer/content.js +10 -2
  128. package/tinymce-assets/skins/content/writer/content.min.css +9 -0
  129. package/tinymce-assets/skins/ui/oxide/content.css +157 -49
  130. package/tinymce-assets/skins/ui/oxide/content.inline.css +157 -49
  131. package/tinymce-assets/skins/ui/oxide/content.inline.js +10 -2
  132. package/tinymce-assets/skins/ui/oxide/content.inline.min.css +10 -1
  133. package/tinymce-assets/skins/ui/oxide/content.js +10 -2
  134. package/tinymce-assets/skins/ui/oxide/content.min.css +10 -1
  135. package/tinymce-assets/skins/ui/oxide/skin.css +1592 -214
  136. package/tinymce-assets/skins/ui/oxide/skin.js +1 -2
  137. package/tinymce-assets/skins/ui/oxide/skin.min.css +1 -1
  138. package/tinymce-assets/skins/ui/oxide/skin.shadowdom.js +1 -2
  139. package/tinymce-assets/skins/ui/oxide-dark/content.css +157 -42
  140. package/tinymce-assets/skins/ui/oxide-dark/content.inline.css +157 -49
  141. package/tinymce-assets/skins/ui/oxide-dark/content.inline.js +10 -2
  142. package/tinymce-assets/skins/ui/oxide-dark/content.inline.min.css +10 -1
  143. package/tinymce-assets/skins/ui/oxide-dark/content.js +10 -2
  144. package/tinymce-assets/skins/ui/oxide-dark/content.min.css +10 -1
  145. package/tinymce-assets/skins/ui/oxide-dark/skin.css +1595 -217
  146. package/tinymce-assets/skins/ui/oxide-dark/skin.js +1 -2
  147. package/tinymce-assets/skins/ui/oxide-dark/skin.min.css +1 -1
  148. package/tinymce-assets/skins/ui/oxide-dark/skin.shadowdom.js +1 -2
  149. package/tinymce-assets/skins/ui/tinymce-5/content.css +157 -49
  150. package/tinymce-assets/skins/ui/tinymce-5/content.inline.css +157 -49
  151. package/tinymce-assets/skins/ui/tinymce-5/content.inline.js +10 -2
  152. package/tinymce-assets/skins/ui/tinymce-5/content.inline.min.css +10 -1
  153. package/tinymce-assets/skins/ui/tinymce-5/content.js +10 -2
  154. package/tinymce-assets/skins/ui/tinymce-5/content.min.css +10 -1
  155. package/tinymce-assets/skins/ui/tinymce-5/skin.css +1606 -203
  156. package/tinymce-assets/skins/ui/tinymce-5/skin.js +1 -2
  157. package/tinymce-assets/skins/ui/tinymce-5/skin.min.css +1 -1
  158. package/tinymce-assets/skins/ui/tinymce-5/skin.shadowdom.js +1 -2
  159. package/tinymce-assets/skins/ui/tinymce-5-dark/content.css +157 -42
  160. package/tinymce-assets/skins/ui/tinymce-5-dark/content.inline.css +157 -49
  161. package/tinymce-assets/skins/ui/tinymce-5-dark/content.inline.js +10 -2
  162. package/tinymce-assets/skins/ui/tinymce-5-dark/content.inline.min.css +10 -1
  163. package/tinymce-assets/skins/ui/tinymce-5-dark/content.js +10 -2
  164. package/tinymce-assets/skins/ui/tinymce-5-dark/content.min.css +10 -1
  165. package/tinymce-assets/skins/ui/tinymce-5-dark/skin.css +1607 -204
  166. package/tinymce-assets/skins/ui/tinymce-5-dark/skin.js +1 -2
  167. package/tinymce-assets/skins/ui/tinymce-5-dark/skin.min.css +1 -1
  168. package/tinymce-assets/skins/ui/tinymce-5-dark/skin.shadowdom.js +1 -2
  169. package/tinymce-assets/themes/silver/theme.js +32786 -28738
  170. package/tinymce-assets/themes/silver/theme.min.js +1 -4
  171. package/types/dangl-angular-material-shared-tiny-mce.d.ts +12 -13
  172. package/types/dangl-angular-material-shared.d.ts +26 -26
  173. package/tinymce-assets/plugins/template/index.js +0 -7
  174. package/tinymce-assets/plugins/template/plugin.js +0 -567
  175. package/tinymce-assets/plugins/template/plugin.min.js +0 -4
@@ -1,5 +1,5 @@
1
1
  /**
2
- * TinyMCE version 6.8.3 (2024-02-08)
2
+ * TinyMCE version 7.9.3 (2026-05-19)
3
3
  */
4
4
 
5
5
  (function () {
@@ -7,200 +7,400 @@
7
7
 
8
8
  var global$6 = tinymce.util.Tools.resolve('tinymce.PluginManager');
9
9
 
10
+ /* eslint-disable @typescript-eslint/no-wrapper-object-types */
10
11
  const hasProto = (v, constructor, predicate) => {
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
- }
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
+ }
17
20
  };
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
- }
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
+ }
29
35
  };
30
- const isType = type => value => typeOf(value) === type;
36
+ const isType = (type) => (value) => typeOf(value) === type;
37
+ const isSimpleType = (type) => (value) => typeof value === type;
31
38
  const isString = isType('string');
32
39
  const isObject = isType('object');
33
40
  const isArray = isType('array');
34
- const isNullable = a => a === null || a === undefined;
35
- const isNonNullable = a => !isNullable(a);
41
+ const isNullable = (a) => a === null || a === undefined;
42
+ const isNonNullable = (a) => !isNullable(a);
43
+ const isFunction = isSimpleType('function');
36
44
 
45
+ /**
46
+ * The `Optional` type represents a value (of any type) that potentially does
47
+ * not exist. Any `Optional<T>` can either be a `Some<T>` (in which case the
48
+ * value does exist) or a `None` (in which case the value does not exist). This
49
+ * module defines a whole lot of FP-inspired utility functions for dealing with
50
+ * `Optional` objects.
51
+ *
52
+ * Comparison with null or undefined:
53
+ * - We don't get fancy null coalescing operators with `Optional`
54
+ * - We do get fancy helper functions with `Optional`
55
+ * - `Optional` support nesting, and allow for the type to still be nullable (or
56
+ * another `Optional`)
57
+ * - There is no option to turn off strict-optional-checks like there is for
58
+ * strict-null-checks
59
+ */
37
60
  class Optional {
38
- constructor(tag, value) {
39
- this.tag = tag;
40
- this.value = value;
41
- }
42
- static some(value) {
43
- return new Optional(true, value);
44
- }
45
- static none() {
46
- return Optional.singletonNone;
47
- }
48
- fold(onNone, onSome) {
49
- if (this.tag) {
50
- return onSome(this.value);
51
- } else {
52
- return onNone();
53
- }
54
- }
55
- isSome() {
56
- return this.tag;
57
- }
58
- isNone() {
59
- return !this.tag;
60
- }
61
- map(mapper) {
62
- if (this.tag) {
63
- return Optional.some(mapper(this.value));
64
- } else {
65
- return Optional.none();
66
- }
67
- }
68
- bind(binder) {
69
- if (this.tag) {
70
- return binder(this.value);
71
- } else {
72
- return Optional.none();
73
- }
74
- }
75
- exists(predicate) {
76
- return this.tag && predicate(this.value);
77
- }
78
- forall(predicate) {
79
- return !this.tag || predicate(this.value);
80
- }
81
- filter(predicate) {
82
- if (!this.tag || predicate(this.value)) {
83
- return this;
84
- } else {
85
- return Optional.none();
86
- }
87
- }
88
- getOr(replacement) {
89
- return this.tag ? this.value : replacement;
90
- }
91
- or(replacement) {
92
- return this.tag ? this : replacement;
93
- }
94
- getOrThunk(thunk) {
95
- return this.tag ? this.value : thunk();
96
- }
97
- orThunk(thunk) {
98
- return this.tag ? this : thunk();
99
- }
100
- getOrDie(message) {
101
- if (!this.tag) {
102
- throw new Error(message !== null && message !== void 0 ? message : 'Called getOrDie on None');
103
- } else {
104
- return this.value;
105
- }
106
- }
107
- static from(value) {
108
- return isNonNullable(value) ? Optional.some(value) : Optional.none();
109
- }
110
- getOrNull() {
111
- return this.tag ? this.value : null;
112
- }
113
- getOrUndefined() {
114
- return this.value;
115
- }
116
- each(worker) {
117
- if (this.tag) {
118
- worker(this.value);
119
- }
120
- }
121
- toArray() {
122
- return this.tag ? [this.value] : [];
123
- }
124
- toString() {
125
- return this.tag ? `some(${ this.value })` : 'none()';
126
- }
61
+ // The internal representation has a `tag` and a `value`, but both are
62
+ // private: able to be console.logged, but not able to be accessed by code
63
+ constructor(tag, value) {
64
+ this.tag = tag;
65
+ this.value = value;
66
+ }
67
+ // --- Identities ---
68
+ /**
69
+ * Creates a new `Optional<T>` that **does** contain a value.
70
+ */
71
+ static some(value) {
72
+ return new Optional(true, value);
73
+ }
74
+ /**
75
+ * Create a new `Optional<T>` that **does not** contain a value. `T` can be
76
+ * any type because we don't actually have a `T`.
77
+ */
78
+ static none() {
79
+ return Optional.singletonNone;
80
+ }
81
+ /**
82
+ * Perform a transform on an `Optional` type. Regardless of whether this
83
+ * `Optional` contains a value or not, `fold` will return a value of type `U`.
84
+ * If this `Optional` does not contain a value, the `U` will be created by
85
+ * calling `onNone`. If this `Optional` does contain a value, the `U` will be
86
+ * created by calling `onSome`.
87
+ *
88
+ * For the FP enthusiasts in the room, this function:
89
+ * 1. Could be used to implement all of the functions below
90
+ * 2. Forms a catamorphism
91
+ */
92
+ fold(onNone, onSome) {
93
+ if (this.tag) {
94
+ return onSome(this.value);
95
+ }
96
+ else {
97
+ return onNone();
98
+ }
99
+ }
100
+ /**
101
+ * Determine if this `Optional` object contains a value.
102
+ */
103
+ isSome() {
104
+ return this.tag;
105
+ }
106
+ /**
107
+ * Determine if this `Optional` object **does not** contain a value.
108
+ */
109
+ isNone() {
110
+ return !this.tag;
111
+ }
112
+ // --- Functor (name stolen from Haskell / maths) ---
113
+ /**
114
+ * Perform a transform on an `Optional` object, **if** there is a value. If
115
+ * you provide a function to turn a T into a U, this is the function you use
116
+ * to turn an `Optional<T>` into an `Optional<U>`. If this **does** contain
117
+ * a value then the output will also contain a value (that value being the
118
+ * output of `mapper(this.value)`), and if this **does not** contain a value
119
+ * then neither will the output.
120
+ */
121
+ map(mapper) {
122
+ if (this.tag) {
123
+ return Optional.some(mapper(this.value));
124
+ }
125
+ else {
126
+ return Optional.none();
127
+ }
128
+ }
129
+ // --- Monad (name stolen from Haskell / maths) ---
130
+ /**
131
+ * Perform a transform on an `Optional` object, **if** there is a value.
132
+ * Unlike `map`, here the transform itself also returns an `Optional`.
133
+ */
134
+ bind(binder) {
135
+ if (this.tag) {
136
+ return binder(this.value);
137
+ }
138
+ else {
139
+ return Optional.none();
140
+ }
141
+ }
142
+ // --- Traversable (name stolen from Haskell / maths) ---
143
+ /**
144
+ * For a given predicate, this function finds out if there **exists** a value
145
+ * inside this `Optional` object that meets the predicate. In practice, this
146
+ * means that for `Optional`s that do not contain a value it returns false (as
147
+ * no predicate-meeting value exists).
148
+ */
149
+ exists(predicate) {
150
+ return this.tag && predicate(this.value);
151
+ }
152
+ /**
153
+ * For a given predicate, this function finds out if **all** the values inside
154
+ * this `Optional` object meet the predicate. In practice, this means that
155
+ * for `Optional`s that do not contain a value it returns true (as all 0
156
+ * objects do meet the predicate).
157
+ */
158
+ forall(predicate) {
159
+ return !this.tag || predicate(this.value);
160
+ }
161
+ filter(predicate) {
162
+ if (!this.tag || predicate(this.value)) {
163
+ return this;
164
+ }
165
+ else {
166
+ return Optional.none();
167
+ }
168
+ }
169
+ // --- Getters ---
170
+ /**
171
+ * Get the value out of the inside of the `Optional` object, using a default
172
+ * `replacement` value if the provided `Optional` object does not contain a
173
+ * value.
174
+ */
175
+ getOr(replacement) {
176
+ return this.tag ? this.value : replacement;
177
+ }
178
+ /**
179
+ * Get the value out of the inside of the `Optional` object, using a default
180
+ * `replacement` value if the provided `Optional` object does not contain a
181
+ * value. Unlike `getOr`, in this method the `replacement` object is also
182
+ * `Optional` - meaning that this method will always return an `Optional`.
183
+ */
184
+ or(replacement) {
185
+ return this.tag ? this : replacement;
186
+ }
187
+ /**
188
+ * Get the value out of the inside of the `Optional` object, using a default
189
+ * `replacement` value if the provided `Optional` object does not contain a
190
+ * value. Unlike `getOr`, in this method the `replacement` value is
191
+ * "thunked" - that is to say that you don't pass a value to `getOrThunk`, you
192
+ * pass a function which (if called) will **return** the `value` you want to
193
+ * use.
194
+ */
195
+ getOrThunk(thunk) {
196
+ return this.tag ? this.value : thunk();
197
+ }
198
+ /**
199
+ * Get the value out of the inside of the `Optional` object, using a default
200
+ * `replacement` value if the provided Optional object does not contain a
201
+ * value.
202
+ *
203
+ * Unlike `or`, in this method the `replacement` value is "thunked" - that is
204
+ * to say that you don't pass a value to `orThunk`, you pass a function which
205
+ * (if called) will **return** the `value` you want to use.
206
+ *
207
+ * Unlike `getOrThunk`, in this method the `replacement` value is also
208
+ * `Optional`, meaning that this method will always return an `Optional`.
209
+ */
210
+ orThunk(thunk) {
211
+ return this.tag ? this : thunk();
212
+ }
213
+ /**
214
+ * Get the value out of the inside of the `Optional` object, throwing an
215
+ * exception if the provided `Optional` object does not contain a value.
216
+ *
217
+ * WARNING:
218
+ * You should only be using this function if you know that the `Optional`
219
+ * object **is not** empty (otherwise you're throwing exceptions in production
220
+ * code, which is bad).
221
+ *
222
+ * In tests this is more acceptable.
223
+ *
224
+ * Prefer other methods to this, such as `.each`.
225
+ */
226
+ getOrDie(message) {
227
+ if (!this.tag) {
228
+ throw new Error(message !== null && message !== void 0 ? message : 'Called getOrDie on None');
229
+ }
230
+ else {
231
+ return this.value;
232
+ }
233
+ }
234
+ // --- Interop with null and undefined ---
235
+ /**
236
+ * Creates an `Optional` value from a nullable (or undefined-able) input.
237
+ * Null, or undefined, is converted to `None`, and anything else is converted
238
+ * to `Some`.
239
+ */
240
+ static from(value) {
241
+ return isNonNullable(value) ? Optional.some(value) : Optional.none();
242
+ }
243
+ /**
244
+ * Converts an `Optional` to a nullable type, by getting the value if it
245
+ * exists, or returning `null` if it does not.
246
+ */
247
+ getOrNull() {
248
+ return this.tag ? this.value : null;
249
+ }
250
+ /**
251
+ * Converts an `Optional` to an undefined-able type, by getting the value if
252
+ * it exists, or returning `undefined` if it does not.
253
+ */
254
+ getOrUndefined() {
255
+ return this.value;
256
+ }
257
+ // --- Utilities ---
258
+ /**
259
+ * If the `Optional` contains a value, perform an action on that value.
260
+ * Unlike the rest of the methods on this type, `.each` has side-effects. If
261
+ * you want to transform an `Optional<T>` **into** something, then this is not
262
+ * the method for you. If you want to use an `Optional<T>` to **do**
263
+ * something, then this is the method for you - provided you're okay with not
264
+ * doing anything in the case where the `Optional` doesn't have a value inside
265
+ * it. If you're not sure whether your use-case fits into transforming
266
+ * **into** something or **doing** something, check whether it has a return
267
+ * value. If it does, you should be performing a transform.
268
+ */
269
+ each(worker) {
270
+ if (this.tag) {
271
+ worker(this.value);
272
+ }
273
+ }
274
+ /**
275
+ * Turn the `Optional` object into an array that contains all of the values
276
+ * stored inside the `Optional`. In practice, this means the output will have
277
+ * either 0 or 1 elements.
278
+ */
279
+ toArray() {
280
+ return this.tag ? [this.value] : [];
281
+ }
282
+ /**
283
+ * Turn the `Optional` object into a string for debugging or printing. Not
284
+ * recommended for production code, but good for debugging. Also note that
285
+ * these days an `Optional` object can be logged to the console directly, and
286
+ * its inner value (if it exists) will be visible.
287
+ */
288
+ toString() {
289
+ return this.tag ? `some(${this.value})` : 'none()';
290
+ }
127
291
  }
292
+ // Sneaky optimisation: every instance of Optional.none is identical, so just
293
+ // reuse the same object
128
294
  Optional.singletonNone = new Optional(false);
129
295
 
296
+ /* eslint-disable @typescript-eslint/unbound-method */
297
+ const nativeSlice = Array.prototype.slice;
130
298
  const nativePush = Array.prototype.push;
299
+ // Unwound implementing other functions in terms of each.
300
+ // The code size is roughly the same, and it should allow for better optimisation.
301
+ // const each = function<T, U>(xs: T[], f: (x: T, i?: number, xs?: T[]) => void): void {
131
302
  const each$1 = (xs, f) => {
132
- for (let i = 0, len = xs.length; i < len; i++) {
133
- const x = xs[i];
134
- f(x, i);
135
- }
136
- };
137
- const flatten = xs => {
138
- const r = [];
139
- for (let i = 0, len = xs.length; i < len; ++i) {
140
- if (!isArray(xs[i])) {
141
- throw new Error('Arr.flatten item ' + i + ' was not an array, input: ' + xs);
142
- }
143
- nativePush.apply(r, xs[i]);
144
- }
145
- return r;
303
+ for (let i = 0, len = xs.length; i < len; i++) {
304
+ const x = xs[i];
305
+ f(x, i);
306
+ }
146
307
  };
147
-
148
- const Cell = initial => {
149
- let value = initial;
150
- const get = () => {
151
- return value;
152
- };
153
- const set = v => {
154
- value = v;
155
- };
156
- return {
157
- get,
158
- set
159
- };
308
+ const flatten = (xs) => {
309
+ // Note, this is possible because push supports multiple arguments:
310
+ // http://jsperf.com/concat-push/6
311
+ // Note that in the past, concat() would silently work (very slowly) for array-like objects.
312
+ // With this change it will throw an error.
313
+ const r = [];
314
+ for (let i = 0, len = xs.length; i < len; ++i) {
315
+ // Ensure that each value is an array itself
316
+ if (!isArray(xs[i])) {
317
+ throw new Error('Arr.flatten item ' + i + ' was not an array, input: ' + xs);
318
+ }
319
+ nativePush.apply(r, xs[i]);
320
+ }
321
+ return r;
160
322
  };
323
+ isFunction(Array.from) ? Array.from : (x) => nativeSlice.call(x);
161
324
 
325
+ // There are many variations of Object iteration that are faster than the 'for-in' style:
326
+ // http://jsperf.com/object-keys-iteration/107
327
+ //
328
+ // Use the native keys if it is available (IE9+), otherwise fall back to manually filtering
162
329
  const keys = Object.keys;
330
+ // eslint-disable-next-line @typescript-eslint/unbound-method
163
331
  const hasOwnProperty = Object.hasOwnProperty;
164
332
  const each = (obj, f) => {
165
- const props = keys(obj);
166
- for (let k = 0, len = props.length; k < len; k++) {
167
- const i = props[k];
168
- const x = obj[i];
169
- f(x, i);
170
- }
333
+ const props = keys(obj);
334
+ for (let k = 0, len = props.length; k < len; k++) {
335
+ const i = props[k];
336
+ const x = obj[i];
337
+ f(x, i);
338
+ }
171
339
  };
172
340
  const get$1 = (obj, key) => {
173
- return has(obj, key) ? Optional.from(obj[key]) : Optional.none();
341
+ return has(obj, key) ? Optional.from(obj[key]) : Optional.none();
174
342
  };
175
343
  const has = (obj, key) => hasOwnProperty.call(obj, key);
176
344
 
177
- const option = name => editor => editor.options.get(name);
178
- const register$2 = editor => {
179
- const registerOption = editor.options.register;
180
- registerOption('audio_template_callback', { processor: 'function' });
181
- registerOption('video_template_callback', { processor: 'function' });
182
- registerOption('iframe_template_callback', { processor: 'function' });
183
- registerOption('media_live_embeds', {
184
- processor: 'boolean',
185
- default: true
186
- });
187
- registerOption('media_filter_html', {
188
- processor: 'boolean',
189
- default: true
190
- });
191
- registerOption('media_url_resolver', { processor: 'function' });
192
- registerOption('media_alt_source', {
193
- processor: 'boolean',
194
- default: true
195
- });
196
- registerOption('media_poster', {
197
- processor: 'boolean',
198
- default: true
199
- });
200
- registerOption('media_dimensions', {
201
- processor: 'boolean',
202
- default: true
203
- });
345
+ const Cell = (initial) => {
346
+ let value = initial;
347
+ const get = () => {
348
+ return value;
349
+ };
350
+ const set = (v) => {
351
+ value = v;
352
+ };
353
+ return {
354
+ get,
355
+ set
356
+ };
357
+ };
358
+
359
+ const checkRange = (str, substr, start) => substr === '' || str.length >= substr.length && str.substr(start, start + substr.length) === substr;
360
+ /** Does 'str' start with 'prefix'?
361
+ * Note: all strings start with the empty string.
362
+ * More formally, for all strings x, startsWith(x, "").
363
+ * This is so that for all strings x and y, startsWith(y + x, y)
364
+ */
365
+ const startsWith = (str, prefix) => {
366
+ return checkRange(str, prefix, 0);
367
+ };
368
+
369
+ const option = (name) => (editor) => editor.options.get(name);
370
+ const register$2 = (editor) => {
371
+ const registerOption = editor.options.register;
372
+ registerOption('audio_template_callback', {
373
+ processor: 'function'
374
+ });
375
+ registerOption('video_template_callback', {
376
+ processor: 'function'
377
+ });
378
+ registerOption('iframe_template_callback', {
379
+ processor: 'function'
380
+ });
381
+ registerOption('media_live_embeds', {
382
+ processor: 'boolean',
383
+ default: true
384
+ });
385
+ registerOption('media_filter_html', {
386
+ processor: 'boolean',
387
+ default: true
388
+ });
389
+ registerOption('media_url_resolver', {
390
+ processor: 'function'
391
+ });
392
+ registerOption('media_alt_source', {
393
+ processor: 'boolean',
394
+ default: true
395
+ });
396
+ registerOption('media_poster', {
397
+ processor: 'boolean',
398
+ default: true
399
+ });
400
+ registerOption('media_dimensions', {
401
+ processor: 'boolean',
402
+ default: true
403
+ });
204
404
  };
205
405
  const getAudioTemplateCallback = option('audio_template_callback');
206
406
  const getVideoTemplateCallback = option('video_template_callback');
@@ -219,74 +419,75 @@
219
419
  var global$3 = tinymce.util.Tools.resolve('tinymce.html.DomParser');
220
420
 
221
421
  const DOM$1 = global$4.DOM;
222
- const trimPx = value => value.replace(/px$/, '');
223
- const getEphoxEmbedData = node => {
224
- const style = node.attr('style');
225
- const styles = style ? DOM$1.parseStyle(style) : {};
226
- return {
227
- type: 'ephox-embed-iri',
228
- source: node.attr('data-ephox-embed-iri'),
229
- altsource: '',
230
- poster: '',
231
- width: get$1(styles, 'max-width').map(trimPx).getOr(''),
232
- height: get$1(styles, 'max-height').map(trimPx).getOr('')
233
- };
422
+ const trimPx = (value) => value.replace(/px$/, '');
423
+ const getEphoxEmbedData = (node) => {
424
+ const style = node.attr('style');
425
+ const styles = style ? DOM$1.parseStyle(style) : {};
426
+ return {
427
+ type: 'ephox-embed-iri',
428
+ source: node.attr('data-ephox-embed-iri'),
429
+ altsource: '',
430
+ poster: '',
431
+ width: get$1(styles, 'max-width').map(trimPx).getOr(''),
432
+ height: get$1(styles, 'max-height').map(trimPx).getOr('')
433
+ };
234
434
  };
235
435
  const htmlToData = (html, schema) => {
236
- let data = {};
237
- const parser = global$3({
238
- validate: false,
239
- forced_root_block: false
240
- }, schema);
241
- const rootNode = parser.parse(html);
242
- for (let node = rootNode; node; node = node.walk()) {
243
- if (node.type === 1) {
244
- const name = node.name;
245
- if (node.attr('data-ephox-embed-iri')) {
246
- data = getEphoxEmbedData(node);
247
- break;
248
- } else {
249
- if (!data.source && name === 'param') {
250
- data.source = node.attr('movie');
251
- }
252
- if (name === 'iframe' || name === 'object' || name === 'embed' || name === 'video' || name === 'audio') {
253
- if (!data.type) {
254
- data.type = name;
255
- }
256
- data = global$5.extend(node.attributes.map, data);
257
- }
258
- if (name === 'source') {
259
- if (!data.source) {
260
- data.source = node.attr('src');
261
- } else if (!data.altsource) {
262
- data.altsource = node.attr('src');
263
- }
264
- }
265
- if (name === 'img' && !data.poster) {
266
- data.poster = node.attr('src');
436
+ let data = {};
437
+ const parser = global$3({ validate: false, forced_root_block: false }, schema);
438
+ const rootNode = parser.parse(html);
439
+ for (let node = rootNode; node; node = node.walk()) {
440
+ if (node.type === 1) {
441
+ const name = node.name;
442
+ if (node.attr('data-ephox-embed-iri')) {
443
+ data = getEphoxEmbedData(node);
444
+ // Don't continue to collect if we find an EME embed
445
+ break;
446
+ }
447
+ else {
448
+ if (!data.source && name === 'param') {
449
+ data.source = node.attr('movie');
450
+ }
451
+ if (name === 'iframe' || name === 'object' || name === 'embed' || name === 'video' || name === 'audio') {
452
+ if (!data.type) {
453
+ data.type = name;
454
+ }
455
+ // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
456
+ data = global$5.extend(node.attributes.map, data);
457
+ }
458
+ if (name === 'source') {
459
+ if (!data.source) {
460
+ data.source = node.attr('src');
461
+ }
462
+ else if (!data.altsource) {
463
+ data.altsource = node.attr('src');
464
+ }
465
+ }
466
+ if (name === 'img' && !data.poster) {
467
+ data.poster = node.attr('src');
468
+ }
469
+ }
267
470
  }
268
- }
269
471
  }
270
- }
271
- data.source = data.source || data.src || '';
272
- data.altsource = data.altsource || '';
273
- data.poster = data.poster || '';
274
- return data;
472
+ data.source = data.source || data.src || '';
473
+ data.altsource = data.altsource || '';
474
+ data.poster = data.poster || '';
475
+ return data;
275
476
  };
276
477
 
277
- const guess = url => {
278
- var _a;
279
- const mimes = {
280
- mp3: 'audio/mpeg',
281
- m4a: 'audio/x-m4a',
282
- wav: 'audio/wav',
283
- mp4: 'video/mp4',
284
- webm: 'video/webm',
285
- ogg: 'video/ogg',
286
- swf: 'application/x-shockwave-flash'
287
- };
288
- const fileEnd = (_a = url.toLowerCase().split('.').pop()) !== null && _a !== void 0 ? _a : '';
289
- return get$1(mimes, fileEnd).getOr('');
478
+ const guess = (url) => {
479
+ var _a;
480
+ const mimes = {
481
+ mp3: 'audio/mpeg',
482
+ m4a: 'audio/x-m4a',
483
+ wav: 'audio/wav',
484
+ mp4: 'video/mp4',
485
+ webm: 'video/webm',
486
+ ogg: 'video/ogg',
487
+ swf: 'application/x-shockwave-flash'
488
+ };
489
+ const fileEnd = (_a = url.toLowerCase().split('.').pop()) !== null && _a !== void 0 ? _a : '';
490
+ return get$1(mimes, fileEnd).getOr('');
290
491
  };
291
492
 
292
493
  var global$2 = tinymce.util.Tools.resolve('tinymce.html.Node');
@@ -294,924 +495,981 @@
294
495
  var global$1 = tinymce.util.Tools.resolve('tinymce.html.Serializer');
295
496
 
296
497
  const Parser = (schema, settings = {}) => global$3({
297
- forced_root_block: false,
298
- validate: false,
299
- allow_conditional_comments: true,
300
- ...settings
498
+ forced_root_block: false,
499
+ validate: false,
500
+ allow_conditional_comments: true,
501
+ ...settings
301
502
  }, schema);
302
503
 
303
504
  const DOM = global$4.DOM;
304
- const addPx = value => /^[0-9.]+$/.test(value) ? value + 'px' : value;
505
+ const addPx = (value) => /^[0-9.]+$/.test(value) ? (value + 'px') : value;
305
506
  const updateEphoxEmbed = (data, node) => {
306
- const style = node.attr('style');
307
- const styleMap = style ? DOM.parseStyle(style) : {};
308
- if (isNonNullable(data.width)) {
309
- styleMap['max-width'] = addPx(data.width);
310
- }
311
- if (isNonNullable(data.height)) {
312
- styleMap['max-height'] = addPx(data.height);
313
- }
314
- node.attr('style', DOM.serializeStyle(styleMap));
507
+ const style = node.attr('style');
508
+ const styleMap = style ? DOM.parseStyle(style) : {};
509
+ if (isNonNullable(data.width)) {
510
+ styleMap['max-width'] = addPx(data.width);
511
+ }
512
+ if (isNonNullable(data.height)) {
513
+ styleMap['max-height'] = addPx(data.height);
514
+ }
515
+ node.attr('style', DOM.serializeStyle(styleMap));
315
516
  };
316
- const sources = [
317
- 'source',
318
- 'altsource'
319
- ];
517
+ const sources = ['source', 'altsource'];
320
518
  const updateHtml = (html, data, updateAll, schema) => {
321
- let numSources = 0;
322
- let sourceCount = 0;
323
- const parser = Parser(schema);
324
- parser.addNodeFilter('source', nodes => numSources = nodes.length);
325
- const rootNode = parser.parse(html);
326
- for (let node = rootNode; node; node = node.walk()) {
327
- if (node.type === 1) {
328
- const name = node.name;
329
- if (node.attr('data-ephox-embed-iri')) {
330
- updateEphoxEmbed(data, node);
331
- break;
332
- } else {
333
- switch (name) {
334
- case 'video':
335
- case 'object':
336
- case 'embed':
337
- case 'img':
338
- case 'iframe':
339
- if (data.height !== undefined && data.width !== undefined) {
340
- node.attr('width', data.width);
341
- node.attr('height', data.height);
342
- }
343
- break;
344
- }
345
- if (updateAll) {
346
- switch (name) {
347
- case 'video':
348
- node.attr('poster', data.poster);
349
- node.attr('src', null);
350
- for (let index = numSources; index < 2; index++) {
351
- if (data[sources[index]]) {
352
- const source = new global$2('source', 1);
353
- source.attr('src', data[sources[index]]);
354
- source.attr('type', data[sources[index] + 'mime'] || null);
355
- node.append(source);
356
- }
357
- }
358
- break;
359
- case 'iframe':
360
- node.attr('src', data.source);
361
- break;
362
- case 'object':
363
- const hasImage = node.getAll('img').length > 0;
364
- if (data.poster && !hasImage) {
365
- node.attr('src', data.poster);
366
- const img = new global$2('img', 1);
367
- img.attr('src', data.poster);
368
- img.attr('width', data.width);
369
- img.attr('height', data.height);
370
- node.append(img);
371
- }
372
- break;
373
- case 'source':
374
- if (sourceCount < 2) {
375
- node.attr('src', data[sources[sourceCount]]);
376
- node.attr('type', data[sources[sourceCount] + 'mime'] || null);
377
- if (!data[sources[sourceCount]]) {
378
- node.remove();
379
- continue;
380
- }
519
+ let numSources = 0;
520
+ let sourceCount = 0;
521
+ const parser = Parser(schema);
522
+ parser.addNodeFilter('source', (nodes) => numSources = nodes.length);
523
+ const rootNode = parser.parse(html);
524
+ for (let node = rootNode; node; node = node.walk()) {
525
+ if (node.type === 1) {
526
+ const name = node.name;
527
+ if (node.attr('data-ephox-embed-iri')) {
528
+ updateEphoxEmbed(data, node);
529
+ // Don't continue to update if we find an EME embed
530
+ break;
381
531
  }
382
- sourceCount++;
383
- break;
384
- case 'img':
385
- if (!data.poster) {
386
- node.remove();
532
+ else {
533
+ switch (name) {
534
+ case 'video':
535
+ case 'object':
536
+ case 'embed':
537
+ case 'img':
538
+ case 'iframe':
539
+ if (data.height !== undefined && data.width !== undefined) {
540
+ node.attr('width', data.width);
541
+ node.attr('height', data.height);
542
+ }
543
+ break;
544
+ }
545
+ if (updateAll) {
546
+ switch (name) {
547
+ case 'video':
548
+ node.attr('poster', data.poster);
549
+ node.attr('src', null);
550
+ // Add <source> child elements
551
+ for (let index = numSources; index < 2; index++) {
552
+ if (data[sources[index]]) {
553
+ const source = new global$2('source', 1);
554
+ source.attr('src', data[sources[index]]);
555
+ source.attr('type', data[sources[index] + 'mime'] || null);
556
+ node.append(source);
557
+ }
558
+ }
559
+ break;
560
+ case 'iframe':
561
+ node.attr('src', data.source);
562
+ break;
563
+ case 'object':
564
+ const hasImage = node.getAll('img').length > 0;
565
+ if (data.poster && !hasImage) {
566
+ node.attr('src', data.poster);
567
+ const img = new global$2('img', 1);
568
+ img.attr('src', data.poster);
569
+ img.attr('width', data.width);
570
+ img.attr('height', data.height);
571
+ node.append(img);
572
+ }
573
+ break;
574
+ case 'source':
575
+ if (sourceCount < 2) {
576
+ node.attr('src', data[sources[sourceCount]]);
577
+ node.attr('type', data[sources[sourceCount] + 'mime'] || null);
578
+ if (!data[sources[sourceCount]]) {
579
+ node.remove();
580
+ continue;
581
+ }
582
+ }
583
+ sourceCount++;
584
+ break;
585
+ case 'img':
586
+ if (!data.poster) {
587
+ node.remove();
588
+ }
589
+ break;
590
+ }
591
+ }
387
592
  }
388
- break;
389
- }
390
593
  }
391
- }
392
594
  }
393
- }
394
- return global$1({}, schema).serialize(rootNode);
595
+ return global$1({}, schema).serialize(rootNode);
395
596
  };
396
597
 
397
598
  const urlPatterns = [
398
- {
399
- regex: /youtu\.be\/([\w\-_\?&=.]+)/i,
400
- type: 'iframe',
401
- w: 560,
402
- h: 314,
403
- url: 'www.youtube.com/embed/$1',
404
- allowFullscreen: true
405
- },
406
- {
407
- regex: /youtube\.com(.+)v=([^&]+)(&([a-z0-9&=\-_]+))?/i,
408
- type: 'iframe',
409
- w: 560,
410
- h: 314,
411
- url: 'www.youtube.com/embed/$2?$4',
412
- allowFullscreen: true
413
- },
414
- {
415
- regex: /youtube.com\/embed\/([a-z0-9\?&=\-_]+)/i,
416
- type: 'iframe',
417
- w: 560,
418
- h: 314,
419
- url: 'www.youtube.com/embed/$1',
420
- allowFullscreen: true
421
- },
422
- {
423
- regex: /vimeo\.com\/([0-9]+)\?h=(\w+)/,
424
- type: 'iframe',
425
- w: 425,
426
- h: 350,
427
- url: 'player.vimeo.com/video/$1?h=$2&title=0&byline=0&portrait=0&color=8dc7dc',
428
- allowFullscreen: true
429
- },
430
- {
431
- regex: /vimeo\.com\/(.*)\/([0-9]+)\?h=(\w+)/,
432
- type: 'iframe',
433
- w: 425,
434
- h: 350,
435
- url: 'player.vimeo.com/video/$2?h=$3&title=0&amp;byline=0',
436
- allowFullscreen: true
437
- },
438
- {
439
- regex: /vimeo\.com\/([0-9]+)/,
440
- type: 'iframe',
441
- w: 425,
442
- h: 350,
443
- url: 'player.vimeo.com/video/$1?title=0&byline=0&portrait=0&color=8dc7dc',
444
- allowFullscreen: true
445
- },
446
- {
447
- regex: /vimeo\.com\/(.*)\/([0-9]+)/,
448
- type: 'iframe',
449
- w: 425,
450
- h: 350,
451
- url: 'player.vimeo.com/video/$2?title=0&amp;byline=0',
452
- allowFullscreen: true
453
- },
454
- {
455
- regex: /maps\.google\.([a-z]{2,3})\/maps\/(.+)msid=(.+)/,
456
- type: 'iframe',
457
- w: 425,
458
- h: 350,
459
- url: 'maps.google.com/maps/ms?msid=$2&output=embed"',
460
- allowFullscreen: false
461
- },
462
- {
463
- regex: /dailymotion\.com\/video\/([^_]+)/,
464
- type: 'iframe',
465
- w: 480,
466
- h: 270,
467
- url: 'www.dailymotion.com/embed/video/$1',
468
- allowFullscreen: true
469
- },
470
- {
471
- regex: /dai\.ly\/([^_]+)/,
472
- type: 'iframe',
473
- w: 480,
474
- h: 270,
475
- url: 'www.dailymotion.com/embed/video/$1',
476
- allowFullscreen: true
477
- }
599
+ {
600
+ regex: /youtu\.be\/([\w\-_\?&=.]+)/i,
601
+ type: 'iframe', w: 560, h: 314,
602
+ url: 'www.youtube.com/embed/$1',
603
+ allowFullscreen: true
604
+ },
605
+ {
606
+ regex: /youtube\.com(.+)v=([^&]+)(&([a-z0-9&=\-_]+))?/i,
607
+ type: 'iframe', w: 560, h: 314,
608
+ url: 'www.youtube.com/embed/$2?$4',
609
+ allowFullscreen: true
610
+ },
611
+ {
612
+ regex: /youtube.com\/embed\/([a-z0-9\?&=\-_]+)/i,
613
+ type: 'iframe', w: 560, h: 314,
614
+ url: 'www.youtube.com/embed/$1',
615
+ allowFullscreen: true
616
+ },
617
+ {
618
+ regex: /vimeo\.com\/([0-9]+)\?h=(\w+)/,
619
+ type: 'iframe', w: 425, h: 350,
620
+ url: 'player.vimeo.com/video/$1?h=$2&title=0&byline=0&portrait=0&color=8dc7dc',
621
+ allowFullscreen: true
622
+ },
623
+ {
624
+ regex: /vimeo\.com\/(.*)\/([0-9]+)\?h=(\w+)/,
625
+ type: 'iframe', w: 425, h: 350,
626
+ url: 'player.vimeo.com/video/$2?h=$3&title=0&amp;byline=0',
627
+ allowFullscreen: true
628
+ },
629
+ {
630
+ regex: /vimeo\.com\/([0-9]+)/,
631
+ type: 'iframe', w: 425, h: 350,
632
+ url: 'player.vimeo.com/video/$1?title=0&byline=0&portrait=0&color=8dc7dc',
633
+ allowFullscreen: true
634
+ },
635
+ {
636
+ regex: /vimeo\.com\/(.*)\/([0-9]+)/,
637
+ type: 'iframe', w: 425, h: 350,
638
+ url: 'player.vimeo.com/video/$2?title=0&amp;byline=0',
639
+ allowFullscreen: true
640
+ },
641
+ {
642
+ regex: /maps\.google\.([a-z]{2,3})\/maps\/(.+)msid=(.+)/,
643
+ type: 'iframe', w: 425, h: 350,
644
+ url: 'maps.google.com/maps/ms?msid=$2&output=embed"',
645
+ allowFullscreen: false
646
+ },
647
+ {
648
+ regex: /dailymotion\.com\/video\/([^_]+)/,
649
+ type: 'iframe', w: 480, h: 270,
650
+ url: 'www.dailymotion.com/embed/video/$1',
651
+ allowFullscreen: true
652
+ },
653
+ {
654
+ regex: /dai\.ly\/([^_]+)/,
655
+ type: 'iframe', w: 480, h: 270,
656
+ url: 'www.dailymotion.com/embed/video/$1',
657
+ allowFullscreen: true
658
+ }
478
659
  ];
479
- const getProtocol = url => {
480
- const protocolMatches = url.match(/^(https?:\/\/|www\.)(.+)$/i);
481
- if (protocolMatches && protocolMatches.length > 1) {
482
- return protocolMatches[1] === 'www.' ? 'https://' : protocolMatches[1];
483
- } else {
484
- return 'https://';
485
- }
660
+ const getProtocol = (url) => {
661
+ const protocolMatches = url.match(/^(https?:\/\/|www\.)(.+)$/i);
662
+ if (protocolMatches && protocolMatches.length > 1) {
663
+ return protocolMatches[1] === 'www.' ? 'https://' : protocolMatches[1];
664
+ }
665
+ else {
666
+ return 'https://';
667
+ }
486
668
  };
487
669
  const getUrl = (pattern, url) => {
488
- const protocol = getProtocol(url);
489
- const match = pattern.regex.exec(url);
490
- let newUrl = protocol + pattern.url;
491
- if (isNonNullable(match)) {
492
- for (let i = 0; i < match.length; i++) {
493
- newUrl = newUrl.replace('$' + i, () => match[i] ? match[i] : '');
494
- }
495
- }
496
- return newUrl.replace(/\?$/, '');
670
+ const protocol = getProtocol(url);
671
+ const match = pattern.regex.exec(url);
672
+ let newUrl = protocol + pattern.url;
673
+ if (isNonNullable(match)) {
674
+ for (let i = 0; i < match.length; i++) {
675
+ newUrl = newUrl.replace('$' + i, () => match[i] ? match[i] : '');
676
+ }
677
+ }
678
+ return newUrl.replace(/\?$/, '');
497
679
  };
498
- const matchPattern = url => {
499
- const patterns = urlPatterns.filter(pattern => pattern.regex.test(url));
500
- if (patterns.length > 0) {
501
- return global$5.extend({}, patterns[0], { url: getUrl(patterns[0], url) });
502
- } else {
503
- return null;
504
- }
680
+ const matchPattern = (url) => {
681
+ const patterns = urlPatterns.filter((pattern) => pattern.regex.test(url));
682
+ if (patterns.length > 0) {
683
+ return global$5.extend({}, patterns[0], { url: getUrl(patterns[0], url) });
684
+ }
685
+ else {
686
+ return null;
687
+ }
505
688
  };
506
689
 
507
690
  const getIframeHtml = (data, iframeTemplateCallback) => {
508
- if (iframeTemplateCallback) {
509
- return iframeTemplateCallback(data);
510
- } else {
511
- const allowFullscreen = data.allowfullscreen ? ' allowFullscreen="1"' : '';
512
- return '<iframe src="' + data.source + '" width="' + data.width + '" height="' + data.height + '"' + allowFullscreen + '></iframe>';
513
- }
691
+ if (iframeTemplateCallback) {
692
+ return iframeTemplateCallback(data);
693
+ }
694
+ else {
695
+ const allowFullscreen = data.allowfullscreen ? ' allowFullscreen="1"' : '';
696
+ return '<iframe src="' + data.source + '" width="' + data.width + '" height="' + data.height + '"' + allowFullscreen + '></iframe>';
697
+ }
514
698
  };
515
- const getFlashHtml = data => {
516
- let html = '<object data="' + data.source + '" width="' + data.width + '" height="' + data.height + '" type="application/x-shockwave-flash">';
517
- if (data.poster) {
518
- html += '<img src="' + data.poster + '" width="' + data.width + '" height="' + data.height + '" />';
519
- }
520
- html += '</object>';
521
- return html;
699
+ const getFlashHtml = (data) => {
700
+ let html = '<object data="' + data.source + '" width="' + data.width + '" height="' + data.height + '" type="application/x-shockwave-flash">';
701
+ if (data.poster) {
702
+ html += '<img src="' + data.poster + '" width="' + data.width + '" height="' + data.height + '" />';
703
+ }
704
+ html += '</object>';
705
+ return html;
522
706
  };
523
707
  const getAudioHtml = (data, audioTemplateCallback) => {
524
- if (audioTemplateCallback) {
525
- return audioTemplateCallback(data);
526
- } else {
527
- return '<audio controls="controls" src="' + data.source + '">' + (data.altsource ? '\n<source src="' + data.altsource + '"' + (data.altsourcemime ? ' type="' + data.altsourcemime + '"' : '') + ' />\n' : '') + '</audio>';
528
- }
708
+ if (audioTemplateCallback) {
709
+ return audioTemplateCallback(data);
710
+ }
711
+ else {
712
+ return ('<audio controls="controls" src="' + data.source + '">' +
713
+ (data.altsource ?
714
+ '\n<source src="' + data.altsource + '"' +
715
+ (data.altsourcemime ? ' type="' + data.altsourcemime + '"' : '') +
716
+ ' />\n' : '') +
717
+ '</audio>');
718
+ }
529
719
  };
530
720
  const getVideoHtml = (data, videoTemplateCallback) => {
531
- if (videoTemplateCallback) {
532
- return videoTemplateCallback(data);
533
- } else {
534
- return '<video width="' + data.width + '" height="' + data.height + '"' + (data.poster ? ' poster="' + data.poster + '"' : '') + ' controls="controls">\n' + '<source src="' + data.source + '"' + (data.sourcemime ? ' type="' + data.sourcemime + '"' : '') + ' />\n' + (data.altsource ? '<source src="' + data.altsource + '"' + (data.altsourcemime ? ' type="' + data.altsourcemime + '"' : '') + ' />\n' : '') + '</video>';
535
- }
721
+ if (videoTemplateCallback) {
722
+ return videoTemplateCallback(data);
723
+ }
724
+ else {
725
+ return ('<video width="' + data.width +
726
+ '" height="' + data.height + '"' +
727
+ (data.poster ? ' poster="' + data.poster + '"' : '') + ' controls="controls">\n' +
728
+ '<source src="' + data.source + '"' +
729
+ (data.sourcemime ? ' type="' + data.sourcemime + '"' : '') + ' />\n' +
730
+ (data.altsource ? '<source src="' + data.altsource + '"' +
731
+ (data.altsourcemime ? ' type="' + data.altsourcemime + '"' : '') + ' />\n' : '') +
732
+ '</video>');
733
+ }
536
734
  };
537
735
  const dataToHtml = (editor, dataIn) => {
538
- var _a;
539
- const data = global$5.extend({}, dataIn);
540
- if (!data.source) {
541
- global$5.extend(data, htmlToData((_a = data.embed) !== null && _a !== void 0 ? _a : '', editor.schema));
736
+ var _a;
737
+ const data = global$5.extend({}, dataIn);
542
738
  if (!data.source) {
543
- return '';
544
- }
545
- }
546
- if (!data.altsource) {
547
- data.altsource = '';
548
- }
549
- if (!data.poster) {
550
- data.poster = '';
551
- }
552
- data.source = editor.convertURL(data.source, 'source');
553
- data.altsource = editor.convertURL(data.altsource, 'source');
554
- data.sourcemime = guess(data.source);
555
- data.altsourcemime = guess(data.altsource);
556
- data.poster = editor.convertURL(data.poster, 'poster');
557
- const pattern = matchPattern(data.source);
558
- if (pattern) {
559
- data.source = pattern.url;
560
- data.type = pattern.type;
561
- data.allowfullscreen = pattern.allowFullscreen;
562
- data.width = data.width || String(pattern.w);
563
- data.height = data.height || String(pattern.h);
564
- }
565
- if (data.embed) {
566
- return updateHtml(data.embed, data, true, editor.schema);
567
- } else {
568
- const audioTemplateCallback = getAudioTemplateCallback(editor);
569
- const videoTemplateCallback = getVideoTemplateCallback(editor);
570
- const iframeTemplateCallback = getIframeTemplateCallback(editor);
571
- data.width = data.width || '300';
572
- data.height = data.height || '150';
573
- global$5.each(data, (value, key) => {
574
- data[key] = editor.dom.encode('' + value);
575
- });
576
- if (data.type === 'iframe') {
577
- return getIframeHtml(data, iframeTemplateCallback);
578
- } else if (data.sourcemime === 'application/x-shockwave-flash') {
579
- return getFlashHtml(data);
580
- } else if (data.sourcemime.indexOf('audio') !== -1) {
581
- return getAudioHtml(data, audioTemplateCallback);
582
- } else {
583
- return getVideoHtml(data, videoTemplateCallback);
584
- }
585
- }
739
+ global$5.extend(data, htmlToData((_a = data.embed) !== null && _a !== void 0 ? _a : '', editor.schema));
740
+ if (!data.source) {
741
+ return '';
742
+ }
743
+ }
744
+ if (!data.altsource) {
745
+ data.altsource = '';
746
+ }
747
+ if (!data.poster) {
748
+ data.poster = '';
749
+ }
750
+ data.source = editor.convertURL(data.source, 'source');
751
+ data.altsource = editor.convertURL(data.altsource, 'source');
752
+ data.sourcemime = guess(data.source);
753
+ data.altsourcemime = guess(data.altsource);
754
+ data.poster = editor.convertURL(data.poster, 'poster');
755
+ const pattern = matchPattern(data.source);
756
+ if (pattern) {
757
+ data.source = pattern.url;
758
+ data.type = pattern.type;
759
+ data.allowfullscreen = pattern.allowFullscreen;
760
+ data.width = data.width || String(pattern.w);
761
+ data.height = data.height || String(pattern.h);
762
+ }
763
+ if (data.embed) {
764
+ return updateHtml(data.embed, data, true, editor.schema);
765
+ }
766
+ else {
767
+ const audioTemplateCallback = getAudioTemplateCallback(editor);
768
+ const videoTemplateCallback = getVideoTemplateCallback(editor);
769
+ const iframeTemplateCallback = getIframeTemplateCallback(editor);
770
+ data.width = data.width || '300';
771
+ data.height = data.height || '150';
772
+ global$5.each(data, (value, key) => {
773
+ data[key] = editor.dom.encode('' + value);
774
+ });
775
+ if (data.type === 'iframe') {
776
+ return getIframeHtml(data, iframeTemplateCallback);
777
+ }
778
+ else if (data.sourcemime === 'application/x-shockwave-flash') {
779
+ return getFlashHtml(data);
780
+ }
781
+ else if (data.sourcemime.indexOf('audio') !== -1) {
782
+ return getAudioHtml(data, audioTemplateCallback);
783
+ }
784
+ else {
785
+ return getVideoHtml(data, videoTemplateCallback);
786
+ }
787
+ }
586
788
  };
587
789
 
588
- const isMediaElement = element => element.hasAttribute('data-mce-object') || element.hasAttribute('data-ephox-embed-iri');
589
- const setup$2 = editor => {
590
- editor.on('click keyup touchend', () => {
591
- const selectedNode = editor.selection.getNode();
592
- if (selectedNode && editor.dom.hasClass(selectedNode, 'mce-preview-object')) {
593
- if (editor.dom.getAttrib(selectedNode, 'data-mce-selected')) {
594
- selectedNode.setAttribute('data-mce-selected', '2');
595
- }
596
- }
597
- });
598
- editor.on('ObjectResized', e => {
599
- const target = e.target;
600
- if (target.getAttribute('data-mce-object')) {
601
- let html = target.getAttribute('data-mce-html');
602
- if (html) {
603
- html = unescape(html);
604
- target.setAttribute('data-mce-html', escape(updateHtml(html, {
605
- width: String(e.width),
606
- height: String(e.height)
607
- }, false, editor.schema)));
608
- }
609
- }
610
- });
790
+ const isMediaElement = (element) => element.hasAttribute('data-mce-object') || element.hasAttribute('data-ephox-embed-iri');
791
+ const setup$2 = (editor) => {
792
+ // TINY-10774: On Safari all events bubble out even if you click on the video play button on other browsers the video element doesn't bubble the event
793
+ editor.on('mousedown', (e) => {
794
+ const previewObj = editor.dom.getParent(e.target, '.mce-preview-object');
795
+ if (previewObj && editor.dom.getAttrib(previewObj, 'data-mce-selected') === '2') {
796
+ e.stopImmediatePropagation();
797
+ }
798
+ });
799
+ editor.on('click keyup touchend', () => {
800
+ const selectedNode = editor.selection.getNode();
801
+ if (selectedNode && editor.dom.hasClass(selectedNode, 'mce-preview-object')) {
802
+ if (editor.dom.getAttrib(selectedNode, 'data-mce-selected')) {
803
+ selectedNode.setAttribute('data-mce-selected', '2');
804
+ }
805
+ }
806
+ });
807
+ editor.on('ObjectResized', (e) => {
808
+ const target = e.target;
809
+ if (target.getAttribute('data-mce-object')) {
810
+ let html = target.getAttribute('data-mce-html');
811
+ if (html) {
812
+ html = unescape(html);
813
+ target.setAttribute('data-mce-html', escape(updateHtml(html, {
814
+ width: String(e.width),
815
+ height: String(e.height)
816
+ }, false, editor.schema)));
817
+ }
818
+ }
819
+ });
611
820
  };
612
821
 
613
822
  const cache = {};
614
823
  const embedPromise = (data, dataToHtml, handler) => {
615
- return new Promise((res, rej) => {
616
- const wrappedResolve = response => {
617
- if (response.html) {
618
- cache[data.source] = response;
619
- }
620
- return res({
621
- url: data.source,
622
- html: response.html ? response.html : dataToHtml(data)
623
- });
624
- };
625
- if (cache[data.source]) {
626
- wrappedResolve(cache[data.source]);
627
- } else {
628
- handler({ url: data.source }, wrappedResolve, rej);
629
- }
630
- });
824
+ return new Promise((res, rej) => {
825
+ const wrappedResolve = (response) => {
826
+ if (response.html) {
827
+ cache[data.source] = response;
828
+ }
829
+ return res({
830
+ url: data.source,
831
+ html: response.html ? response.html : dataToHtml(data)
832
+ });
833
+ };
834
+ if (cache[data.source]) {
835
+ wrappedResolve(cache[data.source]);
836
+ }
837
+ else {
838
+ handler({ url: data.source }).then(wrappedResolve).catch(rej);
839
+ }
840
+ });
631
841
  };
632
- const defaultPromise = (data, dataToHtml) => Promise.resolve({
633
- html: dataToHtml(data),
634
- url: data.source
635
- });
636
- const loadedData = editor => data => dataToHtml(editor, data);
842
+ const defaultPromise = (data, dataToHtml) => Promise.resolve({ html: dataToHtml(data), url: data.source });
843
+ const loadedData = (editor) => (data) => dataToHtml(editor, data);
637
844
  const getEmbedHtml = (editor, data) => {
638
- const embedHandler = getUrlResolver(editor);
639
- return embedHandler ? embedPromise(data, loadedData(editor), embedHandler) : defaultPromise(data, loadedData(editor));
845
+ const embedHandler = getUrlResolver(editor);
846
+ return embedHandler ? embedPromise(data, loadedData(editor), embedHandler) : defaultPromise(data, loadedData(editor));
640
847
  };
641
- const isCached = url => has(cache, url);
848
+ const isCached = (url) => has(cache, url);
642
849
 
643
- const extractMeta = (sourceInput, data) => get$1(data, sourceInput).bind(mainData => get$1(mainData, 'meta'));
644
- const getValue = (data, metaData, sourceInput) => prop => {
645
- const getFromData = () => get$1(data, prop);
646
- const getFromMetaData = () => get$1(metaData, prop);
647
- const getNonEmptyValue = c => get$1(c, 'value').bind(v => v.length > 0 ? Optional.some(v) : Optional.none());
648
- const getFromValueFirst = () => getFromData().bind(child => isObject(child) ? getNonEmptyValue(child).orThunk(getFromMetaData) : getFromMetaData().orThunk(() => Optional.from(child)));
649
- const getFromMetaFirst = () => getFromMetaData().orThunk(() => getFromData().bind(child => isObject(child) ? getNonEmptyValue(child) : Optional.from(child)));
650
- return { [prop]: (prop === sourceInput ? getFromValueFirst() : getFromMetaFirst()).getOr('') };
850
+ const extractMeta = (sourceInput, data) => get$1(data, sourceInput).bind((mainData) => get$1(mainData, 'meta'));
851
+ const getValue = (data, metaData, sourceInput) => (prop) => {
852
+ // Cases:
853
+ // 1. Get the nested value prop (component is the executed urlinput)
854
+ // 2. Get from metadata (a urlinput was executed but urlinput != this component)
855
+ // 3. Not a urlinput so just get string
856
+ // If prop === sourceInput do 1, 2 then 3, else do 2 then 1 or 3
857
+ // ASSUMPTION: we only want to get values for props that already exist in data
858
+ const getFromData = () => get$1(data, prop);
859
+ const getFromMetaData = () => get$1(metaData, prop);
860
+ const getNonEmptyValue = (c) => get$1(c, 'value').bind((v) => v.length > 0 ? Optional.some(v) : Optional.none());
861
+ const getFromValueFirst = () => getFromData().bind((child) => isObject(child)
862
+ ? getNonEmptyValue(child).orThunk(getFromMetaData)
863
+ : getFromMetaData().orThunk(() => Optional.from(child)));
864
+ const getFromMetaFirst = () => getFromMetaData().orThunk(() => getFromData().bind((child) => isObject(child)
865
+ ? getNonEmptyValue(child)
866
+ : Optional.from(child)));
867
+ return { [prop]: (prop === sourceInput ? getFromValueFirst() : getFromMetaFirst()).getOr('') };
651
868
  };
652
869
  const getDimensions = (data, metaData) => {
653
- const dimensions = {};
654
- get$1(data, 'dimensions').each(dims => {
655
- each$1([
656
- 'width',
657
- 'height'
658
- ], prop => {
659
- get$1(metaData, prop).orThunk(() => get$1(dims, prop)).each(value => dimensions[prop] = value);
870
+ const dimensions = {};
871
+ get$1(data, 'dimensions').each((dims) => {
872
+ each$1(['width', 'height'], (prop) => {
873
+ get$1(metaData, prop).orThunk(() => get$1(dims, prop)).each((value) => dimensions[prop] = value);
874
+ });
660
875
  });
661
- });
662
- return dimensions;
876
+ return dimensions;
663
877
  };
664
878
  const unwrap = (data, sourceInput) => {
665
- const metaData = sourceInput && sourceInput !== 'dimensions' ? extractMeta(sourceInput, data).getOr({}) : {};
666
- const get = getValue(data, metaData, sourceInput);
667
- return {
668
- ...get('source'),
669
- ...get('altsource'),
670
- ...get('poster'),
671
- ...get('embed'),
672
- ...getDimensions(data, metaData)
673
- };
879
+ const metaData = sourceInput && sourceInput !== 'dimensions' ? extractMeta(sourceInput, data).getOr({}) : {};
880
+ const get = getValue(data, metaData, sourceInput);
881
+ return {
882
+ ...get('source'),
883
+ ...get('altsource'),
884
+ ...get('poster'),
885
+ ...get('embed'),
886
+ ...getDimensions(data, metaData)
887
+ };
674
888
  };
675
- const wrap = data => {
676
- const wrapped = {
677
- ...data,
678
- source: { value: get$1(data, 'source').getOr('') },
679
- altsource: { value: get$1(data, 'altsource').getOr('') },
680
- poster: { value: get$1(data, 'poster').getOr('') }
681
- };
682
- each$1([
683
- 'width',
684
- 'height'
685
- ], prop => {
686
- get$1(data, prop).each(value => {
687
- const dimensions = wrapped.dimensions || {};
688
- dimensions[prop] = value;
689
- wrapped.dimensions = dimensions;
889
+ const wrap = (data) => {
890
+ const wrapped = {
891
+ ...data,
892
+ source: { value: get$1(data, 'source').getOr('') },
893
+ altsource: { value: get$1(data, 'altsource').getOr('') },
894
+ poster: { value: get$1(data, 'poster').getOr('') }
895
+ };
896
+ // Add additional size values that may or may not have been in the html
897
+ each$1(['width', 'height'], (prop) => {
898
+ get$1(data, prop).each((value) => {
899
+ const dimensions = wrapped.dimensions || {};
900
+ dimensions[prop] = value;
901
+ wrapped.dimensions = dimensions;
902
+ });
690
903
  });
691
- });
692
- return wrapped;
693
- };
694
- const handleError = editor => error => {
695
- const errorMessage = error && error.msg ? 'Media embed handler error: ' + error.msg : 'Media embed handler threw unknown error.';
696
- editor.notificationManager.open({
697
- type: 'error',
698
- text: errorMessage
699
- });
904
+ return wrapped;
700
905
  };
701
- const getEditorData = editor => {
702
- const element = editor.selection.getNode();
703
- const snippet = isMediaElement(element) ? editor.serializer.serialize(element, { selection: true }) : '';
704
- const data = htmlToData(snippet, editor.schema);
705
- const getDimensionsOfElement = () => {
706
- if (isEmbedIframe(data.source, data.type)) {
707
- const rect = editor.dom.getRect(element);
708
- return {
709
- width: rect.w.toString().replace(/px$/, ''),
710
- height: rect.h.toString().replace(/px$/, '')
711
- };
712
- } else {
713
- return {};
714
- }
715
- };
716
- const dimensions = getDimensionsOfElement();
717
- return {
718
- embed: snippet,
719
- ...data,
720
- ...dimensions
721
- };
906
+ const handleError = (editor) => (error) => {
907
+ const errorMessage = error && error.msg ?
908
+ 'Media embed handler error: ' + error.msg :
909
+ 'Media embed handler threw unknown error.';
910
+ editor.notificationManager.open({ type: 'error', text: errorMessage });
722
911
  };
723
- const addEmbedHtml = (api, editor) => response => {
724
- if (isString(response.url) && response.url.trim().length > 0) {
725
- const html = response.html;
726
- const snippetData = htmlToData(html, editor.schema);
727
- const nuData = {
728
- ...snippetData,
729
- source: response.url,
730
- embed: html
912
+ const getEditorData = (editor) => {
913
+ const element = editor.selection.getNode();
914
+ const snippet = isMediaElement(element) ? editor.serializer.serialize(element, { selection: true }) : '';
915
+ const data = htmlToData(snippet, editor.schema);
916
+ const getDimensionsOfElement = () => {
917
+ if (isEmbedIframe(data.source, data.type)) {
918
+ const rect = editor.dom.getRect(element);
919
+ return {
920
+ width: rect.w.toString().replace(/px$/, ''),
921
+ height: rect.h.toString().replace(/px$/, ''),
922
+ };
923
+ }
924
+ else {
925
+ return {};
926
+ }
731
927
  };
732
- api.setData(wrap(nuData));
733
- }
928
+ const dimensions = getDimensionsOfElement();
929
+ return {
930
+ embed: snippet,
931
+ ...data,
932
+ ...dimensions
933
+ };
934
+ };
935
+ const addEmbedHtml = (api, editor) => (response) => {
936
+ // Only set values if a URL has been defined
937
+ if (isString(response.url) && response.url.trim().length > 0) {
938
+ const html = response.html;
939
+ const snippetData = htmlToData(html, editor.schema);
940
+ const nuData = {
941
+ ...snippetData,
942
+ source: response.url,
943
+ embed: html
944
+ };
945
+ api.setData(wrap(nuData));
946
+ }
734
947
  };
735
948
  const selectPlaceholder = (editor, beforeObjects) => {
736
- const afterObjects = editor.dom.select('*[data-mce-object]');
737
- for (let i = 0; i < beforeObjects.length; i++) {
738
- for (let y = afterObjects.length - 1; y >= 0; y--) {
739
- if (beforeObjects[i] === afterObjects[y]) {
740
- afterObjects.splice(y, 1);
741
- }
742
- }
743
- }
744
- editor.selection.select(afterObjects[0]);
949
+ const afterObjects = editor.dom.select('*[data-mce-object]');
950
+ // Find new image placeholder so we can select it
951
+ for (let i = 0; i < beforeObjects.length; i++) {
952
+ for (let y = afterObjects.length - 1; y >= 0; y--) {
953
+ if (beforeObjects[i] === afterObjects[y]) {
954
+ afterObjects.splice(y, 1);
955
+ }
956
+ }
957
+ }
958
+ editor.selection.select(afterObjects[0]);
745
959
  };
746
960
  const handleInsert = (editor, html) => {
747
- const beforeObjects = editor.dom.select('*[data-mce-object]');
748
- editor.insertContent(html);
749
- selectPlaceholder(editor, beforeObjects);
750
- editor.nodeChanged();
961
+ const beforeObjects = editor.dom.select('*[data-mce-object]');
962
+ editor.insertContent(html);
963
+ selectPlaceholder(editor, beforeObjects);
964
+ editor.nodeChanged();
751
965
  };
752
966
  const isEmbedIframe = (url, mediaDataType) => isNonNullable(mediaDataType) && mediaDataType === 'ephox-embed-iri' && isNonNullable(matchPattern(url));
753
967
  const shouldInsertAsNewIframe = (prevData, newData) => {
754
- const hasDimensionsChanged = (prevData, newData) => prevData.width !== newData.width || prevData.height !== newData.height;
755
- return hasDimensionsChanged(prevData, newData) && isEmbedIframe(newData.source, prevData.type);
968
+ const hasDimensionsChanged = (prevData, newData) => prevData.width !== newData.width || prevData.height !== newData.height;
969
+ return hasDimensionsChanged(prevData, newData) && isEmbedIframe(newData.source, prevData.type);
756
970
  };
757
971
  const submitForm = (prevData, newData, editor) => {
758
- var _a;
759
- newData.embed = shouldInsertAsNewIframe(prevData, newData) && hasDimensions(editor) ? dataToHtml(editor, {
760
- ...newData,
761
- embed: ''
762
- }) : updateHtml((_a = newData.embed) !== null && _a !== void 0 ? _a : '', newData, false, editor.schema);
763
- if (newData.embed && (prevData.source === newData.source || isCached(newData.source))) {
764
- handleInsert(editor, newData.embed);
765
- } else {
766
- getEmbedHtml(editor, newData).then(response => {
767
- handleInsert(editor, response.html);
768
- }).catch(handleError(editor));
769
- }
770
- };
771
- const showDialog = editor => {
772
- const editorData = getEditorData(editor);
773
- const currentData = Cell(editorData);
774
- const initialData = wrap(editorData);
775
- const handleSource = (prevData, api) => {
776
- const serviceData = unwrap(api.getData(), 'source');
777
- if (prevData.source !== serviceData.source) {
778
- addEmbedHtml(win, editor)({
779
- url: serviceData.source,
780
- html: ''
781
- });
782
- getEmbedHtml(editor, serviceData).then(addEmbedHtml(win, editor)).catch(handleError(editor));
783
- }
784
- };
785
- const handleEmbed = api => {
786
972
  var _a;
787
- const data = unwrap(api.getData());
788
- const dataFromEmbed = htmlToData((_a = data.embed) !== null && _a !== void 0 ? _a : '', editor.schema);
789
- api.setData(wrap(dataFromEmbed));
790
- };
791
- const handleUpdate = (api, sourceInput, prevData) => {
792
- const dialogData = unwrap(api.getData(), sourceInput);
793
- const data = shouldInsertAsNewIframe(prevData, dialogData) && hasDimensions(editor) ? {
794
- ...dialogData,
795
- embed: ''
796
- } : dialogData;
797
- const embed = dataToHtml(editor, data);
798
- api.setData(wrap({
799
- ...data,
800
- embed
801
- }));
802
- };
803
- const mediaInput = [{
804
- name: 'source',
805
- type: 'urlinput',
806
- filetype: 'media',
807
- label: 'Source',
808
- picker_text: 'Browse files'
809
- }];
810
- const sizeInput = !hasDimensions(editor) ? [] : [{
811
- type: 'sizeinput',
812
- name: 'dimensions',
813
- label: 'Constrain proportions',
814
- constrain: true
815
- }];
816
- const generalTab = {
817
- title: 'General',
818
- name: 'general',
819
- items: flatten([
820
- mediaInput,
821
- sizeInput
822
- ])
823
- };
824
- const embedTextarea = {
825
- type: 'textarea',
826
- name: 'embed',
827
- label: 'Paste your embed code below:'
828
- };
829
- const embedTab = {
830
- title: 'Embed',
831
- items: [embedTextarea]
832
- };
833
- const advancedFormItems = [];
834
- if (hasAltSource(editor)) {
835
- advancedFormItems.push({
836
- name: 'altsource',
837
- type: 'urlinput',
838
- filetype: 'media',
839
- label: 'Alternative source URL'
840
- });
841
- }
842
- if (hasPoster(editor)) {
843
- advancedFormItems.push({
844
- name: 'poster',
845
- type: 'urlinput',
846
- filetype: 'image',
847
- label: 'Media poster (Image URL)'
848
- });
849
- }
850
- const advancedTab = {
851
- title: 'Advanced',
852
- name: 'advanced',
853
- items: advancedFormItems
854
- };
855
- const tabs = [
856
- generalTab,
857
- embedTab
858
- ];
859
- if (advancedFormItems.length > 0) {
860
- tabs.push(advancedTab);
861
- }
862
- const body = {
863
- type: 'tabpanel',
864
- tabs
865
- };
866
- const win = editor.windowManager.open({
867
- title: 'Insert/Edit Media',
868
- size: 'normal',
869
- body,
870
- buttons: [
871
- {
872
- type: 'cancel',
873
- name: 'cancel',
874
- text: 'Cancel'
875
- },
876
- {
877
- type: 'submit',
878
- name: 'save',
879
- text: 'Save',
880
- primary: true
881
- }
882
- ],
883
- onSubmit: api => {
884
- const serviceData = unwrap(api.getData());
885
- submitForm(currentData.get(), serviceData, editor);
886
- api.close();
887
- },
888
- onChange: (api, detail) => {
889
- switch (detail.name) {
890
- case 'source':
891
- handleSource(currentData.get(), api);
892
- break;
893
- case 'embed':
894
- handleEmbed(api);
895
- break;
896
- case 'dimensions':
897
- case 'altsource':
898
- case 'poster':
899
- handleUpdate(api, detail.name, currentData.get());
900
- break;
901
- }
902
- currentData.set(unwrap(api.getData()));
903
- },
904
- initialData
905
- });
973
+ newData.embed =
974
+ shouldInsertAsNewIframe(prevData, newData) && hasDimensions(editor)
975
+ ? dataToHtml(editor, { ...newData, embed: '' })
976
+ : updateHtml((_a = newData.embed) !== null && _a !== void 0 ? _a : '', newData, false, editor.schema);
977
+ // Only fetch the embed HTML content if the URL has changed from what it previously was
978
+ if (newData.embed && (prevData.source === newData.source || isCached(newData.source))) {
979
+ handleInsert(editor, newData.embed);
980
+ }
981
+ else {
982
+ getEmbedHtml(editor, newData)
983
+ .then((response) => {
984
+ handleInsert(editor, response.html);
985
+ }).catch(handleError(editor));
986
+ }
906
987
  };
907
-
908
- const get = editor => {
909
- const showDialog$1 = () => {
910
- showDialog(editor);
911
- };
912
- return { showDialog: showDialog$1 };
988
+ const showDialog = (editor) => {
989
+ const editorData = getEditorData(editor);
990
+ const currentData = Cell(editorData);
991
+ const initialData = wrap(editorData);
992
+ const handleSource = (prevData, api) => {
993
+ const serviceData = unwrap(api.getData(), 'source');
994
+ // If a new URL is entered, then clear the embed html and fetch the new data
995
+ if (prevData.source !== serviceData.source) {
996
+ addEmbedHtml(win, editor)({ url: serviceData.source, html: '' });
997
+ getEmbedHtml(editor, serviceData)
998
+ .then(addEmbedHtml(win, editor))
999
+ .catch(handleError(editor));
1000
+ }
1001
+ };
1002
+ const handleEmbed = (api) => {
1003
+ var _a;
1004
+ const data = unwrap(api.getData());
1005
+ const dataFromEmbed = htmlToData((_a = data.embed) !== null && _a !== void 0 ? _a : '', editor.schema);
1006
+ api.setData(wrap(dataFromEmbed));
1007
+ };
1008
+ const handleUpdate = (api, sourceInput, prevData) => {
1009
+ const dialogData = unwrap(api.getData(), sourceInput);
1010
+ const data = shouldInsertAsNewIframe(prevData, dialogData) && hasDimensions(editor)
1011
+ ? { ...dialogData, embed: '' }
1012
+ : dialogData;
1013
+ const embed = dataToHtml(editor, data);
1014
+ api.setData(wrap({
1015
+ ...data,
1016
+ embed
1017
+ }));
1018
+ };
1019
+ const mediaInput = [{
1020
+ name: 'source',
1021
+ type: 'urlinput',
1022
+ filetype: 'media',
1023
+ label: 'Source',
1024
+ picker_text: 'Browse files'
1025
+ }];
1026
+ const sizeInput = !hasDimensions(editor) ? [] : [{
1027
+ type: 'sizeinput',
1028
+ name: 'dimensions',
1029
+ label: 'Constrain proportions',
1030
+ constrain: true
1031
+ }];
1032
+ const generalTab = {
1033
+ title: 'General',
1034
+ name: 'general',
1035
+ items: flatten([mediaInput, sizeInput])
1036
+ };
1037
+ const embedTextarea = {
1038
+ type: 'textarea',
1039
+ name: 'embed',
1040
+ label: 'Paste your embed code below:'
1041
+ };
1042
+ const embedTab = {
1043
+ title: 'Embed',
1044
+ items: [
1045
+ embedTextarea
1046
+ ]
1047
+ };
1048
+ const advancedFormItems = [];
1049
+ if (hasAltSource(editor)) {
1050
+ advancedFormItems.push({
1051
+ name: 'altsource',
1052
+ type: 'urlinput',
1053
+ filetype: 'media',
1054
+ label: 'Alternative source URL'
1055
+ });
1056
+ }
1057
+ if (hasPoster(editor)) {
1058
+ advancedFormItems.push({
1059
+ name: 'poster',
1060
+ type: 'urlinput',
1061
+ filetype: 'image',
1062
+ label: 'Media poster (Image URL)'
1063
+ });
1064
+ }
1065
+ const advancedTab = {
1066
+ title: 'Advanced',
1067
+ name: 'advanced',
1068
+ items: advancedFormItems
1069
+ };
1070
+ const tabs = [
1071
+ generalTab,
1072
+ embedTab
1073
+ ];
1074
+ if (advancedFormItems.length > 0) {
1075
+ tabs.push(advancedTab);
1076
+ }
1077
+ const body = {
1078
+ type: 'tabpanel',
1079
+ tabs
1080
+ };
1081
+ const win = editor.windowManager.open({
1082
+ title: 'Insert/Edit Media',
1083
+ size: 'normal',
1084
+ body,
1085
+ buttons: [
1086
+ {
1087
+ type: 'cancel',
1088
+ name: 'cancel',
1089
+ text: 'Cancel'
1090
+ },
1091
+ {
1092
+ type: 'submit',
1093
+ name: 'save',
1094
+ text: 'Save',
1095
+ primary: true
1096
+ }
1097
+ ],
1098
+ onSubmit: (api) => {
1099
+ const serviceData = unwrap(api.getData());
1100
+ submitForm(currentData.get(), serviceData, editor);
1101
+ api.close();
1102
+ },
1103
+ onChange: (api, detail) => {
1104
+ switch (detail.name) {
1105
+ case 'source':
1106
+ handleSource(currentData.get(), api);
1107
+ break;
1108
+ case 'embed':
1109
+ handleEmbed(api);
1110
+ break;
1111
+ case 'dimensions':
1112
+ case 'altsource':
1113
+ case 'poster':
1114
+ handleUpdate(api, detail.name, currentData.get());
1115
+ break;
1116
+ }
1117
+ currentData.set(unwrap(api.getData()));
1118
+ },
1119
+ initialData
1120
+ });
913
1121
  };
914
1122
 
915
- const register$1 = editor => {
916
- const showDialog$1 = () => {
917
- showDialog(editor);
918
- };
919
- editor.addCommand('mceMedia', showDialog$1);
1123
+ const get = (editor) => {
1124
+ const showDialog$1 = () => {
1125
+ showDialog(editor);
1126
+ };
1127
+ return {
1128
+ showDialog: showDialog$1
1129
+ };
920
1130
  };
921
1131
 
922
- const checkRange = (str, substr, start) => substr === '' || str.length >= substr.length && str.substr(start, start + substr.length) === substr;
923
- const startsWith = (str, prefix) => {
924
- return checkRange(str, prefix, 0);
1132
+ const register$1 = (editor) => {
1133
+ const showDialog$1 = () => {
1134
+ showDialog(editor);
1135
+ };
1136
+ editor.addCommand('mceMedia', showDialog$1);
925
1137
  };
926
1138
 
927
1139
  var global = tinymce.util.Tools.resolve('tinymce.Env');
928
1140
 
929
- const isLiveEmbedNode = node => {
930
- const name = node.name;
931
- return name === 'iframe' || name === 'video' || name === 'audio';
1141
+ const isLiveEmbedNode = (node) => {
1142
+ const name = node.name;
1143
+ return name === 'iframe' || name === 'video' || name === 'audio';
932
1144
  };
933
1145
  const getDimension = (node, styles, dimension, defaultValue = null) => {
934
- const value = node.attr(dimension);
935
- if (isNonNullable(value)) {
936
- return value;
937
- } else if (!has(styles, dimension)) {
938
- return defaultValue;
939
- } else {
940
- return null;
941
- }
1146
+ const value = node.attr(dimension);
1147
+ if (isNonNullable(value)) {
1148
+ return value;
1149
+ }
1150
+ else if (!has(styles, dimension)) {
1151
+ return defaultValue;
1152
+ }
1153
+ else {
1154
+ return null;
1155
+ }
942
1156
  };
943
1157
  const setDimensions = (node, previewNode, styles) => {
944
- const useDefaults = previewNode.name === 'img' || node.name === 'video';
945
- const defaultWidth = useDefaults ? '300' : null;
946
- const fallbackHeight = node.name === 'audio' ? '30' : '150';
947
- const defaultHeight = useDefaults ? fallbackHeight : null;
948
- previewNode.attr({
949
- width: getDimension(node, styles, 'width', defaultWidth),
950
- height: getDimension(node, styles, 'height', defaultHeight)
951
- });
1158
+ // Apply dimensions for video elements to maintain legacy behaviour
1159
+ const useDefaults = previewNode.name === 'img' || node.name === 'video';
1160
+ // Determine the defaults
1161
+ const defaultWidth = useDefaults ? '300' : null;
1162
+ const fallbackHeight = node.name === 'audio' ? '30' : '150';
1163
+ const defaultHeight = useDefaults ? fallbackHeight : null;
1164
+ previewNode.attr({
1165
+ width: getDimension(node, styles, 'width', defaultWidth),
1166
+ height: getDimension(node, styles, 'height', defaultHeight)
1167
+ });
952
1168
  };
953
1169
  const appendNodeContent = (editor, nodeName, previewNode, html) => {
954
- const newNode = Parser(editor.schema).parse(html, { context: nodeName });
955
- while (newNode.firstChild) {
956
- previewNode.append(newNode.firstChild);
957
- }
1170
+ const newNode = Parser(editor.schema).parse(html, { context: nodeName });
1171
+ while (newNode.firstChild) {
1172
+ previewNode.append(newNode.firstChild);
1173
+ }
958
1174
  };
959
1175
  const createPlaceholderNode = (editor, node) => {
960
- const name = node.name;
961
- const placeHolder = new global$2('img', 1);
962
- retainAttributesAndInnerHtml(editor, node, placeHolder);
963
- setDimensions(node, placeHolder, {});
964
- placeHolder.attr({
965
- 'style': node.attr('style'),
966
- 'src': global.transparentSrc,
967
- 'data-mce-object': name,
968
- 'class': 'mce-object mce-object-' + name
969
- });
970
- return placeHolder;
1176
+ const name = node.name;
1177
+ const placeHolder = new global$2('img', 1);
1178
+ retainAttributesAndInnerHtml(editor, node, placeHolder);
1179
+ setDimensions(node, placeHolder, {});
1180
+ placeHolder.attr({
1181
+ 'style': node.attr('style'),
1182
+ 'src': global.transparentSrc,
1183
+ 'data-mce-object': name,
1184
+ 'class': 'mce-object mce-object-' + name
1185
+ });
1186
+ return placeHolder;
971
1187
  };
972
1188
  const createPreviewNode = (editor, node) => {
973
- var _a;
974
- const name = node.name;
975
- const previewWrapper = new global$2('span', 1);
976
- previewWrapper.attr({
977
- 'contentEditable': 'false',
978
- 'style': node.attr('style'),
979
- 'data-mce-object': name,
980
- 'class': 'mce-preview-object mce-object-' + name
981
- });
982
- retainAttributesAndInnerHtml(editor, node, previewWrapper);
983
- const styles = editor.dom.parseStyle((_a = node.attr('style')) !== null && _a !== void 0 ? _a : '');
984
- const previewNode = new global$2(name, 1);
985
- setDimensions(node, previewNode, styles);
986
- previewNode.attr({
987
- src: node.attr('src'),
988
- style: node.attr('style'),
989
- class: node.attr('class')
990
- });
991
- if (name === 'iframe') {
992
- previewNode.attr({
993
- allowfullscreen: node.attr('allowfullscreen'),
994
- frameborder: '0',
995
- sandbox: node.attr('sandbox')
1189
+ var _a;
1190
+ const name = node.name;
1191
+ const previewWrapper = new global$2('span', 1);
1192
+ previewWrapper.attr({
1193
+ 'contentEditable': 'false',
1194
+ 'style': node.attr('style'),
1195
+ 'data-mce-object': name,
1196
+ 'class': 'mce-preview-object mce-object-' + name
996
1197
  });
997
- } else {
998
- const attrs = [
999
- 'controls',
1000
- 'crossorigin',
1001
- 'currentTime',
1002
- 'loop',
1003
- 'muted',
1004
- 'poster',
1005
- 'preload'
1006
- ];
1007
- each$1(attrs, attrName => {
1008
- previewNode.attr(attrName, node.attr(attrName));
1198
+ retainAttributesAndInnerHtml(editor, node, previewWrapper);
1199
+ const styles = editor.dom.parseStyle((_a = node.attr('style')) !== null && _a !== void 0 ? _a : '');
1200
+ const previewNode = new global$2(name, 1);
1201
+ setDimensions(node, previewNode, styles);
1202
+ previewNode.attr({
1203
+ src: node.attr('src'),
1204
+ style: node.attr('style'),
1205
+ class: node.attr('class')
1009
1206
  });
1010
- const sanitizedHtml = previewWrapper.attr('data-mce-html');
1011
- if (isNonNullable(sanitizedHtml)) {
1012
- appendNodeContent(editor, name, previewNode, unescape(sanitizedHtml));
1013
- }
1014
- }
1015
- const shimNode = new global$2('span', 1);
1016
- shimNode.attr('class', 'mce-shim');
1017
- previewWrapper.append(previewNode);
1018
- previewWrapper.append(shimNode);
1019
- return previewWrapper;
1207
+ if (name === 'iframe') {
1208
+ previewNode.attr({
1209
+ allowfullscreen: node.attr('allowfullscreen'),
1210
+ frameborder: '0',
1211
+ sandbox: node.attr('sandbox'),
1212
+ referrerpolicy: node.attr('referrerpolicy')
1213
+ });
1214
+ }
1215
+ else {
1216
+ // Exclude autoplay as we don't want video/audio to play by default
1217
+ const attrs = ['controls', 'crossorigin', 'currentTime', 'loop', 'muted', 'poster', 'preload'];
1218
+ each$1(attrs, (attrName) => {
1219
+ previewNode.attr(attrName, node.attr(attrName));
1220
+ });
1221
+ // Recreate the child nodes using the sanitized inner HTML
1222
+ const sanitizedHtml = previewWrapper.attr('data-mce-html');
1223
+ if (isNonNullable(sanitizedHtml)) {
1224
+ appendNodeContent(editor, name, previewNode, unescape(sanitizedHtml));
1225
+ }
1226
+ }
1227
+ const shimNode = new global$2('span', 1);
1228
+ shimNode.attr('class', 'mce-shim');
1229
+ previewWrapper.append(previewNode);
1230
+ previewWrapper.append(shimNode);
1231
+ return previewWrapper;
1020
1232
  };
1021
1233
  const retainAttributesAndInnerHtml = (editor, sourceNode, targetNode) => {
1022
- var _a;
1023
- const attribs = (_a = sourceNode.attributes) !== null && _a !== void 0 ? _a : [];
1024
- let ai = attribs.length;
1025
- while (ai--) {
1026
- const attrName = attribs[ai].name;
1027
- let attrValue = attribs[ai].value;
1028
- if (attrName !== 'width' && attrName !== 'height' && attrName !== 'style' && !startsWith(attrName, 'data-mce-')) {
1029
- if (attrName === 'data' || attrName === 'src') {
1030
- attrValue = editor.convertURL(attrValue, attrName);
1031
- }
1032
- targetNode.attr('data-mce-p-' + attrName, attrValue);
1033
- }
1034
- }
1035
- const serializer = global$1({ inner: true }, editor.schema);
1036
- const tempNode = new global$2('div', 1);
1037
- each$1(sourceNode.children(), child => tempNode.append(child));
1038
- const innerHtml = serializer.serialize(tempNode);
1039
- if (innerHtml) {
1040
- targetNode.attr('data-mce-html', escape(innerHtml));
1041
- targetNode.empty();
1042
- }
1234
+ var _a;
1235
+ // Prefix all attributes except internal (data-mce-*), width, height and style since we
1236
+ // will add these to the placeholder
1237
+ const attribs = (_a = sourceNode.attributes) !== null && _a !== void 0 ? _a : [];
1238
+ let ai = attribs.length;
1239
+ while (ai--) {
1240
+ const attrName = attribs[ai].name;
1241
+ let attrValue = attribs[ai].value;
1242
+ if (attrName !== 'width' && attrName !== 'height' && attrName !== 'style' && !startsWith(attrName, 'data-mce-')) {
1243
+ if (attrName === 'data' || attrName === 'src') {
1244
+ attrValue = editor.convertURL(attrValue, attrName);
1245
+ }
1246
+ targetNode.attr('data-mce-p-' + attrName, attrValue);
1247
+ }
1248
+ }
1249
+ // Place the inner HTML contents inside an escaped attribute
1250
+ // This enables us to copy/paste the fake object
1251
+ const serializer = global$1({ inner: true }, editor.schema);
1252
+ const tempNode = new global$2('div', 1);
1253
+ each$1(sourceNode.children(), (child) => tempNode.append(child));
1254
+ const innerHtml = serializer.serialize(tempNode);
1255
+ if (innerHtml) {
1256
+ targetNode.attr('data-mce-html', escape(innerHtml));
1257
+ targetNode.empty();
1258
+ }
1043
1259
  };
1044
- const isPageEmbedWrapper = node => {
1045
- const nodeClass = node.attr('class');
1046
- return isString(nodeClass) && /\btiny-pageembed\b/.test(nodeClass);
1260
+ const isPageEmbedWrapper = (node) => {
1261
+ const nodeClass = node.attr('class');
1262
+ return isString(nodeClass) && /\btiny-pageembed\b/.test(nodeClass);
1047
1263
  };
1048
- const isWithinEmbedWrapper = node => {
1049
- let tempNode = node;
1050
- while (tempNode = tempNode.parent) {
1051
- if (tempNode.attr('data-ephox-embed-iri') || isPageEmbedWrapper(tempNode)) {
1052
- return true;
1053
- }
1054
- }
1055
- return false;
1264
+ const isWithinEmbedWrapper = (node) => {
1265
+ let tempNode = node;
1266
+ while ((tempNode = tempNode.parent)) {
1267
+ if (tempNode.attr('data-ephox-embed-iri') || isPageEmbedWrapper(tempNode)) {
1268
+ return true;
1269
+ }
1270
+ }
1271
+ return false;
1056
1272
  };
1057
- const placeHolderConverter = editor => nodes => {
1058
- let i = nodes.length;
1059
- let node;
1060
- while (i--) {
1061
- node = nodes[i];
1062
- if (!node.parent) {
1063
- continue;
1064
- }
1065
- if (node.parent.attr('data-mce-object')) {
1066
- continue;
1067
- }
1068
- if (isLiveEmbedNode(node) && hasLiveEmbeds(editor)) {
1069
- if (!isWithinEmbedWrapper(node)) {
1070
- node.replace(createPreviewNode(editor, node));
1071
- }
1072
- } else {
1073
- if (!isWithinEmbedWrapper(node)) {
1074
- node.replace(createPlaceholderNode(editor, node));
1075
- }
1076
- }
1077
- }
1273
+ const placeHolderConverter = (editor) => (nodes) => {
1274
+ let i = nodes.length;
1275
+ let node;
1276
+ while (i--) {
1277
+ node = nodes[i];
1278
+ if (!node.parent) {
1279
+ continue;
1280
+ }
1281
+ if (node.parent.attr('data-mce-object')) {
1282
+ continue;
1283
+ }
1284
+ if (isLiveEmbedNode(node) && hasLiveEmbeds(editor)) {
1285
+ if (!isWithinEmbedWrapper(node)) {
1286
+ node.replace(createPreviewNode(editor, node));
1287
+ }
1288
+ }
1289
+ else {
1290
+ if (!isWithinEmbedWrapper(node)) {
1291
+ node.replace(createPlaceholderNode(editor, node));
1292
+ }
1293
+ }
1294
+ }
1078
1295
  };
1079
1296
 
1080
- const parseAndSanitize = (editor, context, html) => {
1081
- const getEditorOption = editor.options.get;
1082
- const sanitize = getEditorOption('xss_sanitization');
1083
- const validate = shouldFilterHtml(editor);
1084
- return Parser(editor.schema, {
1085
- sanitize,
1086
- validate
1087
- }).parse(html, { context });
1297
+ const parseAndSanitize = (editor, html) => {
1298
+ const getEditorOption = editor.options.get;
1299
+ const sanitize = getEditorOption('xss_sanitization');
1300
+ const validate = shouldFilterHtml(editor);
1301
+ return Parser(editor.schema, { sanitize, validate }).parse(html);
1088
1302
  };
1089
1303
 
1090
- const setup$1 = editor => {
1091
- editor.on('PreInit', () => {
1092
- const {schema, serializer, parser} = editor;
1093
- const boolAttrs = schema.getBoolAttrs();
1094
- each$1('webkitallowfullscreen mozallowfullscreen'.split(' '), name => {
1095
- boolAttrs[name] = {};
1096
- });
1097
- each({ embed: ['wmode'] }, (attrs, name) => {
1098
- const rule = schema.getElementRule(name);
1099
- if (rule) {
1100
- each$1(attrs, attr => {
1101
- rule.attributes[attr] = {};
1102
- rule.attributesOrder.push(attr);
1103
- });
1104
- }
1105
- });
1106
- parser.addNodeFilter('iframe,video,audio,object,embed', placeHolderConverter(editor));
1107
- serializer.addAttributeFilter('data-mce-object', (nodes, name) => {
1108
- var _a;
1109
- let i = nodes.length;
1110
- while (i--) {
1111
- const node = nodes[i];
1112
- if (!node.parent) {
1113
- continue;
1304
+ const buildMediaElement = (editor, node) => {
1305
+ var _a;
1306
+ const realElmName = node.attr('data-mce-object');
1307
+ const element = document.createElement(realElmName);
1308
+ // Add width/height to everything but audio
1309
+ if (realElmName !== 'audio') {
1310
+ const className = node.attr('class');
1311
+ const firstChild = node.firstChild;
1312
+ if (className && className.indexOf('mce-preview-object') !== -1 && firstChild) {
1313
+ const width = firstChild.attr('width');
1314
+ const height = firstChild.attr('height');
1315
+ if (isString(width)) {
1316
+ element.setAttribute('width', width);
1317
+ }
1318
+ if (isString(height)) {
1319
+ element.setAttribute('height', height);
1320
+ }
1114
1321
  }
1115
- const realElmName = node.attr(name);
1116
- const realElm = new global$2(realElmName, 1);
1117
- if (realElmName !== 'audio') {
1118
- const className = node.attr('class');
1119
- if (className && className.indexOf('mce-preview-object') !== -1 && node.firstChild) {
1120
- realElm.attr({
1121
- width: node.firstChild.attr('width'),
1122
- height: node.firstChild.attr('height')
1123
- });
1124
- } else {
1125
- realElm.attr({
1126
- width: node.attr('width'),
1127
- height: node.attr('height')
1128
- });
1129
- }
1322
+ else {
1323
+ const width = node.attr('width');
1324
+ const height = node.attr('height');
1325
+ if (isString(width)) {
1326
+ element.setAttribute('width', width);
1327
+ }
1328
+ if (isString(height)) {
1329
+ element.setAttribute('height', height);
1330
+ }
1130
1331
  }
1131
- realElm.attr({ style: node.attr('style') });
1132
- const attribs = (_a = node.attributes) !== null && _a !== void 0 ? _a : [];
1133
- let ai = attribs.length;
1134
- while (ai--) {
1135
- const attrName = attribs[ai].name;
1136
- if (attrName.indexOf('data-mce-p-') === 0) {
1137
- realElm.attr(attrName.substr(11), attribs[ai].value);
1138
- }
1332
+ }
1333
+ const style = node.attr('style');
1334
+ if (isString(style)) {
1335
+ element.setAttribute('style', style);
1336
+ }
1337
+ // Unprefix all placeholder attributes
1338
+ const attribs = (_a = node.attributes) !== null && _a !== void 0 ? _a : [];
1339
+ let ai = attribs.length;
1340
+ while (ai--) {
1341
+ const attrName = attribs[ai].name;
1342
+ if (attrName.indexOf('data-mce-p-') === 0) {
1343
+ element.setAttribute(attrName.substr(11), attribs[ai].value);
1139
1344
  }
1140
- const innerHtml = node.attr('data-mce-html');
1141
- if (innerHtml) {
1142
- const fragment = parseAndSanitize(editor, realElmName, unescape(innerHtml));
1143
- each$1(fragment.children(), child => realElm.append(child));
1345
+ }
1346
+ // Inject innerhtml
1347
+ const innerHtml = node.attr('data-mce-html');
1348
+ if (isString(innerHtml)) {
1349
+ element.innerHTML = unescape(innerHtml);
1350
+ }
1351
+ else {
1352
+ element.innerHTML = '\u00a0';
1353
+ }
1354
+ const fragment = parseAndSanitize(editor, element.outerHTML);
1355
+ const newElement = fragment.getAll(realElmName)[0];
1356
+ if (isNonNullable(newElement)) {
1357
+ if (!isString(innerHtml)) {
1358
+ newElement.empty();
1144
1359
  }
1145
- node.replace(realElm);
1146
- }
1360
+ return Optional.some(newElement);
1361
+ }
1362
+ else {
1363
+ return Optional.none();
1364
+ }
1365
+ };
1366
+ const setup$1 = (editor) => {
1367
+ editor.on('PreInit', () => {
1368
+ const { schema, serializer, parser } = editor;
1369
+ // Set browser specific allowFullscreen attribs as boolean
1370
+ const boolAttrs = schema.getBoolAttrs();
1371
+ each$1('webkitallowfullscreen mozallowfullscreen'.split(' '), (name) => {
1372
+ boolAttrs[name] = {};
1373
+ });
1374
+ // Add some non-standard attributes to the schema
1375
+ each({
1376
+ embed: ['wmode']
1377
+ }, (attrs, name) => {
1378
+ const rule = schema.getElementRule(name);
1379
+ if (rule) {
1380
+ each$1(attrs, (attr) => {
1381
+ rule.attributes[attr] = {};
1382
+ rule.attributesOrder.push(attr);
1383
+ });
1384
+ }
1385
+ });
1386
+ // Converts iframe, video etc into placeholder images
1387
+ parser.addNodeFilter('iframe,video,audio,object,embed', placeHolderConverter(editor));
1388
+ // Replaces placeholder images with real elements for video, object, iframe etc
1389
+ serializer.addAttributeFilter('data-mce-object', (nodes) => {
1390
+ let i = nodes.length;
1391
+ while (i--) {
1392
+ const node = nodes[i];
1393
+ if (!node.parent) {
1394
+ continue;
1395
+ }
1396
+ buildMediaElement(editor, node).fold(() => node.remove(), (realElm) => node.replace(realElm));
1397
+ }
1398
+ });
1147
1399
  });
1148
- });
1149
- editor.on('SetContent', () => {
1150
- const dom = editor.dom;
1151
- each$1(dom.select('span.mce-preview-object'), elm => {
1152
- if (dom.select('span.mce-shim', elm).length === 0) {
1153
- dom.add(elm, 'span', { class: 'mce-shim' });
1154
- }
1400
+ editor.on('SetContent', () => {
1401
+ // TODO: This shouldn't be needed there should be a way to mark bogus
1402
+ // elements so they are never removed except external save
1403
+ const dom = editor.dom;
1404
+ each$1(dom.select('span.mce-preview-object'), (elm) => {
1405
+ if (dom.select('span.mce-shim', elm).length === 0) {
1406
+ dom.add(elm, 'span', { class: 'mce-shim' });
1407
+ }
1408
+ });
1155
1409
  });
1156
- });
1157
1410
  };
1158
1411
 
1159
- const setup = editor => {
1160
- editor.on('ResolveName', e => {
1161
- let name;
1162
- if (e.target.nodeType === 1 && (name = e.target.getAttribute('data-mce-object'))) {
1163
- e.name = name;
1164
- }
1165
- });
1412
+ const setup = (editor) => {
1413
+ editor.on('ResolveName', (e) => {
1414
+ let name;
1415
+ if (e.target.nodeType === 1 && (name = e.target.getAttribute('data-mce-object'))) {
1416
+ e.name = name;
1417
+ }
1418
+ });
1166
1419
  };
1167
1420
 
1168
- const onSetupEditable = editor => api => {
1169
- const nodeChanged = () => {
1170
- api.setEnabled(editor.selection.isEditable());
1171
- };
1172
- editor.on('NodeChange', nodeChanged);
1173
- nodeChanged();
1174
- return () => {
1175
- editor.off('NodeChange', nodeChanged);
1176
- };
1421
+ const onSetupEditable = (editor) => (api) => {
1422
+ const nodeChanged = () => {
1423
+ api.setEnabled(editor.selection.isEditable());
1424
+ };
1425
+ editor.on('NodeChange', nodeChanged);
1426
+ nodeChanged();
1427
+ return () => {
1428
+ editor.off('NodeChange', nodeChanged);
1429
+ };
1177
1430
  };
1178
- const register = editor => {
1179
- const onAction = () => editor.execCommand('mceMedia');
1180
- editor.ui.registry.addToggleButton('media', {
1181
- tooltip: 'Insert/edit media',
1182
- icon: 'embed',
1183
- onAction,
1184
- onSetup: buttonApi => {
1185
- const selection = editor.selection;
1186
- buttonApi.setActive(isMediaElement(selection.getNode()));
1187
- const unbindSelectorChanged = selection.selectorChangedWithUnbind('img[data-mce-object],span[data-mce-object],div[data-ephox-embed-iri]', buttonApi.setActive).unbind;
1188
- const unbindEditable = onSetupEditable(editor)(buttonApi);
1189
- return () => {
1190
- unbindSelectorChanged();
1191
- unbindEditable();
1192
- };
1193
- }
1194
- });
1195
- editor.ui.registry.addMenuItem('media', {
1196
- icon: 'embed',
1197
- text: 'Media...',
1198
- onAction,
1199
- onSetup: onSetupEditable(editor)
1200
- });
1431
+ const register = (editor) => {
1432
+ const onAction = () => editor.execCommand('mceMedia');
1433
+ editor.ui.registry.addToggleButton('media', {
1434
+ tooltip: 'Insert/edit media',
1435
+ icon: 'embed',
1436
+ onAction,
1437
+ onSetup: (buttonApi) => {
1438
+ const selection = editor.selection;
1439
+ buttonApi.setActive(isMediaElement(selection.getNode()));
1440
+ const unbindSelectorChanged = selection.selectorChangedWithUnbind('img[data-mce-object],span[data-mce-object],div[data-ephox-embed-iri]', buttonApi.setActive).unbind;
1441
+ const unbindEditable = onSetupEditable(editor)(buttonApi);
1442
+ return () => {
1443
+ unbindSelectorChanged();
1444
+ unbindEditable();
1445
+ };
1446
+ }
1447
+ });
1448
+ editor.ui.registry.addMenuItem('media', {
1449
+ icon: 'embed',
1450
+ text: 'Media...',
1451
+ onAction,
1452
+ onSetup: onSetupEditable(editor)
1453
+ });
1201
1454
  };
1202
1455
 
1203
1456
  var Plugin = () => {
1204
- global$6.add('media', editor => {
1205
- register$2(editor);
1206
- register$1(editor);
1207
- register(editor);
1208
- setup(editor);
1209
- setup$1(editor);
1210
- setup$2(editor);
1211
- return get(editor);
1212
- });
1457
+ global$6.add('media', (editor) => {
1458
+ register$2(editor);
1459
+ register$1(editor);
1460
+ register(editor);
1461
+ setup(editor);
1462
+ setup$1(editor);
1463
+ setup$2(editor);
1464
+ return get(editor);
1465
+ });
1213
1466
  };
1214
1467
 
1215
1468
  Plugin();
1469
+ /** *****
1470
+ * DO NOT EXPORT ANYTHING
1471
+ *
1472
+ * IF YOU DO ROLLUP WILL LEAVE A GLOBAL ON THE PAGE
1473
+ *******/
1216
1474
 
1217
1475
  })();