@ckeditor/ckeditor5-ckbox 0.0.0-internal-20241017.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (309) hide show
  1. package/CHANGELOG.md +4 -0
  2. package/LICENSE.md +21 -0
  3. package/README.md +24 -0
  4. package/build/ckbox.js +5 -0
  5. package/build/translations/ar.js +1 -0
  6. package/build/translations/az.js +1 -0
  7. package/build/translations/bg.js +1 -0
  8. package/build/translations/bn.js +1 -0
  9. package/build/translations/ca.js +1 -0
  10. package/build/translations/cs.js +1 -0
  11. package/build/translations/da.js +1 -0
  12. package/build/translations/de.js +1 -0
  13. package/build/translations/el.js +1 -0
  14. package/build/translations/en-au.js +1 -0
  15. package/build/translations/es-co.js +1 -0
  16. package/build/translations/es.js +1 -0
  17. package/build/translations/et.js +1 -0
  18. package/build/translations/fa.js +1 -0
  19. package/build/translations/fi.js +1 -0
  20. package/build/translations/fr.js +1 -0
  21. package/build/translations/gl.js +1 -0
  22. package/build/translations/he.js +1 -0
  23. package/build/translations/hi.js +1 -0
  24. package/build/translations/hr.js +1 -0
  25. package/build/translations/hu.js +1 -0
  26. package/build/translations/id.js +1 -0
  27. package/build/translations/it.js +1 -0
  28. package/build/translations/ja.js +1 -0
  29. package/build/translations/ko.js +1 -0
  30. package/build/translations/lt.js +1 -0
  31. package/build/translations/lv.js +1 -0
  32. package/build/translations/ms.js +1 -0
  33. package/build/translations/nl.js +1 -0
  34. package/build/translations/no.js +1 -0
  35. package/build/translations/pl.js +1 -0
  36. package/build/translations/pt-br.js +1 -0
  37. package/build/translations/pt.js +1 -0
  38. package/build/translations/ro.js +1 -0
  39. package/build/translations/ru.js +1 -0
  40. package/build/translations/sk.js +1 -0
  41. package/build/translations/sq.js +1 -0
  42. package/build/translations/sr-latn.js +1 -0
  43. package/build/translations/sr.js +1 -0
  44. package/build/translations/sv.js +1 -0
  45. package/build/translations/th.js +1 -0
  46. package/build/translations/tr.js +1 -0
  47. package/build/translations/ug.js +1 -0
  48. package/build/translations/uk.js +1 -0
  49. package/build/translations/ur.js +1 -0
  50. package/build/translations/uz.js +1 -0
  51. package/build/translations/vi.js +1 -0
  52. package/build/translations/zh-cn.js +1 -0
  53. package/build/translations/zh.js +1 -0
  54. package/ckeditor5-metadata.json +58 -0
  55. package/dist/augmentation.d.ts +36 -0
  56. package/dist/ckbox.d.ts +41 -0
  57. package/dist/ckboxcommand.d.ts +130 -0
  58. package/dist/ckboxconfig.d.ts +434 -0
  59. package/dist/ckboxediting.d.ts +65 -0
  60. package/dist/ckboximageedit/ckboximageeditcommand.d.ts +109 -0
  61. package/dist/ckboximageedit/ckboximageeditediting.d.ts +36 -0
  62. package/dist/ckboximageedit/ckboximageeditui.d.ts +32 -0
  63. package/dist/ckboximageedit/utils.d.ts +14 -0
  64. package/dist/ckboximageedit.d.ts +32 -0
  65. package/dist/ckboxui.d.ts +60 -0
  66. package/dist/ckboxuploadadapter.d.ts +41 -0
  67. package/dist/ckboxutils.d.ts +58 -0
  68. package/dist/index-content.css +4 -0
  69. package/dist/index-editor.css +46 -0
  70. package/dist/index.css +55 -0
  71. package/dist/index.css.map +1 -0
  72. package/dist/index.d.ts +21 -0
  73. package/dist/index.js +1787 -0
  74. package/dist/index.js.map +1 -0
  75. package/dist/translations/ar.d.ts +8 -0
  76. package/dist/translations/ar.js +5 -0
  77. package/dist/translations/ar.umd.js +11 -0
  78. package/dist/translations/az.d.ts +8 -0
  79. package/dist/translations/az.js +5 -0
  80. package/dist/translations/az.umd.js +11 -0
  81. package/dist/translations/bg.d.ts +8 -0
  82. package/dist/translations/bg.js +5 -0
  83. package/dist/translations/bg.umd.js +11 -0
  84. package/dist/translations/bn.d.ts +8 -0
  85. package/dist/translations/bn.js +5 -0
  86. package/dist/translations/bn.umd.js +11 -0
  87. package/dist/translations/ca.d.ts +8 -0
  88. package/dist/translations/ca.js +5 -0
  89. package/dist/translations/ca.umd.js +11 -0
  90. package/dist/translations/cs.d.ts +8 -0
  91. package/dist/translations/cs.js +5 -0
  92. package/dist/translations/cs.umd.js +11 -0
  93. package/dist/translations/da.d.ts +8 -0
  94. package/dist/translations/da.js +5 -0
  95. package/dist/translations/da.umd.js +11 -0
  96. package/dist/translations/de.d.ts +8 -0
  97. package/dist/translations/de.js +5 -0
  98. package/dist/translations/de.umd.js +11 -0
  99. package/dist/translations/el.d.ts +8 -0
  100. package/dist/translations/el.js +5 -0
  101. package/dist/translations/el.umd.js +11 -0
  102. package/dist/translations/en-au.d.ts +8 -0
  103. package/dist/translations/en-au.js +5 -0
  104. package/dist/translations/en-au.umd.js +11 -0
  105. package/dist/translations/en.d.ts +8 -0
  106. package/dist/translations/en.js +5 -0
  107. package/dist/translations/en.umd.js +11 -0
  108. package/dist/translations/es-co.d.ts +8 -0
  109. package/dist/translations/es-co.js +5 -0
  110. package/dist/translations/es-co.umd.js +11 -0
  111. package/dist/translations/es.d.ts +8 -0
  112. package/dist/translations/es.js +5 -0
  113. package/dist/translations/es.umd.js +11 -0
  114. package/dist/translations/et.d.ts +8 -0
  115. package/dist/translations/et.js +5 -0
  116. package/dist/translations/et.umd.js +11 -0
  117. package/dist/translations/fa.d.ts +8 -0
  118. package/dist/translations/fa.js +5 -0
  119. package/dist/translations/fa.umd.js +11 -0
  120. package/dist/translations/fi.d.ts +8 -0
  121. package/dist/translations/fi.js +5 -0
  122. package/dist/translations/fi.umd.js +11 -0
  123. package/dist/translations/fr.d.ts +8 -0
  124. package/dist/translations/fr.js +5 -0
  125. package/dist/translations/fr.umd.js +11 -0
  126. package/dist/translations/gl.d.ts +8 -0
  127. package/dist/translations/gl.js +5 -0
  128. package/dist/translations/gl.umd.js +11 -0
  129. package/dist/translations/he.d.ts +8 -0
  130. package/dist/translations/he.js +5 -0
  131. package/dist/translations/he.umd.js +11 -0
  132. package/dist/translations/hi.d.ts +8 -0
  133. package/dist/translations/hi.js +5 -0
  134. package/dist/translations/hi.umd.js +11 -0
  135. package/dist/translations/hr.d.ts +8 -0
  136. package/dist/translations/hr.js +5 -0
  137. package/dist/translations/hr.umd.js +11 -0
  138. package/dist/translations/hu.d.ts +8 -0
  139. package/dist/translations/hu.js +5 -0
  140. package/dist/translations/hu.umd.js +11 -0
  141. package/dist/translations/id.d.ts +8 -0
  142. package/dist/translations/id.js +5 -0
  143. package/dist/translations/id.umd.js +11 -0
  144. package/dist/translations/it.d.ts +8 -0
  145. package/dist/translations/it.js +5 -0
  146. package/dist/translations/it.umd.js +11 -0
  147. package/dist/translations/ja.d.ts +8 -0
  148. package/dist/translations/ja.js +5 -0
  149. package/dist/translations/ja.umd.js +11 -0
  150. package/dist/translations/ko.d.ts +8 -0
  151. package/dist/translations/ko.js +5 -0
  152. package/dist/translations/ko.umd.js +11 -0
  153. package/dist/translations/lt.d.ts +8 -0
  154. package/dist/translations/lt.js +5 -0
  155. package/dist/translations/lt.umd.js +11 -0
  156. package/dist/translations/lv.d.ts +8 -0
  157. package/dist/translations/lv.js +5 -0
  158. package/dist/translations/lv.umd.js +11 -0
  159. package/dist/translations/ms.d.ts +8 -0
  160. package/dist/translations/ms.js +5 -0
  161. package/dist/translations/ms.umd.js +11 -0
  162. package/dist/translations/nl.d.ts +8 -0
  163. package/dist/translations/nl.js +5 -0
  164. package/dist/translations/nl.umd.js +11 -0
  165. package/dist/translations/no.d.ts +8 -0
  166. package/dist/translations/no.js +5 -0
  167. package/dist/translations/no.umd.js +11 -0
  168. package/dist/translations/pl.d.ts +8 -0
  169. package/dist/translations/pl.js +5 -0
  170. package/dist/translations/pl.umd.js +11 -0
  171. package/dist/translations/pt-br.d.ts +8 -0
  172. package/dist/translations/pt-br.js +5 -0
  173. package/dist/translations/pt-br.umd.js +11 -0
  174. package/dist/translations/pt.d.ts +8 -0
  175. package/dist/translations/pt.js +5 -0
  176. package/dist/translations/pt.umd.js +11 -0
  177. package/dist/translations/ro.d.ts +8 -0
  178. package/dist/translations/ro.js +5 -0
  179. package/dist/translations/ro.umd.js +11 -0
  180. package/dist/translations/ru.d.ts +8 -0
  181. package/dist/translations/ru.js +5 -0
  182. package/dist/translations/ru.umd.js +11 -0
  183. package/dist/translations/sk.d.ts +8 -0
  184. package/dist/translations/sk.js +5 -0
  185. package/dist/translations/sk.umd.js +11 -0
  186. package/dist/translations/sq.d.ts +8 -0
  187. package/dist/translations/sq.js +5 -0
  188. package/dist/translations/sq.umd.js +11 -0
  189. package/dist/translations/sr-latn.d.ts +8 -0
  190. package/dist/translations/sr-latn.js +5 -0
  191. package/dist/translations/sr-latn.umd.js +11 -0
  192. package/dist/translations/sr.d.ts +8 -0
  193. package/dist/translations/sr.js +5 -0
  194. package/dist/translations/sr.umd.js +11 -0
  195. package/dist/translations/sv.d.ts +8 -0
  196. package/dist/translations/sv.js +5 -0
  197. package/dist/translations/sv.umd.js +11 -0
  198. package/dist/translations/th.d.ts +8 -0
  199. package/dist/translations/th.js +5 -0
  200. package/dist/translations/th.umd.js +11 -0
  201. package/dist/translations/tr.d.ts +8 -0
  202. package/dist/translations/tr.js +5 -0
  203. package/dist/translations/tr.umd.js +11 -0
  204. package/dist/translations/ug.d.ts +8 -0
  205. package/dist/translations/ug.js +5 -0
  206. package/dist/translations/ug.umd.js +11 -0
  207. package/dist/translations/uk.d.ts +8 -0
  208. package/dist/translations/uk.js +5 -0
  209. package/dist/translations/uk.umd.js +11 -0
  210. package/dist/translations/ur.d.ts +8 -0
  211. package/dist/translations/ur.js +5 -0
  212. package/dist/translations/ur.umd.js +11 -0
  213. package/dist/translations/uz.d.ts +8 -0
  214. package/dist/translations/uz.js +5 -0
  215. package/dist/translations/uz.umd.js +11 -0
  216. package/dist/translations/vi.d.ts +8 -0
  217. package/dist/translations/vi.js +5 -0
  218. package/dist/translations/vi.umd.js +11 -0
  219. package/dist/translations/zh-cn.d.ts +8 -0
  220. package/dist/translations/zh-cn.js +5 -0
  221. package/dist/translations/zh-cn.umd.js +11 -0
  222. package/dist/translations/zh.d.ts +8 -0
  223. package/dist/translations/zh.js +5 -0
  224. package/dist/translations/zh.umd.js +11 -0
  225. package/dist/utils.d.ts +67 -0
  226. package/lang/contexts.json +10 -0
  227. package/lang/translations/ar.po +50 -0
  228. package/lang/translations/az.po +50 -0
  229. package/lang/translations/bg.po +50 -0
  230. package/lang/translations/bn.po +50 -0
  231. package/lang/translations/ca.po +50 -0
  232. package/lang/translations/cs.po +50 -0
  233. package/lang/translations/da.po +50 -0
  234. package/lang/translations/de.po +50 -0
  235. package/lang/translations/el.po +50 -0
  236. package/lang/translations/en-au.po +50 -0
  237. package/lang/translations/en.po +50 -0
  238. package/lang/translations/es-co.po +50 -0
  239. package/lang/translations/es.po +50 -0
  240. package/lang/translations/et.po +50 -0
  241. package/lang/translations/fa.po +50 -0
  242. package/lang/translations/fi.po +50 -0
  243. package/lang/translations/fr.po +50 -0
  244. package/lang/translations/gl.po +50 -0
  245. package/lang/translations/he.po +50 -0
  246. package/lang/translations/hi.po +50 -0
  247. package/lang/translations/hr.po +50 -0
  248. package/lang/translations/hu.po +50 -0
  249. package/lang/translations/id.po +50 -0
  250. package/lang/translations/it.po +50 -0
  251. package/lang/translations/ja.po +50 -0
  252. package/lang/translations/ko.po +50 -0
  253. package/lang/translations/lt.po +50 -0
  254. package/lang/translations/lv.po +50 -0
  255. package/lang/translations/ms.po +50 -0
  256. package/lang/translations/nl.po +50 -0
  257. package/lang/translations/no.po +50 -0
  258. package/lang/translations/pl.po +50 -0
  259. package/lang/translations/pt-br.po +50 -0
  260. package/lang/translations/pt.po +50 -0
  261. package/lang/translations/ro.po +50 -0
  262. package/lang/translations/ru.po +50 -0
  263. package/lang/translations/sk.po +50 -0
  264. package/lang/translations/sq.po +50 -0
  265. package/lang/translations/sr-latn.po +50 -0
  266. package/lang/translations/sr.po +50 -0
  267. package/lang/translations/sv.po +50 -0
  268. package/lang/translations/th.po +50 -0
  269. package/lang/translations/tr.po +50 -0
  270. package/lang/translations/ug.po +50 -0
  271. package/lang/translations/uk.po +50 -0
  272. package/lang/translations/ur.po +50 -0
  273. package/lang/translations/uz.po +50 -0
  274. package/lang/translations/vi.po +50 -0
  275. package/lang/translations/zh-cn.po +50 -0
  276. package/lang/translations/zh.po +50 -0
  277. package/package.json +45 -0
  278. package/src/augmentation.d.ts +32 -0
  279. package/src/augmentation.js +5 -0
  280. package/src/ckbox.d.ts +37 -0
  281. package/src/ckbox.js +43 -0
  282. package/src/ckboxcommand.d.ts +126 -0
  283. package/src/ckboxcommand.js +364 -0
  284. package/src/ckboxconfig.d.ts +430 -0
  285. package/src/ckboxconfig.js +5 -0
  286. package/src/ckboxediting.d.ts +61 -0
  287. package/src/ckboxediting.js +389 -0
  288. package/src/ckboximageedit/ckboximageeditcommand.d.ts +105 -0
  289. package/src/ckboximageedit/ckboximageeditcommand.js +310 -0
  290. package/src/ckboximageedit/ckboximageeditediting.d.ts +32 -0
  291. package/src/ckboximageedit/ckboximageeditediting.js +42 -0
  292. package/src/ckboximageedit/ckboximageeditui.d.ts +28 -0
  293. package/src/ckboximageedit/ckboximageeditui.js +57 -0
  294. package/src/ckboximageedit/utils.d.ts +10 -0
  295. package/src/ckboximageedit/utils.js +48 -0
  296. package/src/ckboximageedit.d.ts +28 -0
  297. package/src/ckboximageedit.js +34 -0
  298. package/src/ckboxui.d.ts +56 -0
  299. package/src/ckboxui.js +136 -0
  300. package/src/ckboxuploadadapter.d.ts +37 -0
  301. package/src/ckboxuploadadapter.js +136 -0
  302. package/src/ckboxutils.d.ts +54 -0
  303. package/src/ckboxutils.js +189 -0
  304. package/src/index.d.ts +17 -0
  305. package/src/index.js +14 -0
  306. package/src/utils.d.ts +63 -0
  307. package/src/utils.js +175 -0
  308. package/theme/ckboximageedit.css +53 -0
  309. package/theme/icons/ckbox-image-edit.svg +1 -0
@@ -0,0 +1,389 @@
1
+ /**
2
+ * @license Copyright (c) 2003-2024, CKSource Holding sp. z o.o. All rights reserved.
3
+ * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
4
+ */
5
+ /* globals window */
6
+ /**
7
+ * @module ckbox/ckboxediting
8
+ */
9
+ import { Plugin } from 'ckeditor5/src/core.js';
10
+ import { Range } from 'ckeditor5/src/engine.js';
11
+ import { logError } from 'ckeditor5/src/utils.js';
12
+ import CKBoxCommand from './ckboxcommand.js';
13
+ import CKBoxUploadAdapter from './ckboxuploadadapter.js';
14
+ import CKBoxUtils from './ckboxutils.js';
15
+ import { sendHttpRequest } from './utils.js';
16
+ const COMMAND_FORCE_DISABLE_ID = 'NoPermission';
17
+ /**
18
+ * The CKBox editing feature. It introduces the {@link module:ckbox/ckboxcommand~CKBoxCommand CKBox command} and
19
+ * {@link module:ckbox/ckboxuploadadapter~CKBoxUploadAdapter CKBox upload adapter}.
20
+ */
21
+ export default class CKBoxEditing extends Plugin {
22
+ /**
23
+ * @inheritDoc
24
+ */
25
+ static get pluginName() {
26
+ return 'CKBoxEditing';
27
+ }
28
+ /**
29
+ * @inheritDoc
30
+ */
31
+ static get isOfficialPlugin() {
32
+ return true;
33
+ }
34
+ /**
35
+ * @inheritDoc
36
+ */
37
+ static get requires() {
38
+ return ['LinkEditing', 'PictureEditing', CKBoxUploadAdapter, CKBoxUtils];
39
+ }
40
+ /**
41
+ * @inheritDoc
42
+ */
43
+ init() {
44
+ const editor = this.editor;
45
+ if (!this._shouldBeInitialised()) {
46
+ return;
47
+ }
48
+ this._checkImagePlugins();
49
+ // Registering the `ckbox` command makes sense only if the CKBox library is loaded, as the `ckbox` command opens the CKBox dialog.
50
+ if (isLibraryLoaded()) {
51
+ editor.commands.add('ckbox', new CKBoxCommand(editor));
52
+ }
53
+ // Promise is not handled intentionally. Errors should be displayed in console if there are so.
54
+ isUploadPermissionGranted(editor).then(isCreateAssetAllowed => {
55
+ if (!isCreateAssetAllowed) {
56
+ this._blockImageCommands();
57
+ }
58
+ });
59
+ }
60
+ /**
61
+ * @inheritDoc
62
+ */
63
+ afterInit() {
64
+ const editor = this.editor;
65
+ if (!this._shouldBeInitialised()) {
66
+ return;
67
+ }
68
+ // Extending the schema, registering converters and applying fixers only make sense if the configuration option to assign
69
+ // the assets ID with the model elements is enabled.
70
+ if (!editor.config.get('ckbox.ignoreDataId')) {
71
+ this._initSchema();
72
+ this._initConversion();
73
+ this._initFixers();
74
+ }
75
+ }
76
+ /**
77
+ * Returns true only when the integrator intentionally wants to use the plugin, i.e. when the `config.ckbox` exists or
78
+ * the CKBox JavaScript library is loaded.
79
+ */
80
+ _shouldBeInitialised() {
81
+ const editor = this.editor;
82
+ const hasConfiguration = !!editor.config.get('ckbox');
83
+ return hasConfiguration || isLibraryLoaded();
84
+ }
85
+ /**
86
+ * Blocks `uploadImage` and `ckboxImageEdit` commands.
87
+ */
88
+ _blockImageCommands() {
89
+ const editor = this.editor;
90
+ const uploadImageCommand = editor.commands.get('uploadImage');
91
+ const imageEditingCommand = editor.commands.get('ckboxImageEdit');
92
+ if (uploadImageCommand) {
93
+ uploadImageCommand.isAccessAllowed = false;
94
+ uploadImageCommand.forceDisabled(COMMAND_FORCE_DISABLE_ID);
95
+ }
96
+ if (imageEditingCommand) {
97
+ imageEditingCommand.forceDisabled(COMMAND_FORCE_DISABLE_ID);
98
+ }
99
+ }
100
+ /**
101
+ * Checks if at least one image plugin is loaded.
102
+ */
103
+ _checkImagePlugins() {
104
+ const editor = this.editor;
105
+ if (!editor.plugins.has('ImageBlockEditing') && !editor.plugins.has('ImageInlineEditing')) {
106
+ /**
107
+ * The CKBox feature requires one of the following plugins to be loaded to work correctly:
108
+ *
109
+ * * {@link module:image/imageblock~ImageBlock},
110
+ * * {@link module:image/imageinline~ImageInline},
111
+ * * {@link module:image/image~Image} (loads both `ImageBlock` and `ImageInline`)
112
+ *
113
+ * Please make sure your editor configuration is correct.
114
+ *
115
+ * @error ckbox-plugin-image-feature-missing
116
+ * @param {module:core/editor/editor~Editor} editor
117
+ */
118
+ logError('ckbox-plugin-image-feature-missing', editor);
119
+ }
120
+ }
121
+ /**
122
+ * Extends the schema to allow the `ckboxImageId` and `ckboxLinkId` attributes for links and images.
123
+ */
124
+ _initSchema() {
125
+ const editor = this.editor;
126
+ const schema = editor.model.schema;
127
+ schema.extend('$text', { allowAttributes: 'ckboxLinkId' });
128
+ if (schema.isRegistered('imageBlock')) {
129
+ schema.extend('imageBlock', { allowAttributes: ['ckboxImageId', 'ckboxLinkId'] });
130
+ }
131
+ if (schema.isRegistered('imageInline')) {
132
+ schema.extend('imageInline', { allowAttributes: ['ckboxImageId', 'ckboxLinkId'] });
133
+ }
134
+ schema.addAttributeCheck(context => {
135
+ // Don't allow `ckboxLinkId` on elements which do not have `linkHref` attribute.
136
+ if (!context.last.getAttribute('linkHref')) {
137
+ return false;
138
+ }
139
+ }, 'ckboxLinkId');
140
+ }
141
+ /**
142
+ * Configures the upcast and downcast conversions for the `ckboxImageId` and `ckboxLinkId` attributes.
143
+ */
144
+ _initConversion() {
145
+ const editor = this.editor;
146
+ // Convert `ckboxLinkId` => `data-ckbox-resource-id`.
147
+ editor.conversion.for('downcast').add(dispatcher => {
148
+ // Due to custom converters for linked block images, handle the `ckboxLinkId` attribute manually.
149
+ dispatcher.on('attribute:ckboxLinkId:imageBlock', (evt, data, conversionApi) => {
150
+ const { writer, mapper, consumable } = conversionApi;
151
+ if (!consumable.consume(data.item, evt.name)) {
152
+ return;
153
+ }
154
+ const viewFigure = mapper.toViewElement(data.item);
155
+ const linkInImage = [...viewFigure.getChildren()]
156
+ .find((child) => child.name === 'a');
157
+ // No link inside an image - no conversion needed.
158
+ if (!linkInImage) {
159
+ return;
160
+ }
161
+ if (data.item.hasAttribute('ckboxLinkId')) {
162
+ writer.setAttribute('data-ckbox-resource-id', data.item.getAttribute('ckboxLinkId'), linkInImage);
163
+ }
164
+ else {
165
+ writer.removeAttribute('data-ckbox-resource-id', linkInImage);
166
+ }
167
+ }, { priority: 'low' });
168
+ dispatcher.on('attribute:ckboxLinkId', (evt, data, conversionApi) => {
169
+ const { writer, mapper, consumable } = conversionApi;
170
+ if (!consumable.consume(data.item, evt.name)) {
171
+ return;
172
+ }
173
+ // Remove the previous attribute value if it was applied.
174
+ if (data.attributeOldValue) {
175
+ const viewElement = createLinkElement(writer, data.attributeOldValue);
176
+ writer.unwrap(mapper.toViewRange(data.range), viewElement);
177
+ }
178
+ // Add the new attribute value if specified in a model element.
179
+ if (data.attributeNewValue) {
180
+ const viewElement = createLinkElement(writer, data.attributeNewValue);
181
+ if (data.item.is('selection')) {
182
+ const viewSelection = writer.document.selection;
183
+ writer.wrap(viewSelection.getFirstRange(), viewElement);
184
+ }
185
+ else {
186
+ writer.wrap(mapper.toViewRange(data.range), viewElement);
187
+ }
188
+ }
189
+ }, { priority: 'low' });
190
+ });
191
+ // Convert `data-ckbox-resource-id` => `ckboxLinkId`.
192
+ //
193
+ // The helper conversion does not handle all cases, so take care of the `data-ckbox-resource-id` attribute manually for images
194
+ // and links.
195
+ editor.conversion.for('upcast').add(dispatcher => {
196
+ dispatcher.on('element:a', (evt, data, conversionApi) => {
197
+ const { writer, consumable } = conversionApi;
198
+ // Upcast the `data-ckbox-resource-id` attribute only for valid link elements.
199
+ if (!data.viewItem.getAttribute('href')) {
200
+ return;
201
+ }
202
+ const consumableAttributes = { attributes: ['data-ckbox-resource-id'] };
203
+ if (!consumable.consume(data.viewItem, consumableAttributes)) {
204
+ return;
205
+ }
206
+ const attributeValue = data.viewItem.getAttribute('data-ckbox-resource-id');
207
+ // Missing the `data-ckbox-resource-id` attribute.
208
+ if (!attributeValue) {
209
+ return;
210
+ }
211
+ if (data.modelRange) {
212
+ // If the `<a>` element contains more than single children (e.g. a linked image), set the `ckboxLinkId` for each
213
+ // allowed child.
214
+ for (let item of data.modelRange.getItems()) {
215
+ if (item.is('$textProxy')) {
216
+ item = item.textNode;
217
+ }
218
+ // Do not copy the `ckboxLinkId` attribute when wrapping an element in a block element, e.g. when
219
+ // auto-paragraphing.
220
+ if (shouldUpcastAttributeForNode(item)) {
221
+ writer.setAttribute('ckboxLinkId', attributeValue, item);
222
+ }
223
+ }
224
+ }
225
+ else {
226
+ // Otherwise, just set the `ckboxLinkId` for the model element.
227
+ const modelElement = data.modelCursor.nodeBefore || data.modelCursor.parent;
228
+ writer.setAttribute('ckboxLinkId', attributeValue, modelElement);
229
+ }
230
+ }, { priority: 'low' });
231
+ });
232
+ // Convert `ckboxImageId` => `data-ckbox-resource-id`.
233
+ editor.conversion.for('downcast').attributeToAttribute({
234
+ model: 'ckboxImageId',
235
+ view: 'data-ckbox-resource-id'
236
+ });
237
+ // Convert `data-ckbox-resource-id` => `ckboxImageId`.
238
+ editor.conversion.for('upcast').elementToAttribute({
239
+ model: {
240
+ key: 'ckboxImageId',
241
+ value: (viewElement) => viewElement.getAttribute('data-ckbox-resource-id')
242
+ },
243
+ view: {
244
+ attributes: {
245
+ 'data-ckbox-resource-id': /[\s\S]+/
246
+ }
247
+ }
248
+ });
249
+ const replaceImageSourceCommand = editor.commands.get('replaceImageSource');
250
+ if (replaceImageSourceCommand) {
251
+ this.listenTo(replaceImageSourceCommand, 'cleanupImage', (_, [writer, image]) => {
252
+ writer.removeAttribute('ckboxImageId', image);
253
+ });
254
+ }
255
+ }
256
+ /**
257
+ * Registers post-fixers that add or remove the `ckboxLinkId` and `ckboxImageId` attributes.
258
+ */
259
+ _initFixers() {
260
+ const editor = this.editor;
261
+ const model = editor.model;
262
+ const selection = model.document.selection;
263
+ // Registers the post-fixer to sync the asset ID with the model elements.
264
+ model.document.registerPostFixer(syncDataIdPostFixer(editor));
265
+ // Registers the post-fixer to remove the `ckboxLinkId` attribute from the model selection.
266
+ model.document.registerPostFixer(injectSelectionPostFixer(selection));
267
+ }
268
+ }
269
+ /**
270
+ * A post-fixer that synchronizes the asset ID with the model element.
271
+ */
272
+ function syncDataIdPostFixer(editor) {
273
+ return (writer) => {
274
+ let changed = false;
275
+ const model = editor.model;
276
+ const ckboxCommand = editor.commands.get('ckbox');
277
+ // The ID from chosen assets are stored in the `CKBoxCommand#_chosenAssets`. If there is no command, it makes no sense to check
278
+ // for changes in the model.
279
+ if (!ckboxCommand) {
280
+ return changed;
281
+ }
282
+ for (const entry of model.document.differ.getChanges()) {
283
+ if (entry.type !== 'insert' && entry.type !== 'attribute') {
284
+ continue;
285
+ }
286
+ const range = entry.type === 'insert' ?
287
+ new Range(entry.position, entry.position.getShiftedBy(entry.length)) :
288
+ entry.range;
289
+ const isLinkHrefAttributeRemoval = entry.type === 'attribute' &&
290
+ entry.attributeKey === 'linkHref' &&
291
+ entry.attributeNewValue === null;
292
+ for (const item of range.getItems()) {
293
+ // If the `linkHref` attribute has been removed, sync the change with the `ckboxLinkId` attribute.
294
+ if (isLinkHrefAttributeRemoval && item.hasAttribute('ckboxLinkId')) {
295
+ writer.removeAttribute('ckboxLinkId', item);
296
+ changed = true;
297
+ continue;
298
+ }
299
+ // Otherwise, the change concerns either a new model element or an attribute change. Try to find the assets for the modified
300
+ // model element.
301
+ const assets = findAssetsForItem(item, ckboxCommand._chosenAssets);
302
+ for (const asset of assets) {
303
+ const attributeName = asset.type === 'image' ? 'ckboxImageId' : 'ckboxLinkId';
304
+ if (asset.id === item.getAttribute(attributeName)) {
305
+ continue;
306
+ }
307
+ writer.setAttribute(attributeName, asset.id, item);
308
+ changed = true;
309
+ }
310
+ }
311
+ }
312
+ return changed;
313
+ };
314
+ }
315
+ /**
316
+ * A post-fixer that removes the `ckboxLinkId` from the selection if it does not represent a link anymore.
317
+ */
318
+ function injectSelectionPostFixer(selection) {
319
+ return (writer) => {
320
+ const shouldRemoveLinkIdAttribute = !selection.hasAttribute('linkHref') && selection.hasAttribute('ckboxLinkId');
321
+ if (shouldRemoveLinkIdAttribute) {
322
+ writer.removeSelectionAttribute('ckboxLinkId');
323
+ return true;
324
+ }
325
+ return false;
326
+ };
327
+ }
328
+ /**
329
+ * Tries to find the asset that is associated with the model element by comparing the attributes:
330
+ * - the image fallback URL with the `src` attribute for images,
331
+ * - the link URL with the `href` attribute for links.
332
+ *
333
+ * For any model element, zero, one or more than one asset can be found (e.g. a linked image may be associated with the link asset and the
334
+ * image asset).
335
+ */
336
+ function findAssetsForItem(item, assets) {
337
+ const isImageElement = item.is('element', 'imageInline') || item.is('element', 'imageBlock');
338
+ const isLinkElement = item.hasAttribute('linkHref');
339
+ return [...assets].filter(asset => {
340
+ if (asset.type === 'image' && isImageElement) {
341
+ return asset.attributes.imageFallbackUrl === item.getAttribute('src');
342
+ }
343
+ if (asset.type === 'link' && isLinkElement) {
344
+ return asset.attributes.linkHref === item.getAttribute('linkHref');
345
+ }
346
+ });
347
+ }
348
+ /**
349
+ * Creates view link element with the requested ID.
350
+ */
351
+ function createLinkElement(writer, id) {
352
+ // Priority equal 5 is needed to merge adjacent `<a>` elements together.
353
+ const viewElement = writer.createAttributeElement('a', { 'data-ckbox-resource-id': id }, { priority: 5 });
354
+ writer.setCustomProperty('link', true, viewElement);
355
+ return viewElement;
356
+ }
357
+ /**
358
+ * Checks if the model element may have the `ckboxLinkId` attribute.
359
+ */
360
+ function shouldUpcastAttributeForNode(node) {
361
+ if (node.is('$text')) {
362
+ return true;
363
+ }
364
+ if (node.is('element', 'imageInline') || node.is('element', 'imageBlock')) {
365
+ return true;
366
+ }
367
+ return false;
368
+ }
369
+ /**
370
+ * Returns true if the CKBox library is loaded, false otherwise.
371
+ */
372
+ function isLibraryLoaded() {
373
+ return !!window.CKBox;
374
+ }
375
+ /**
376
+ * Checks is access allowed to upload assets.
377
+ */
378
+ async function isUploadPermissionGranted(editor) {
379
+ const ckboxUtils = editor.plugins.get(CKBoxUtils);
380
+ const origin = editor.config.get('ckbox.serviceOrigin');
381
+ const url = new URL('permissions', origin);
382
+ const { value } = await ckboxUtils.getToken();
383
+ const response = (await sendHttpRequest({
384
+ url,
385
+ authorization: value,
386
+ signal: (new AbortController()).signal // Aborting is unnecessary.
387
+ }));
388
+ return Object.values(response).some(category => category['asset:create']);
389
+ }
@@ -0,0 +1,105 @@
1
+ /**
2
+ * @license Copyright (c) 2003-2024, CKSource Holding sp. z o.o. All rights reserved.
3
+ * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
4
+ */
5
+ /**
6
+ * @module ckbox/ckboximageedit/ckboximageeditcommand
7
+ */
8
+ import { Command, type Editor } from 'ckeditor5/src/core.js';
9
+ /**
10
+ * The CKBox edit image command.
11
+ *
12
+ * Opens the CKBox dialog for editing the image.
13
+ */
14
+ export default class CKBoxImageEditCommand extends Command {
15
+ /**
16
+ * Flag indicating whether the command is active, i.e. dialog is open.
17
+ */
18
+ value: boolean;
19
+ /**
20
+ * The DOM element that acts as a mounting point for the CKBox Edit Image dialog.
21
+ */
22
+ private _wrapper;
23
+ /**
24
+ * The states of image processing in progress.
25
+ */
26
+ private _processInProgress;
27
+ /**
28
+ * Determines if the element can be edited.
29
+ */
30
+ private _canEdit;
31
+ /**
32
+ * A wrapper function to prepare mount options. Ensures that at most one preparation is in-flight.
33
+ */
34
+ private _prepareOptions;
35
+ /**
36
+ * CKBox's onClose function runs before the final cleanup, potentially causing
37
+ * page layout changes after it finishes. To address this, we use a setTimeout hack
38
+ * to ensure that floating elements on the page maintain their correct position.
39
+ *
40
+ * See: https://github.com/ckeditor/ckeditor5/issues/16153.
41
+ */
42
+ private _updateUiDelayed;
43
+ /**
44
+ * @inheritDoc
45
+ */
46
+ constructor(editor: Editor);
47
+ /**
48
+ * @inheritDoc
49
+ */
50
+ refresh(): void;
51
+ /**
52
+ * Opens the CKBox Image Editor dialog for editing the image.
53
+ */
54
+ execute(): void;
55
+ /**
56
+ * @inheritDoc
57
+ */
58
+ destroy(): void;
59
+ /**
60
+ * Indicates if the CKBox Image Editor dialog is already opened.
61
+ */
62
+ private _getValue;
63
+ /**
64
+ * Creates the options object for the CKBox Image Editor dialog.
65
+ */
66
+ private _prepareOptionsAbortable;
67
+ /**
68
+ * Initializes event lister for an event of removing an image.
69
+ */
70
+ private _prepareListeners;
71
+ /**
72
+ * Gets processing states of images that have been deleted in the mean time.
73
+ */
74
+ private _getProcessingStatesOfDeletedImages;
75
+ private _checkIfElementIsBeingProcessed;
76
+ /**
77
+ * Closes the CKBox Image Editor dialog.
78
+ */
79
+ private _handleImageEditorClose;
80
+ /**
81
+ * Save edited image. In case server respond with "success" replace with edited image,
82
+ * otherwise show notification error.
83
+ */
84
+ private _handleImageEditorSave;
85
+ /**
86
+ * Get asset's status on server. If server responds with "success" status then
87
+ * image is already proceeded and ready for saving.
88
+ */
89
+ private _getAssetStatusFromServer;
90
+ /**
91
+ * Waits for an asset to be processed.
92
+ * It retries retrieving asset status from the server in case of failure.
93
+ */
94
+ private _waitForAssetProcessed;
95
+ /**
96
+ * Shows processing indicator while image is processing.
97
+ *
98
+ * @param asset Data about certain asset.
99
+ */
100
+ private _showImageProcessingIndicator;
101
+ /**
102
+ * Replace the edited image with the new one.
103
+ */
104
+ private _replaceImage;
105
+ }