8
0
Просмотр исходного кода

Merge branch 'master' into t/306

Piotrek Koszuliński 6 лет назад
Родитель
Сommit
8df17d10bd
25 измененных файлов с 561 добавлено и 175 удалено
  1. 3 3
      packages/ckeditor5-image/.travis.yml
  2. 26 0
      packages/ckeditor5-image/CHANGELOG.md
  3. 0 1
      packages/ckeditor5-image/README.md
  4. 2 2
      packages/ckeditor5-image/docs/_snippets/features/image-style.html
  5. 1 1
      packages/ckeditor5-image/docs/api/image.md
  6. 97 26
      packages/ckeditor5-image/docs/features/image.md
  7. 61 0
      packages/ckeditor5-image/lang/translations/en-gb.po
  8. 1 1
      packages/ckeditor5-image/lang/translations/nl.po
  9. 23 23
      packages/ckeditor5-image/package.json
  10. 10 11
      packages/ckeditor5-image/src/imageresize.js
  11. 43 0
      packages/ckeditor5-image/src/imageupload.js
  12. 99 46
      packages/ckeditor5-image/src/imageupload/imageuploadediting.js
  13. 14 0
      packages/ckeditor5-image/src/imageupload/imageuploadprogress.js
  14. 5 3
      packages/ckeditor5-image/src/imageupload/imageuploadui.js
  15. 11 6
      packages/ckeditor5-image/src/imageupload/utils.js
  16. 3 2
      packages/ckeditor5-image/tests/image/imageediting.js
  17. 32 4
      packages/ckeditor5-image/tests/imageupload/imageuploadediting.js
  18. 50 1
      packages/ckeditor5-image/tests/imageupload/imageuploadprogress.js
  19. 8 0
      packages/ckeditor5-image/tests/imageupload/imageuploadui.js
  20. 18 15
      packages/ckeditor5-image/tests/imageupload/utils.js
  21. 28 2
      packages/ckeditor5-image/tests/manual/imagestyle.js
  22. 18 18
      packages/ckeditor5-image/tests/manual/imageupload.js
  23. 5 5
      packages/ckeditor5-image/theme/imageresize.css
  24. 1 3
      packages/ckeditor5-image/theme/imagestyle.css
  25. 2 2
      packages/ckeditor5-image/theme/imageuploadprogress.css

+ 3 - 3
packages/ckeditor5-image/.travis.yml

@@ -1,9 +1,11 @@
 sudo: required
-dist: trusty
+dist: xenial
 addons:
   chrome: stable
   firefox: latest
 language: node_js
+services:
+- xvfb
 node_js:
 - '8'
 cache:
@@ -13,8 +15,6 @@ branches:
   - stable
 before_install:
 - export START_TIME=$( date +%s )
-- export DISPLAY=:99.0
-- sh -e /etc/init.d/xvfb start
 - npm i -g yarn
 install:
 - yarn add @ckeditor/ckeditor5-dev-tests

+ 26 - 0
packages/ckeditor5-image/CHANGELOG.md

@@ -1,6 +1,32 @@
 Changelog
 =========
 
+## [14.0.0](https://github.com/ckeditor/ckeditor5-image/compare/v13.1.2...v14.0.0) (2019-08-26)
+
+### Features
+
+* Introduced widget resizer. Closes [#241](https://github.com/ckeditor/ckeditor5-image/issues/241). ([ddcb1b3](https://github.com/ckeditor/ckeditor5-image/commit/ddcb1b3))
+
+### Bug fixes
+
+* Image upload should handle images that are deeply nested in other blocks. Closes [ckeditor/ckeditor5#1985](https://github.com/ckeditor/ckeditor5/issues/1985). ([5a729d3](https://github.com/ckeditor/ckeditor5-image/commit/5a729d3))
+* Image widgets should not span the entire width of the editor. Closes [ckeditor/ckeditor5#1870](https://github.com/ckeditor/ckeditor5/issues/1870). ([b82ea85](https://github.com/ckeditor/ckeditor5-image/commit/b82ea85))
+* Improved stability of `ImageTextAlternative` balloon used in rotator. ([2e979cd](https://github.com/ckeditor/ckeditor5-image/commit/2e979cd))
+* The UI buttons should be marked as toggleable for better assistive technologies support (see [ckeditor/ckeditor5#1403](https://github.com/ckeditor/ckeditor5/issues/1403)). ([6c74d59](https://github.com/ckeditor/ckeditor5-image/commit/6c74d59))
+* Worked around Safari's image size bug. Closes [ckeditor/ckeditor5#1975](https://github.com/ckeditor/ckeditor5/issues/1975). ([8e14b03](https://github.com/ckeditor/ckeditor5-image/commit/8e14b03))
+
+### Other changes
+
+* The issue tracker for this package was moved to https://github.com/ckeditor/ckeditor5/issues. See [ckeditor/ckeditor5#1988](https://github.com/ckeditor/ckeditor5/issues/1988). ([a5451d6](https://github.com/ckeditor/ckeditor5-image/commit/a5451d6))
+* Removed the obsolete `--ck-color-upload-infinite-background` CSS custom property. See https://github.com/ckeditor/ckeditor5-theme-lark/pull/240. ([65c07cd](https://github.com/ckeditor/ckeditor5-image/commit/65c07cd))
+* The image widget toolbar should have a proper `aria-label` attribute (see [ckeditor/ckeditor5#1404](https://github.com/ckeditor/ckeditor5/issues/1404)). ([13af143](https://github.com/ckeditor/ckeditor5-image/commit/13af143))
+* Updated translations. ([f2a760d](https://github.com/ckeditor/ckeditor5-image/commit/f2a760d))
+
+### BREAKING CHANGES
+
+* From now on, all images in the editor use CSS `display: table` by default (`.ck-content .image { display: table }`). It can affect integrations and we recommend checking if images render correctly in your project after this update. There is a possibility you might need to adjust the CSS to adapt to this change.
+
+
 ## [13.1.2](https://github.com/ckeditor/ckeditor5-image/compare/v13.1.1...v13.1.2) (2019-07-10)
 
 Internal changes only (updated dependencies, documentation, etc.).

+ 0 - 1
packages/ckeditor5-image/README.md

@@ -1,7 +1,6 @@
 CKEditor 5 image feature
 ========================================
 
-[![Join the chat at https://gitter.im/ckeditor/ckeditor5](https://badges.gitter.im/ckeditor/ckeditor5.svg)](https://gitter.im/ckeditor/ckeditor5?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
 [![npm version](https://badge.fury.io/js/%40ckeditor%2Fckeditor5-image.svg)](https://www.npmjs.com/package/@ckeditor/ckeditor5-image)
 [![Build Status](https://travis-ci.org/ckeditor/ckeditor5-image.svg?branch=master)](https://travis-ci.org/ckeditor/ckeditor5-image)
 [![Coverage Status](https://coveralls.io/repos/github/ckeditor/ckeditor5-image/badge.svg?branch=master)](https://coveralls.io/github/ckeditor/ckeditor5-image?branch=master)

+ 2 - 2
packages/ckeditor5-image/docs/_snippets/features/image-style.html

@@ -1,11 +1,11 @@
 <div id="snippet-image-style">
-	<p>This is full width image (default style):</p>
+	<p>This is a full-width image (default style):</p>
 
 	<figure class="image">
 		<img src="%BASE_PATH%/assets/img/fields.jpg" alt="Autumn fields">
 	</figure>
 
-	<p>This is side image:</p>
+	<p>This is a side image:</p>
 
 	<figure class="image image-style-side">
 		<img src="%BASE_PATH%/assets/img/fields.jpg" alt="Autumn fields">

+ 1 - 1
packages/ckeditor5-image/docs/api/image.md

@@ -37,5 +37,5 @@ The source code of this package is available on GitHub in https://github.com/cke
 
 * [`@ckeditor/ckeditor5-image` on npm](https://www.npmjs.com/package/@ckeditor/ckeditor5-image)
 * [`ckeditor/ckeditor5-image` on GitHub](https://github.com/ckeditor/ckeditor5-image)
-* [Issue tracker](https://github.com/ckeditor/ckeditor5-image/issues)
+* [Issue tracker](https://github.com/ckeditor/ckeditor5/issues)
 * [Changelog](https://github.com/ckeditor/ckeditor5-image/blob/master/CHANGELOG.md)

+ 97 - 26
packages/ckeditor5-image/docs/features/image.md

@@ -16,9 +16,9 @@ The [`@ckeditor/ckeditor5-image`](https://www.npmjs.com/package/@ckeditor/ckedit
 * {@link module:image/imageresize~ImageResize} adds support for resizing images.
 
 <info-box info>
-	All features listed above expect image resize are enabled by default in all builds.
+	All features listed above except the image resize are enabled by default in all WYSIWYG editor builds.
 
-	Check the documentation of each sub-feature to learn more about it.
+	Check the documentation of each subfeature to learn more about it.
 </info-box>
 
 ## Base image support
@@ -35,7 +35,7 @@ The {@link module:image/image~Image} feature adds support for plain images with
 	This feature follows the markup proposed by the [Editor Recommendations](https://ckeditor.github.io/editor-recommendations/features/image.html) project.
 </info-box>
 
-You can see the demo of an editor with the base image feature enabled below:
+You can see the demo of a WYSIWYG editor with the base image feature enabled below:
 
 {@snippet features/image}
 
@@ -47,7 +47,7 @@ You can see the demo of an editor with the base image feature enabled below:
 
 The {@link module:image/imagetoolbar~ImageToolbar} plugin introduces a contextual toolbar for images. The toolbar appears when an image is selected and can be configured to contain any buttons you want. Usually, these will be image-related options such as the text alternative (which is introduced by the base image plugin) button and [image styles buttons](#image-styles).
 
-See a demo of an editor with the contextual toolbar enabled:
+See a demo of a WYSIWYG editor with the contextual toolbar enabled:
 
 {@snippet features/image-toolbar}
 
@@ -85,9 +85,9 @@ In more advanced scenarios, the user may need to be able to decide whether the i
 
 This is what the {@link module:image/imagestyle~ImageStyle} feature is designed for.
 
-However, unlike in CKEditor 4, in CKEditor 5 the end user does not set the image border, alignment, margins, width, etc. separately. Instead, they can pick one of the styles defined by the developer who prepared the editor integration. This gives the developer control over how the users style images and makes the user's life easier by setting multiple properties at once.
+However, unlike in CKEditor 4, in CKEditor 5 the end user does not set the image border, alignment, margins, width, etc. separately. Instead, they can pick one of the styles defined by the developer who prepared the WYSIWYG editor integration. This gives the developer control over how the users style images and makes the user's life easier by setting multiple properties at once.
 
-A style is applied to the image in form of a class. By default, the editor is configured to support two styles: "full width" (which does not apply any class &mdash; it is the default style) and "side image" (which applies the `image-style-side` class).
+A style is applied to the image in form of a class. By default, CKEditor 5 is configured to support two styles: "full width" (which does not apply any class &mdash; it is the default style) and "side image" (which applies the `image-style-side` class).
 
 A normal (full width) image:
 
@@ -102,12 +102,12 @@ A side image:
 ```
 
 <info-box>
-	The actual styling of the images is the developer's job. The editor comes with some default styles, but they will only be applied to images inside the editor. The developer needs to style them appropriately on the target pages.
+	The actual styling of the images is the developer's job. CKEditor 5 WYSIWYG editor comes with some default styles, but they will only be applied to images inside the editor. The developer needs to style them appropriately on the target pages.
 
 	You can find the source of the default styles applied by the editor here: [`ckeditor5-image/theme/imagestyle.css`](https://github.com/ckeditor/ckeditor5-image/blob/master/theme/imagestyle.css).
 </info-box>
 
-Below you can see a demo of the editor with the image styles feature enabled. The default configuration is used. You can change the styles of images through the image's contextual toolbar.
+Below you can see a demo of the WYSIWYG editor with the image styles feature enabled. The default configuration is used. You can change the styles of images through the image's contextual toolbar.
 
 {@snippet features/image-style}
 
@@ -115,7 +115,7 @@ Below you can see a demo of the editor with the image styles feature enabled. Th
 
 The available image styles can be configured using the {@link module:image/image~ImageConfig#styles `image.styles`} option.
 
-The following editor supports the default full image style plus left- and right-aligned images:
+The following WYSIWYG editor supports the default full image style plus left- and right-aligned images:
 
 ```js
 ClassicEditor
@@ -147,12 +147,12 @@ See the result below:
 {@snippet features/image-style-custom}
 
 <info-box hint>
-	In the example above the options used represent simple "align left" and "align right" styles. Most text editors support left, center and right alignments, however, try not to think about CKEditor 5's image styles in this way. Try to understand what use cases the system needs to support and define semantic options accordingly. Defining useful and clear styles is one of the steps towards a good user experience and clear, portable output. For example, the "side image" style can be displayed as a floated image on wide screens and as a normal image on low resolution screens.
+	In the example above the options represent simple "align left" and "align right" styles. Most text editors support left, center and right alignments, however, it is better not to think about CKEditor 5's image styles in this way. Try to understand what use cases the system needs to support and define semantic options accordingly. Defining useful and clear styles is one of the steps towards a good user experience and clear, portable output. For example, the "side image" style can be displayed as a floated image on wide screens and as a normal image on low resolution screens.
 </info-box>
 
 ### Defining custom styles
 
-Besides using the {@link module:image/imagestyle/utils~defaultStyles 5 predefined styles}:
+Besides using the {@link module:image/imagestyle/utils~defaultStyles five predefined styles}:
 
 * `'full'`,
 * `'side'`,
@@ -163,7 +163,7 @@ Besides using the {@link module:image/imagestyle/utils~defaultStyles 5 predefine
 you can also define your own styles or modify the existing ones.
 
 <info-box>
-	Reusing (or modifying) predefined styles has this advantage that CKEditor 5 will use its official translations for the defined button titles.
+	Reusing (or modifying) predefined styles has the following advantage: CKEditor 5 will use its official translations for the defined button titles.
 </info-box>
 
 You can find advanced examples in the {@link module:image/image~ImageConfig#styles `image.styles`} configuration option documentation.
@@ -176,34 +176,100 @@ See the {@link features/image-upload Image upload} guide.
 
 ## Responsive images
 
-Responsive images support in CKEditor 5 is brought by the {@link features/easy-image Easy Image} feature without any additional configuration. Learn more how to use the feature in your project in the {@link features/easy-image#responsive-images "Easy Image integration"} guide.
+Support for responsive images in CKEditor 5 is brought by the {@link features/easy-image Easy Image} feature without any additional configuration. Learn more how to use the feature in your project in the {@link features/easy-image#responsive-images Easy Image integration} guide.
 
 ## Resizing images
 
-TODO:
+The [image styles](#image-styles) feature is meant to give the user the choice between a set of styling options provided by the system (so by the developer or administrator who created it). There are also scenarios where the user should be able to freely set the width of an image. And that is where the image resize feature comes to play.
 
-* overview
-* markup
-* styling concerns
-* installation
-* note about it not being enabled by default
-* a note about followups? a dialog, a toggle predefined sizes (e.g. 40%, 50%, 75%, 100%)
+It is implemented by the {@link module:image/imageresize~ImageResize} plugin and enables four "resize handles" displayed over the selected image. The user can freely resize the image by dragging them. The feature can be configured to use either percentage (default) or pixel values.
 
 {@snippet features/image-resize}
 
+### Enabling image resizing
+
+The image resize feature is not enabled by default in any of the editor builds. In order to enable it, you need to load the {@link module:image/imageresize~ImageResize} plugin. Read more in the [Installation](#installation) section.
+
+### Markup and styling
+
+When you resize an image, the inline `width` style is used and the `<figure>` is assigned the `image_resized` class:
+
+```html
+<figure class="image image_resized" style="width: 75%;">
+	<img src="..." alt="...">
+</figure>
+```
+
+The `image_resized` class is used to disable `max-width` assigned by the [image styles](#image-styles) if one is applied to this image. For instance, the "side image" style is defined like this:
+
+```css
+.ck-content .image-style-side {
+	max-width: 50%;
+	float: right;
+	margin-left: var(--ck-image-style-spacing);
+}
+```
+
+And the `max-width` gets overridden by the following rule:
+
+```css
+.ck-content .image.image_resized {
+	max-width: 100%;
+}
+```
+
+Another concern when styling resized images is that by default, CKEditor 5 uses `display: table` on `<figure class="image">` to make it take the size of the `<img>` element inside it. Unfortunately, [browsers do not yet support using `max-width` and `width` on the same element if it is styled with `display: table`](https://stackoverflow.com/questions/4019604/chrome-safari-ignoring-max-width-in-table/14420691#14420691). Therefore, `display: block` needs to be used when the image is resized:
+
+```css
+.ck-content .image.image_resized {
+	display: block;
+	box-sizing: border-box;
+}
+
+.ck-content .image.image_resized img {
+	width: 100%;
+}
+
+.ck-content .image.image_resized > figcaption {
+	display: block;
+}
+```
+
 ### Using pixels instead of percentage width
 
-TODO:
+Using percentage widths ensures that content stays responsive when displayed in different places than in the WYSIWYG editor. If the user made an image take 60% of the content's width in the editor, if you ever change the width of the target page (where this content is displayed), the image will still take 60% of that space. The same is true if the page is responsive and adjusts to the viewport's width.
+
+If you configured the editor to use pixel values, the image could take, for example, too much space after you introduced a new layout for your website.
 
-* overview
-* downsides
-* configuration
+However, there are cases where pixel values may be preferred. You can thus configure the editor to use them by setting the {@link module:image/image~ImageConfig#resizeUnit `config.image.resizeUnit`} option:
+
+```js
+ClassicEditor
+	.create( editorElement, {
+		image: {
+			resizeUnit: 'px'
+		}
+	} )
+	.then( ... )
+	.catch( ... );
+```
 
 {@snippet features/image-resize-px}
 
+### Future development
+
+Resizing by dragging handles displayed over the image is the first option provided, but we consider implementing more with time. Some of the possible next steps include:
+
+* [Buttons such as "50%", "75%" and "100%" in the image toolbar](https://github.com/ckeditor/ckeditor5-image/issues/322), allowing the user to choose only from predefined widths.
+* [A traditional "width" input](https://github.com/ckeditor/ckeditor5-image/issues/319). Or an option to set both width and height separately.
+* [An option to restore the original image size](https://github.com/ckeditor/ckeditor5-image/issues/318).
+* [Limiting image resize](https://github.com/ckeditor/ckeditor5-image/issues/320) with min and max values.
+
+We count on your feedback. React with 👍 under the respective tickets or [report new ones](https://github.com/ckeditor/ckeditor5-image/issues) if you have different ideas.
+
 ## Installation
 
-To add image features to your editor, install the [`@ckeditor/ckeditor5-image`](https://www.npmjs.com/package/@ckeditor/ckeditor5-image) package:
+To add image features to your rich-text editor, install the [`@ckeditor/ckeditor5-image`](https://www.npmjs.com/package/@ckeditor/ckeditor5-image) package:
 
 ```bash
 npm install --save @ckeditor/ckeditor5-image
@@ -216,10 +282,11 @@ import Image from '@ckeditor/ckeditor5-image/src/image';
 import ImageToolbar from '@ckeditor/ckeditor5-image/src/imagetoolbar';
 import ImageCaption from '@ckeditor/ckeditor5-image/src/imagecaption';
 import ImageStyle from '@ckeditor/ckeditor5-image/src/imagestyle';
+import ImageResize from '@ckeditor/ckeditor5-image/src/imageresize';
 
 ClassicEditor
 	.create( document.querySelector( '#editor' ), {
-		plugins: [ Image, ImageToolbar, ImageCaption, ImageStyle ],
+		plugins: [ Image, ImageToolbar, ImageCaption, ImageStyle, ImageResize ],
 		image: {
 			toolbar: [ 'imageTextAlternative', '|', 'imageStyle:full', 'imageStyle:side' ]
 		}
@@ -254,6 +321,10 @@ The {@link module:image/imageupload~ImageUpload} plugin registers:
 * The `'imageUpload'` button which opens the native file browser to let you upload a file directly from your disk.
 * The {@link module:image/imageupload/imageuploadcommand~ImageUploadCommand `'imageUpload'` command} which accepts the file to upload.
 
+The {@link module:image/imageresize~ImageResize} plugin registers:
+
+* The {@link module:image/imageresize/imageresizecommand~ImageResizeCommand `'imageResize'` command} which accepts the target width.
+
 <info-box>
 	We recommend using the official {@link framework/guides/development-tools#ckeditor-5-inspector CKEditor 5 inspector} for development and debugging. It will give you tons of useful information about the state of the editor such as internal data structures, selection, commands, and many more.
 </info-box>

+ 61 - 0
packages/ckeditor5-image/lang/translations/en-gb.po

@@ -0,0 +1,61 @@
+# Copyright (c) 2003-2019, CKSource - Frederico Knabben. All rights reserved.
+#
+#                                     !!! IMPORTANT !!!
+#
+#         Before you edit this file, please keep in mind that contributing to the project
+#                translations is possible ONLY via the Transifex online service.
+#
+#         To submit your translations, visit https://www.transifex.com/ckeditor/ckeditor5.
+#
+#                   To learn more, check out the official contributor's guide:
+#     https://ckeditor.com/docs/ckeditor5/latest/framework/guides/contributing/contributing.html
+#
+msgid ""
+msgstr ""
+"Language-Team: English (United Kingdom) (https://www.transifex.com/ckeditor/teams/11143/en_GB/)\n"
+"Language: en_GB\n"
+"Plural-Forms: nplurals=2; plural=(n != 1);\n"
+
+msgctxt "Label for the image widget."
+msgid "image widget"
+msgstr "Image widget"
+
+msgctxt "Label for the Side image option."
+msgid "Side image"
+msgstr "Side image"
+
+msgctxt "Label for the Full size image option."
+msgid "Full size image"
+msgstr "Full size image"
+
+msgctxt "Label for the Left aligned image option"
+msgid "Left aligned image"
+msgstr "Left aligned image"
+
+msgctxt "Label for the Centered image option"
+msgid "Centered image"
+msgstr "Centred image"
+
+msgctxt "Label for the Right aligned image option"
+msgid "Right aligned image"
+msgstr "Right aligned image"
+
+msgctxt "Label for the Change image text alternative button."
+msgid "Change image text alternative"
+msgstr "Change image text alternative"
+
+msgctxt "Label for the image text alternative input."
+msgid "Text alternative"
+msgstr "Text alternative"
+
+msgctxt "Placeholder text for image caption displayed when caption is empty."
+msgid "Enter image caption"
+msgstr "Enter image caption"
+
+msgctxt "Label for the insert image toolbar button."
+msgid "Insert image"
+msgstr "Insert image"
+
+msgctxt "Title of the notification displayed when upload fails."
+msgid "Upload failed"
+msgstr "Upload failed"

+ 1 - 1
packages/ckeditor5-image/lang/translations/nl.po

@@ -58,4 +58,4 @@ msgstr "Afbeelding toevoegen"
 
 msgctxt "Title of the notification displayed when upload fails."
 msgid "Upload failed"
-msgstr "Opladen afbeelding mislukt"
+msgstr "Uploaden afbeelding mislukt"

+ 23 - 23
packages/ckeditor5-image/package.json

@@ -1,6 +1,6 @@
 {
   "name": "@ckeditor/ckeditor5-image",
-  "version": "13.1.2",
+  "version": "14.0.0",
   "description": "Image feature for CKEditor 5.",
   "keywords": [
     "ckeditor",
@@ -10,29 +10,29 @@
     "ckeditor5-plugin"
   ],
   "dependencies": {
-    "@ckeditor/ckeditor5-core": "^12.2.1",
-    "@ckeditor/ckeditor5-engine": "^13.2.1",
-    "@ckeditor/ckeditor5-ui": "^13.0.2",
-    "@ckeditor/ckeditor5-upload": "^11.1.1",
-    "@ckeditor/ckeditor5-utils": "^13.0.1",
-    "@ckeditor/ckeditor5-widget": "^11.0.4"
+    "@ckeditor/ckeditor5-core": "^12.3.0",
+    "@ckeditor/ckeditor5-engine": "^14.0.0",
+    "@ckeditor/ckeditor5-ui": "^14.0.0",
+    "@ckeditor/ckeditor5-upload": "^12.0.0",
+    "@ckeditor/ckeditor5-utils": "^14.0.0",
+    "@ckeditor/ckeditor5-widget": "^11.1.0"
   },
   "devDependencies": {
-    "@ckeditor/ckeditor5-basic-styles": "^11.1.3",
-    "@ckeditor/ckeditor5-block-quote": "^11.1.2",
-    "@ckeditor/ckeditor5-cloud-services": "^11.0.4",
-    "@ckeditor/ckeditor5-clipboard": "^12.0.1",
-    "@ckeditor/ckeditor5-editor-classic": "^12.1.3",
-    "@ckeditor/ckeditor5-enter": "^11.0.4",
-    "@ckeditor/ckeditor5-easy-image": "^11.0.4",
-    "@ckeditor/ckeditor5-heading": "^11.0.4",
-    "@ckeditor/ckeditor5-indent": "^10.0.1",
-    "@ckeditor/ckeditor5-link": "^11.1.1",
-    "@ckeditor/ckeditor5-list": "^12.0.4",
-    "@ckeditor/ckeditor5-paragraph": "^11.0.4",
-    "@ckeditor/ckeditor5-table": "^13.0.0",
-    "@ckeditor/ckeditor5-typing": "^12.1.1",
-    "@ckeditor/ckeditor5-undo": "^11.0.4",
+    "@ckeditor/ckeditor5-basic-styles": "^11.1.4",
+    "@ckeditor/ckeditor5-block-quote": "^11.1.3",
+    "@ckeditor/ckeditor5-cloud-services": "^11.0.5",
+    "@ckeditor/ckeditor5-clipboard": "^12.0.2",
+    "@ckeditor/ckeditor5-editor-classic": "^12.1.4",
+    "@ckeditor/ckeditor5-enter": "^11.1.0",
+    "@ckeditor/ckeditor5-easy-image": "^11.0.5",
+    "@ckeditor/ckeditor5-heading": "^11.0.5",
+    "@ckeditor/ckeditor5-indent": "^10.1.0",
+    "@ckeditor/ckeditor5-link": "^11.1.2",
+    "@ckeditor/ckeditor5-list": "^12.1.0",
+    "@ckeditor/ckeditor5-paragraph": "^11.0.5",
+    "@ckeditor/ckeditor5-table": "^14.0.0",
+    "@ckeditor/ckeditor5-typing": "^12.2.0",
+    "@ckeditor/ckeditor5-undo": "^11.0.5",
     "eslint": "^5.5.0",
     "eslint-config-ckeditor5": "^2.0.0",
     "husky": "^1.3.1",
@@ -45,7 +45,7 @@
   "author": "CKSource (http://cksource.com/)",
   "license": "GPL-2.0-or-later",
   "homepage": "https://ckeditor.com/ckeditor-5",
-  "bugs": "https://github.com/ckeditor/ckeditor5-image/issues",
+  "bugs": "https://github.com/ckeditor/ckeditor5/issues",
   "repository": {
     "type": "git",
     "url": "https://github.com/ckeditor/ckeditor5-image.git"

+ 10 - 11
packages/ckeditor5-image/src/imageresize.js

@@ -145,18 +145,17 @@ export default class ImageResize extends Plugin {
 /**
  * The available options are `'px'` or `'%'`.
  *
- * Determines size unit applied to resized image.
+ * Determines the size unit applied to the resized image.
+ *
+ *		ClassicEditor
+ *			.create( editorElement, {
+ *				image: {
+ *					resizeUnit: 'px'
+ *				}
+ *			} )
+ *			.then( ... )
+ *			.catch( ... );
  *
- * ```js
- * ClassicEditor
- * 	.create( editorElement, {
- * 		 image: {
- * 			 resizeUnit: 'px'
- * 		 }
- * 	 } )
- * 	.then( ... )
- * 	.catch( ... );
- * ```
  *
  * This option is used by the {@link module:image/imageresize~ImageResize} feature.
  *

+ 43 - 0
packages/ckeditor5-image/src/imageupload.js

@@ -40,3 +40,46 @@ export default class ImageUpload extends Plugin {
 		return [ ImageUploadEditing, ImageUploadUI, ImageUploadProgress ];
 	}
 }
+
+/**
+ * Image upload configuration.
+ *
+ * @member {module:image/imageupload~ImageUploadConfig} module:image/image~ImageConfig#upload
+ */
+
+/**
+ * The configuration of the image upload feature. Used by the image upload feature in the `@ckeditor/ckeditor5-image` package.
+ *
+ *		ClassicEditor
+ *			.create( editorElement, {
+ * 				image: {
+ * 					upload:  ... // Image upload feature options.
+ * 				}
+ *			} )
+ *			.then( ... )
+ *			.catch( ... );
+ *
+ * See {@link module:core/editor/editorconfig~EditorConfig all editor options}.
+ *
+ * @interface module:image/imageupload~ImageUploadConfig
+ */
+
+/**
+ * List of accepted image types.
+ *
+ * The accepted types of images can be customize to allow only certain types of images:
+ *
+ *		// Allow only JPEG and PNG images:
+ *		const imageUploadConfig = {
+ *			types: [ 'png', 'jpeg' ]
+ *		};
+ *
+ * The type string should match [one of the sub-types](https://www.iana.org/assignments/media-types/media-types.xhtml#image)
+ * of the image mime-type. E.g. for the `image/jpeg` mime-type add `'jpeg'`.
+ *
+ * **Note:** This setting only restricts some image types to be selected and uploaded through the CKEditor UI and commands. Image type
+ * recognition and filtering should be also implemented on the server which accepts image uploads
+ *
+ * @member {Array.<String>} module:image/imageupload~ImageUploadConfig#types
+ * @default [ 'jpeg', 'png', 'gif', 'bmp', 'webp', 'tiff' ]
+ */

+ 99 - 46
packages/ckeditor5-image/src/imageupload/imageuploadediting.js

@@ -10,10 +10,13 @@
 import Plugin from '@ckeditor/ckeditor5-core/src/plugin';
 import FileRepository from '@ckeditor/ckeditor5-upload/src/filerepository';
 import Notification from '@ckeditor/ckeditor5-ui/src/notification/notification';
+import Clipboard from '@ckeditor/ckeditor5-clipboard/src/clipboard';
 import UpcastWriter from '@ckeditor/ckeditor5-engine/src/view/upcastwriter';
+import env from '@ckeditor/ckeditor5-utils/src/env';
 
 import ImageUploadCommand from '../../src/imageupload/imageuploadcommand';
-import { isImageType, isLocalImage, fetchLocalImage } from '../../src/imageupload/utils';
+import { fetchLocalImage, isLocalImage } from '../../src/imageupload/utils';
+import { createImageTypeRegExp } from './utils';
 
 /**
  * The editing part of the image upload feature. It registers the `'imageUpload'` command.
@@ -25,7 +28,24 @@ export default class ImageUploadEditing extends Plugin {
 	 * @inheritDoc
 	 */
 	static get requires() {
-		return [ FileRepository, Notification ];
+		return [ FileRepository, Notification, Clipboard ];
+	}
+
+	static get pluginName() {
+		return 'ImageUploadEditing';
+	}
+
+	/**
+	 * @inheritDoc
+	 */
+	constructor( editor ) {
+		super( editor );
+
+		editor.config.define( 'image', {
+			upload: {
+				types: [ 'jpeg', 'png', 'gif', 'bmp', 'webp', 'tiff' ]
+			}
+		} );
 	}
 
 	/**
@@ -38,6 +58,8 @@ export default class ImageUploadEditing extends Plugin {
 		const conversion = editor.conversion;
 		const fileRepository = editor.plugins.get( FileRepository );
 
+		const imageTypes = createImageTypeRegExp( editor.config.get( 'image.upload.types' ) );
+
 		// Setup schema to allow uploadId and uploadStatus for images.
 		schema.extend( 'image', {
 			allowAttributes: [ 'uploadId', 'uploadStatus' ]
@@ -73,7 +95,7 @@ export default class ImageUploadEditing extends Plugin {
 					return false;
 				}
 
-				return isImageType( file );
+				return imageTypes.test( file.type );
 			} );
 
 			const ranges = data.targetRanges.map( viewRange => editor.editing.mapper.toModelRange( viewRange ) );
@@ -97,31 +119,29 @@ export default class ImageUploadEditing extends Plugin {
 		// For every image file, a new file loader is created and a placeholder image is
 		// inserted into the content. Then, those images are uploaded once they appear in the model
 		// (see Document#change listener below).
-		if ( editor.plugins.has( 'Clipboard' ) ) {
-			this.listenTo( editor.plugins.get( 'Clipboard' ), 'inputTransformation', ( evt, data ) => {
-				const fetchableImages = Array.from( editor.editing.view.createRangeIn( data.content ) )
-					.filter( value => isLocalImage( value.item ) && !value.item.getAttribute( 'uploadProcessed' ) )
-					.map( value => { return { promise: fetchLocalImage( value.item ), imageElement: value.item }; } );
-
-				if ( !fetchableImages.length ) {
-					return;
-				}
+		this.listenTo( editor.plugins.get( Clipboard ), 'inputTransformation', ( evt, data ) => {
+			const fetchableImages = Array.from( editor.editing.view.createRangeIn( data.content ) )
+				.filter( value => isLocalImage( value.item ) && !value.item.getAttribute( 'uploadProcessed' ) )
+				.map( value => { return { promise: fetchLocalImage( value.item ), imageElement: value.item }; } );
 
-				const writer = new UpcastWriter();
+			if ( !fetchableImages.length ) {
+				return;
+			}
 
-				for ( const fetchableImage of fetchableImages ) {
-					// Set attribute marking that the image was processed already.
-					writer.setAttribute( 'uploadProcessed', true, fetchableImage.imageElement );
+			const writer = new UpcastWriter();
 
-					const loader = fileRepository.createLoader( fetchableImage.promise );
+			for ( const fetchableImage of fetchableImages ) {
+				// Set attribute marking that the image was processed already.
+				writer.setAttribute( 'uploadProcessed', true, fetchableImage.imageElement );
 
-					if ( loader ) {
-						writer.setAttribute( 'src', '', fetchableImage.imageElement );
-						writer.setAttribute( 'uploadId', loader.id, fetchableImage.imageElement );
-					}
+				const loader = fileRepository.createLoader( fetchableImage.promise );
+
+				if ( loader ) {
+					writer.setAttribute( 'src', '', fetchableImage.imageElement );
+					writer.setAttribute( 'uploadId', loader.id, fetchableImage.imageElement );
 				}
-			} );
-		}
+			}
+		} );
 
 		// Prevents from the browser redirecting to the dropped image.
 		editor.editing.view.document.on( 'dragover', ( evt, data ) => {
@@ -133,30 +153,32 @@ export default class ImageUploadEditing extends Plugin {
 			const changes = doc.differ.getChanges( { includeChangesInGraveyard: true } );
 
 			for ( const entry of changes ) {
-				if ( entry.type == 'insert' && entry.name == 'image' ) {
+				if ( entry.type == 'insert' && entry.name != '$text' ) {
 					const item = entry.position.nodeAfter;
 					const isInGraveyard = entry.position.root.rootName == '$graveyard';
 
-					// Check if the image element still has upload id.
-					const uploadId = item.getAttribute( 'uploadId' );
+					for ( const image of getImagesFromChangeItem( editor, item ) ) {
+						// Check if the image element still has upload id.
+						const uploadId = image.getAttribute( 'uploadId' );
 
-					if ( !uploadId ) {
-						continue;
-					}
+						if ( !uploadId ) {
+							continue;
+						}
 
-					// Check if the image is loaded on this client.
-					const loader = fileRepository.loaders.get( uploadId );
+						// Check if the image is loaded on this client.
+						const loader = fileRepository.loaders.get( uploadId );
 
-					if ( !loader ) {
-						continue;
-					}
+						if ( !loader ) {
+							continue;
+						}
 
-					if ( isInGraveyard ) {
-						// If the image was inserted to the graveyard - abort the loading process.
-						loader.abort();
-					} else if ( loader.status == 'idle' ) {
-						// If the image was inserted into content and has not been loaded yet, start loading it.
-						this._readAndUpload( loader, item );
+						if ( isInGraveyard ) {
+							// If the image was inserted to the graveyard - abort the loading process.
+							loader.abort();
+						} else if ( loader.status == 'idle' ) {
+							// If the image was inserted into content and has not been loaded yet, start loading it.
+							this._readAndUpload( loader, image );
+						}
 					}
 				}
 			}
@@ -187,14 +209,39 @@ export default class ImageUploadEditing extends Plugin {
 		} );
 
 		return loader.read()
-			.then( data => {
-				const viewFigure = editor.editing.mapper.toViewElement( imageElement );
-				const viewImg = viewFigure.getChild( 0 );
+			.then( () => {
 				const promise = loader.upload();
 
-				editor.editing.view.change( writer => {
-					writer.setAttribute( 'src', data, viewImg );
-				} );
+				// Force re–paint in Safari. Without it, the image will display with a wrong size.
+				// https://github.com/ckeditor/ckeditor5/issues/1975
+				/* istanbul ignore next */
+				if ( env.isSafari ) {
+					const viewFigure = editor.editing.mapper.toViewElement( imageElement );
+					const viewImg = viewFigure.getChild( 0 );
+
+					editor.editing.view.once( 'render', () => {
+						// Early returns just to be safe. There might be some code ran
+						// in between the outer scope and this callback.
+						if ( !viewImg.parent ) {
+							return;
+						}
+
+						const domFigure = editor.editing.view.domConverter.mapViewToDom( viewImg.parent );
+
+						if ( !domFigure ) {
+							return;
+						}
+
+						const originalDisplay = domFigure.style.display;
+
+						domFigure.style.display = 'none';
+
+						// Make sure this line will never be removed during minification for having "no effect".
+						domFigure._ckHack = domFigure.offsetHeight;
+
+						domFigure.style.display = originalDisplay;
+					} );
+				}
 
 				model.enqueueChange( 'transparent', writer => {
 					writer.setAttribute( 'uploadStatus', 'uploading', imageElement );
@@ -289,3 +336,9 @@ export default class ImageUploadEditing extends Plugin {
 export function isHtmlIncluded( dataTransfer ) {
 	return Array.from( dataTransfer.types ).includes( 'text/html' ) && dataTransfer.getData( 'text/html' ) !== '';
 }
+
+function getImagesFromChangeItem( editor, item ) {
+	return Array.from( editor.model.createRangeOn( item ) )
+		.filter( value => value.item.is( 'image' ) )
+		.map( value => value.item );
+}

+ 14 - 0
packages/ckeditor5-image/src/imageupload/imageuploadprogress.js

@@ -97,6 +97,7 @@ export default class ImageUploadProgress extends Plugin {
 				// Hide placeholder and initialize progress bar showing upload progress.
 				_hidePlaceholder( viewFigure, viewWriter );
 				_showProgressBar( viewFigure, viewWriter, loader, editor.editing.view );
+				_displayLocalImage( viewFigure, viewWriter, loader );
 			}
 
 			return;
@@ -261,3 +262,16 @@ function _removeUIElement( viewFigure, writer, uniqueProperty ) {
 		writer.remove( writer.createRangeOn( element ) );
 	}
 }
+
+// Displays local data from file loader.
+//
+// @param {module:engine/view/element~Element} imageFigure
+// @param {module:engine/view/downcastwriter~DowncastWriter} writer
+// @param {module:upload/filerepository~FileLoader} loader
+function _displayLocalImage( viewFigure, writer, loader ) {
+	if ( loader.data ) {
+		const viewImg = viewFigure.getChild( 0 );
+
+		writer.setAttribute( 'src', loader.data, viewImg );
+	}
+}

+ 5 - 3
packages/ckeditor5-image/src/imageupload/imageuploadui.js

@@ -10,7 +10,7 @@
 import Plugin from '@ckeditor/ckeditor5-core/src/plugin';
 import FileDialogButtonView from '@ckeditor/ckeditor5-upload/src/ui/filedialogbuttonview';
 import imageIcon from '@ckeditor/ckeditor5-core/theme/icons/image.svg';
-import { isImageType } from './utils';
+import { createImageTypeRegExp } from './utils';
 
 /**
  * The image upload button plugin.
@@ -33,9 +33,11 @@ export default class ImageUploadUI extends Plugin {
 		editor.ui.componentFactory.add( 'imageUpload', locale => {
 			const view = new FileDialogButtonView( locale );
 			const command = editor.commands.get( 'imageUpload' );
+			const imageTypes = editor.config.get( 'image.upload.types' );
+			const imageTypesRegExp = createImageTypeRegExp( imageTypes );
 
 			view.set( {
-				acceptedType: 'image/*',
+				acceptedType: imageTypes.map( type => `image/${ type }` ).join( ',' ),
 				allowMultipleFiles: true
 			} );
 
@@ -48,7 +50,7 @@ export default class ImageUploadUI extends Plugin {
 			view.buttonView.bind( 'isEnabled' ).to( command );
 
 			view.on( 'done', ( evt, files ) => {
-				const imagesToUpload = Array.from( files ).filter( isImageType );
+				const imagesToUpload = Array.from( files ).filter( file => imageTypesRegExp.test( file.type ) );
 
 				if ( imagesToUpload.length ) {
 					editor.execute( 'imageUpload', { file: imagesToUpload } );

+ 11 - 6
packages/ckeditor5-image/src/imageupload/utils.js

@@ -10,15 +10,20 @@
 /* global fetch, File */
 
 /**
- * Checks if a given file is an image.
+ * Creates a RegExp used to test for image files.
  *
- * @param {File} file
- * @returns {Boolean}
+ *		const imageType = createImageTypeRegExp( [ 'png', 'jpeg', 'svg+xml', 'vnd.microsoft.icon' ] );
+ *
+ *		console.log( 'is supported image', imageType.test( file.type ) );
+ *
+ * @param {Array.<String>} types
+ * @returns {RegExp}
  */
-export function isImageType( file ) {
-	const types = /^image\/(jpeg|png|gif|bmp)$/;
+export function createImageTypeRegExp( types ) {
+	// Sanitize mime-type name which may include: "+", "-" or ".".
+	const regExpSafeNames = types.map( type => type.replace( '+', '\\+' ) );
 
-	return types.test( file.type );
+	return new RegExp( `^image\\/(${ regExpSafeNames.join( '|' ) })$` );
 }
 
 /**

+ 3 - 2
packages/ckeditor5-image/tests/image/imageediting.js

@@ -68,7 +68,7 @@ describe( 'ImageEditing', () => {
 		const element = document.createElement( 'div' );
 		document.body.appendChild( element );
 
-		ClassicTestEditor.create( element, {
+		return ClassicTestEditor.create( element, {
 			plugins: [ ImageEditing ]
 		} ).then( editor => {
 			editor.data.set( '<figure class="image"><img src="/assets/sample.png" alt="bar" /></figure>' );
@@ -77,7 +77,8 @@ describe( 'ImageEditing', () => {
 
 			editor.ui.on( 'update', spy );
 
-			element.querySelector( 'img' ).dispatchEvent( new Event( 'load' ) );
+			const htmlImageElement = editor.ui.getEditableElement().querySelector( 'img' );
+			htmlImageElement.dispatchEvent( new Event( 'load' ) );
 
 			sinon.assert.calledOnce( spy );
 

+ 32 - 4
packages/ckeditor5-image/tests/imageupload/imageuploadediting.js

@@ -95,10 +95,13 @@ describe( 'ImageUploadEditing', () => {
 		expect( editor.commands.get( 'imageUpload' ) ).to.be.instanceOf( ImageUploadCommand );
 	} );
 
-	it( 'should not crash when Clipboard plugin is not available', () => {
+	it( 'should load Clipboard plugin', () => {
 		return VirtualTestEditor
 			.create( {
 				plugins: [ ImageEditing, ImageUploadEditing, Paragraph, UndoEditing, UploadAdapterPluginMock ]
+			} )
+			.then( editor => {
+				expect( editor.plugins.get( Clipboard ) ).to.be.instanceOf( Clipboard );
 			} );
 	} );
 
@@ -226,6 +229,30 @@ describe( 'ImageUploadEditing', () => {
 		expect( eventInfo.stop.called ).to.be.undefined;
 	} );
 
+	it( 'should not insert image when file is not an configured image type', () => {
+		const viewDocument = editor.editing.view.document;
+		const fileMock = {
+			type: 'image/svg+xml',
+			size: 1024
+		};
+		const dataTransfer = new DataTransfer( {
+			files: [ fileMock ],
+			types: [ 'Files' ],
+			getData: () => ''
+		} );
+
+		setModelData( model, '<paragraph>foo[]</paragraph>' );
+
+		const targetRange = doc.selection.getFirstRange();
+		const targetViewRange = editor.editing.mapper.toViewRange( targetRange );
+
+		const eventInfo = new EventInfo( viewDocument, 'clipboardInput' );
+		viewDocument.fire( eventInfo, { dataTransfer, targetRanges: [ targetViewRange ] } );
+
+		expect( getModelData( model ) ).to.equal( '<paragraph>foo[]</paragraph>' );
+		expect( eventInfo.stop.called ).to.be.undefined;
+	} );
+
 	it( 'should not insert image when file is null', () => {
 		const viewDocument = editor.editing.view.document;
 		const dataTransfer = new DataTransfer( { files: [ null ], types: [ 'Files' ], getData: () => null } );
@@ -334,7 +361,7 @@ describe( 'ImageUploadEditing', () => {
 			'</figure>]' );
 	} );
 
-	it( 'should use read data once it is present', done => {
+	it( 'should not use read data once it is present', done => {
 		const file = createNativeFileMock();
 		setModelData( model, '<paragraph>{}foo bar</paragraph>' );
 		editor.execute( 'imageUpload', { file } );
@@ -343,7 +370,8 @@ describe( 'ImageUploadEditing', () => {
 			tryExpect( done, () => {
 				expect( getViewData( view ) ).to.equal(
 					'[<figure class="ck-widget image" contenteditable="false">' +
-						`<img src="${ base64Sample }"></img>` +
+						// Rendering the image data is left to a upload progress converter.
+						'<img></img>' +
 						'</figure>]' +
 					'<p>foo bar</p>'
 				);
@@ -682,7 +710,7 @@ describe( 'ImageUploadEditing', () => {
 
 		// Stub `fetch` so it can be rejected.
 		sinon.stub( window, 'fetch' ).callsFake( () => {
-			return new Promise( ( res, rej ) => rej() );
+			return new Promise( ( res, rej ) => rej( 'could not fetch' ) );
 		} );
 
 		viewDocument.fire( 'clipboardInput', { dataTransfer, targetRanges: [ targetViewRange ] } );

+ 50 - 1
packages/ckeditor5-image/tests/imageupload/imageuploadprogress.js

@@ -15,7 +15,7 @@ import Paragraph from '@ckeditor/ckeditor5-paragraph/src/paragraph';
 import FileRepository from '@ckeditor/ckeditor5-upload/src/filerepository';
 import Clipboard from '@ckeditor/ckeditor5-clipboard/src/clipboard';
 
-import { UploadAdapterMock, createNativeFileMock, NativeFileReaderMock } from '@ckeditor/ckeditor5-upload/tests/_utils/mocks';
+import { createNativeFileMock, NativeFileReaderMock, UploadAdapterMock } from '@ckeditor/ckeditor5-upload/tests/_utils/mocks';
 import { setData as setModelData } from '@ckeditor/ckeditor5-engine/src/dev-utils/model';
 import { getData as getViewData } from '@ckeditor/ckeditor5-engine/src/dev-utils/view';
 import testUtils from '@ckeditor/ckeditor5-core/tests/_utils/utils';
@@ -107,6 +107,55 @@ describe( 'ImageUploadProgress', () => {
 		loader.file.then( () => nativeReaderMock.mockSuccess( base64Sample ) );
 	} );
 
+	// See https://github.com/ckeditor/ckeditor5/issues/1985.
+	it( 'should work if image parent is refreshed by the differ', function( done ) {
+		model.schema.register( 'outerBlock', {
+			allowWhere: '$block',
+			isBlock: true
+		} );
+
+		model.schema.register( 'innerBlock', {
+			allowIn: 'outerBlock',
+			isLimit: true
+		} );
+
+		model.schema.extend( '$block', { allowIn: 'innerBlock' } );
+		editor.conversion.elementToElement( { model: 'outerBlock', view: 'outerBlock' } );
+		editor.conversion.elementToElement( { model: 'innerBlock', view: 'innerBlock' } );
+
+		model.document.registerPostFixer( () => {
+			for ( const change of doc.differ.getChanges() ) {
+				// The differ.refreshItem() simulates remove and insert of and image parent thus preventing image from proper work.
+				if ( change.type == 'insert' && change.name == 'image' ) {
+					doc.differ.refreshItem( change.position.parent );
+
+					return true;
+				}
+			}
+		} );
+
+		setModelData( model, '<outerBlock><innerBlock><paragraph>[]</paragraph></innerBlock></outerBlock>' );
+
+		editor.execute( 'imageUpload', { file: createNativeFileMock() } );
+
+		model.document.once( 'change', () => {
+			try {
+				expect( getViewData( view ) ).to.equal(
+					'<outerBlock><innerBlock>[<figure class="ck-appear ck-widget image" contenteditable="false">' +
+					`<img src="${ base64Sample }"></img>` +
+					'<div class="ck-progress-bar"></div>' +
+					'</figure>]</innerBlock></outerBlock>'
+				);
+
+				done();
+			} catch ( err ) {
+				done( err );
+			}
+		}, { priority: 'lowest' } );
+
+		loader.file.then( () => nativeReaderMock.mockSuccess( base64Sample ) );
+	} );
+
 	it( 'should work correctly when there is no "reading" status and go straight to "uploading"', () => {
 		const fileRepository = editor.plugins.get( FileRepository );
 		const file = createNativeFileMock();

+ 8 - 0
packages/ckeditor5-image/tests/imageupload/imageuploadui.js

@@ -62,6 +62,14 @@ describe( 'ImageUploadUI', () => {
 		expect( button ).to.be.instanceOf( FileDialogButtonView );
 	} );
 
+	it( 'should set proper accepted mime-types for imageUpload button as defined in configuration', () => {
+		editor.config.set( 'image.upload.types', [ 'svg+xml', 'jpeg', 'vnd.microsoft.icon', 'x-xbitmap' ] );
+
+		const button = editor.ui.componentFactory.create( 'imageUpload' );
+
+		expect( button.acceptedType ).to.equal( 'image/svg+xml,image/jpeg,image/vnd.microsoft.icon,image/x-xbitmap' );
+	} );
+
 	it( 'should be disabled while ImageUploadCommand is disabled', () => {
 		const button = editor.ui.componentFactory.create( 'imageUpload' );
 		const command = editor.commands.get( 'imageUpload' );

+ 18 - 15
packages/ckeditor5-image/tests/imageupload/utils.js

@@ -3,29 +3,32 @@
  * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
  */
 
-import { isImageType } from '../../src/imageupload/utils';
+import { createImageTypeRegExp } from '../../src/imageupload/utils';
 
 describe( 'upload utils', () => {
-	describe( 'isImageType()', () => {
-		it( 'should return true for png mime type', () => {
-			expect( isImageType( { type: 'image/png' } ) ).to.be.true;
+	describe( 'createImageTypeRegExp()', () => {
+		it( 'should return RegExp for testing regular mime type', () => {
+			expect( createImageTypeRegExp( [ 'png' ] ).test( 'image/png' ) ).to.be.true;
+			expect( createImageTypeRegExp( [ 'png' ] ).test( 'foo/png' ) ).to.be.false;
+			expect( createImageTypeRegExp( [ 'png' ] ).test( 'png' ) ).to.be.false;
 		} );
 
-		it( 'should return true for jpeg mime type', () => {
-			expect( isImageType( { type: 'image/jpeg' } ) ).to.be.true;
+		it( 'should return RegExp for testing mime type with dot', () => {
+			expect( createImageTypeRegExp( [ 'vnd.microsoft.icon' ] ).test( 'image/vnd.microsoft.icon' ) ).to.be.true;
+			expect( createImageTypeRegExp( [ 'png' ] ).test( 'foo/vnd.microsoft.icon' ) ).to.be.false;
+			expect( createImageTypeRegExp( [ 'png' ] ).test( 'vnd.microsoft.icon' ) ).to.be.false;
 		} );
 
-		it( 'should return true for gif mime type', () => {
-			expect( isImageType( { type: 'image/gif' } ) ).to.be.true;
+		it( 'should return RegExp for testing mime type with dash', () => {
+			expect( createImageTypeRegExp( [ 'x-xbitmap' ] ).test( 'image/x-xbitmap' ) ).to.be.true;
+			expect( createImageTypeRegExp( [ 'png' ] ).test( 'foo/x-xbitmap' ) ).to.be.false;
+			expect( createImageTypeRegExp( [ 'png' ] ).test( 'x-xbitmap' ) ).to.be.false;
 		} );
 
-		it( 'should return true for bmp mime type', () => {
-			expect( isImageType( { type: 'image/bmp' } ) ).to.be.true;
-		} );
-
-		it( 'should return false for other mime types', () => {
-			expect( isImageType( { type: 'audio/mp3' } ) ).to.be.false;
-			expect( isImageType( { type: 'video/mpeg' } ) ).to.be.false;
+		it( 'should return RegExp for testing mime type with plus', () => {
+			expect( createImageTypeRegExp( [ 'svg+xml' ] ).test( 'image/svg+xml' ) ).to.be.true;
+			expect( createImageTypeRegExp( [ 'png' ] ).test( 'foo/svg+xml' ) ).to.be.false;
+			expect( createImageTypeRegExp( [ 'png' ] ).test( 'svg+xml' ) ).to.be.false;
 		} );
 	} );
 } );

+ 28 - 2
packages/ckeditor5-image/tests/manual/imagestyle.js

@@ -13,7 +13,20 @@ ClassicEditor
 		plugins: [
 			ArticlePluginSet
 		],
-		toolbar: [ 'heading', '|', 'undo', 'redo' ],
+		toolbar: [
+			'heading',
+			'|',
+			'bold',
+			'italic',
+			'link',
+			'bulletedList',
+			'numberedList',
+			'blockQuote',
+			'insertTable',
+			'mediaEmbed',
+			'undo',
+			'redo'
+		],
 		image: {
 			toolbar: [ 'imageStyle:full', 'imageStyle:side' ]
 		}
@@ -30,7 +43,20 @@ ClassicEditor
 		plugins: [
 			ArticlePluginSet
 		],
-		toolbar: [ 'heading', '|', 'undo', 'redo' ],
+		toolbar: [
+			'heading',
+			'|',
+			'bold',
+			'italic',
+			'link',
+			'bulletedList',
+			'numberedList',
+			'blockQuote',
+			'insertTable',
+			'mediaEmbed',
+			'undo',
+			'redo'
+		],
 		image: {
 			styles: [ 'alignLeft', 'alignCenter', 'alignRight' ],
 			toolbar: [ 'imageStyle:alignLeft', 'imageStyle:alignCenter', 'imageStyle:alignRight' ]

+ 18 - 18
packages/ckeditor5-image/tests/manual/imageupload.js

@@ -6,31 +6,31 @@
 /* globals window, document, console */
 
 import ClassicEditor from '@ckeditor/ckeditor5-editor-classic/src/classiceditor';
-import Bold from '@ckeditor/ckeditor5-basic-styles/src/bold';
-import Clipboard from '@ckeditor/ckeditor5-clipboard/src/clipboard';
-import Enter from '@ckeditor/ckeditor5-enter/src/enter';
-import Heading from '@ckeditor/ckeditor5-heading/src/heading';
-import Italic from '@ckeditor/ckeditor5-basic-styles/src/italic';
-import List from '@ckeditor/ckeditor5-list/src/list';
-import Paragraph from '@ckeditor/ckeditor5-paragraph/src/paragraph';
-import Typing from '@ckeditor/ckeditor5-typing/src/typing';
-import Undo from '@ckeditor/ckeditor5-undo/src/undo';
-import { UploadAdapterMock } from '@ckeditor/ckeditor5-upload/tests/_utils/mocks';
-import ImageStyle from '../../src/imagestyle';
-import ImageToolbar from '../../src/imagetoolbar';
-import Image from '../../src/image';
-import ImageCaption from '../../src/imagecaption';
+import ArticlePluginSet from '@ckeditor/ckeditor5-core/tests/_utils/articlepluginset';
 import ImageUpload from '../../src/imageupload';
 
+import { UploadAdapterMock } from '@ckeditor/ckeditor5-upload/tests/_utils/mocks';
+
 const buttonContainer = document.getElementById( 'button-container' );
 
 ClassicEditor
 	.create( document.querySelector( '#editor' ), {
-		plugins: [
-			Enter, Typing, Paragraph, Heading, Undo, Bold, Italic, Heading, List, Image, ImageToolbar, Clipboard,
-			ImageCaption, ImageStyle, ImageUpload
+		plugins: [ ArticlePluginSet, ImageUpload ],
+		toolbar: [
+			'heading',
+			'|',
+			'bold',
+			'italic',
+			'link',
+			'bulletedList',
+			'numberedList',
+			'blockQuote',
+			'imageUpload',
+			'insertTable',
+			'mediaEmbed',
+			'undo',
+			'redo'
 		],
-		toolbar: [ 'heading', '|', 'undo', 'redo', 'bold', 'italic', 'bulletedList', 'numberedList', 'imageUpload' ],
 		image: {
 			toolbar: [ 'imageStyle:full', 'imageStyle:side', '|', 'imageTextAlternative' ]
 		}

+ 5 - 5
packages/ckeditor5-image/theme/imageresize.css

@@ -6,20 +6,20 @@
 .ck-content .image.image_resized {
 	max-width: 100%;
 	/*
-	The figure element for resized images must not use `display:table` as browsers doesn't support `max-width` for it well.
+	The `<figure>` element for resized images must not use `display:table` as browsers do not support `max-width` for it well.
 	See https://stackoverflow.com/questions/4019604/chrome-safari-ignoring-max-width-in-table/14420691#14420691 for more.
-	Fortunately, since we control width, there's no risk that the image will look bad.
+	Fortunately, since we control the width, there is no risk that the image will look bad.
 	*/
 	display: block;
 	box-sizing: border-box;
 
 	& img {
-		/* For resized images it's the figure that determines the image's width. */
+		/* For resized images it is the `<figure>` element that determines the image width. */
 		width: 100%;
 	}
 
-	&>figcaption {
-		/* Figure uses display block, so figcaption also has to. */
+	& > figcaption {
+		/* The `<figure>` element uses `display:block`, so `<figcaption>` also has to. */
 		display: block;
 	}
 }

+ 1 - 3
packages/ckeditor5-image/theme/imagestyle.css

@@ -12,9 +12,7 @@
 	& .image-style-align-left,
 	& .image-style-align-center,
 	& .image-style-align-right {
-		&:not(.image_resized) {
-			max-width: 50%;
-		}
+		max-width: 50%;
 	}
 
 	& .image-style-side {

+ 2 - 2
packages/ckeditor5-image/theme/imageuploadprogress.css

@@ -3,12 +3,12 @@
  * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
  */
 
-.ck-content .image {
+.ck.ck-editor__editable .image {
 	position: relative;
 }
 
 /* Upload progress bar. */
-.ck .ck-progress-bar {
+.ck.ck-editor__editable .image .ck-progress-bar {
 	position: absolute;
 	top: 0;
 	left: 0;