1 |
|
2 |
|
3 |
|
4 |
|
5 |
|
6 |
|
7 |
|
8 | import { Plugin } from 'ckeditor5/src/core.js';
|
9 | import { ClipboardPipeline } from 'ckeditor5/src/clipboard.js';
|
10 | import { UpcastWriter } from 'ckeditor5/src/engine.js';
|
11 | import { downcastImageAttribute, downcastSrcsetAttribute, upcastImageFigure } from './converters.js';
|
12 | import ImageEditing from './imageediting.js';
|
13 | import ImageSizeAttributes from '../imagesizeattributes.js';
|
14 | import ImageTypeCommand from './imagetypecommand.js';
|
15 | import ImageUtils from '../imageutils.js';
|
16 | import { getImgViewElementMatcher, createBlockImageViewElement, determineImageTypeForInsertionAtSelection } from './utils.js';
|
17 | import ImagePlaceholder from './imageplaceholder.js';
|
18 |
|
19 |
|
20 |
|
21 |
|
22 |
|
23 |
|
24 |
|
25 |
|
26 |
|
27 |
|
28 | export default class ImageBlockEditing extends Plugin {
|
29 | |
30 |
|
31 |
|
32 | static get requires() {
|
33 | return [ImageEditing, ImageSizeAttributes, ImageUtils, ImagePlaceholder, ClipboardPipeline];
|
34 | }
|
35 | |
36 |
|
37 |
|
38 | static get pluginName() {
|
39 | return 'ImageBlockEditing';
|
40 | }
|
41 | |
42 |
|
43 |
|
44 | init() {
|
45 | const editor = this.editor;
|
46 | const schema = editor.model.schema;
|
47 |
|
48 | schema.register('imageBlock', {
|
49 | inheritAllFrom: '$blockObject',
|
50 | allowAttributes: ['alt', 'src', 'srcset']
|
51 | });
|
52 | this._setupConversion();
|
53 | if (editor.plugins.has('ImageInlineEditing')) {
|
54 | editor.commands.add('imageTypeBlock', new ImageTypeCommand(this.editor, 'imageBlock'));
|
55 | this._setupClipboardIntegration();
|
56 | }
|
57 | }
|
58 | |
59 |
|
60 |
|
61 |
|
62 | _setupConversion() {
|
63 | const editor = this.editor;
|
64 | const t = editor.t;
|
65 | const conversion = editor.conversion;
|
66 | const imageUtils = editor.plugins.get('ImageUtils');
|
67 | conversion.for('dataDowncast')
|
68 | .elementToStructure({
|
69 | model: 'imageBlock',
|
70 | view: (modelElement, { writer }) => createBlockImageViewElement(writer)
|
71 | });
|
72 | conversion.for('editingDowncast')
|
73 | .elementToStructure({
|
74 | model: 'imageBlock',
|
75 | view: (modelElement, { writer }) => imageUtils.toImageWidget(createBlockImageViewElement(writer), writer, t('image widget'))
|
76 | });
|
77 | conversion.for('downcast')
|
78 | .add(downcastImageAttribute(imageUtils, 'imageBlock', 'src'))
|
79 | .add(downcastImageAttribute(imageUtils, 'imageBlock', 'alt'))
|
80 | .add(downcastSrcsetAttribute(imageUtils, 'imageBlock'));
|
81 |
|
82 | conversion.for('upcast')
|
83 | .elementToElement({
|
84 | view: getImgViewElementMatcher(editor, 'imageBlock'),
|
85 | model: (viewImage, { writer }) => writer.createElement('imageBlock', viewImage.hasAttribute('src') ? { src: viewImage.getAttribute('src') } : undefined)
|
86 | })
|
87 | .add(upcastImageFigure(imageUtils));
|
88 | }
|
89 | |
90 |
|
91 |
|
92 |
|
93 |
|
94 |
|
95 |
|
96 |
|
97 |
|
98 |
|
99 |
|
100 |
|
101 |
|
102 |
|
103 |
|
104 |
|
105 | _setupClipboardIntegration() {
|
106 | const editor = this.editor;
|
107 | const model = editor.model;
|
108 | const editingView = editor.editing.view;
|
109 | const imageUtils = editor.plugins.get('ImageUtils');
|
110 | const clipboardPipeline = editor.plugins.get('ClipboardPipeline');
|
111 | this.listenTo(clipboardPipeline, 'inputTransformation', (evt, data) => {
|
112 | const docFragmentChildren = Array.from(data.content.getChildren());
|
113 | let modelRange;
|
114 |
|
115 |
|
116 | if (!docFragmentChildren.every(imageUtils.isInlineImageView)) {
|
117 | return;
|
118 | }
|
119 |
|
120 |
|
121 |
|
122 | if (data.targetRanges) {
|
123 | modelRange = editor.editing.mapper.toModelRange(data.targetRanges[0]);
|
124 | }
|
125 |
|
126 | else {
|
127 | modelRange = model.document.selection.getFirstRange();
|
128 | }
|
129 | const selection = model.createSelection(modelRange);
|
130 |
|
131 |
|
132 | if (determineImageTypeForInsertionAtSelection(model.schema, selection) === 'imageBlock') {
|
133 | const writer = new UpcastWriter(editingView.document);
|
134 |
|
135 | const blockViewImages = docFragmentChildren.map(inlineViewImage => writer.createElement('figure', { class: 'image' }, inlineViewImage));
|
136 | data.content = writer.createDocumentFragment(blockViewImages);
|
137 | }
|
138 | });
|
139 | this.listenTo(clipboardPipeline, 'contentInsertion', (evt, data) => {
|
140 | if (data.method !== 'paste') {
|
141 | return;
|
142 | }
|
143 | model.change(writer => {
|
144 | const range = writer.createRangeIn(data.content);
|
145 | for (const item of range.getItems()) {
|
146 | if (item.is('element', 'imageBlock')) {
|
147 | imageUtils.setImageNaturalSizeAttributes(item);
|
148 | }
|
149 | }
|
150 | });
|
151 | });
|
152 | }
|
153 | }
|