UNPKG

4.3 kBJavaScriptView Raw
1/**
2 * @license Copyright (c) 2003-2022, CKSource Holding sp. z o.o. All rights reserved.
3 * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
4 */
5
6/**
7 * @module image/imageresize/imageresizehandles
8 */
9
10import { Plugin } from 'ckeditor5/src/core';
11import { WidgetResize } from 'ckeditor5/src/widget';
12
13import ImageLoadObserver from '../image/imageloadobserver';
14
15const RESIZABLE_IMAGES_CSS_SELECTOR =
16 'figure.image.ck-widget > img,' +
17 'figure.image.ck-widget > picture > img,' +
18 'figure.image.ck-widget > a > img,' +
19 'figure.image.ck-widget > a > picture > img,' +
20 'span.image-inline.ck-widget > img,' +
21 'span.image-inline.ck-widget > picture > img';
22
23const IMAGE_WIDGETS_CLASSES_MATCH_REGEXP = /(image|image-inline)/;
24
25const RESIZED_IMAGE_CLASS = 'image_resized';
26
27/**
28 * The image resize by handles feature.
29 *
30 * It adds the ability to resize each image using handles or manually by
31 * {@link module:image/imageresize/imageresizebuttons~ImageResizeButtons} buttons.
32 *
33 * @extends module:core/plugin~Plugin
34 */
35export default class ImageResizeHandles extends Plugin {
36 /**
37 * @inheritDoc
38 */
39 static get requires() {
40 return [ WidgetResize ];
41 }
42
43 /**
44 * @inheritDoc
45 */
46 static get pluginName() {
47 return 'ImageResizeHandles';
48 }
49
50 /**
51 * @inheritDoc
52 */
53 init() {
54 const command = this.editor.commands.get( 'resizeImage' );
55 this.bind( 'isEnabled' ).to( command );
56
57 this._setupResizerCreator();
58 }
59
60 /**
61 * Attaches the listeners responsible for creating a resizer for each image, except for images inside the HTML embed preview.
62 *
63 * @private
64 */
65 _setupResizerCreator() {
66 const editor = this.editor;
67 const editingView = editor.editing.view;
68
69 editingView.addObserver( ImageLoadObserver );
70
71 this.listenTo( editingView.document, 'imageLoaded', ( evt, domEvent ) => {
72 // The resizer must be attached only to images loaded by the `ImageInsert`, `ImageUpload` or `LinkImage` plugins.
73 if ( !domEvent.target.matches( RESIZABLE_IMAGES_CSS_SELECTOR ) ) {
74 return;
75 }
76
77 const domConverter = editor.editing.view.domConverter;
78 const imageView = domConverter.domToView( domEvent.target );
79 const widgetView = imageView.findAncestor( { classes: IMAGE_WIDGETS_CLASSES_MATCH_REGEXP } );
80 let resizer = this.editor.plugins.get( WidgetResize ).getResizerByViewElement( widgetView );
81
82 if ( resizer ) {
83 // There are rare cases when the image will be triggered multiple times for the same widget, e.g. when
84 // the image's source was changed after upload (https://github.com/ckeditor/ckeditor5/pull/8108#issuecomment-708302992).
85 resizer.redraw();
86
87 return;
88 }
89
90 const mapper = editor.editing.mapper;
91 const imageModel = mapper.toModelElement( widgetView );
92
93 resizer = editor.plugins
94 .get( WidgetResize )
95 .attachTo( {
96 unit: editor.config.get( 'image.resizeUnit' ),
97
98 modelElement: imageModel,
99 viewElement: widgetView,
100 editor,
101
102 getHandleHost( domWidgetElement ) {
103 return domWidgetElement.querySelector( 'img' );
104 },
105 getResizeHost() {
106 // Return the model image element parent to avoid setting an inline element (<a>/<span>) as a resize host.
107 return domConverter.viewToDom( mapper.toViewElement( imageModel.parent ) );
108 },
109 // TODO consider other positions.
110 isCentered() {
111 const imageStyle = imageModel.getAttribute( 'imageStyle' );
112
113 return !imageStyle || imageStyle == 'block' || imageStyle == 'alignCenter';
114 },
115
116 onCommit( newValue ) {
117 // Get rid of the CSS class in case the command execution that follows is unsuccessful
118 // (e.g. Track Changes can override it and the new dimensions will not apply). Otherwise,
119 // the presence of the class and the absence of the width style will cause it to take 100%
120 // of the horizontal space.
121 editingView.change( writer => {
122 writer.removeClass( RESIZED_IMAGE_CLASS, widgetView );
123 } );
124
125 editor.execute( 'resizeImage', { width: newValue } );
126 }
127 } );
128
129 resizer.on( 'updateSize', () => {
130 if ( !widgetView.hasClass( RESIZED_IMAGE_CLASS ) ) {
131 editingView.change( writer => {
132 writer.addClass( RESIZED_IMAGE_CLASS, widgetView );
133 } );
134 }
135 } );
136
137 resizer.bind( 'isEnabled' ).to( this );
138 } );
139 }
140}