@ckeditor/ckeditor5-image 41.3.1 → 41.4.0-alpha.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 (223) hide show
  1. package/build/image.js +1 -1
  2. package/ckeditor5-metadata.json +1 -1
  3. package/dist/index-content.css +105 -0
  4. package/dist/index-editor.css +132 -0
  5. package/dist/index.css +542 -0
  6. package/dist/index.css.map +1 -0
  7. package/dist/index.js +5638 -0
  8. package/dist/index.js.map +1 -0
  9. package/dist/translations/ar.d.ts +8 -0
  10. package/dist/translations/ar.js +5 -0
  11. package/dist/translations/ast.d.ts +8 -0
  12. package/dist/translations/ast.js +5 -0
  13. package/dist/translations/az.d.ts +8 -0
  14. package/dist/translations/az.js +5 -0
  15. package/dist/translations/bg.d.ts +8 -0
  16. package/dist/translations/bg.js +5 -0
  17. package/dist/translations/bn.d.ts +8 -0
  18. package/dist/translations/bn.js +5 -0
  19. package/dist/translations/bs.d.ts +8 -0
  20. package/dist/translations/bs.js +5 -0
  21. package/dist/translations/ca.d.ts +8 -0
  22. package/dist/translations/ca.js +5 -0
  23. package/dist/translations/cs.d.ts +8 -0
  24. package/dist/translations/cs.js +5 -0
  25. package/dist/translations/da.d.ts +8 -0
  26. package/dist/translations/da.js +5 -0
  27. package/dist/translations/de-ch.d.ts +8 -0
  28. package/dist/translations/de-ch.js +5 -0
  29. package/dist/translations/de.d.ts +8 -0
  30. package/dist/translations/de.js +5 -0
  31. package/dist/translations/el.d.ts +8 -0
  32. package/dist/translations/el.js +5 -0
  33. package/dist/translations/en-au.d.ts +8 -0
  34. package/dist/translations/en-au.js +5 -0
  35. package/dist/translations/en-gb.d.ts +8 -0
  36. package/dist/translations/en-gb.js +5 -0
  37. package/dist/translations/en.d.ts +8 -0
  38. package/dist/translations/en.js +5 -0
  39. package/dist/translations/eo.d.ts +8 -0
  40. package/dist/translations/eo.js +5 -0
  41. package/dist/translations/es-co.d.ts +8 -0
  42. package/dist/translations/es-co.js +5 -0
  43. package/dist/translations/es.d.ts +8 -0
  44. package/dist/translations/es.js +5 -0
  45. package/dist/translations/et.d.ts +8 -0
  46. package/dist/translations/et.js +5 -0
  47. package/dist/translations/eu.d.ts +8 -0
  48. package/dist/translations/eu.js +5 -0
  49. package/dist/translations/fa.d.ts +8 -0
  50. package/dist/translations/fa.js +5 -0
  51. package/dist/translations/fi.d.ts +8 -0
  52. package/dist/translations/fi.js +5 -0
  53. package/dist/translations/fr.d.ts +8 -0
  54. package/dist/translations/fr.js +5 -0
  55. package/dist/translations/gl.d.ts +8 -0
  56. package/dist/translations/gl.js +5 -0
  57. package/dist/translations/he.d.ts +8 -0
  58. package/dist/translations/he.js +5 -0
  59. package/dist/translations/hi.d.ts +8 -0
  60. package/dist/translations/hi.js +5 -0
  61. package/dist/translations/hr.d.ts +8 -0
  62. package/dist/translations/hr.js +5 -0
  63. package/dist/translations/hu.d.ts +8 -0
  64. package/dist/translations/hu.js +5 -0
  65. package/dist/translations/id.d.ts +8 -0
  66. package/dist/translations/id.js +5 -0
  67. package/dist/translations/it.d.ts +8 -0
  68. package/dist/translations/it.js +5 -0
  69. package/dist/translations/ja.d.ts +8 -0
  70. package/dist/translations/ja.js +5 -0
  71. package/dist/translations/jv.d.ts +8 -0
  72. package/dist/translations/jv.js +5 -0
  73. package/dist/translations/km.d.ts +8 -0
  74. package/dist/translations/km.js +5 -0
  75. package/dist/translations/kn.d.ts +8 -0
  76. package/dist/translations/kn.js +5 -0
  77. package/dist/translations/ko.d.ts +8 -0
  78. package/dist/translations/ko.js +5 -0
  79. package/dist/translations/ku.d.ts +8 -0
  80. package/dist/translations/ku.js +5 -0
  81. package/dist/translations/lt.d.ts +8 -0
  82. package/dist/translations/lt.js +5 -0
  83. package/dist/translations/lv.d.ts +8 -0
  84. package/dist/translations/lv.js +5 -0
  85. package/dist/translations/ms.d.ts +8 -0
  86. package/dist/translations/ms.js +5 -0
  87. package/dist/translations/nb.d.ts +8 -0
  88. package/dist/translations/nb.js +5 -0
  89. package/dist/translations/ne.d.ts +8 -0
  90. package/dist/translations/ne.js +5 -0
  91. package/dist/translations/nl.d.ts +8 -0
  92. package/dist/translations/nl.js +5 -0
  93. package/dist/translations/no.d.ts +8 -0
  94. package/dist/translations/no.js +5 -0
  95. package/dist/translations/pl.d.ts +8 -0
  96. package/dist/translations/pl.js +5 -0
  97. package/dist/translations/pt-br.d.ts +8 -0
  98. package/dist/translations/pt-br.js +5 -0
  99. package/dist/translations/pt.d.ts +8 -0
  100. package/dist/translations/pt.js +5 -0
  101. package/dist/translations/ro.d.ts +8 -0
  102. package/dist/translations/ro.js +5 -0
  103. package/dist/translations/ru.d.ts +8 -0
  104. package/dist/translations/ru.js +5 -0
  105. package/dist/translations/si.d.ts +8 -0
  106. package/dist/translations/si.js +5 -0
  107. package/dist/translations/sk.d.ts +8 -0
  108. package/dist/translations/sk.js +5 -0
  109. package/dist/translations/sq.d.ts +8 -0
  110. package/dist/translations/sq.js +5 -0
  111. package/dist/translations/sr-latn.d.ts +8 -0
  112. package/dist/translations/sr-latn.js +5 -0
  113. package/dist/translations/sr.d.ts +8 -0
  114. package/dist/translations/sr.js +5 -0
  115. package/dist/translations/sv.d.ts +8 -0
  116. package/dist/translations/sv.js +5 -0
  117. package/dist/translations/th.d.ts +8 -0
  118. package/dist/translations/th.js +5 -0
  119. package/dist/translations/tk.d.ts +8 -0
  120. package/dist/translations/tk.js +5 -0
  121. package/dist/translations/tr.d.ts +8 -0
  122. package/dist/translations/tr.js +5 -0
  123. package/dist/translations/tt.d.ts +8 -0
  124. package/dist/translations/tt.js +5 -0
  125. package/dist/translations/ug.d.ts +8 -0
  126. package/dist/translations/ug.js +5 -0
  127. package/dist/translations/uk.d.ts +8 -0
  128. package/dist/translations/uk.js +5 -0
  129. package/dist/translations/ur.d.ts +8 -0
  130. package/dist/translations/ur.js +5 -0
  131. package/dist/translations/uz.d.ts +8 -0
  132. package/dist/translations/uz.js +5 -0
  133. package/dist/translations/vi.d.ts +8 -0
  134. package/dist/translations/vi.js +5 -0
  135. package/dist/translations/zh-cn.d.ts +8 -0
  136. package/dist/translations/zh-cn.js +5 -0
  137. package/dist/translations/zh.d.ts +8 -0
  138. package/dist/translations/zh.js +5 -0
  139. package/dist/types/augmentation.d.ts +61 -0
  140. package/dist/types/autoimage.d.ts +56 -0
  141. package/dist/types/image/converters.d.ts +70 -0
  142. package/dist/types/image/imageblockediting.d.ts +63 -0
  143. package/dist/types/image/imageediting.d.ts +34 -0
  144. package/dist/types/image/imageinlineediting.d.ts +64 -0
  145. package/dist/types/image/imageloadobserver.d.ts +52 -0
  146. package/dist/types/image/imageplaceholder.d.ts +43 -0
  147. package/dist/types/image/imagetypecommand.d.ts +48 -0
  148. package/dist/types/image/insertimagecommand.d.ts +70 -0
  149. package/dist/types/image/replaceimagesourcecommand.d.ts +55 -0
  150. package/dist/types/image/ui/utils.d.ts +29 -0
  151. package/dist/types/image/utils.d.ts +68 -0
  152. package/dist/types/image.d.ts +38 -0
  153. package/dist/types/imageblock.d.ts +38 -0
  154. package/dist/types/imagecaption/imagecaptionediting.d.ts +93 -0
  155. package/dist/types/imagecaption/imagecaptionui.d.ts +30 -0
  156. package/dist/types/imagecaption/imagecaptionutils.d.ts +42 -0
  157. package/dist/types/imagecaption/toggleimagecaptioncommand.d.ts +70 -0
  158. package/dist/types/imagecaption.d.ts +30 -0
  159. package/dist/types/imageconfig.d.ts +716 -0
  160. package/dist/types/imageinline.d.ts +38 -0
  161. package/dist/types/imageinsert/imageinsertui.d.ts +78 -0
  162. package/dist/types/imageinsert/imageinsertviaurlui.d.ts +48 -0
  163. package/dist/types/imageinsert/ui/imageinsertformview.d.ts +60 -0
  164. package/dist/types/imageinsert/ui/imageinserturlview.d.ts +111 -0
  165. package/dist/types/imageinsert.d.ts +37 -0
  166. package/dist/types/imageinsertviaurl.d.ts +35 -0
  167. package/dist/types/imageresize/imagecustomresizeui.d.ts +65 -0
  168. package/dist/types/imageresize/imageresizebuttons.d.ts +68 -0
  169. package/dist/types/imageresize/imageresizeediting.d.ts +45 -0
  170. package/dist/types/imageresize/imageresizehandles.d.ts +35 -0
  171. package/dist/types/imageresize/resizeimagecommand.d.ts +46 -0
  172. package/dist/types/imageresize/ui/imagecustomresizeformview.d.ts +133 -0
  173. package/dist/types/imageresize/utils/getselectedimageeditornodes.d.ts +28 -0
  174. package/dist/types/imageresize/utils/getselectedimagepossibleresizerange.d.ts +28 -0
  175. package/dist/types/imageresize/utils/getselectedimagewidthinunits.d.ts +22 -0
  176. package/dist/types/imageresize/utils/tryparsedimensionwithunit.d.ts +41 -0
  177. package/dist/types/imageresize.d.ts +32 -0
  178. package/dist/types/imagesizeattributes.d.ts +38 -0
  179. package/dist/types/imagestyle/converters.d.ts +28 -0
  180. package/dist/types/imagestyle/imagestylecommand.d.ts +72 -0
  181. package/dist/types/imagestyle/imagestyleediting.d.ts +54 -0
  182. package/dist/types/imagestyle/imagestyleui.d.ts +60 -0
  183. package/dist/types/imagestyle/utils.d.ts +105 -0
  184. package/dist/types/imagestyle.d.ts +36 -0
  185. package/dist/types/imagetextalternative/imagetextalternativecommand.d.ts +38 -0
  186. package/dist/types/imagetextalternative/imagetextalternativeediting.d.ts +32 -0
  187. package/dist/types/imagetextalternative/imagetextalternativeui.d.ts +72 -0
  188. package/dist/types/imagetextalternative/ui/textalternativeformview.d.ts +94 -0
  189. package/dist/types/imagetextalternative.d.ts +33 -0
  190. package/dist/types/imagetoolbar.d.ts +39 -0
  191. package/dist/types/imageupload/imageuploadediting.d.ts +115 -0
  192. package/dist/types/imageupload/imageuploadprogress.d.ts +46 -0
  193. package/dist/types/imageupload/imageuploadui.d.ts +34 -0
  194. package/dist/types/imageupload/uploadimagecommand.d.ts +64 -0
  195. package/dist/types/imageupload/utils.d.ts +37 -0
  196. package/dist/types/imageupload.d.ts +36 -0
  197. package/dist/types/imageutils.d.ts +129 -0
  198. package/dist/types/index.d.ts +53 -0
  199. package/dist/types/pictureediting.d.ts +92 -0
  200. package/lang/contexts.json +9 -1
  201. package/package.json +4 -3
  202. package/src/augmentation.d.ts +2 -1
  203. package/src/imageresize/imagecustomresizeui.d.ts +61 -0
  204. package/src/imageresize/imagecustomresizeui.js +168 -0
  205. package/src/imageresize/imageresizebuttons.d.ts +0 -3
  206. package/src/imageresize/imageresizebuttons.js +95 -23
  207. package/src/imageresize/imageresizeediting.js +9 -2
  208. package/src/imageresize/ui/imagecustomresizeformview.d.ts +129 -0
  209. package/src/imageresize/ui/imagecustomresizeformview.js +186 -0
  210. package/src/imageresize/utils/getselectedimageeditornodes.d.ts +24 -0
  211. package/src/imageresize/utils/getselectedimageeditornodes.js +24 -0
  212. package/src/imageresize/utils/getselectedimagepossibleresizerange.d.ts +24 -0
  213. package/src/imageresize/utils/getselectedimagepossibleresizerange.js +32 -0
  214. package/src/imageresize/utils/getselectedimagewidthinunits.d.ts +18 -0
  215. package/src/imageresize/utils/getselectedimagewidthinunits.js +41 -0
  216. package/src/imageresize/utils/tryparsedimensionwithunit.d.ts +37 -0
  217. package/src/imageresize/utils/tryparsedimensionwithunit.js +56 -0
  218. package/src/imageresize.d.ts +2 -1
  219. package/src/imageresize.js +2 -1
  220. package/src/imageupload/imageuploadediting.js +9 -0
  221. package/src/index.d.ts +1 -0
  222. package/src/index.js +1 -0
  223. package/theme/imagecustomresizeform.css +33 -0
@@ -5,6 +5,7 @@
5
5
  /**
6
6
  * @module image/imageresize/imageresizebuttons
7
7
  */
8
+ import { map } from 'lodash-es';
8
9
  import { Plugin, icons } from 'ckeditor5/src/core.js';
9
10
  import { ButtonView, DropdownButtonView, ViewModel, createDropdown, addListToDropdown } from 'ckeditor5/src/ui.js';
10
11
  import { CKEditorError, Collection } from 'ckeditor5/src/utils.js';
@@ -13,6 +14,7 @@ const RESIZE_ICONS = {
13
14
  small: icons.objectSizeSmall,
14
15
  medium: icons.objectSizeMedium,
15
16
  large: icons.objectSizeLarge,
17
+ custom: icons.objectSizeCustom,
16
18
  original: icons.objectSizeFull
17
19
  };
18
20
  /**
@@ -61,7 +63,6 @@ export default class ImageResizeButtons extends Plugin {
61
63
  _registerImageResizeButton(option) {
62
64
  const editor = this.editor;
63
65
  const { name, value, icon } = option;
64
- const optionValueWithUnit = value ? value + this._resizeUnit : null;
65
66
  editor.ui.componentFactory.add(name, locale => {
66
67
  const button = new ButtonView(locale);
67
68
  const command = editor.commands.get('resizeImage');
@@ -88,10 +89,19 @@ export default class ImageResizeButtons extends Plugin {
88
89
  });
89
90
  // Bind button to the command.
90
91
  button.bind('isEnabled').to(this);
91
- button.bind('isOn').to(command, 'value', getIsOnButtonCallback(optionValueWithUnit));
92
- this.listenTo(button, 'execute', () => {
93
- editor.execute('resizeImage', { width: optionValueWithUnit });
94
- });
92
+ if (editor.plugins.has('ImageCustomResizeUI') && isCustomImageResizeOption(option)) {
93
+ const customResizeUI = editor.plugins.get('ImageCustomResizeUI');
94
+ this.listenTo(button, 'execute', () => {
95
+ customResizeUI._showForm(this._resizeUnit);
96
+ });
97
+ }
98
+ else {
99
+ const optionValueWithUnit = value ? value + this._resizeUnit : null;
100
+ button.bind('isOn').to(command, 'value', getIsOnButtonCallback(optionValueWithUnit));
101
+ this.listenTo(button, 'execute', () => {
102
+ editor.execute('resizeImage', { width: optionValueWithUnit });
103
+ });
104
+ }
95
105
  return button;
96
106
  });
97
107
  }
@@ -136,8 +146,13 @@ export default class ImageResizeButtons extends Plugin {
136
146
  });
137
147
  // Execute command when an item from the dropdown is selected.
138
148
  this.listenTo(dropdownView, 'execute', evt => {
139
- editor.execute(evt.source.commandName, { width: evt.source.commandValue });
140
- editor.editing.view.focus();
149
+ if ('onClick' in evt.source) {
150
+ evt.source.onClick();
151
+ }
152
+ else {
153
+ editor.execute(evt.source.commandName, { width: evt.source.commandValue });
154
+ editor.editing.view.focus();
155
+ }
141
156
  });
142
157
  return dropdownView;
143
158
  };
@@ -159,7 +174,10 @@ export default class ImageResizeButtons extends Plugin {
159
174
  return option.label;
160
175
  }
161
176
  else if (forTooltip) {
162
- if (option.value) {
177
+ if (isCustomImageResizeOption(option)) {
178
+ return t('Custom image size');
179
+ }
180
+ else if (option.value) {
163
181
  return t('Resize image to %0', option.value + this._resizeUnit);
164
182
  }
165
183
  else {
@@ -167,7 +185,10 @@ export default class ImageResizeButtons extends Plugin {
167
185
  }
168
186
  }
169
187
  else {
170
- if (option.value) {
188
+ if (isCustomImageResizeOption(option)) {
189
+ return t('Custom');
190
+ }
191
+ else if (option.value) {
171
192
  return option.value + this._resizeUnit;
172
193
  }
173
194
  else {
@@ -183,26 +204,71 @@ export default class ImageResizeButtons extends Plugin {
183
204
  * @returns Dropdown item definitions.
184
205
  */
185
206
  _getResizeDropdownListItemDefinitions(options, command) {
207
+ const { editor } = this;
186
208
  const itemDefinitions = new Collection();
187
- options.map(option => {
188
- const optionValueWithUnit = option.value ? option.value + this._resizeUnit : null;
189
- const definition = {
190
- type: 'button',
191
- model: new ViewModel({
192
- commandName: 'resizeImage',
193
- commandValue: optionValueWithUnit,
194
- label: this._getOptionLabelValue(option),
195
- role: 'menuitemradio',
196
- withText: true,
197
- icon: null
198
- })
209
+ const optionsWithSerializedValues = options.map(option => {
210
+ if (isCustomImageResizeOption(option)) {
211
+ return {
212
+ ...option,
213
+ valueWithUnits: 'custom'
214
+ };
215
+ }
216
+ if (!option.value) {
217
+ return {
218
+ ...option,
219
+ valueWithUnits: null
220
+ };
221
+ }
222
+ return {
223
+ ...option,
224
+ valueWithUnits: `${option.value}${this._resizeUnit}`
199
225
  };
200
- definition.model.bind('isOn').to(command, 'value', getIsOnButtonCallback(optionValueWithUnit));
201
- itemDefinitions.add(definition);
202
226
  });
227
+ for (const option of optionsWithSerializedValues) {
228
+ let definition = null;
229
+ if (editor.plugins.has('ImageCustomResizeUI') && isCustomImageResizeOption(option)) {
230
+ const customResizeUI = editor.plugins.get('ImageCustomResizeUI');
231
+ definition = {
232
+ type: 'button',
233
+ model: new ViewModel({
234
+ label: this._getOptionLabelValue(option),
235
+ role: 'menuitemradio',
236
+ withText: true,
237
+ icon: null,
238
+ onClick: () => {
239
+ customResizeUI._showForm(this._resizeUnit);
240
+ }
241
+ })
242
+ };
243
+ const allDropdownValues = map(optionsWithSerializedValues, 'valueWithUnits');
244
+ definition.model.bind('isOn').to(command, 'value', getIsOnCustomButtonCallback(allDropdownValues));
245
+ }
246
+ else {
247
+ definition = {
248
+ type: 'button',
249
+ model: new ViewModel({
250
+ commandName: 'resizeImage',
251
+ commandValue: option.valueWithUnits,
252
+ label: this._getOptionLabelValue(option),
253
+ role: 'menuitemradio',
254
+ withText: true,
255
+ icon: null
256
+ })
257
+ };
258
+ definition.model.bind('isOn').to(command, 'value', getIsOnButtonCallback(option.valueWithUnits));
259
+ }
260
+ definition.model.bind('isEnabled').to(command, 'isEnabled');
261
+ itemDefinitions.add(definition);
262
+ }
203
263
  return itemDefinitions;
204
264
  }
205
265
  }
266
+ /**
267
+ * A helper that checks if provided option triggers custom resize balloon.
268
+ */
269
+ function isCustomImageResizeOption(option) {
270
+ return option.value === 'custom';
271
+ }
206
272
  /**
207
273
  * A helper function for setting the `isOn` state of buttons in value bindings.
208
274
  */
@@ -215,3 +281,9 @@ function getIsOnButtonCallback(value) {
215
281
  return objectCommandValue !== null && objectCommandValue.width === value;
216
282
  };
217
283
  }
284
+ /**
285
+ * A helper function for setting the `isOn` state of custom size button in value bindings.
286
+ */
287
+ function getIsOnCustomButtonCallback(allDropdownValues) {
288
+ return (commandValue) => !allDropdownValues.some(dropdownValue => getIsOnButtonCallback(dropdownValue)(commandValue));
289
+ }
@@ -32,11 +32,17 @@ export default class ImageResizeEditing extends Plugin {
32
32
  super(editor);
33
33
  editor.config.define('image', {
34
34
  resizeUnit: '%',
35
- resizeOptions: [{
35
+ resizeOptions: [
36
+ {
36
37
  name: 'resizeImage:original',
37
38
  value: null,
38
39
  icon: 'original'
39
40
  },
41
+ {
42
+ name: 'resizeImage:custom',
43
+ value: 'custom',
44
+ icon: 'custom'
45
+ },
40
46
  {
41
47
  name: 'resizeImage:25',
42
48
  value: '25',
@@ -51,7 +57,8 @@ export default class ImageResizeEditing extends Plugin {
51
57
  name: 'resizeImage:75',
52
58
  value: '75',
53
59
  icon: 'large'
54
- }]
60
+ }
61
+ ]
55
62
  });
56
63
  }
57
64
  /**
@@ -0,0 +1,129 @@
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 image/imageresize/ui/imagecustomresizeformview
7
+ */
8
+ import { ButtonView, FocusCycler, LabeledFieldView, View, ViewCollection, type FocusableView, type InputNumberView } from 'ckeditor5/src/ui.js';
9
+ import { FocusTracker, KeystrokeHandler, type Locale } from 'ckeditor5/src/utils.js';
10
+ import '../../../theme/imagecustomresizeform.css';
11
+ import '@ckeditor/ckeditor5-ui/theme/components/responsive-form/responsiveform.css';
12
+ /**
13
+ * The ImageCustomResizeFormView class.
14
+ */
15
+ export default class ImageCustomResizeFormView extends View {
16
+ /**
17
+ * Tracks information about the DOM focus in the form.
18
+ */
19
+ readonly focusTracker: FocusTracker;
20
+ /**
21
+ * An instance of the {@link module:utils/keystrokehandler~KeystrokeHandler}.
22
+ */
23
+ readonly keystrokes: KeystrokeHandler;
24
+ /**
25
+ * Resize unit shortcut.
26
+ */
27
+ readonly unit: string;
28
+ /**
29
+ * An input with a label.
30
+ */
31
+ labeledInput: LabeledFieldView<InputNumberView>;
32
+ /**
33
+ * A button used to submit the form.
34
+ */
35
+ saveButtonView: ButtonView;
36
+ /**
37
+ * A button used to cancel the form.
38
+ */
39
+ cancelButtonView: ButtonView;
40
+ /**
41
+ * A collection of views which can be focused in the form.
42
+ */
43
+ protected readonly _focusables: ViewCollection<FocusableView>;
44
+ /**
45
+ * Helps cycling over {@link #_focusables} in the form.
46
+ */
47
+ protected readonly _focusCycler: FocusCycler;
48
+ /**
49
+ * An array of form validators used by {@link #isValid}.
50
+ */
51
+ private readonly _validators;
52
+ /**
53
+ * @inheritDoc
54
+ */
55
+ constructor(locale: Locale, unit: string, validators: Array<ImageCustomResizeFormValidatorCallback>);
56
+ /**
57
+ * @inheritDoc
58
+ */
59
+ render(): void;
60
+ /**
61
+ * @inheritDoc
62
+ */
63
+ destroy(): void;
64
+ /**
65
+ * Creates the button view.
66
+ *
67
+ * @param label The button label
68
+ * @param icon The button's icon.
69
+ * @param className The additional button CSS class name.
70
+ * @param eventName The event name that the ButtonView#execute event will be delegated to.
71
+ * @returns The button view instance.
72
+ */
73
+ private _createButton;
74
+ /**
75
+ * Creates an input with a label.
76
+ *
77
+ * @returns Labeled field view instance.
78
+ */
79
+ private _createLabeledInputView;
80
+ /**
81
+ * Validates the form and returns `false` when some fields are invalid.
82
+ */
83
+ isValid(): boolean;
84
+ /**
85
+ * Cleans up the supplementary error and information text of the {@link #labeledInput}
86
+ * bringing them back to the state when the form has been displayed for the first time.
87
+ *
88
+ * See {@link #isValid}.
89
+ */
90
+ resetFormStatus(): void;
91
+ /**
92
+ * The native DOM `value` of the input element of {@link #labeledInput}.
93
+ */
94
+ get rawSize(): string | null;
95
+ /**
96
+ * Get numeric value of size. Returns `null` if value of size input element in {@link #labeledInput}.is not a number.
97
+ */
98
+ get parsedSize(): number | null;
99
+ /**
100
+ * Returns serialized image input size with unit.
101
+ * Returns `null` if value of size input element in {@link #labeledInput}.is not a number.
102
+ */
103
+ get sizeWithUnits(): string | null;
104
+ }
105
+ /**
106
+ * Callback used by {@link ~ImageCustomResizeFormView} to check if passed form value is valid.
107
+ *
108
+ * * If `undefined` is returned, it is assumed that the form value is correct and there is no error.
109
+ * * If string is returned, it is assumed that the form value is incorrect and the returned string is displayed in the error label
110
+ */
111
+ export type ImageCustomResizeFormValidatorCallback = (form: ImageCustomResizeFormView) => string | undefined;
112
+ /**
113
+ * Fired when the form view is submitted.
114
+ *
115
+ * @eventName ~ImageCustomResizeFormView#submit
116
+ */
117
+ export type ImageCustomResizeFormViewSubmitEvent = {
118
+ name: 'submit';
119
+ args: [];
120
+ };
121
+ /**
122
+ * Fired when the form view is canceled.
123
+ *
124
+ * @eventName ~ImageCustomResizeFormView#cancel
125
+ */
126
+ export type ImageCustomResizeFormViewCancelEvent = {
127
+ name: 'cancel';
128
+ args: [];
129
+ };
@@ -0,0 +1,186 @@
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 image/imageresize/ui/imagecustomresizeformview
7
+ */
8
+ import { ButtonView, FocusCycler, LabeledFieldView, View, ViewCollection, createLabeledInputNumber, submitHandler } from 'ckeditor5/src/ui.js';
9
+ import { FocusTracker, KeystrokeHandler } from 'ckeditor5/src/utils.js';
10
+ import { icons } from 'ckeditor5/src/core.js';
11
+ import '../../../theme/imagecustomresizeform.css';
12
+ // See: #8833.
13
+ // eslint-disable-next-line ckeditor5-rules/ckeditor-imports
14
+ import '@ckeditor/ckeditor5-ui/theme/components/responsive-form/responsiveform.css';
15
+ /**
16
+ * The ImageCustomResizeFormView class.
17
+ */
18
+ export default class ImageCustomResizeFormView extends View {
19
+ /**
20
+ * @inheritDoc
21
+ */
22
+ constructor(locale, unit, validators) {
23
+ super(locale);
24
+ const t = this.locale.t;
25
+ this.focusTracker = new FocusTracker();
26
+ this.keystrokes = new KeystrokeHandler();
27
+ this.unit = unit;
28
+ this.labeledInput = this._createLabeledInputView();
29
+ this.saveButtonView = this._createButton(t('Save'), icons.check, 'ck-button-save');
30
+ this.saveButtonView.type = 'submit';
31
+ this.cancelButtonView = this._createButton(t('Cancel'), icons.cancel, 'ck-button-cancel', 'cancel');
32
+ this._focusables = new ViewCollection();
33
+ this._validators = validators;
34
+ this._focusCycler = new FocusCycler({
35
+ focusables: this._focusables,
36
+ focusTracker: this.focusTracker,
37
+ keystrokeHandler: this.keystrokes,
38
+ actions: {
39
+ // Navigate form fields backwards using the Shift + Tab keystroke.
40
+ focusPrevious: 'shift + tab',
41
+ // Navigate form fields forwards using the Tab key.
42
+ focusNext: 'tab'
43
+ }
44
+ });
45
+ this.setTemplate({
46
+ tag: 'form',
47
+ attributes: {
48
+ class: [
49
+ 'ck',
50
+ 'ck-image-custom-resize-form',
51
+ 'ck-responsive-form'
52
+ ],
53
+ // https://github.com/ckeditor/ckeditor5-image/issues/40
54
+ tabindex: '-1'
55
+ },
56
+ children: [
57
+ this.labeledInput,
58
+ this.saveButtonView,
59
+ this.cancelButtonView
60
+ ]
61
+ });
62
+ }
63
+ /**
64
+ * @inheritDoc
65
+ */
66
+ render() {
67
+ super.render();
68
+ this.keystrokes.listenTo(this.element);
69
+ submitHandler({ view: this });
70
+ [this.labeledInput, this.saveButtonView, this.cancelButtonView]
71
+ .forEach(v => {
72
+ // Register the view as focusable.
73
+ this._focusables.add(v);
74
+ // Register the view in the focus tracker.
75
+ this.focusTracker.add(v.element);
76
+ });
77
+ }
78
+ /**
79
+ * @inheritDoc
80
+ */
81
+ destroy() {
82
+ super.destroy();
83
+ this.focusTracker.destroy();
84
+ this.keystrokes.destroy();
85
+ }
86
+ /**
87
+ * Creates the button view.
88
+ *
89
+ * @param label The button label
90
+ * @param icon The button's icon.
91
+ * @param className The additional button CSS class name.
92
+ * @param eventName The event name that the ButtonView#execute event will be delegated to.
93
+ * @returns The button view instance.
94
+ */
95
+ _createButton(label, icon, className, eventName) {
96
+ const button = new ButtonView(this.locale);
97
+ button.set({
98
+ label,
99
+ icon,
100
+ tooltip: true
101
+ });
102
+ button.extendTemplate({
103
+ attributes: {
104
+ class: className
105
+ }
106
+ });
107
+ if (eventName) {
108
+ button.delegate('execute').to(this, eventName);
109
+ }
110
+ return button;
111
+ }
112
+ /**
113
+ * Creates an input with a label.
114
+ *
115
+ * @returns Labeled field view instance.
116
+ */
117
+ _createLabeledInputView() {
118
+ const t = this.locale.t;
119
+ const labeledInput = new LabeledFieldView(this.locale, createLabeledInputNumber);
120
+ labeledInput.label = t('Resize image (in %0)', this.unit);
121
+ labeledInput.fieldView.set({
122
+ step: 0.1
123
+ });
124
+ return labeledInput;
125
+ }
126
+ /**
127
+ * Validates the form and returns `false` when some fields are invalid.
128
+ */
129
+ isValid() {
130
+ this.resetFormStatus();
131
+ for (const validator of this._validators) {
132
+ const errorText = validator(this);
133
+ // One error per field is enough.
134
+ if (errorText) {
135
+ // Apply updated error.
136
+ this.labeledInput.errorText = errorText;
137
+ return false;
138
+ }
139
+ }
140
+ return true;
141
+ }
142
+ /**
143
+ * Cleans up the supplementary error and information text of the {@link #labeledInput}
144
+ * bringing them back to the state when the form has been displayed for the first time.
145
+ *
146
+ * See {@link #isValid}.
147
+ */
148
+ resetFormStatus() {
149
+ this.labeledInput.errorText = null;
150
+ }
151
+ /**
152
+ * The native DOM `value` of the input element of {@link #labeledInput}.
153
+ */
154
+ get rawSize() {
155
+ const { element } = this.labeledInput.fieldView;
156
+ if (!element) {
157
+ return null;
158
+ }
159
+ return element.value;
160
+ }
161
+ /**
162
+ * Get numeric value of size. Returns `null` if value of size input element in {@link #labeledInput}.is not a number.
163
+ */
164
+ get parsedSize() {
165
+ const { rawSize } = this;
166
+ if (rawSize === null) {
167
+ return null;
168
+ }
169
+ const parsed = Number.parseFloat(rawSize);
170
+ if (Number.isNaN(parsed)) {
171
+ return null;
172
+ }
173
+ return parsed;
174
+ }
175
+ /**
176
+ * Returns serialized image input size with unit.
177
+ * Returns `null` if value of size input element in {@link #labeledInput}.is not a number.
178
+ */
179
+ get sizeWithUnits() {
180
+ const { parsedSize, unit } = this;
181
+ if (parsedSize === null) {
182
+ return null;
183
+ }
184
+ return `${parsedSize}${unit}`;
185
+ }
186
+ }
@@ -0,0 +1,24 @@
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 image/imageresize/utils/getselectedimageeditornodes
7
+ */
8
+ import type { ViewElement, Element } from 'ckeditor5/src/engine.js';
9
+ import type { Editor } from 'ckeditor5/src/core.js';
10
+ /**
11
+ * Finds model, view and DOM element for selected image element. Returns `null` if there is no image selected.
12
+ *
13
+ * @param editor Editor instance.
14
+ */
15
+ export declare function getSelectedImageEditorNodes(editor: Editor): ImageEditorNodes | null;
16
+ /**
17
+ * @internal;
18
+ */
19
+ type ImageEditorNodes = {
20
+ model: Element;
21
+ view: ViewElement;
22
+ dom: HTMLElement;
23
+ };
24
+ export {};
@@ -0,0 +1,24 @@
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
+ * Finds model, view and DOM element for selected image element. Returns `null` if there is no image selected.
7
+ *
8
+ * @param editor Editor instance.
9
+ */
10
+ export function getSelectedImageEditorNodes(editor) {
11
+ const { editing } = editor;
12
+ const imageUtils = editor.plugins.get('ImageUtils');
13
+ const imageModelElement = imageUtils.getClosestSelectedImageElement(editor.model.document.selection);
14
+ if (!imageModelElement) {
15
+ return null;
16
+ }
17
+ const imageViewElement = editing.mapper.toViewElement(imageModelElement);
18
+ const imageDOMElement = editing.view.domConverter.mapViewToDom(imageViewElement);
19
+ return {
20
+ model: imageModelElement,
21
+ view: imageViewElement,
22
+ dom: imageDOMElement
23
+ };
24
+ }
@@ -0,0 +1,24 @@
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 image/imageresize/utils/getselectedimagepossibleresizerange
7
+ */
8
+ import type { Editor } from 'ckeditor5/src/core.js';
9
+ /**
10
+ * Returns min and max value of resize image in specified unit.
11
+ *
12
+ * @param editor Editor instance.
13
+ * @param targetUnit Unit in which dimension will be returned.
14
+ * @returns Possible resize range in numeric form.
15
+ */
16
+ export declare function getSelectedImagePossibleResizeRange(editor: Editor, targetUnit: string): PossibleResizeImageRange | null;
17
+ /**
18
+ * @internal
19
+ */
20
+ export type PossibleResizeImageRange = {
21
+ unit: string;
22
+ lower: number;
23
+ upper: number;
24
+ };
@@ -0,0 +1,32 @@
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
+ import { calculateResizeHostAncestorWidth } from 'ckeditor5/src/widget.js';
6
+ import { getSelectedImageEditorNodes } from './getselectedimageeditornodes.js';
7
+ import { tryCastDimensionsToUnit, tryParseDimensionWithUnit } from './tryparsedimensionwithunit.js';
8
+ /**
9
+ * Returns min and max value of resize image in specified unit.
10
+ *
11
+ * @param editor Editor instance.
12
+ * @param targetUnit Unit in which dimension will be returned.
13
+ * @returns Possible resize range in numeric form.
14
+ */
15
+ export function getSelectedImagePossibleResizeRange(editor, targetUnit) {
16
+ const imageNodes = getSelectedImageEditorNodes(editor);
17
+ if (!imageNodes) {
18
+ return null;
19
+ }
20
+ const imageParentWidthPx = calculateResizeHostAncestorWidth(imageNodes.dom);
21
+ const minimumImageWidth = tryParseDimensionWithUnit(window.getComputedStyle(imageNodes.dom).minWidth) || {
22
+ value: 1,
23
+ unit: 'px'
24
+ };
25
+ const lower = Math.max(0.1, tryCastDimensionsToUnit(imageParentWidthPx, minimumImageWidth, targetUnit).value);
26
+ const upper = targetUnit === 'px' ? imageParentWidthPx : 100;
27
+ return {
28
+ unit: targetUnit,
29
+ lower,
30
+ upper
31
+ };
32
+ }
@@ -0,0 +1,18 @@
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
+ import type { Editor } from 'ckeditor5/src/core.js';
6
+ import { type DimensionWithUnit } from './tryparsedimensionwithunit.js';
7
+ /**
8
+ * Returns image width in specified units. It is width of image after resize.
9
+ *
10
+ * * If image is not selected or command is disabled then `null` will be returned.
11
+ * * If image is not fully loaded (and it is impossible to determine its natural size) then `null` will be returned.
12
+ * * If `targetUnit` percentage is passed then it will return width percentage of image related to its accessors.
13
+ *
14
+ * @param editor Editor instance.
15
+ * @param targetUnit Unit in which dimension will be returned.
16
+ * @returns Parsed image width after resize (with unit).
17
+ */
18
+ export declare function getSelectedImageWidthInUnits(editor: Editor, targetUnit: string): DimensionWithUnit | null;