From a54561284fbeac8d2ea436c71511000ec403f121 Mon Sep 17 00:00:00 2001 From: DawidKossowskii Date: Mon, 22 Jul 2024 15:32:46 +0200 Subject: [PATCH 1/9] Added the possibility to register array of items in image insert UI. --- .../src/imageinsert/imageinsertui.ts | 42 +++++++++---------- 1 file changed, 19 insertions(+), 23 deletions(-) diff --git a/packages/ckeditor5-image/src/imageinsert/imageinsertui.ts b/packages/ckeditor5-image/src/imageinsert/imageinsertui.ts index 86b25165291..a8b6d455cb2 100644 --- a/packages/ckeditor5-image/src/imageinsert/imageinsertui.ts +++ b/packages/ckeditor5-image/src/imageinsert/imageinsertui.ts @@ -136,8 +136,8 @@ export default class ImageInsertUI extends Plugin { name: string; observable: Observable & { isEnabled: boolean } | ( () => Observable & { isEnabled: boolean } ); buttonViewCreator: ( isOnlyOne: boolean ) => ButtonView; - formViewCreator: ( isOnlyOne: boolean ) => FocusableView; - menuBarButtonViewCreator: ( isOnlyOne: boolean ) => MenuBarMenuListItemButtonView; + formViewCreator: ( isOnlyOne: boolean ) => FocusableView | Array; + menuBarButtonViewCreator: ( isOnlyOne: boolean ) => MenuBarMenuListItemButtonView | Array; requiresForm?: boolean; } ): void { if ( this._integrations.has( name ) ) { @@ -203,7 +203,7 @@ export default class ImageInsertUI extends Plugin { ) ); dropdownView.once( 'change:isOpen', () => { - const integrationViews = integrations.map( ( { formViewCreator } ) => formViewCreator( integrations.length == 1 ) ); + const integrationViews = integrations.flatMap( ( { formViewCreator } ) => formViewCreator( integrations.length == 1 ) ); const imageInsertFormView = new ImageInsertFormView( editor.locale, integrationViews ); dropdownView.panelView.children.add( imageInsertFormView ); @@ -224,28 +224,24 @@ export default class ImageInsertUI extends Plugin { return null as any; } - let resultView: MenuBarMenuListItemButtonView | MenuBarMenuView | undefined; - const firstIntegration = integrations[ 0 ]; + const integrationViews = integrations.flatMap( ( { + menuBarButtonViewCreator + } ) => menuBarButtonViewCreator( integrations.length == 1 ) ); - if ( integrations.length == 1 ) { - resultView = firstIntegration.menuBarButtonViewCreator( true ); - } else { - resultView = new MenuBarMenuView( locale ); - const listView = new MenuBarMenuListView( locale ); - resultView.panelView.children.add( listView ); + const resultView = new MenuBarMenuView( locale ); + const listView = new MenuBarMenuListView( locale ); + resultView.panelView.children.add( listView ); - resultView.buttonView.set( { - icon: icons.image, - label: t( 'Image' ) - } ); + resultView.buttonView.set( { + icon: icons.image, + label: t( 'Image' ) + } ); - for ( const integration of integrations ) { - const listItemView = new MenuBarMenuListItemView( locale, resultView ); - const buttonView = integration.menuBarButtonViewCreator( false ); + for ( const integrationView of integrationViews ) { + const listItemView = new MenuBarMenuListItemView( locale, resultView ); - listItemView.children.add( buttonView ); - listView.items.add( listItemView ); - } + listItemView.children.add( integrationView ); + listView.items.add( listItemView ); } return resultView; @@ -313,7 +309,7 @@ export default class ImageInsertUI extends Plugin { type IntegrationData = { observable: Observable & { isEnabled: boolean } | ( () => Observable & { isEnabled: boolean } ); buttonViewCreator: ( isOnlyOne: boolean ) => ButtonView; - menuBarButtonViewCreator: ( isOnlyOne: boolean ) => MenuBarMenuListItemButtonView; - formViewCreator: ( isOnlyOne: boolean ) => FocusableView; + menuBarButtonViewCreator: ( isOnlyOne: boolean ) => MenuBarMenuListItemButtonView | Array; + formViewCreator: ( isOnlyOne: boolean ) => FocusableView | Array; requiresForm: boolean; }; From 026eb989478f4b65a5e8b6756d30e00675354f0c Mon Sep 17 00:00:00 2001 From: DawidKossowskii Date: Tue, 23 Jul 2024 13:18:09 +0200 Subject: [PATCH 2/9] Implemented integration with image insert UI. --- packages/ckeditor5-image/src/imageinsert/imageinsertui.ts | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/packages/ckeditor5-image/src/imageinsert/imageinsertui.ts b/packages/ckeditor5-image/src/imageinsert/imageinsertui.ts index a8b6d455cb2..cf28dbf0c0c 100644 --- a/packages/ckeditor5-image/src/imageinsert/imageinsertui.ts +++ b/packages/ckeditor5-image/src/imageinsert/imageinsertui.ts @@ -131,7 +131,8 @@ export default class ImageInsertUI extends Plugin { buttonViewCreator, formViewCreator, menuBarButtonViewCreator, - requiresForm = false + requiresForm = false, + override = false }: { name: string; observable: Observable & { isEnabled: boolean } | ( () => Observable & { isEnabled: boolean } ); @@ -139,8 +140,9 @@ export default class ImageInsertUI extends Plugin { formViewCreator: ( isOnlyOne: boolean ) => FocusableView | Array; menuBarButtonViewCreator: ( isOnlyOne: boolean ) => MenuBarMenuListItemButtonView | Array; requiresForm?: boolean; + override?: boolean; } ): void { - if ( this._integrations.has( name ) ) { + if ( this._integrations.has( name ) && !override ) { /** * There are two insert-image integrations registered with the same name. * From f6d705ea65190fe30a6872cc370233ff5210efc3 Mon Sep 17 00:00:00 2001 From: DawidKossowskii Date: Thu, 8 Aug 2024 16:12:34 +0200 Subject: [PATCH 3/9] UI and UX improvements. --- packages/ckeditor5-image/src/imageinsert/imageinsertui.ts | 2 ++ 1 file changed, 2 insertions(+) diff --git a/packages/ckeditor5-image/src/imageinsert/imageinsertui.ts b/packages/ckeditor5-image/src/imageinsert/imageinsertui.ts index cf28dbf0c0c..004ff0a085d 100644 --- a/packages/ckeditor5-image/src/imageinsert/imageinsertui.ts +++ b/packages/ckeditor5-image/src/imageinsert/imageinsertui.ts @@ -244,6 +244,8 @@ export default class ImageInsertUI extends Plugin { listItemView.children.add( integrationView ); listView.items.add( listItemView ); + + integrationView.delegate( 'execute' ).to( resultView ); } return resultView; From 105f1b3211b300ef75ac344f751e26748b4b3aba Mon Sep 17 00:00:00 2001 From: f1ames Date: Wed, 25 Sep 2024 12:15:27 +0200 Subject: [PATCH 4/9] Fix failing 'InsertImageUI' tests. --- packages/ckeditor5-ckbox/tests/ckboxui.js | 3 ++- packages/ckeditor5-ckfinder/tests/ckfinderui.js | 3 ++- .../ckeditor5-image/tests/imageinsert/imageinsertui.js | 7 ++++++- .../tests/imageinsert/imageinsertviaurlui.js | 5 ++++- .../ckeditor5-image/tests/imageupload/imageuploadui.js | 4 +++- 5 files changed, 17 insertions(+), 5 deletions(-) diff --git a/packages/ckeditor5-ckbox/tests/ckboxui.js b/packages/ckeditor5-ckbox/tests/ckboxui.js index 9b2894d2333..69224fe8fa6 100644 --- a/packages/ckeditor5-ckbox/tests/ckboxui.js +++ b/packages/ckeditor5-ckbox/tests/ckboxui.js @@ -175,7 +175,8 @@ describe( 'CKBoxUI', () => { } ); it( 'should create CKBox button in menu bar - only integration', () => { - const buttonView = editor.ui.componentFactory.create( 'menuBar:insertImage' ); + const submenu = editor.ui.componentFactory.create( 'menuBar:insertImage' ); + const buttonView = submenu.panelView.children.first.items.first.children.first; expect( buttonView ).to.be.instanceOf( MenuBarMenuListItemButtonView ); expect( buttonView.withText ).to.be.true; diff --git a/packages/ckeditor5-ckfinder/tests/ckfinderui.js b/packages/ckeditor5-ckfinder/tests/ckfinderui.js index dda7299901e..e9c600d9dd7 100644 --- a/packages/ckeditor5-ckfinder/tests/ckfinderui.js +++ b/packages/ckeditor5-ckfinder/tests/ckfinderui.js @@ -123,7 +123,8 @@ describe( 'CKFinderUI', () => { } ); it( 'should create CKFinder button in menu bar - only integration', () => { - const buttonView = editor.ui.componentFactory.create( 'menuBar:insertImage' ); + const submenu = editor.ui.componentFactory.create( 'menuBar:insertImage' ); + const buttonView = submenu.panelView.children.first.items.first.children.first; expect( buttonView ).to.be.instanceOf( MenuBarMenuListItemButtonView ); expect( buttonView.withText ).to.be.true; diff --git a/packages/ckeditor5-image/tests/imageinsert/imageinsertui.js b/packages/ckeditor5-image/tests/imageinsert/imageinsertui.js index 0186d7f2363..dc8ad51f37f 100644 --- a/packages/ckeditor5-image/tests/imageinsert/imageinsertui.js +++ b/packages/ckeditor5-image/tests/imageinsert/imageinsertui.js @@ -321,7 +321,12 @@ describe( 'ImageInsertUI', () => { } ); it( 'should create a menu bar button', () => { - const button = editor.ui.componentFactory.create( 'menuBar:insertImage' ); + const menu = editor.ui.componentFactory.create( 'menuBar:insertImage' ); + + expect( menu ).to.be.instanceOf( MenuBarMenuView ); + + const submenuList = menu.panelView.children.get( 0 ); + const button = submenuList.items.get( 0 ).children.get( 0 ); expect( button ).to.be.instanceOf( MenuBarMenuListItemButtonView ); expect( button.label ).to.equal( 'button url' ); diff --git a/packages/ckeditor5-image/tests/imageinsert/imageinsertviaurlui.js b/packages/ckeditor5-image/tests/imageinsert/imageinsertviaurlui.js index 3fb53f631b1..f7e50458fb9 100644 --- a/packages/ckeditor5-image/tests/imageinsert/imageinsertviaurlui.js +++ b/packages/ckeditor5-image/tests/imageinsert/imageinsertviaurlui.js @@ -274,7 +274,10 @@ describe( 'ImageInsertViaUrlUI', () => { describe( 'menu bar button', () => { beforeEach( () => { - button = editor.ui.componentFactory.create( 'menuBar:insertImage' ); + const menu = editor.ui.componentFactory.create( 'menuBar:insertImage' ); + const submenuList = menu.panelView.children.get( 0 ); + + button = submenuList.items.get( 0 ).children.get( 0 ); } ); testButton( MenuBarMenuListItemButtonView, 'Image' ); diff --git a/packages/ckeditor5-image/tests/imageupload/imageuploadui.js b/packages/ckeditor5-image/tests/imageupload/imageuploadui.js index 5c01da9187a..74073c965a4 100644 --- a/packages/ckeditor5-image/tests/imageupload/imageuploadui.js +++ b/packages/ckeditor5-image/tests/imageupload/imageuploadui.js @@ -203,7 +203,9 @@ describe( 'ImageUploadUI', () => { } ); it( 'should create FileDialogButtonView in insert image submenu - only integration', () => { - button = editor.ui.componentFactory.create( 'menuBar:insertImage' ); + const submenu = editor.ui.componentFactory.create( 'menuBar:insertImage' ); + + button = submenu.panelView.children.first.items.first.children.first; expect( button ).to.be.instanceOf( MenuBarMenuListItemFileDialogButtonView ); expect( button.withText ).to.be.true; From 8b84d6a3dbda8cffc00fd0831b91be4dc9785ab1 Mon Sep 17 00:00:00 2001 From: f1ames Date: Wed, 9 Oct 2024 14:22:49 +0200 Subject: [PATCH 5/9] Add sections about Uploadcare integration to image docs pages. --- docs/features/image-upload.md | 12 ++++++++++++ docs/features/using-file-managers.md | 20 ++++++++++++++++++++ 2 files changed, 32 insertions(+) diff --git a/docs/features/image-upload.md b/docs/features/image-upload.md index dccc37b8e5c..d3dec5c9933 100644 --- a/docs/features/image-upload.md +++ b/docs/features/image-upload.md @@ -51,6 +51,18 @@ With CKBox, users can upload files and categorize them into different groups. Th {@link features/ckbox **Learn how to use CKBox in your project**}. +### Uploadcare + +Uploadcare is the ultimate solution for image upload and editing in CKEditor 5. + +It is a modern file uploader with a clean interface, automatic support for responsive images, on-fly image optimization, fast delivery through global CDN network, multiple 3-rd party integrations and vast image editing capabilities like cropping, filtering and adjusting image parameters. + +Thanks to the native CKEditor 5 integration, Uploadcare supports drag and drop file upload as well as pasting images from the clipboard, Microsoft Word, or Google Docs. + +With Uploadcare, users can upload files from external services like Dropbox, Facebook, Google Drive, Google Photos, Instagram, OneDrive or from local computer. Images can be easily adjusted with built-in image editor. + +{@link features/uploadcare **Learn how to use Uploadcare in your project**}. + ### CKFinder The {@link features/ckfinder CKFinder feature} provides a bridge between the rich-text editor and [CKFinder](https://ckeditor.com/ckfinder/), a browser-based file uploader with server-side connectors (PHP, Java, and ASP.NET). diff --git a/docs/features/using-file-managers.md b/docs/features/using-file-managers.md index 5c483d68de5..87a7d9d5890 100644 --- a/docs/features/using-file-managers.md +++ b/docs/features/using-file-managers.md @@ -29,6 +29,26 @@ With CKBox you can: {@link features/ckbox **Read a separate guide on CKBox**} to learn about its installation and configuration. The guide also lets you try CKBox in action. +## Uploadcare file manager + +Uploadcare is a modern file management platform with multiple integrations with services like Dropbox, Google Drive, OneDrive and similar. + +With Uploadcare you can: +- Upload images directly from: + - Dropbox, + - Facebook, + - Google Drive, + - Google Photos, + - Instagram, + - OneDrive, + - Local computer, + - External URL. +- Manage all uploaded images through a dedicated platform. +- Edit images by changing dimensions, applying filters and adjusting various image parameters. +- Get your images served quickly through global CDN. + +{@link features/uploadcare **Read a separate guide on Uploadcare**} to learn about its installation and configuration. The guide also lets you try Uploadcare in action. + ## CKFinder file manager CKFinder is a powerful file manager with various image editing and image upload options. From 958edbebec123f3c9136ce26f55d269bf657d189 Mon Sep 17 00:00:00 2001 From: f1ames Date: Fri, 11 Oct 2024 12:05:27 +0200 Subject: [PATCH 6/9] Use full services list in docs. --- docs/features/using-file-managers.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/features/using-file-managers.md b/docs/features/using-file-managers.md index 87a7d9d5890..3c8891b959a 100644 --- a/docs/features/using-file-managers.md +++ b/docs/features/using-file-managers.md @@ -31,7 +31,7 @@ With CKBox you can: ## Uploadcare file manager -Uploadcare is a modern file management platform with multiple integrations with services like Dropbox, Google Drive, OneDrive and similar. +Uploadcare is a modern file management platform with multiple integrations with services like Dropbox, Facebook, Google Drive, Google Photos, Instagram and OneDrive. With Uploadcare you can: - Upload images directly from: From 4e04053a1d64fc0922d8f266e6c63081819489e0 Mon Sep 17 00:00:00 2001 From: DawidKossowskii Date: Wed, 23 Oct 2024 16:03:08 +0200 Subject: [PATCH 7/9] Extending dialog API to support keystroke handler options. --- packages/ckeditor5-ui/src/dialog/dialog.ts | 14 ++++++++++++-- packages/ckeditor5-ui/src/dialog/dialogview.ts | 10 +++++++--- 2 files changed, 19 insertions(+), 5 deletions(-) diff --git a/packages/ckeditor5-ui/src/dialog/dialog.ts b/packages/ckeditor5-ui/src/dialog/dialog.ts index b054d2655b3..e4b8e1fb9c5 100644 --- a/packages/ckeditor5-ui/src/dialog/dialog.ts +++ b/packages/ckeditor5-ui/src/dialog/dialog.ts @@ -12,6 +12,7 @@ import { type Editor, Plugin } from '@ckeditor/ckeditor5-core'; import DialogView, { type DialogViewCloseEvent, DialogViewPosition } from './dialogview.js'; import type { DialogActionButtonDefinition } from './dialogactionsview.js'; import type { DocumentChangeEvent } from '@ckeditor/ckeditor5-engine'; +import type { KeystrokeHandlerOptions } from '@ckeditor/ckeditor5-utils'; /** * The dialog controller class. It is used to show and hide the {@link module:ui/dialog/dialogview~DialogView}. @@ -283,7 +284,8 @@ export default class Dialog extends Plugin { className, isModal, position, - onHide + onHide, + keystrokeHandlerOptions }: DialogDefinition ) { const editor = this.editor; @@ -293,7 +295,8 @@ export default class Dialog extends Plugin { }, getViewportOffset: () => { return editor.ui.viewportOffset; - } + }, + keystrokeHandlerOptions } ); const view = this.view; @@ -476,6 +479,13 @@ export interface DialogDefinition { * It allows for cleaning up (for example, resetting) the dialog's {@link #content}. */ onHide?: ( dialog: Dialog ) => void; + + /** + * Options that will be passed to the {@link module:utils/keystrokehandler~KeystrokeHandler keystroke handler} of the dialog view. + * + * See {@link module:utils/keystrokehandler~KeystrokeHandlerOptions KeystrokeHandlerOptions} to learn more about the available options. + */ + keystrokeHandlerOptions?: KeystrokeHandlerOptions; } /** diff --git a/packages/ckeditor5-ui/src/dialog/dialogview.ts b/packages/ckeditor5-ui/src/dialog/dialogview.ts index 25c855220f6..4acbb913319 100644 --- a/packages/ckeditor5-ui/src/dialog/dialogview.ts +++ b/packages/ckeditor5-ui/src/dialog/dialogview.ts @@ -15,7 +15,8 @@ import { toUnit, type EventInfo, type Locale, - type DecoratedMethodEvent + type DecoratedMethodEvent, + type KeystrokeHandlerOptions } from '@ckeditor/ckeditor5-utils'; import { icons } from '@ckeditor/ckeditor5-core'; import ViewCollection from '../viewcollection.js'; @@ -204,10 +205,12 @@ export default class DialogView extends /* #__PURE__ */ DraggableViewMixin( View constructor( locale: Locale, { getCurrentDomRoot, - getViewportOffset + getViewportOffset, + keystrokeHandlerOptions }: { getCurrentDomRoot: () => HTMLElement; getViewportOffset: () => EditorUI[ 'viewportOffset' ]; + keystrokeHandlerOptions?: KeystrokeHandlerOptions; } ) { super( locale ); @@ -243,7 +246,8 @@ export default class DialogView extends /* #__PURE__ */ DraggableViewMixin( View // Navigate form fields forwards using the Tab key. focusNext: 'tab' - } + }, + keystrokeHandlerOptions } ); this.setTemplate( { From 3f2cb60288369c6f9180f0ae0b3a8417a725e603 Mon Sep 17 00:00:00 2001 From: f1ames Date: Wed, 30 Oct 2024 15:54:41 +0100 Subject: [PATCH 8/9] Add CC for keystrokeHandlerOptions. --- packages/ckeditor5-ui/tests/dialog/dialog.js | 25 +++++++++++++++++- .../ckeditor5-ui/tests/dialog/dialogview.js | 26 +++++++++++++++++++ 2 files changed, 50 insertions(+), 1 deletion(-) diff --git a/packages/ckeditor5-ui/tests/dialog/dialog.js b/packages/ckeditor5-ui/tests/dialog/dialog.js index 4ec39ff8c71..463cf39d9a8 100644 --- a/packages/ckeditor5-ui/tests/dialog/dialog.js +++ b/packages/ckeditor5-ui/tests/dialog/dialog.js @@ -7,7 +7,7 @@ import ClassicTestEditor from '@ckeditor/ckeditor5-core/tests/_utils/classictest import { Paragraph } from '@ckeditor/ckeditor5-paragraph'; import { Dialog, DialogView, DialogViewPosition, IconView } from '../../src/index.js'; -import { env, keyCodes } from '@ckeditor/ckeditor5-utils'; +import { env, keyCodes, KeystrokeHandler } from '@ckeditor/ckeditor5-utils'; import loupeIcon from '@ckeditor/ckeditor5-find-and-replace/theme/icons/find-replace.svg'; /* global document */ @@ -469,6 +469,29 @@ describe( 'Dialog', () => { expect( document.documentElement.classList.contains( 'ck-dialog-scroll-locked' ) ).to.be.false; } ); + + it( 'should pass keystrokeHandlerOptions to its view', () => { + // The 'keystrokeHandlerOptions' are not stored anywhere so we need to somehow + // detect if those are passed correctly. It is passed like shown below: + // + // Dialog._show -> new DialogView( { ..., keystrokeHandlerOptions } ) + // DialogView.constructor -> new FocusCycler( { ..., keystrokeHandler, keystrokeHandlerOptions } ) + // FocusCycler.constructor -> keystrokeHandler.set( { ..., keystrokeHandlerOptions } ) + // + // And so we spy on the `set` method of the KeystrokeHandler to check if options is passed there. + const spy = sinon.spy( KeystrokeHandler.prototype, 'set' ); + + const keystrokeHandlerOptions = { + filter: () => {} + }; + + dialogPlugin._show( { + keystrokeHandlerOptions + } ); + + expect( spy.args[ 0 ][ 2 ] ).to.equal( keystrokeHandlerOptions ); + expect( spy.args[ 1 ][ 2 ] ).to.equal( keystrokeHandlerOptions ); + } ); } ); describe( 'hide()', () => { diff --git a/packages/ckeditor5-ui/tests/dialog/dialogview.js b/packages/ckeditor5-ui/tests/dialog/dialogview.js index 3fb4fb50a0d..af5791076a8 100644 --- a/packages/ckeditor5-ui/tests/dialog/dialogview.js +++ b/packages/ckeditor5-ui/tests/dialog/dialogview.js @@ -404,6 +404,32 @@ describe( 'DialogView', () => { } ); } ); } ); + + describe( 'keystrokeHandlerOptions', () => { + it( 'should use passed keystroke handler options filter', async () => { + const filterSpy = sinon.spy(); + + const newView = new DialogView( locale, { + getCurrentDomRoot: getCurrentDomRootStub, + getViewportOffset: getViewportOffsetStub, + keystrokeHandlerOptions: { + filter: filterSpy + } + } ); + + newView.render(); + + newView.keystrokes.press( { + keyCode: keyCodes.tab, + preventDefault: sinon.spy(), + stopPropagation: sinon.spy() + } ); + + await wait( 5 ); + + expect( filterSpy ).to.be.calledOnce; + } ); + } ); } ); describe( 'render()', () => { From 996c6e32734f4ded253f8788401f76f627444fda Mon Sep 17 00:00:00 2001 From: Bartek Biedrzycki Date: Tue, 12 Nov 2024 09:25:27 +0100 Subject: [PATCH 9/9] Docs: minor language fixes. [short flow] --- docs/features/image-upload.md | 4 +- docs/features/using-file-managers.md | 56 ++++++++++++++-------------- 2 files changed, 30 insertions(+), 30 deletions(-) diff --git a/docs/features/image-upload.md b/docs/features/image-upload.md index d3dec5c9933..8aa80cca9ef 100644 --- a/docs/features/image-upload.md +++ b/docs/features/image-upload.md @@ -55,9 +55,9 @@ With CKBox, users can upload files and categorize them into different groups. Th Uploadcare is the ultimate solution for image upload and editing in CKEditor 5. -It is a modern file uploader with a clean interface, automatic support for responsive images, on-fly image optimization, fast delivery through global CDN network, multiple 3-rd party integrations and vast image editing capabilities like cropping, filtering and adjusting image parameters. +It is a modern file uploader with a clean interface, automatic support for responsive images, on-the-fly image optimization, fast delivery through global CDN network, multiple 3-rd party integrations and vast image editing capabilities like cropping, filtering and adjusting image parameters. -Thanks to the native CKEditor 5 integration, Uploadcare supports drag and drop file upload as well as pasting images from the clipboard, Microsoft Word, or Google Docs. +Thanks to the native CKEditor 5 integration, Uploadcare supports drag-and-drop file upload as well as pasting images from the clipboard, Microsoft Word, or Google Docs. With Uploadcare, users can upload files from external services like Dropbox, Facebook, Google Drive, Google Photos, Instagram, OneDrive or from local computer. Images can be easily adjusted with built-in image editor. diff --git a/docs/features/using-file-managers.md b/docs/features/using-file-managers.md index 3c8891b959a..9c5100854fb 100644 --- a/docs/features/using-file-managers.md +++ b/docs/features/using-file-managers.md @@ -19,45 +19,45 @@ The most convenient way to upload, manage, and insert images into content in CKE CKBox is a modern file management platform with a clean UI and a top-notch UX. With CKBox you can: -- Organize images and other files into customizable categories. -- Create, rename, and delete folders. -- Delete, rename, and tag files. -- Search files and filter results by numerous properties. -- Easily access recently used files. -- View images in high-resolution full-page preview. -- Define and reuse alternative text for images. +* Organize images and other files into customizable categories. +* Create, rename, and delete folders. +* Delete, rename, and tag files. +* Search files and filter results by numerous properties. +* Easily access recently used files. +* View images in high-resolution full-page preview. +* Define and reuse alternative text for images. -{@link features/ckbox **Read a separate guide on CKBox**} to learn about its installation and configuration. The guide also lets you try CKBox in action. +{@link features/ckbox **Read a dedicated guide on CKBox**} to learn about its installation and configuration. The guide also lets you try CKBox in action. ## Uploadcare file manager Uploadcare is a modern file management platform with multiple integrations with services like Dropbox, Facebook, Google Drive, Google Photos, Instagram and OneDrive. With Uploadcare you can: -- Upload images directly from: - - Dropbox, - - Facebook, - - Google Drive, - - Google Photos, - - Instagram, - - OneDrive, - - Local computer, - - External URL. -- Manage all uploaded images through a dedicated platform. -- Edit images by changing dimensions, applying filters and adjusting various image parameters. -- Get your images served quickly through global CDN. - -{@link features/uploadcare **Read a separate guide on Uploadcare**} to learn about its installation and configuration. The guide also lets you try Uploadcare in action. +* Upload images directly from: + * Dropbox, + * Facebook, + * Google Drive, + * Google Photos, + * Instagram, + * OneDrive, + * Local computer, + * External URL. +* Manage all uploaded images through a dedicated platform. +* Edit images by changing dimensions, applying filters and adjusting various image parameters. +* Get your images served quickly through global CDN. + +{@link features/uploadcare **Read a dedicated guide on Uploadcare**} to learn about its installation and configuration. The guide also lets you try Uploadcare in action. ## CKFinder file manager CKFinder is a powerful file manager with various image editing and image upload options. With CKFinder you can: -- Group images and other files into folders and subfolders. -- Move or copy files between folders. -- Easily filter files. -- Drag and drop images and paste them from the clipboard into the editor. -- Crop, rotate, edit, and resize images. +* Group images and other files into folders and subfolders. +* Move or copy files between folders. +* Easily filter files. +* Drag and drop images and paste them from the clipboard into the editor. +* Crop, rotate, edit, and resize images. -{@link features/ckfinder **Read a separate guide on CKFinder**} to learn about its installation and configuration. The guide also lets you try CKFinder in action. +{@link features/ckfinder **Read a dedicated guide on CKFinder**} to learn about its installation and configuration. The guide also lets you try CKFinder in action.