@ckeditor/ckeditor5-image 27.1.0 → 29.2.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 (167) hide show
  1. package/LICENSE.md +1 -1
  2. package/README.md +3 -3
  3. package/build/image.js +1 -1
  4. package/build/translations/ar.js +1 -0
  5. package/build/translations/ast.js +1 -0
  6. package/build/translations/az.js +1 -0
  7. package/build/translations/bg.js +1 -0
  8. package/build/translations/cs.js +1 -0
  9. package/build/translations/da.js +1 -0
  10. package/build/translations/de-ch.js +1 -0
  11. package/build/translations/de.js +1 -0
  12. package/build/translations/el.js +1 -0
  13. package/build/translations/en-au.js +1 -0
  14. package/build/translations/en-gb.js +1 -0
  15. package/build/translations/eo.js +1 -0
  16. package/build/translations/es.js +1 -0
  17. package/build/translations/et.js +1 -0
  18. package/build/translations/eu.js +1 -0
  19. package/build/translations/fa.js +1 -0
  20. package/build/translations/fi.js +1 -0
  21. package/build/translations/fr.js +1 -0
  22. package/build/translations/gl.js +1 -0
  23. package/build/translations/he.js +1 -0
  24. package/build/translations/hi.js +1 -0
  25. package/build/translations/hr.js +1 -0
  26. package/build/translations/hu.js +1 -0
  27. package/build/translations/id.js +1 -0
  28. package/build/translations/it.js +1 -0
  29. package/build/translations/ja.js +1 -0
  30. package/build/translations/km.js +1 -0
  31. package/build/translations/kn.js +1 -0
  32. package/build/translations/ko.js +1 -0
  33. package/build/translations/ku.js +1 -0
  34. package/build/translations/lt.js +1 -0
  35. package/build/translations/lv.js +1 -0
  36. package/build/translations/nb.js +1 -0
  37. package/build/translations/ne.js +1 -0
  38. package/build/translations/nl.js +1 -0
  39. package/build/translations/no.js +1 -0
  40. package/build/translations/pl.js +1 -0
  41. package/build/translations/pt-br.js +1 -0
  42. package/build/translations/pt.js +1 -0
  43. package/build/translations/ro.js +1 -0
  44. package/build/translations/ru.js +1 -0
  45. package/build/translations/si.js +1 -0
  46. package/build/translations/sk.js +1 -0
  47. package/build/translations/sq.js +1 -0
  48. package/build/translations/sr-latn.js +1 -0
  49. package/build/translations/sr.js +1 -0
  50. package/build/translations/sv.js +1 -0
  51. package/build/translations/th.js +1 -0
  52. package/build/translations/tk.js +1 -0
  53. package/build/translations/tr.js +1 -0
  54. package/build/translations/ug.js +1 -0
  55. package/build/translations/uk.js +1 -0
  56. package/build/translations/vi.js +1 -0
  57. package/build/translations/zh-cn.js +1 -0
  58. package/build/translations/zh.js +1 -0
  59. package/ckeditor5-metadata.json +233 -0
  60. package/lang/contexts.json +3 -0
  61. package/lang/translations/ar.po +12 -0
  62. package/lang/translations/ast.po +12 -0
  63. package/lang/translations/az.po +12 -0
  64. package/lang/translations/bg.po +12 -0
  65. package/lang/translations/cs.po +12 -0
  66. package/lang/translations/da.po +12 -0
  67. package/lang/translations/de-ch.po +113 -0
  68. package/lang/translations/de.po +15 -3
  69. package/lang/translations/el.po +12 -0
  70. package/lang/translations/en-au.po +12 -0
  71. package/lang/translations/en-gb.po +12 -0
  72. package/lang/translations/en.po +12 -0
  73. package/lang/translations/eo.po +12 -0
  74. package/lang/translations/es.po +12 -0
  75. package/lang/translations/et.po +12 -0
  76. package/lang/translations/eu.po +12 -0
  77. package/lang/translations/fa.po +12 -0
  78. package/lang/translations/fi.po +12 -0
  79. package/lang/translations/fr.po +12 -0
  80. package/lang/translations/gl.po +12 -0
  81. package/lang/translations/he.po +12 -0
  82. package/lang/translations/hi.po +12 -0
  83. package/lang/translations/hr.po +12 -0
  84. package/lang/translations/hu.po +13 -1
  85. package/lang/translations/id.po +21 -9
  86. package/lang/translations/it.po +12 -0
  87. package/lang/translations/ja.po +12 -0
  88. package/lang/translations/km.po +12 -0
  89. package/lang/translations/kn.po +12 -0
  90. package/lang/translations/ko.po +12 -0
  91. package/lang/translations/ku.po +12 -0
  92. package/lang/translations/lt.po +12 -0
  93. package/lang/translations/lv.po +12 -0
  94. package/lang/translations/nb.po +12 -0
  95. package/lang/translations/ne.po +12 -0
  96. package/lang/translations/nl.po +12 -0
  97. package/lang/translations/no.po +12 -0
  98. package/lang/translations/pl.po +20 -8
  99. package/lang/translations/pt-br.po +12 -0
  100. package/lang/translations/pt.po +12 -0
  101. package/lang/translations/ro.po +21 -9
  102. package/lang/translations/ru.po +12 -0
  103. package/lang/translations/si.po +12 -0
  104. package/lang/translations/sk.po +12 -0
  105. package/lang/translations/sq.po +12 -0
  106. package/lang/translations/sr-latn.po +12 -0
  107. package/lang/translations/sr.po +12 -0
  108. package/lang/translations/sv.po +12 -0
  109. package/lang/translations/th.po +12 -0
  110. package/lang/translations/tk.po +12 -0
  111. package/lang/translations/tr.po +12 -0
  112. package/lang/translations/ug.po +12 -0
  113. package/lang/translations/uk.po +12 -0
  114. package/lang/translations/vi.po +12 -0
  115. package/lang/translations/zh-cn.po +12 -0
  116. package/lang/translations/zh.po +12 -0
  117. package/package.json +36 -29
  118. package/src/autoimage.js +6 -4
  119. package/src/image/converters.js +192 -13
  120. package/src/image/imageblockediting.js +179 -0
  121. package/src/image/imageediting.js +13 -70
  122. package/src/image/imageinlineediting.js +204 -0
  123. package/src/image/imagetypecommand.js +105 -0
  124. package/src/image/insertimagecommand.js +77 -10
  125. package/src/image/ui/utils.js +3 -3
  126. package/src/image/utils.js +70 -121
  127. package/src/image.js +7 -19
  128. package/src/imageblock.js +46 -0
  129. package/src/imagecaption/imagecaptionediting.js +202 -230
  130. package/src/imagecaption/imagecaptionui.js +78 -0
  131. package/src/imagecaption/toggleimagecaptioncommand.js +165 -0
  132. package/src/imagecaption/utils.js +25 -40
  133. package/src/imagecaption.js +3 -2
  134. package/src/imageinline.js +46 -0
  135. package/src/imageinsert/imageinsertui.js +5 -6
  136. package/src/imageinsert.js +16 -4
  137. package/src/imageresize/imageresizebuttons.js +1 -1
  138. package/src/imageresize/imageresizeediting.js +21 -8
  139. package/src/imageresize/imageresizehandles.js +30 -8
  140. package/src/imageresize/resizeimagecommand.js +8 -5
  141. package/src/imagestyle/converters.js +25 -17
  142. package/src/imagestyle/imagestylecommand.js +73 -33
  143. package/src/imagestyle/imagestyleediting.js +113 -52
  144. package/src/imagestyle/imagestyleui.js +197 -31
  145. package/src/imagestyle/utils.js +300 -85
  146. package/src/imagestyle.js +218 -47
  147. package/src/imagetextalternative/imagetextalternativecommand.js +10 -7
  148. package/src/imagetextalternative/imagetextalternativeediting.js +9 -1
  149. package/src/imagetextalternative/imagetextalternativeui.js +2 -2
  150. package/src/imagetextalternative.js +1 -1
  151. package/src/imagetoolbar.js +33 -11
  152. package/src/imageupload/imageuploadediting.js +91 -31
  153. package/src/imageupload/imageuploadprogress.js +17 -9
  154. package/src/imageupload/imageuploadui.js +1 -1
  155. package/src/imageupload/uploadimagecommand.js +50 -24
  156. package/src/imageupload/utils.js +3 -2
  157. package/src/imageupload.js +1 -1
  158. package/src/imageutils.js +342 -0
  159. package/src/index.js +22 -47
  160. package/src/pictureediting.js +149 -0
  161. package/theme/image.css +101 -21
  162. package/theme/imagecaption.css +24 -2
  163. package/theme/imageresize.css +11 -0
  164. package/theme/imagestyle.css +76 -0
  165. package/theme/imageuploadicon.css +8 -2
  166. package/theme/imageuploadprogress.css +12 -8
  167. package/build/image.js.map +0 -1
@@ -8,18 +8,30 @@
8
8
  */
9
9
 
10
10
  import { Plugin } from 'ckeditor5/src/core';
11
- import { ButtonView } from 'ckeditor5/src/ui';
12
-
13
- import { normalizeImageStyles } from './utils';
11
+ import { ButtonView, createDropdown, addToolbarToDropdown, SplitButtonView } from 'ckeditor5/src/ui';
12
+ import ImageStyleEditing from './imagestyleediting';
13
+ import utils from './utils';
14
+ import { isObject, identity } from 'lodash-es';
14
15
 
15
16
  import '../../theme/imagestyle.css';
16
17
 
17
18
  /**
18
19
  * The image style UI plugin.
19
20
  *
21
+ * It registers buttons corresponding to the {@link module:image/image~ImageConfig#styles} configuration.
22
+ * It also registers the {@link module:image/imagestyle/utils~DEFAULT_DROPDOWN_DEFINITIONS default drop-downs} and the
23
+ * custom drop-downs defined by the developer in the {@link module:image/image~ImageConfig#toolbar} configuration.
24
+ *
20
25
  * @extends module:core/plugin~Plugin
21
26
  */
22
27
  export default class ImageStyleUI extends Plugin {
28
+ /**
29
+ * @inheritDoc
30
+ */
31
+ static get requires() {
32
+ return [ ImageStyleEditing ];
33
+ }
34
+
23
35
  /**
24
36
  * @inheritDoc
25
37
  */
@@ -31,8 +43,11 @@ export default class ImageStyleUI extends Plugin {
31
43
  * Returns the default localized style titles provided by the plugin.
32
44
  *
33
45
  * The following localized titles corresponding with
34
- * {@link module:image/imagestyle/utils~defaultStyles} are available:
46
+ * {@link module:image/imagestyle/utils~DEFAULT_OPTIONS} are available:
35
47
  *
48
+ * * `'Wrap text'`,
49
+ * * `'Break text'`,
50
+ * * `'In line'`,
36
51
  * * `'Full size image'`,
37
52
  * * `'Side image'`,
38
53
  * * `'Left aligned image'`,
@@ -45,6 +60,9 @@ export default class ImageStyleUI extends Plugin {
45
60
  const t = this.editor.t;
46
61
 
47
62
  return {
63
+ 'Wrap text': t( 'Wrap text' ),
64
+ 'Break text': t( 'Break text' ),
65
+ 'In line': t( 'In line' ),
48
66
  'Full size image': t( 'Full size image' ),
49
67
  'Side image': t( 'Side image' ),
50
68
  'Left aligned image': t( 'Left aligned image' ),
@@ -57,58 +75,142 @@ export default class ImageStyleUI extends Plugin {
57
75
  * @inheritDoc
58
76
  */
59
77
  init() {
60
- const editor = this.editor;
61
- const configuredStyles = editor.config.get( 'image.styles' );
78
+ const plugins = this.editor.plugins;
79
+ const toolbarConfig = this.editor.config.get( 'image.toolbar' ) || [];
80
+
81
+ const definedStyles = translateStyles(
82
+ plugins.get( 'ImageStyleEditing' ).normalizedStyles,
83
+ this.localizedDefaultStylesTitles
84
+ );
62
85
 
63
- const translatedStyles = translateStyles( normalizeImageStyles( configuredStyles ), this.localizedDefaultStylesTitles );
86
+ for ( const styleConfig of definedStyles ) {
87
+ this._createButton( styleConfig );
88
+ }
89
+
90
+ const definedDropdowns = translateStyles(
91
+ [ ...toolbarConfig.filter( isObject ), ...utils.getDefaultDropdownDefinitions( plugins ) ],
92
+ this.localizedDefaultStylesTitles
93
+ );
64
94
 
65
- for ( const style of translatedStyles ) {
66
- this._createButton( style );
95
+ for ( const dropdownConfig of definedDropdowns ) {
96
+ this._createDropdown( dropdownConfig, definedStyles );
67
97
  }
68
98
  }
69
99
 
70
100
  /**
71
- * Creates a button for each style and stores it in the editor {@link module:ui/componentfactory~ComponentFactory ComponentFactory}.
101
+ * Creates a dropdown and stores it in the editor {@link module:ui/componentfactory~ComponentFactory}.
72
102
  *
73
103
  * @private
74
- * @param {module:image/imagestyle/imagestyleediting~ImageStyleFormat} style
104
+ * @param {module:image/imagestyle/imagestyleui~ImageStyleDropdownDefinition} dropdownConfig
105
+ * @param {Array.<module:image/imagestyle~ImageStyleOptionDefinition>} definedStyles
75
106
  */
76
- _createButton( style ) {
77
- const editor = this.editor;
107
+ _createDropdown( dropdownConfig, definedStyles ) {
108
+ const factory = this.editor.ui.componentFactory;
109
+
110
+ factory.add( dropdownConfig.name, locale => {
111
+ let defaultButton;
112
+
113
+ const { defaultItem, items, title } = dropdownConfig;
114
+ const buttonViews = items
115
+ .filter( itemName => definedStyles.find( ( { name } ) => getUIComponentName( name ) === itemName ) )
116
+ .map( buttonName => {
117
+ const button = factory.create( buttonName );
118
+
119
+ if ( buttonName === defaultItem ) {
120
+ defaultButton = button;
121
+ }
122
+
123
+ return button;
124
+ } );
125
+
126
+ if ( items.length !== buttonViews.length ) {
127
+ utils.warnInvalidStyle( { dropdown: dropdownConfig } );
128
+ }
129
+
130
+ const dropdownView = createDropdown( locale, SplitButtonView );
131
+ const splitButtonView = dropdownView.buttonView;
78
132
 
79
- const componentName = `imageStyle:${ style.name }`;
133
+ addToolbarToDropdown( dropdownView, buttonViews );
80
134
 
81
- editor.ui.componentFactory.add( componentName, locale => {
82
- const command = editor.commands.get( 'imageStyle' );
135
+ splitButtonView.set( {
136
+ label: getDropdownButtonTitle( title, defaultButton.label ),
137
+ class: null,
138
+ tooltip: true
139
+ } );
140
+
141
+ splitButtonView.bind( 'icon' ).toMany( buttonViews, 'isOn', ( ...areOn ) => {
142
+ const index = areOn.findIndex( identity );
143
+
144
+ return ( index < 0 ) ? defaultButton.icon : buttonViews[ index ].icon;
145
+ } );
146
+
147
+ splitButtonView.bind( 'label' ).toMany( buttonViews, 'isOn', ( ...areOn ) => {
148
+ const index = areOn.findIndex( identity );
149
+
150
+ return getDropdownButtonTitle( title, ( index < 0 ) ? defaultButton.label : buttonViews[ index ].label );
151
+ } );
152
+
153
+ splitButtonView.bind( 'isOn' ).toMany( buttonViews, 'isOn', ( ...areOn ) => areOn.some( identity ) );
154
+
155
+ splitButtonView.bind( 'class' )
156
+ .toMany( buttonViews, 'isOn', ( ...areOn ) => areOn.some( identity ) ? 'ck-splitbutton_flatten' : null );
157
+
158
+ splitButtonView.on( 'execute', () => {
159
+ if ( !buttonViews.some( ( { isOn } ) => isOn ) ) {
160
+ defaultButton.fire( 'execute' );
161
+ } else {
162
+ dropdownView.isOpen = !dropdownView.isOpen;
163
+ }
164
+ } );
165
+
166
+ dropdownView.bind( 'isEnabled' )
167
+ .toMany( buttonViews, 'isEnabled', ( ...areEnabled ) => areEnabled.some( identity ) );
168
+
169
+ return dropdownView;
170
+ } );
171
+ }
172
+
173
+ /**
174
+ * Creates a button and stores it in the editor {@link module:ui/componentfactory~ComponentFactory}.
175
+ *
176
+ * @private
177
+ * @param {module:image/imagestyle~ImageStyleOptionDefinition} buttonConfig
178
+ */
179
+ _createButton( buttonConfig ) {
180
+ const buttonName = buttonConfig.name;
181
+
182
+ this.editor.ui.componentFactory.add( getUIComponentName( buttonName ), locale => {
183
+ const command = this.editor.commands.get( 'imageStyle' );
83
184
  const view = new ButtonView( locale );
84
185
 
85
186
  view.set( {
86
- label: style.title,
87
- icon: style.icon,
187
+ label: buttonConfig.title,
188
+ icon: buttonConfig.icon,
88
189
  tooltip: true,
89
190
  isToggleable: true
90
191
  } );
91
192
 
92
193
  view.bind( 'isEnabled' ).to( command, 'isEnabled' );
93
- view.bind( 'isOn' ).to( command, 'value', value => value === style.name );
94
-
95
- this.listenTo( view, 'execute', () => {
96
- editor.execute( 'imageStyle', { value: style.name } );
97
- editor.editing.view.focus();
98
- } );
194
+ view.bind( 'isOn' ).to( command, 'value', value => value === buttonName );
195
+ view.on( 'execute', this._executeCommand.bind( this, buttonName ) );
99
196
 
100
197
  return view;
101
198
  } );
102
199
  }
200
+
201
+ _executeCommand( name ) {
202
+ this.editor.execute( 'imageStyle', { value: name } );
203
+ this.editor.editing.view.focus();
204
+ }
103
205
  }
104
206
 
105
- /**
106
- * Returns the translated `title` from the passed styles array.
107
- *
108
- * @param {Array.<module:image/imagestyle/imagestyleediting~ImageStyleFormat>} styles
109
- * @param titles
110
- * @returns {Array.<module:image/imagestyle/imagestyleediting~ImageStyleFormat>}
111
- */
207
+ // Returns the translated `title` from the passed styles array.
208
+ //
209
+ // @param {Array.<module:image/imagestyle~ImageStyleOptionDefinition|
210
+ // module:image/imagestyle/imagestyleui~ImageStyleDropdownDefinition>} styles
211
+ // @param {Object.<String,String>} titles
212
+ //
213
+ // @returns {Array.<module:image/imagestyle~ImageStyleOptionDefinition|module:image/imagestyle/imagestyleui~ImageStyleDropdownDefinition>}
112
214
  function translateStyles( styles, titles ) {
113
215
  for ( const style of styles ) {
114
216
  // Localize the titles of the styles, if a title corresponds with
@@ -120,3 +222,67 @@ function translateStyles( styles, titles ) {
120
222
 
121
223
  return styles;
122
224
  }
225
+
226
+ // Returns the image style component name with the "imageStyle:" prefix.
227
+ //
228
+ // @param {String} name
229
+ // @returns {String}
230
+ function getUIComponentName( name ) {
231
+ return `imageStyle:${ name }`;
232
+ }
233
+
234
+ // Returns title for the splitbutton containing the dropdown title and default action item title.
235
+ //
236
+ // @param {String|undefined} dropdownTitle
237
+ // @param {String} buttonTitle
238
+ // @returns {String}
239
+ function getDropdownButtonTitle( dropdownTitle, buttonTitle ) {
240
+ return ( dropdownTitle ? dropdownTitle + ': ' : '' ) + buttonTitle;
241
+ }
242
+
243
+ /**
244
+ * # **The image style custom drop-down definition descriptor**
245
+ *
246
+ * This definition can be implemented in the {@link module:image/image~ImageConfig#toolbar image toolbar configuration}
247
+ * to define a completely custom drop-down in the image toolbar.
248
+ *
249
+ * ClassicEditor.create( editorElement, {
250
+ * image: { toolbar: [
251
+ * // One of the predefined drop-downs
252
+ * 'imageStyle:wrapText',
253
+ * // Custom drop-down
254
+ * {
255
+ * name: 'imageStyle:customDropdown',
256
+ * title: Custom drop-down title,
257
+ * items: [ 'imageStyle:alignLeft', 'imageStyle:alignRight' ],
258
+ * defaultItem: 'imageStyle:alignLeft'
259
+ * }
260
+ * ] }
261
+ * } );
262
+ *
263
+ * **Note:** At the moment it is possible to populate the custom drop-down with only the buttons registered by the `ImageStyle` plugin.
264
+ *
265
+ * The defined drop-down will be registered
266
+ * as the {@link module:ui/dropdown/dropdownview~DropdownView}
267
+ * with the {@link module:ui/dropdown/button/splitbuttonview~SplitButtonView} under the provided name in the
268
+ * {@link module:ui/componentfactory~ComponentFactory}
269
+ *
270
+ * @property {String} name The unique name of the drop-down. It is recommended to precede it with the "imageStyle:" prefix
271
+ * to avoid collision with the components' names registered by other plugins.
272
+ *
273
+ * @property {String} [title] The drop-down's title. It will be used as the split button label along with the title of the default item
274
+ * in the following manner: "Custom drop-down title: Default item title".
275
+ *
276
+ * Setting `title` to one of
277
+ * {@link module:image/imagestyle/imagestyleui~ImageStyleUI#localizedDefaultStylesTitles}
278
+ * will automatically translate it to the language of the editor.
279
+ *
280
+ * @property {Array.<String>} items The list of the names of the buttons that will be placed in the drop-down's toolbar.
281
+ * Each of the buttons has to be one of the {@link module:image/image~ImageConfig#styles default image style buttons}
282
+ * or to be defined as the {@link module:image/imagestyle~ImageStyleOptionDefinition image styling option}.
283
+ *
284
+ * @property {String} defaultItem The name of one of the buttons from the items list,
285
+ * which will be used as a default button for the drop-down's split button.
286
+ *
287
+ * @typedef {Object} module:image/imagestyle/imagestyleui~ImageStyleDropdownDefinition
288
+ */