@ckeditor/ckeditor5-html-embed 47.6.1 → 48.0.0-alpha.1

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 (168) hide show
  1. package/ckeditor5-metadata.json +2 -2
  2. package/{src → dist}/htmlembed.d.ts +2 -2
  3. package/{src → dist}/htmlembedcommand.d.ts +1 -1
  4. package/{src → dist}/htmlembedediting.d.ts +1 -1
  5. package/{src → dist}/htmlembedui.d.ts +1 -1
  6. package/dist/index-editor.css +165 -35
  7. package/dist/index.css +164 -56
  8. package/dist/index.css.map +1 -1
  9. package/dist/index.js.map +1 -1
  10. package/package.json +24 -47
  11. package/build/html-embed.js +0 -5
  12. package/build/translations/af.js +0 -1
  13. package/build/translations/ar.js +0 -1
  14. package/build/translations/ast.js +0 -1
  15. package/build/translations/az.js +0 -1
  16. package/build/translations/be.js +0 -1
  17. package/build/translations/bg.js +0 -1
  18. package/build/translations/bn.js +0 -1
  19. package/build/translations/bs.js +0 -1
  20. package/build/translations/ca.js +0 -1
  21. package/build/translations/cs.js +0 -1
  22. package/build/translations/da.js +0 -1
  23. package/build/translations/de-ch.js +0 -1
  24. package/build/translations/de.js +0 -1
  25. package/build/translations/el.js +0 -1
  26. package/build/translations/en-au.js +0 -1
  27. package/build/translations/en-gb.js +0 -1
  28. package/build/translations/eo.js +0 -1
  29. package/build/translations/es-co.js +0 -1
  30. package/build/translations/es.js +0 -1
  31. package/build/translations/et.js +0 -1
  32. package/build/translations/eu.js +0 -1
  33. package/build/translations/fa.js +0 -1
  34. package/build/translations/fi.js +0 -1
  35. package/build/translations/fr.js +0 -1
  36. package/build/translations/gl.js +0 -1
  37. package/build/translations/gu.js +0 -1
  38. package/build/translations/he.js +0 -1
  39. package/build/translations/hi.js +0 -1
  40. package/build/translations/hr.js +0 -1
  41. package/build/translations/hu.js +0 -1
  42. package/build/translations/hy.js +0 -1
  43. package/build/translations/id.js +0 -1
  44. package/build/translations/it.js +0 -1
  45. package/build/translations/ja.js +0 -1
  46. package/build/translations/jv.js +0 -1
  47. package/build/translations/kk.js +0 -1
  48. package/build/translations/km.js +0 -1
  49. package/build/translations/kn.js +0 -1
  50. package/build/translations/ko.js +0 -1
  51. package/build/translations/ku.js +0 -1
  52. package/build/translations/lt.js +0 -1
  53. package/build/translations/lv.js +0 -1
  54. package/build/translations/ms.js +0 -1
  55. package/build/translations/nb.js +0 -1
  56. package/build/translations/ne.js +0 -1
  57. package/build/translations/nl.js +0 -1
  58. package/build/translations/no.js +0 -1
  59. package/build/translations/oc.js +0 -1
  60. package/build/translations/pl.js +0 -1
  61. package/build/translations/pt-br.js +0 -1
  62. package/build/translations/pt.js +0 -1
  63. package/build/translations/ro.js +0 -1
  64. package/build/translations/ru.js +0 -1
  65. package/build/translations/si.js +0 -1
  66. package/build/translations/sk.js +0 -1
  67. package/build/translations/sl.js +0 -1
  68. package/build/translations/sq.js +0 -1
  69. package/build/translations/sr-latn.js +0 -1
  70. package/build/translations/sr.js +0 -1
  71. package/build/translations/sv.js +0 -1
  72. package/build/translations/th.js +0 -1
  73. package/build/translations/ti.js +0 -1
  74. package/build/translations/tk.js +0 -1
  75. package/build/translations/tr.js +0 -1
  76. package/build/translations/tt.js +0 -1
  77. package/build/translations/ug.js +0 -1
  78. package/build/translations/uk.js +0 -1
  79. package/build/translations/ur.js +0 -1
  80. package/build/translations/uz.js +0 -1
  81. package/build/translations/vi.js +0 -1
  82. package/build/translations/zh-cn.js +0 -1
  83. package/build/translations/zh.js +0 -1
  84. package/lang/contexts.json +0 -9
  85. package/lang/translations/af.po +0 -40
  86. package/lang/translations/ar.po +0 -40
  87. package/lang/translations/ast.po +0 -40
  88. package/lang/translations/az.po +0 -40
  89. package/lang/translations/be.po +0 -40
  90. package/lang/translations/bg.po +0 -40
  91. package/lang/translations/bn.po +0 -40
  92. package/lang/translations/bs.po +0 -40
  93. package/lang/translations/ca.po +0 -40
  94. package/lang/translations/cs.po +0 -40
  95. package/lang/translations/da.po +0 -40
  96. package/lang/translations/de-ch.po +0 -40
  97. package/lang/translations/de.po +0 -40
  98. package/lang/translations/el.po +0 -40
  99. package/lang/translations/en-au.po +0 -40
  100. package/lang/translations/en-gb.po +0 -40
  101. package/lang/translations/en.po +0 -40
  102. package/lang/translations/eo.po +0 -40
  103. package/lang/translations/es-co.po +0 -40
  104. package/lang/translations/es.po +0 -40
  105. package/lang/translations/et.po +0 -40
  106. package/lang/translations/eu.po +0 -40
  107. package/lang/translations/fa.po +0 -40
  108. package/lang/translations/fi.po +0 -40
  109. package/lang/translations/fr.po +0 -40
  110. package/lang/translations/gl.po +0 -40
  111. package/lang/translations/gu.po +0 -40
  112. package/lang/translations/he.po +0 -40
  113. package/lang/translations/hi.po +0 -40
  114. package/lang/translations/hr.po +0 -40
  115. package/lang/translations/hu.po +0 -40
  116. package/lang/translations/hy.po +0 -40
  117. package/lang/translations/id.po +0 -40
  118. package/lang/translations/it.po +0 -40
  119. package/lang/translations/ja.po +0 -40
  120. package/lang/translations/jv.po +0 -40
  121. package/lang/translations/kk.po +0 -40
  122. package/lang/translations/km.po +0 -40
  123. package/lang/translations/kn.po +0 -40
  124. package/lang/translations/ko.po +0 -40
  125. package/lang/translations/ku.po +0 -40
  126. package/lang/translations/lt.po +0 -40
  127. package/lang/translations/lv.po +0 -40
  128. package/lang/translations/ms.po +0 -40
  129. package/lang/translations/nb.po +0 -40
  130. package/lang/translations/ne.po +0 -40
  131. package/lang/translations/nl.po +0 -40
  132. package/lang/translations/no.po +0 -40
  133. package/lang/translations/oc.po +0 -40
  134. package/lang/translations/pl.po +0 -40
  135. package/lang/translations/pt-br.po +0 -40
  136. package/lang/translations/pt.po +0 -40
  137. package/lang/translations/ro.po +0 -40
  138. package/lang/translations/ru.po +0 -40
  139. package/lang/translations/si.po +0 -40
  140. package/lang/translations/sk.po +0 -40
  141. package/lang/translations/sl.po +0 -40
  142. package/lang/translations/sq.po +0 -40
  143. package/lang/translations/sr-latn.po +0 -40
  144. package/lang/translations/sr.po +0 -40
  145. package/lang/translations/sv.po +0 -40
  146. package/lang/translations/th.po +0 -40
  147. package/lang/translations/ti.po +0 -40
  148. package/lang/translations/tk.po +0 -40
  149. package/lang/translations/tr.po +0 -40
  150. package/lang/translations/tt.po +0 -40
  151. package/lang/translations/ug.po +0 -40
  152. package/lang/translations/uk.po +0 -40
  153. package/lang/translations/ur.po +0 -40
  154. package/lang/translations/uz.po +0 -40
  155. package/lang/translations/vi.po +0 -40
  156. package/lang/translations/zh-cn.po +0 -40
  157. package/lang/translations/zh.po +0 -40
  158. package/src/augmentation.js +0 -5
  159. package/src/htmlembed.js +0 -38
  160. package/src/htmlembedcommand.js +0 -95
  161. package/src/htmlembedconfig.js +0 -5
  162. package/src/htmlembedediting.js +0 -347
  163. package/src/htmlembedui.js +0 -73
  164. package/src/index.js +0 -12
  165. package/theme/htmlembed.css +0 -68
  166. /package/{src → dist}/augmentation.d.ts +0 -0
  167. /package/{src → dist}/htmlembedconfig.d.ts +0 -0
  168. /package/{src → dist}/index.d.ts +0 -0
@@ -1,40 +0,0 @@
1
- # Copyright (c) 2003-2026, CKSource Holding sp. z o.o. All rights reserved.
2
- #
3
- # Want to contribute to this file? Submit your changes via a GitHub Pull Request.
4
- #
5
- # Check out the official contributor's guide:
6
- # https://ckeditor.com/docs/ckeditor5/latest/framework/guides/contributing/contributing.html
7
- #
8
- msgid ""
9
- msgstr ""
10
- "Language: uz\n"
11
- "Plural-Forms: nplurals=2; plural=(n > 1);\n"
12
- "Content-Type: text/plain; charset=UTF-8\n"
13
-
14
- msgctxt "Toolbar button tooltip for the HTML embed feature."
15
- msgid "Insert HTML"
16
- msgstr "HTML kiritish"
17
-
18
- msgctxt "The HTML snippet."
19
- msgid "HTML snippet"
20
- msgstr "HTML snippet"
21
-
22
- msgctxt "A placeholder that will be displayed in the raw HTML textarea field."
23
- msgid "Paste raw HTML here..."
24
- msgstr "HTML kodini shu yerga joylashtiring..."
25
-
26
- msgctxt "A label of a button that switches the HTML embed to the source editing mode."
27
- msgid "Edit source"
28
- msgstr "Kodni o'zgartirish"
29
-
30
- msgctxt "A label of a button that saves the HTML embed content and navigates back to the preview."
31
- msgid "Save changes"
32
- msgstr "O'zgarishlarni saqlash"
33
-
34
- msgctxt "An information displayed in the HTML embed preview if the content is not previewable."
35
- msgid "No preview available"
36
- msgstr ""
37
-
38
- msgctxt "An information displayed in the HTML embed preview if the HTML snippet has no content."
39
- msgid "Empty snippet content"
40
- msgstr ""
@@ -1,40 +0,0 @@
1
- # Copyright (c) 2003-2026, CKSource Holding sp. z o.o. All rights reserved.
2
- #
3
- # Want to contribute to this file? Submit your changes via a GitHub Pull Request.
4
- #
5
- # Check out the official contributor's guide:
6
- # https://ckeditor.com/docs/ckeditor5/latest/framework/guides/contributing/contributing.html
7
- #
8
- msgid ""
9
- msgstr ""
10
- "Language: vi\n"
11
- "Plural-Forms: nplurals=1; plural=0;\n"
12
- "Content-Type: text/plain; charset=UTF-8\n"
13
-
14
- msgctxt "Toolbar button tooltip for the HTML embed feature."
15
- msgid "Insert HTML"
16
- msgstr "Chèn HTML"
17
-
18
- msgctxt "The HTML snippet."
19
- msgid "HTML snippet"
20
- msgstr "Mẫu HTML"
21
-
22
- msgctxt "A placeholder that will be displayed in the raw HTML textarea field."
23
- msgid "Paste raw HTML here..."
24
- msgstr "Dán mã HTML nguyên bản tại đây..."
25
-
26
- msgctxt "A label of a button that switches the HTML embed to the source editing mode."
27
- msgid "Edit source"
28
- msgstr "Sửa nguồn"
29
-
30
- msgctxt "A label of a button that saves the HTML embed content and navigates back to the preview."
31
- msgid "Save changes"
32
- msgstr "Lưu thay đổi"
33
-
34
- msgctxt "An information displayed in the HTML embed preview if the content is not previewable."
35
- msgid "No preview available"
36
- msgstr "Không có sẵn bản xem trước"
37
-
38
- msgctxt "An information displayed in the HTML embed preview if the HTML snippet has no content."
39
- msgid "Empty snippet content"
40
- msgstr "Nội dung đoạn mã trống"
@@ -1,40 +0,0 @@
1
- # Copyright (c) 2003-2026, CKSource Holding sp. z o.o. All rights reserved.
2
- #
3
- # Want to contribute to this file? Submit your changes via a GitHub Pull Request.
4
- #
5
- # Check out the official contributor's guide:
6
- # https://ckeditor.com/docs/ckeditor5/latest/framework/guides/contributing/contributing.html
7
- #
8
- msgid ""
9
- msgstr ""
10
- "Language: zh_CN\n"
11
- "Plural-Forms: nplurals=1; plural=0;\n"
12
- "Content-Type: text/plain; charset=UTF-8\n"
13
-
14
- msgctxt "Toolbar button tooltip for the HTML embed feature."
15
- msgid "Insert HTML"
16
- msgstr "插入 HTML"
17
-
18
- msgctxt "The HTML snippet."
19
- msgid "HTML snippet"
20
- msgstr "HTML 代码片段"
21
-
22
- msgctxt "A placeholder that will be displayed in the raw HTML textarea field."
23
- msgid "Paste raw HTML here..."
24
- msgstr "在这里粘贴 HTML 源代码"
25
-
26
- msgctxt "A label of a button that switches the HTML embed to the source editing mode."
27
- msgid "Edit source"
28
- msgstr "编辑源代码"
29
-
30
- msgctxt "A label of a button that saves the HTML embed content and navigates back to the preview."
31
- msgid "Save changes"
32
- msgstr "保存更改"
33
-
34
- msgctxt "An information displayed in the HTML embed preview if the content is not previewable."
35
- msgid "No preview available"
36
- msgstr "预览不可用"
37
-
38
- msgctxt "An information displayed in the HTML embed preview if the HTML snippet has no content."
39
- msgid "Empty snippet content"
40
- msgstr "空片段内容"
@@ -1,40 +0,0 @@
1
- # Copyright (c) 2003-2026, CKSource Holding sp. z o.o. All rights reserved.
2
- #
3
- # Want to contribute to this file? Submit your changes via a GitHub Pull Request.
4
- #
5
- # Check out the official contributor's guide:
6
- # https://ckeditor.com/docs/ckeditor5/latest/framework/guides/contributing/contributing.html
7
- #
8
- msgid ""
9
- msgstr ""
10
- "Language: zh_TW\n"
11
- "Plural-Forms: nplurals=1; plural=0;\n"
12
- "Content-Type: text/plain; charset=UTF-8\n"
13
-
14
- msgctxt "Toolbar button tooltip for the HTML embed feature."
15
- msgid "Insert HTML"
16
- msgstr "輸入HTML"
17
-
18
- msgctxt "The HTML snippet."
19
- msgid "HTML snippet"
20
- msgstr "HTML標籤"
21
-
22
- msgctxt "A placeholder that will be displayed in the raw HTML textarea field."
23
- msgid "Paste raw HTML here..."
24
- msgstr "在此貼上純HTML"
25
-
26
- msgctxt "A label of a button that switches the HTML embed to the source editing mode."
27
- msgid "Edit source"
28
- msgstr "編輯HTML"
29
-
30
- msgctxt "A label of a button that saves the HTML embed content and navigates back to the preview."
31
- msgid "Save changes"
32
- msgstr "儲存變更"
33
-
34
- msgctxt "An information displayed in the HTML embed preview if the content is not previewable."
35
- msgid "No preview available"
36
- msgstr "無法顯示預覽"
37
-
38
- msgctxt "An information displayed in the HTML embed preview if the HTML snippet has no content."
39
- msgid "Empty snippet content"
40
- msgstr "HTML標籤中無內容"
@@ -1,5 +0,0 @@
1
- /**
2
- * @license Copyright (c) 2003-2026, CKSource Holding sp. z o.o. All rights reserved.
3
- * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-licensing-options
4
- */
5
- export {};
package/src/htmlembed.js DELETED
@@ -1,38 +0,0 @@
1
- /**
2
- * @license Copyright (c) 2003-2026, CKSource Holding sp. z o.o. All rights reserved.
3
- * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-licensing-options
4
- */
5
- /**
6
- * @module html-embed/htmlembed
7
- */
8
- import { Plugin } from 'ckeditor5/src/core.js';
9
- import { Widget } from 'ckeditor5/src/widget.js';
10
- import { HtmlEmbedEditing } from './htmlembedediting.js';
11
- import { HtmlEmbedUI } from './htmlembedui.js';
12
- /**
13
- * The HTML embed feature.
14
- *
15
- * It allows inserting HTML snippets directly into the editor.
16
- *
17
- * For a detailed overview, check the {@glink features/html/html-embed HTML embed feature} documentation.
18
- */
19
- export class HtmlEmbed extends Plugin {
20
- /**
21
- * @inheritDoc
22
- */
23
- static get requires() {
24
- return [HtmlEmbedEditing, HtmlEmbedUI, Widget];
25
- }
26
- /**
27
- * @inheritDoc
28
- */
29
- static get pluginName() {
30
- return 'HtmlEmbed';
31
- }
32
- /**
33
- * @inheritDoc
34
- */
35
- static get isOfficialPlugin() {
36
- return true;
37
- }
38
- }
@@ -1,95 +0,0 @@
1
- /**
2
- * @license Copyright (c) 2003-2026, CKSource Holding sp. z o.o. All rights reserved.
3
- * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-licensing-options
4
- */
5
- import { Command } from 'ckeditor5/src/core.js';
6
- import { findOptimalInsertionRange } from 'ckeditor5/src/widget.js';
7
- /**
8
- * The insert HTML embed element command.
9
- *
10
- * The command is registered by {@link module:html-embed/htmlembedediting~HtmlEmbedEditing} as `'htmlEmbed'`.
11
- *
12
- * To insert an empty HTML embed element at the current selection, execute the command:
13
- *
14
- * ```ts
15
- * editor.execute( 'htmlEmbed' );
16
- * ```
17
- *
18
- * You can specify the initial content of a new HTML embed in the argument:
19
- *
20
- * ```ts
21
- * editor.execute( 'htmlEmbed', '<b>Initial content.</b>' );
22
- * ```
23
- *
24
- * To update the content of the HTML embed, select it in the model and pass the content in the argument:
25
- *
26
- * ```ts
27
- * editor.execute( 'htmlEmbed', '<b>New content of an existing embed.</b>' );
28
- * ```
29
- */
30
- export class HtmlEmbedCommand extends Command {
31
- /**
32
- * @inheritDoc
33
- */
34
- refresh() {
35
- const model = this.editor.model;
36
- const schema = model.schema;
37
- const selection = model.document.selection;
38
- const selectedRawHtmlElement = getSelectedRawHtmlModelWidget(selection);
39
- this.isEnabled = isHtmlEmbedAllowedInParent(selection, schema, model);
40
- this.value = selectedRawHtmlElement ? selectedRawHtmlElement.getAttribute('value') || '' : null;
41
- }
42
- /**
43
- * Executes the command, which either:
44
- *
45
- * * creates and inserts a new HTML embed element if none was selected,
46
- * * updates the content of the HTML embed if one was selected.
47
- *
48
- * @fires execute
49
- * @param value When passed, the value (content) will be set on a new embed or a selected one.
50
- */
51
- execute(value) {
52
- const model = this.editor.model;
53
- const selection = model.document.selection;
54
- model.change(writer => {
55
- let htmlEmbedElement;
56
- // If the command has a non-null value, there must be some HTML embed selected in the model.
57
- if (this.value !== null) {
58
- htmlEmbedElement = getSelectedRawHtmlModelWidget(selection);
59
- }
60
- else {
61
- htmlEmbedElement = writer.createElement('rawHtml');
62
- model.insertObject(htmlEmbedElement, null, null, { setSelection: 'on' });
63
- }
64
- writer.setAttribute('value', value, htmlEmbedElement);
65
- });
66
- }
67
- }
68
- /**
69
- * Checks if an HTML embed is allowed by the schema in the optimal insertion parent.
70
- */
71
- function isHtmlEmbedAllowedInParent(selection, schema, model) {
72
- const parent = getInsertHtmlEmbedParent(selection, model);
73
- return schema.checkChild(parent, 'rawHtml');
74
- }
75
- /**
76
- * Returns a node that will be used to insert a html embed with `model.insertContent` to check if a html embed element can be placed there.
77
- */
78
- function getInsertHtmlEmbedParent(selection, model) {
79
- const insertionRange = findOptimalInsertionRange(selection, model);
80
- const parent = insertionRange.start.parent;
81
- if (parent.isEmpty && !parent.is('rootElement')) {
82
- return parent.parent;
83
- }
84
- return parent;
85
- }
86
- /**
87
- * Returns the selected HTML embed element in the model, if any.
88
- */
89
- function getSelectedRawHtmlModelWidget(selection) {
90
- const selectedElement = selection.getSelectedElement();
91
- if (selectedElement && selectedElement.is('element', 'rawHtml')) {
92
- return selectedElement;
93
- }
94
- return null;
95
- }
@@ -1,5 +0,0 @@
1
- /**
2
- * @license Copyright (c) 2003-2026, CKSource Holding sp. z o.o. All rights reserved.
3
- * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-licensing-options
4
- */
5
- export {};
@@ -1,347 +0,0 @@
1
- /**
2
- * @license Copyright (c) 2003-2026, CKSource Holding sp. z o.o. All rights reserved.
3
- * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-licensing-options
4
- */
5
- /**
6
- * @module html-embed/htmlembedediting
7
- */
8
- import { Plugin } from 'ckeditor5/src/core.js';
9
- import { ButtonView } from 'ckeditor5/src/ui.js';
10
- import { toWidget } from 'ckeditor5/src/widget.js';
11
- import { logWarning, createElement } from 'ckeditor5/src/utils.js';
12
- import { IconCancel, IconCheck, IconPencil } from 'ckeditor5/src/icons.js';
13
- import { HtmlEmbedCommand } from './htmlembedcommand.js';
14
- import '../theme/htmlembed.css';
15
- /**
16
- * The HTML embed editing feature.
17
- */
18
- export class HtmlEmbedEditing extends Plugin {
19
- /**
20
- * Keeps references to {@link module:ui/button/buttonview~ButtonView edit, save, and cancel} button instances created for
21
- * each widget so they can be destroyed if they are no longer in DOM after the editing view was re-rendered.
22
- */
23
- _widgetButtonViewReferences = new Set();
24
- /**
25
- * @inheritDoc
26
- */
27
- static get pluginName() {
28
- return 'HtmlEmbedEditing';
29
- }
30
- /**
31
- * @inheritDoc
32
- * @internal
33
- */
34
- static get licenseFeatureCode() {
35
- return 'HE';
36
- }
37
- /**
38
- * @inheritDoc
39
- */
40
- static get isOfficialPlugin() {
41
- return true;
42
- }
43
- /**
44
- * @inheritDoc
45
- */
46
- static get isPremiumPlugin() {
47
- return true;
48
- }
49
- /**
50
- * @inheritDoc
51
- */
52
- constructor(editor) {
53
- super(editor);
54
- editor.config.define('htmlEmbed', {
55
- showPreviews: false,
56
- sanitizeHtml: rawHtml => {
57
- /**
58
- * When using the HTML embed feature with the `config.htmlEmbed.showPreviews` set to `true`, it is strongly recommended to
59
- * define a sanitize function that will clean up the input HTML in order to avoid XSS vulnerability.
60
- *
61
- * For a detailed overview, check the {@glink features/html/html-embed HTML embed feature} documentation.
62
- *
63
- * @error html-embed-provide-sanitize-function
64
- */
65
- logWarning('html-embed-provide-sanitize-function');
66
- return {
67
- html: rawHtml,
68
- hasChanged: false
69
- };
70
- }
71
- });
72
- }
73
- /**
74
- * @inheritDoc
75
- */
76
- init() {
77
- const editor = this.editor;
78
- const schema = editor.model.schema;
79
- schema.register('rawHtml', {
80
- inheritAllFrom: '$blockObject',
81
- allowAttributes: ['value']
82
- });
83
- editor.commands.add('htmlEmbed', new HtmlEmbedCommand(editor));
84
- this._setupConversion();
85
- }
86
- /**
87
- * Prepares converters for the feature.
88
- */
89
- _setupConversion() {
90
- const editor = this.editor;
91
- const t = editor.t;
92
- const view = editor.editing.view;
93
- const widgetButtonViewReferences = this._widgetButtonViewReferences;
94
- const htmlEmbedConfig = editor.config.get('htmlEmbed');
95
- // Destroy UI buttons created for widgets that have been removed from the view document (e.g. in the previous conversion).
96
- // This prevents unexpected memory leaks from UI views.
97
- this.editor.editing.view.on('render', () => {
98
- for (const buttonView of widgetButtonViewReferences) {
99
- if (buttonView.element && buttonView.element.isConnected) {
100
- return;
101
- }
102
- buttonView.destroy();
103
- widgetButtonViewReferences.delete(buttonView);
104
- }
105
- }, { priority: 'lowest' });
106
- // Register div.raw-html-embed as a raw content element so all of it's content will be provided
107
- // as a view element's custom property while data upcasting.
108
- editor.data.registerRawContentMatcher({
109
- name: 'div',
110
- classes: 'raw-html-embed'
111
- });
112
- editor.conversion.for('upcast').elementToElement({
113
- view: {
114
- name: 'div',
115
- classes: 'raw-html-embed'
116
- },
117
- model: (viewElement, { writer }) => {
118
- // The div.raw-html-embed is registered as a raw content element,
119
- // so all it's content is available in a custom property.
120
- return writer.createElement('rawHtml', {
121
- value: viewElement.getCustomProperty('$rawContent')
122
- });
123
- }
124
- });
125
- editor.conversion.for('dataDowncast').elementToElement({
126
- model: 'rawHtml',
127
- view: (modelElement, { writer }) => {
128
- return writer.createRawElement('div', { class: 'raw-html-embed' }, function (domElement) {
129
- domElement.innerHTML = modelElement.getAttribute('value') || '';
130
- });
131
- }
132
- });
133
- editor.conversion.for('editingDowncast').elementToStructure({
134
- model: { name: 'rawHtml', attributes: ['value'] },
135
- view: (modelElement, { writer }) => {
136
- let domContentWrapper;
137
- let state;
138
- let props;
139
- const viewContentWrapper = writer.createRawElement('div', {
140
- class: 'raw-html-embed__content-wrapper'
141
- }, function (domElement) {
142
- domContentWrapper = domElement;
143
- renderContent({ editor, domElement, state, props });
144
- // Since there is a `data-cke-ignore-events` attribute set on the wrapper element in the editable mode,
145
- // the explicit `mousedown` handler on the `capture` phase is needed to move the selection onto the whole
146
- // HTML embed widget.
147
- domContentWrapper.addEventListener('mousedown', () => {
148
- if (state.isEditable) {
149
- const model = editor.model;
150
- const selectedElement = model.document.selection.getSelectedElement();
151
- // Move the selection onto the whole HTML embed widget if it's currently not selected.
152
- if (selectedElement !== modelElement) {
153
- model.change(writer => writer.setSelection(modelElement, 'on'));
154
- }
155
- }
156
- }, true);
157
- });
158
- // API exposed on each raw HTML embed widget so other features can control a particular widget.
159
- const rawHtmlApi = {
160
- makeEditable() {
161
- state = Object.assign({}, state, {
162
- isEditable: true
163
- });
164
- renderContent({ domElement: domContentWrapper, editor, state, props });
165
- view.change(writer => {
166
- writer.setAttribute('data-cke-ignore-events', 'true', viewContentWrapper);
167
- });
168
- // This could be potentially pulled to a separate method called focusTextarea().
169
- domContentWrapper.querySelector('textarea').focus();
170
- },
171
- save(newValue) {
172
- // If the value didn't change, we just cancel. If it changed,
173
- // it's enough to update the model – the entire widget will be reconverted.
174
- if (newValue !== state.getRawHtmlValue()) {
175
- editor.execute('htmlEmbed', newValue);
176
- editor.editing.view.focus();
177
- }
178
- else {
179
- this.cancel();
180
- }
181
- },
182
- cancel() {
183
- state = Object.assign({}, state, {
184
- isEditable: false
185
- });
186
- renderContent({ domElement: domContentWrapper, editor, state, props });
187
- editor.editing.view.focus();
188
- view.change(writer => {
189
- writer.removeAttribute('data-cke-ignore-events', viewContentWrapper);
190
- });
191
- }
192
- };
193
- state = {
194
- showPreviews: htmlEmbedConfig.showPreviews,
195
- isEditable: false,
196
- getRawHtmlValue: () => modelElement.getAttribute('value') || ''
197
- };
198
- props = {
199
- sanitizeHtml: htmlEmbedConfig.sanitizeHtml,
200
- textareaPlaceholder: t('Paste raw HTML here...'),
201
- onEditClick() {
202
- rawHtmlApi.makeEditable();
203
- },
204
- onSaveClick(newValue) {
205
- rawHtmlApi.save(newValue);
206
- },
207
- onCancelClick() {
208
- rawHtmlApi.cancel();
209
- }
210
- };
211
- const viewContainer = writer.createContainerElement('div', {
212
- class: 'raw-html-embed',
213
- 'data-html-embed-label': t('HTML snippet'),
214
- dir: editor.locale.uiLanguageDirection
215
- }, viewContentWrapper);
216
- writer.setCustomProperty('rawHtmlApi', rawHtmlApi, viewContainer);
217
- writer.setCustomProperty('rawHtml', true, viewContainer);
218
- return toWidget(viewContainer, writer, {
219
- label: t('HTML snippet'),
220
- hasSelectionHandle: true
221
- });
222
- }
223
- });
224
- function renderContent({ editor, domElement, state, props }) {
225
- // Remove all children;
226
- domElement.textContent = '';
227
- const domDocument = domElement.ownerDocument;
228
- let domTextarea;
229
- if (state.isEditable) {
230
- const textareaProps = {
231
- isDisabled: false,
232
- placeholder: props.textareaPlaceholder
233
- };
234
- domTextarea = createDomTextarea({ domDocument, state, props: textareaProps });
235
- domElement.append(domTextarea);
236
- }
237
- else if (state.showPreviews) {
238
- const previewContainerProps = {
239
- sanitizeHtml: props.sanitizeHtml
240
- };
241
- domElement.append(createPreviewContainer({ domDocument, state, props: previewContainerProps, editor }));
242
- }
243
- else {
244
- const textareaProps = {
245
- isDisabled: true,
246
- placeholder: props.textareaPlaceholder
247
- };
248
- domElement.append(createDomTextarea({ domDocument, state, props: textareaProps }));
249
- }
250
- const buttonsWrapperProps = {
251
- onEditClick: props.onEditClick,
252
- onSaveClick: () => {
253
- props.onSaveClick(domTextarea.value);
254
- },
255
- onCancelClick: props.onCancelClick
256
- };
257
- domElement.prepend(createDomButtonsWrapper({ editor, domDocument, state, props: buttonsWrapperProps }));
258
- }
259
- function createDomButtonsWrapper({ editor, domDocument, state, props }) {
260
- const domButtonsWrapper = createElement(domDocument, 'div', {
261
- class: 'raw-html-embed__buttons-wrapper'
262
- });
263
- if (state.isEditable) {
264
- const saveButtonView = createUIButton(editor, 'save', props.onSaveClick);
265
- const cancelButtonView = createUIButton(editor, 'cancel', props.onCancelClick);
266
- domButtonsWrapper.append(saveButtonView.element, cancelButtonView.element);
267
- widgetButtonViewReferences.add(saveButtonView).add(cancelButtonView);
268
- }
269
- else {
270
- const editButtonView = createUIButton(editor, 'edit', props.onEditClick);
271
- domButtonsWrapper.append(editButtonView.element);
272
- widgetButtonViewReferences.add(editButtonView);
273
- }
274
- return domButtonsWrapper;
275
- }
276
- function createDomTextarea({ domDocument, state, props }) {
277
- const domTextarea = createElement(domDocument, 'textarea', {
278
- placeholder: props.placeholder,
279
- class: 'ck ck-reset ck-input ck-input-text raw-html-embed__source'
280
- });
281
- domTextarea.disabled = props.isDisabled;
282
- domTextarea.value = state.getRawHtmlValue();
283
- return domTextarea;
284
- }
285
- function createPreviewContainer({ editor, domDocument, state, props }) {
286
- const sanitizedOutput = props.sanitizeHtml(state.getRawHtmlValue());
287
- const placeholderText = state.getRawHtmlValue().length > 0 ?
288
- t('No preview available') :
289
- t('Empty snippet content');
290
- const domPreviewPlaceholder = createElement(domDocument, 'div', {
291
- class: 'ck ck-reset_all raw-html-embed__preview-placeholder'
292
- }, placeholderText);
293
- const domPreviewContent = createElement(domDocument, 'div', {
294
- class: 'raw-html-embed__preview-content',
295
- dir: editor.locale.contentLanguageDirection
296
- });
297
- // Creating a contextual document fragment allows executing scripts when inserting into the preview element.
298
- // See: #8326.
299
- const domRange = domDocument.createRange();
300
- const domDocumentFragment = domRange.createContextualFragment(sanitizedOutput.html);
301
- domPreviewContent.appendChild(domDocumentFragment);
302
- const domPreviewContainer = createElement(domDocument, 'div', {
303
- class: 'raw-html-embed__preview'
304
- }, [
305
- domPreviewPlaceholder, domPreviewContent
306
- ]);
307
- return domPreviewContainer;
308
- }
309
- }
310
- }
311
- /**
312
- * Returns a UI button view that can be used in conversion.
313
- */
314
- function createUIButton(editor, type, onClick) {
315
- const { t } = editor.locale;
316
- const buttonView = new ButtonView(editor.locale);
317
- const command = editor.commands.get('htmlEmbed');
318
- buttonView.set({
319
- class: `raw-html-embed__${type}-button`,
320
- icon: IconPencil,
321
- tooltip: true,
322
- tooltipPosition: editor.locale.uiLanguageDirection === 'rtl' ? 'e' : 'w'
323
- });
324
- buttonView.render();
325
- if (type === 'edit') {
326
- buttonView.set({
327
- icon: IconPencil,
328
- label: t('Edit source')
329
- });
330
- buttonView.bind('isEnabled').to(command);
331
- }
332
- else if (type === 'save') {
333
- buttonView.set({
334
- icon: IconCheck,
335
- label: t('Save changes')
336
- });
337
- buttonView.bind('isEnabled').to(command);
338
- }
339
- else {
340
- buttonView.set({
341
- icon: IconCancel,
342
- label: t('Cancel')
343
- });
344
- }
345
- buttonView.on('execute', onClick);
346
- return buttonView;
347
- }