@ckeditor/ckeditor5-link 29.0.0 → 31.0.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.
- package/LICENSE.md +1 -1
- package/README.md +4 -0
- package/build/link.js +1 -1
- package/build/translations/ar.js +1 -0
- package/build/translations/ast.js +1 -0
- package/build/translations/az.js +1 -0
- package/build/translations/bg.js +1 -0
- package/build/translations/cs.js +1 -0
- package/build/translations/da.js +1 -0
- package/build/translations/de-ch.js +1 -0
- package/build/translations/de.js +1 -0
- package/build/translations/el.js +1 -0
- package/build/translations/en-au.js +1 -0
- package/build/translations/en-gb.js +1 -0
- package/build/translations/eo.js +1 -0
- package/build/translations/es.js +1 -0
- package/build/translations/et.js +1 -0
- package/build/translations/eu.js +1 -0
- package/build/translations/fa.js +1 -0
- package/build/translations/fi.js +1 -0
- package/build/translations/fr.js +1 -0
- package/build/translations/gl.js +1 -0
- package/build/translations/he.js +1 -0
- package/build/translations/hi.js +1 -0
- package/build/translations/hr.js +1 -0
- package/build/translations/hu.js +1 -0
- package/build/translations/id.js +1 -0
- package/build/translations/it.js +1 -0
- package/build/translations/ja.js +1 -0
- package/build/translations/km.js +1 -0
- package/build/translations/kn.js +1 -0
- package/build/translations/ko.js +1 -0
- package/build/translations/ku.js +1 -0
- package/build/translations/lt.js +1 -0
- package/build/translations/lv.js +1 -0
- package/build/translations/nb.js +1 -0
- package/build/translations/ne.js +1 -0
- package/build/translations/nl.js +1 -0
- package/build/translations/no.js +1 -0
- package/build/translations/pl.js +1 -0
- package/build/translations/pt-br.js +1 -0
- package/build/translations/pt.js +1 -0
- package/build/translations/ro.js +1 -0
- package/build/translations/ru.js +1 -0
- package/build/translations/sk.js +1 -0
- package/build/translations/sq.js +1 -0
- package/build/translations/sr-latn.js +1 -0
- package/build/translations/sr.js +1 -0
- package/build/translations/sv.js +1 -0
- package/build/translations/tk.js +1 -0
- package/build/translations/tr.js +1 -0
- package/build/translations/ug.js +1 -0
- package/build/translations/uk.js +1 -0
- package/build/translations/vi.js +1 -0
- package/build/translations/zh-cn.js +1 -0
- package/build/translations/zh.js +1 -0
- package/ckeditor5-metadata.json +76 -0
- package/package.json +25 -23
- package/src/autolink.js +13 -1
- package/src/link.js +14 -2
- package/src/linkediting.js +15 -5
- package/src/linkimageediting.js +62 -56
- package/src/utils/automaticdecorators.js +33 -6
- package/src/utils/manualdecorator.js +31 -1
- package/CHANGELOG.md +0 -313
- package/build/link.js.map +0 -1
package/package.json
CHANGED
|
@@ -1,39 +1,40 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ckeditor/ckeditor5-link",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "31.0.0",
|
|
4
4
|
"description": "Link feature for CKEditor 5.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"ckeditor",
|
|
7
7
|
"ckeditor5",
|
|
8
8
|
"ckeditor 5",
|
|
9
9
|
"ckeditor5-feature",
|
|
10
|
-
"ckeditor5-plugin"
|
|
10
|
+
"ckeditor5-plugin",
|
|
11
|
+
"ckeditor5-dll"
|
|
11
12
|
],
|
|
12
13
|
"main": "src/index.js",
|
|
13
14
|
"dependencies": {
|
|
14
|
-
"@ckeditor/ckeditor5-ui": "^
|
|
15
|
-
"ckeditor5": "^
|
|
15
|
+
"@ckeditor/ckeditor5-ui": "^31.0.0",
|
|
16
|
+
"ckeditor5": "^31.0.0",
|
|
16
17
|
"lodash-es": "^4.17.15"
|
|
17
18
|
},
|
|
18
19
|
"devDependencies": {
|
|
19
|
-
"@ckeditor/ckeditor5-basic-styles": "^
|
|
20
|
-
"@ckeditor/ckeditor5-block-quote": "^
|
|
21
|
-
"@ckeditor/ckeditor5-clipboard": "^
|
|
22
|
-
"@ckeditor/ckeditor5-cloud-services": "^
|
|
23
|
-
"@ckeditor/ckeditor5-code-block": "^
|
|
24
|
-
"@ckeditor/ckeditor5-core": "^
|
|
25
|
-
"@ckeditor/ckeditor5-dev-utils": "^25.
|
|
26
|
-
"@ckeditor/ckeditor5-easy-image": "^
|
|
27
|
-
"@ckeditor/ckeditor5-editor-classic": "^
|
|
28
|
-
"@ckeditor/ckeditor5-engine": "^
|
|
29
|
-
"@ckeditor/ckeditor5-enter": "^
|
|
30
|
-
"@ckeditor/ckeditor5-image": "^
|
|
31
|
-
"@ckeditor/ckeditor5-paragraph": "^
|
|
32
|
-
"@ckeditor/ckeditor5-theme-lark": "^
|
|
33
|
-
"@ckeditor/ckeditor5-typing": "^
|
|
34
|
-
"@ckeditor/ckeditor5-undo": "^
|
|
35
|
-
"@ckeditor/ckeditor5-utils": "^
|
|
36
|
-
"@ckeditor/ckeditor5-widget": "^
|
|
20
|
+
"@ckeditor/ckeditor5-basic-styles": "^31.0.0",
|
|
21
|
+
"@ckeditor/ckeditor5-block-quote": "^31.0.0",
|
|
22
|
+
"@ckeditor/ckeditor5-clipboard": "^31.0.0",
|
|
23
|
+
"@ckeditor/ckeditor5-cloud-services": "^31.0.0",
|
|
24
|
+
"@ckeditor/ckeditor5-code-block": "^31.0.0",
|
|
25
|
+
"@ckeditor/ckeditor5-core": "^31.0.0",
|
|
26
|
+
"@ckeditor/ckeditor5-dev-utils": "^25.4.0",
|
|
27
|
+
"@ckeditor/ckeditor5-easy-image": "^31.0.0",
|
|
28
|
+
"@ckeditor/ckeditor5-editor-classic": "^31.0.0",
|
|
29
|
+
"@ckeditor/ckeditor5-engine": "^31.0.0",
|
|
30
|
+
"@ckeditor/ckeditor5-enter": "^31.0.0",
|
|
31
|
+
"@ckeditor/ckeditor5-image": "^31.0.0",
|
|
32
|
+
"@ckeditor/ckeditor5-paragraph": "^31.0.0",
|
|
33
|
+
"@ckeditor/ckeditor5-theme-lark": "^31.0.0",
|
|
34
|
+
"@ckeditor/ckeditor5-typing": "^31.0.0",
|
|
35
|
+
"@ckeditor/ckeditor5-undo": "^31.0.0",
|
|
36
|
+
"@ckeditor/ckeditor5-utils": "^31.0.0",
|
|
37
|
+
"@ckeditor/ckeditor5-widget": "^31.0.0",
|
|
37
38
|
"webpack": "^4.43.0",
|
|
38
39
|
"webpack-cli": "^3.3.11"
|
|
39
40
|
},
|
|
@@ -54,7 +55,8 @@
|
|
|
54
55
|
"lang",
|
|
55
56
|
"src",
|
|
56
57
|
"theme",
|
|
57
|
-
"build"
|
|
58
|
+
"build",
|
|
59
|
+
"ckeditor5-metadata.json"
|
|
58
60
|
],
|
|
59
61
|
"scripts": {
|
|
60
62
|
"dll:build": "webpack"
|
package/src/autolink.js
CHANGED
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
*/
|
|
9
9
|
|
|
10
10
|
import { Plugin } from 'ckeditor5/src/core';
|
|
11
|
-
import { TextWatcher, getLastTextLine } from 'ckeditor5/src/typing';
|
|
11
|
+
import { Delete, TextWatcher, getLastTextLine } from 'ckeditor5/src/typing';
|
|
12
12
|
|
|
13
13
|
import { addLinkProtocolIfApplicable } from './utils';
|
|
14
14
|
|
|
@@ -69,6 +69,13 @@ const URL_GROUP_IN_MATCH = 2;
|
|
|
69
69
|
* @extends module:core/plugin~Plugin
|
|
70
70
|
*/
|
|
71
71
|
export default class AutoLink extends Plugin {
|
|
72
|
+
/**
|
|
73
|
+
* @inheritDoc
|
|
74
|
+
*/
|
|
75
|
+
static get requires() {
|
|
76
|
+
return [ Delete ];
|
|
77
|
+
}
|
|
78
|
+
|
|
72
79
|
/**
|
|
73
80
|
* @inheritDoc
|
|
74
81
|
*/
|
|
@@ -226,6 +233,7 @@ export default class AutoLink extends Plugin {
|
|
|
226
233
|
*/
|
|
227
234
|
_applyAutoLink( link, range ) {
|
|
228
235
|
const model = this.editor.model;
|
|
236
|
+
const deletePlugin = this.editor.plugins.get( 'Delete' );
|
|
229
237
|
|
|
230
238
|
if ( !this.isEnabled || !isLinkAllowedOnRange( range, model ) ) {
|
|
231
239
|
return;
|
|
@@ -236,6 +244,10 @@ export default class AutoLink extends Plugin {
|
|
|
236
244
|
const defaultProtocol = this.editor.config.get( 'link.defaultProtocol' );
|
|
237
245
|
const parsedUrl = addLinkProtocolIfApplicable( link, defaultProtocol );
|
|
238
246
|
writer.setAttribute( 'linkHref', parsedUrl, range );
|
|
247
|
+
|
|
248
|
+
model.enqueueChange( () => {
|
|
249
|
+
deletePlugin.requestUndoOnBackspace();
|
|
250
|
+
} );
|
|
239
251
|
} );
|
|
240
252
|
}
|
|
241
253
|
}
|
package/src/link.js
CHANGED
|
@@ -215,9 +215,15 @@ export default class Link extends Plugin {
|
|
|
215
215
|
* @typedef {Object} module:link/link~LinkDecoratorAutomaticDefinition
|
|
216
216
|
* @property {'automatic'} mode Link decorator type. It is `'automatic'` for all automatic decorators.
|
|
217
217
|
* @property {Function} callback Takes a `url` as a parameter and returns `true` if the `attributes` should be applied to the link.
|
|
218
|
-
* @property {Object} attributes Key-value pairs used as link attributes added to the output during the
|
|
218
|
+
* @property {Object} [attributes] Key-value pairs used as link attributes added to the output during the
|
|
219
219
|
* {@glink framework/guides/architecture/editing-engine#conversion downcasting}.
|
|
220
220
|
* Attributes should follow the {@link module:engine/view/elementdefinition~ElementDefinition} syntax.
|
|
221
|
+
* @property {Object} [styles] Key-value pairs used as link styles added to the output during the
|
|
222
|
+
* {@glink framework/guides/architecture/editing-engine#conversion downcasting}.
|
|
223
|
+
* Styles should follow the {@link module:engine/view/elementdefinition~ElementDefinition} syntax.
|
|
224
|
+
* @property {String|Array.<String>} [classes] Class names used as link classes added to the output during the
|
|
225
|
+
* {@glink framework/guides/architecture/editing-engine#conversion downcasting}.
|
|
226
|
+
* Classes should follow the {@link module:engine/view/elementdefinition~ElementDefinition} syntax.
|
|
221
227
|
*/
|
|
222
228
|
|
|
223
229
|
/**
|
|
@@ -241,8 +247,14 @@ export default class Link extends Plugin {
|
|
|
241
247
|
* @typedef {Object} module:link/link~LinkDecoratorManualDefinition
|
|
242
248
|
* @property {'manual'} mode Link decorator type. It is `'manual'` for all manual decorators.
|
|
243
249
|
* @property {String} label The label of the UI button that the user can use to control the presence of link attributes.
|
|
244
|
-
* @property {Object} attributes Key-value pairs used as link attributes added to the output during the
|
|
250
|
+
* @property {Object} [attributes] Key-value pairs used as link attributes added to the output during the
|
|
245
251
|
* {@glink framework/guides/architecture/editing-engine#conversion downcasting}.
|
|
246
252
|
* Attributes should follow the {@link module:engine/view/elementdefinition~ElementDefinition} syntax.
|
|
253
|
+
* @property {Object} [styles] Key-value pairs used as link styles added to the output during the
|
|
254
|
+
* {@glink framework/guides/architecture/editing-engine#conversion downcasting}.
|
|
255
|
+
* Styles should follow the {@link module:engine/view/elementdefinition~ElementDefinition} syntax.
|
|
256
|
+
* @property {String|Array.<String>} [classes] Class names used as link classes added to the output during the
|
|
257
|
+
* {@glink framework/guides/architecture/editing-engine#conversion downcasting}.
|
|
258
|
+
* Classes should follow the {@link module:engine/view/elementdefinition~ElementDefinition} syntax.
|
|
247
259
|
* @property {Boolean} [defaultValue] Controls whether the decorator is "on" by default.
|
|
248
260
|
*/
|
package/src/linkediting.js
CHANGED
|
@@ -184,14 +184,24 @@ export default class LinkEditing extends Plugin {
|
|
|
184
184
|
editor.model.schema.extend( '$text', { allowAttributes: decorator.id } );
|
|
185
185
|
|
|
186
186
|
// Keeps reference to manual decorator to decode its name to attributes during downcast.
|
|
187
|
-
|
|
187
|
+
decorator = new ManualDecorator( decorator );
|
|
188
|
+
|
|
189
|
+
manualDecorators.add( decorator );
|
|
188
190
|
|
|
189
191
|
editor.conversion.for( 'downcast' ).attributeToElement( {
|
|
190
192
|
model: decorator.id,
|
|
191
193
|
view: ( manualDecoratorName, { writer } ) => {
|
|
192
194
|
if ( manualDecoratorName ) {
|
|
193
|
-
const
|
|
194
|
-
|
|
195
|
+
const element = writer.createAttributeElement( 'a', decorator.attributes, { priority: 5 } );
|
|
196
|
+
|
|
197
|
+
if ( decorator.classes ) {
|
|
198
|
+
writer.addClass( decorator.classes, element );
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
for ( const key in decorator.styles ) {
|
|
202
|
+
writer.setStyle( key, decorator.styles[ key ], element );
|
|
203
|
+
}
|
|
204
|
+
|
|
195
205
|
writer.setCustomProperty( 'link', true, element );
|
|
196
206
|
|
|
197
207
|
return element;
|
|
@@ -201,7 +211,7 @@ export default class LinkEditing extends Plugin {
|
|
|
201
211
|
editor.conversion.for( 'upcast' ).elementToAttribute( {
|
|
202
212
|
view: {
|
|
203
213
|
name: 'a',
|
|
204
|
-
|
|
214
|
+
...decorator._createPattern()
|
|
205
215
|
},
|
|
206
216
|
model: {
|
|
207
217
|
key: decorator.id
|
|
@@ -572,7 +582,7 @@ function isTyping( editor ) {
|
|
|
572
582
|
return input.isInput( editor.model.change( writer => writer.batch ) );
|
|
573
583
|
}
|
|
574
584
|
|
|
575
|
-
// Returns an array containing names of attributes allowed on `$text` that describes the link item.
|
|
585
|
+
// Returns an array containing names of the attributes allowed on `$text` that describes the link item.
|
|
576
586
|
//
|
|
577
587
|
// @param {module:engine/model/schema~Schema} schema
|
|
578
588
|
// @returns {Array.<String>}
|
package/src/linkimageediting.js
CHANGED
|
@@ -49,7 +49,7 @@ export default class LinkImageEditing extends Plugin {
|
|
|
49
49
|
}
|
|
50
50
|
|
|
51
51
|
editor.conversion.for( 'upcast' ).add( upcastLink( editor ) );
|
|
52
|
-
editor.conversion.for( 'downcast' ).add( downcastImageLink );
|
|
52
|
+
editor.conversion.for( 'downcast' ).add( downcastImageLink( editor ) );
|
|
53
53
|
|
|
54
54
|
// Definitions for decorators are provided by the `link` command and the `LinkEditing` plugin.
|
|
55
55
|
this._enableAutomaticDecorators();
|
|
@@ -81,7 +81,6 @@ export default class LinkImageEditing extends Plugin {
|
|
|
81
81
|
_enableManualDecorators() {
|
|
82
82
|
const editor = this.editor;
|
|
83
83
|
const command = editor.commands.get( 'link' );
|
|
84
|
-
const manualDecorators = command.manualDecorators;
|
|
85
84
|
|
|
86
85
|
for ( const decorator of command.manualDecorators ) {
|
|
87
86
|
if ( editor.plugins.has( 'ImageBlockEditing' ) ) {
|
|
@@ -92,8 +91,8 @@ export default class LinkImageEditing extends Plugin {
|
|
|
92
91
|
editor.model.schema.extend( 'imageInline', { allowAttributes: decorator.id } );
|
|
93
92
|
}
|
|
94
93
|
|
|
95
|
-
editor.conversion.for( 'downcast' ).add( downcastImageLinkManualDecorator(
|
|
96
|
-
editor.conversion.for( 'upcast' ).add( upcastImageLinkManualDecorator(
|
|
94
|
+
editor.conversion.for( 'downcast' ).add( downcastImageLinkManualDecorator( decorator ) );
|
|
95
|
+
editor.conversion.for( 'upcast' ).add( upcastImageLinkManualDecorator( editor, decorator ) );
|
|
97
96
|
}
|
|
98
97
|
}
|
|
99
98
|
}
|
|
@@ -106,25 +105,27 @@ export default class LinkImageEditing extends Plugin {
|
|
|
106
105
|
// @returns {Function}
|
|
107
106
|
function upcastLink( editor ) {
|
|
108
107
|
const isImageInlinePluginLoaded = editor.plugins.has( 'ImageInlineEditing' );
|
|
109
|
-
const
|
|
108
|
+
const imageUtils = editor.plugins.get( 'ImageUtils' );
|
|
110
109
|
|
|
111
110
|
return dispatcher => {
|
|
112
111
|
dispatcher.on( 'element:a', ( evt, data, conversionApi ) => {
|
|
113
112
|
const viewLink = data.viewItem;
|
|
114
|
-
const imageInLink =
|
|
113
|
+
const imageInLink = imageUtils.findViewImgElement( viewLink );
|
|
115
114
|
|
|
116
115
|
if ( !imageInLink ) {
|
|
117
116
|
return;
|
|
118
117
|
}
|
|
119
118
|
|
|
120
|
-
const blockImageView = imageInLink.findAncestor( element =>
|
|
119
|
+
const blockImageView = imageInLink.findAncestor( element => imageUtils.isBlockImageView( element ) );
|
|
121
120
|
|
|
122
|
-
// There are
|
|
121
|
+
// There are four possible cases to consider here
|
|
123
122
|
//
|
|
124
123
|
// 1. A "root > ... > figure.image > a > img" structure.
|
|
125
|
-
// 2. A "root > ... >
|
|
124
|
+
// 2. A "root > ... > figure.image > a > picture > img" structure.
|
|
125
|
+
// 3. A "root > ... > block > a > img" structure.
|
|
126
|
+
// 4. A "root > ... > block > a > picture > img" structure.
|
|
126
127
|
//
|
|
127
|
-
// but the
|
|
128
|
+
// but the last 2 cases should only be considered by this converter when the inline image plugin
|
|
128
129
|
// is NOT loaded in the editor (because otherwise, that would be a plain, linked inline image).
|
|
129
130
|
if ( isImageInlinePluginLoaded && !blockImageView ) {
|
|
130
131
|
return;
|
|
@@ -176,47 +177,55 @@ function upcastLink( editor ) {
|
|
|
176
177
|
// Creates a converter that adds `<a>` to linked block image view elements.
|
|
177
178
|
//
|
|
178
179
|
// @private
|
|
179
|
-
function downcastImageLink(
|
|
180
|
-
|
|
181
|
-
// The image will be already converted - so it will be present in the view.
|
|
182
|
-
const viewFigure = conversionApi.mapper.toViewElement( data.item );
|
|
183
|
-
const writer = conversionApi.writer;
|
|
184
|
-
|
|
185
|
-
// But we need to check whether the link element exists.
|
|
186
|
-
const linkInImage = Array.from( viewFigure.getChildren() ).find( child => child.name === 'a' );
|
|
187
|
-
|
|
188
|
-
// If so, update the attribute if it's defined or remove the entire link if the attribute is empty.
|
|
189
|
-
if ( linkInImage ) {
|
|
190
|
-
if ( data.attributeNewValue ) {
|
|
191
|
-
writer.setAttribute( 'href', data.attributeNewValue, linkInImage );
|
|
192
|
-
} else {
|
|
193
|
-
const viewImage = Array.from( linkInImage.getChildren() ).find( child => child.name === 'img' );
|
|
180
|
+
function downcastImageLink( editor ) {
|
|
181
|
+
const imageUtils = editor.plugins.get( 'ImageUtils' );
|
|
194
182
|
|
|
195
|
-
|
|
196
|
-
|
|
183
|
+
return dispatcher => {
|
|
184
|
+
dispatcher.on( 'attribute:linkHref:imageBlock', ( evt, data, conversionApi ) => {
|
|
185
|
+
if ( !conversionApi.consumable.consume( data.item, evt.name ) ) {
|
|
186
|
+
return;
|
|
197
187
|
}
|
|
198
|
-
} else {
|
|
199
|
-
// But if it does not exist. Let's wrap already converted image by newly created link element.
|
|
200
|
-
// 1. Create an empty link element.
|
|
201
|
-
const linkElement = writer.createContainerElement( 'a', { href: data.attributeNewValue } );
|
|
202
188
|
|
|
203
|
-
//
|
|
204
|
-
|
|
189
|
+
// The image will be already converted - so it will be present in the view.
|
|
190
|
+
const viewFigure = conversionApi.mapper.toViewElement( data.item );
|
|
191
|
+
const writer = conversionApi.writer;
|
|
205
192
|
|
|
206
|
-
//
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
193
|
+
// But we need to check whether the link element exists.
|
|
194
|
+
const linkInImage = Array.from( viewFigure.getChildren() ).find( child => child.name === 'a' );
|
|
195
|
+
const viewImage = imageUtils.findViewImgElement( viewFigure );
|
|
196
|
+
// <picture>...<img/></picture> or <img/>
|
|
197
|
+
const viewImgOrPicture = viewImage.parent.is( 'element', 'picture' ) ? viewImage.parent : viewImage;
|
|
198
|
+
|
|
199
|
+
// If so, update the attribute if it's defined or remove the entire link if the attribute is empty.
|
|
200
|
+
if ( linkInImage ) {
|
|
201
|
+
if ( data.attributeNewValue ) {
|
|
202
|
+
writer.setAttribute( 'href', data.attributeNewValue, linkInImage );
|
|
203
|
+
} else {
|
|
204
|
+
writer.move( writer.createRangeOn( viewImgOrPicture ), writer.createPositionAt( viewFigure, 0 ) );
|
|
205
|
+
writer.remove( linkInImage );
|
|
206
|
+
}
|
|
207
|
+
} else {
|
|
208
|
+
// But if it does not exist. Let's wrap already converted image by newly created link element.
|
|
209
|
+
// 1. Create an empty link element.
|
|
210
|
+
const linkElement = writer.createContainerElement( 'a', { href: data.attributeNewValue } );
|
|
211
|
+
|
|
212
|
+
// 2. Insert link inside the associated image.
|
|
213
|
+
writer.insert( writer.createPositionAt( viewFigure, 0 ), linkElement );
|
|
214
|
+
|
|
215
|
+
// 3. Move the image to the link.
|
|
216
|
+
writer.move( writer.createRangeOn( viewImgOrPicture ), writer.createPositionAt( linkElement, 0 ) );
|
|
217
|
+
}
|
|
218
|
+
}, { priority: 'high' } );
|
|
219
|
+
};
|
|
210
220
|
}
|
|
211
221
|
|
|
212
222
|
// Returns a converter that decorates the `<a>` element when the image is the link label.
|
|
213
223
|
//
|
|
214
224
|
// @private
|
|
215
225
|
// @returns {Function}
|
|
216
|
-
function downcastImageLinkManualDecorator(
|
|
226
|
+
function downcastImageLinkManualDecorator( decorator ) {
|
|
217
227
|
return dispatcher => {
|
|
218
228
|
dispatcher.on( `attribute:${ decorator.id }:imageBlock`, ( evt, data, conversionApi ) => {
|
|
219
|
-
const attributes = manualDecorators.get( decorator.id ).attributes;
|
|
220
229
|
const viewFigure = conversionApi.mapper.toViewElement( data.item );
|
|
221
230
|
const linkInImage = Array.from( viewFigure.getChildren() ).find( child => child.name === 'a' );
|
|
222
231
|
|
|
@@ -227,9 +236,17 @@ function downcastImageLinkManualDecorator( manualDecorators, decorator ) {
|
|
|
227
236
|
return;
|
|
228
237
|
}
|
|
229
238
|
|
|
230
|
-
for ( const [ key, val ] of toMap( attributes ) ) {
|
|
239
|
+
for ( const [ key, val ] of toMap( decorator.attributes ) ) {
|
|
231
240
|
conversionApi.writer.setAttribute( key, val, linkInImage );
|
|
232
241
|
}
|
|
242
|
+
|
|
243
|
+
if ( decorator.classes ) {
|
|
244
|
+
conversionApi.writer.addClass( decorator.classes, linkInImage );
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
for ( const key in decorator.styles ) {
|
|
248
|
+
conversionApi.writer.setStyle( key, decorator.styles[ key ], linkInImage );
|
|
249
|
+
}
|
|
233
250
|
} );
|
|
234
251
|
};
|
|
235
252
|
}
|
|
@@ -238,11 +255,13 @@ function downcastImageLinkManualDecorator( manualDecorators, decorator ) {
|
|
|
238
255
|
//
|
|
239
256
|
// @private
|
|
240
257
|
// @returns {Function}
|
|
241
|
-
function upcastImageLinkManualDecorator(
|
|
258
|
+
function upcastImageLinkManualDecorator( editor, decorator ) {
|
|
259
|
+
const imageUtils = editor.plugins.get( 'ImageUtils' );
|
|
260
|
+
|
|
242
261
|
return dispatcher => {
|
|
243
262
|
dispatcher.on( 'element:a', ( evt, data, conversionApi ) => {
|
|
244
263
|
const viewLink = data.viewItem;
|
|
245
|
-
const imageInLink =
|
|
264
|
+
const imageInLink = imageUtils.findViewImgElement( viewLink );
|
|
246
265
|
|
|
247
266
|
// We need to check whether an image is inside a link because the converter handles
|
|
248
267
|
// only manual decorators for linked images. See #7975.
|
|
@@ -250,11 +269,7 @@ function upcastImageLinkManualDecorator( manualDecorators, decorator ) {
|
|
|
250
269
|
return;
|
|
251
270
|
}
|
|
252
271
|
|
|
253
|
-
const
|
|
254
|
-
attributes: manualDecorators.get( decorator.id ).attributes
|
|
255
|
-
};
|
|
256
|
-
|
|
257
|
-
const matcher = new Matcher( consumableAttributes );
|
|
272
|
+
const matcher = new Matcher( decorator._createPattern() );
|
|
258
273
|
const result = matcher.match( viewLink );
|
|
259
274
|
|
|
260
275
|
// The link element does not have required attributes or/and proper values.
|
|
@@ -278,12 +293,3 @@ function upcastImageLinkManualDecorator( manualDecorators, decorator ) {
|
|
|
278
293
|
// Using the same priority that `upcastLink()` converter guarantees that the linked image was properly converted.
|
|
279
294
|
};
|
|
280
295
|
}
|
|
281
|
-
|
|
282
|
-
// Returns the first image in a given view element.
|
|
283
|
-
//
|
|
284
|
-
// @private
|
|
285
|
-
// @param {module:engine/view/element~Element}
|
|
286
|
-
// @returns {module:engine/view/element~Element|undefined}
|
|
287
|
-
function getFirstImage( viewElement ) {
|
|
288
|
-
return Array.from( viewElement.getChildren() ).find( child => child.name === 'img' );
|
|
289
|
-
}
|
|
@@ -73,6 +73,15 @@ export default class AutomaticDecorators {
|
|
|
73
73
|
const viewElement = viewWriter.createAttributeElement( 'a', item.attributes, {
|
|
74
74
|
priority: 5
|
|
75
75
|
} );
|
|
76
|
+
|
|
77
|
+
if ( item.classes ) {
|
|
78
|
+
viewWriter.addClass( item.classes, viewElement );
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
for ( const key in item.styles ) {
|
|
82
|
+
viewWriter.setStyle( key, item.styles[ key ], viewElement );
|
|
83
|
+
}
|
|
84
|
+
|
|
76
85
|
viewWriter.setCustomProperty( 'link', true, viewElement );
|
|
77
86
|
if ( item.callback( data.attributeNewValue ) ) {
|
|
78
87
|
if ( data.item.is( 'selection' ) ) {
|
|
@@ -97,8 +106,8 @@ export default class AutomaticDecorators {
|
|
|
97
106
|
*/
|
|
98
107
|
getDispatcherForLinkedImage() {
|
|
99
108
|
return dispatcher => {
|
|
100
|
-
dispatcher.on( 'attribute:linkHref:imageBlock', ( evt, data,
|
|
101
|
-
const viewFigure =
|
|
109
|
+
dispatcher.on( 'attribute:linkHref:imageBlock', ( evt, data, { writer, mapper } ) => {
|
|
110
|
+
const viewFigure = mapper.toViewElement( data.item );
|
|
102
111
|
const linkInImage = Array.from( viewFigure.getChildren() ).find( child => child.name === 'a' );
|
|
103
112
|
|
|
104
113
|
for ( const item of this._definitions ) {
|
|
@@ -106,20 +115,38 @@ export default class AutomaticDecorators {
|
|
|
106
115
|
|
|
107
116
|
if ( item.callback( data.attributeNewValue ) ) {
|
|
108
117
|
for ( const [ key, val ] of attributes ) {
|
|
118
|
+
// Left for backward compatibility. Since v30 decorator should
|
|
119
|
+
// accept `classes` and `styles` separately from `attributes`.
|
|
109
120
|
if ( key === 'class' ) {
|
|
110
|
-
|
|
121
|
+
writer.addClass( val, linkInImage );
|
|
111
122
|
} else {
|
|
112
|
-
|
|
123
|
+
writer.setAttribute( key, val, linkInImage );
|
|
113
124
|
}
|
|
114
125
|
}
|
|
126
|
+
|
|
127
|
+
if ( item.classes ) {
|
|
128
|
+
writer.addClass( item.classes, linkInImage );
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
for ( const key in item.styles ) {
|
|
132
|
+
writer.setStyle( key, item.styles[ key ], linkInImage );
|
|
133
|
+
}
|
|
115
134
|
} else {
|
|
116
135
|
for ( const [ key, val ] of attributes ) {
|
|
117
136
|
if ( key === 'class' ) {
|
|
118
|
-
|
|
137
|
+
writer.removeClass( val, linkInImage );
|
|
119
138
|
} else {
|
|
120
|
-
|
|
139
|
+
writer.removeAttribute( key, linkInImage );
|
|
121
140
|
}
|
|
122
141
|
}
|
|
142
|
+
|
|
143
|
+
if ( item.classes ) {
|
|
144
|
+
writer.removeClass( item.classes, linkInImage );
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
for ( const key in item.styles ) {
|
|
148
|
+
writer.removeStyle( key, linkInImage );
|
|
149
|
+
}
|
|
123
150
|
}
|
|
124
151
|
}
|
|
125
152
|
} );
|
|
@@ -28,7 +28,7 @@ export default class ManualDecorator {
|
|
|
28
28
|
* Attributes should keep the format of attributes defined in {@link module:engine/view/elementdefinition~ElementDefinition}.
|
|
29
29
|
* @param {Boolean} [config.defaultValue] Controls whether the decorator is "on" by default.
|
|
30
30
|
*/
|
|
31
|
-
constructor( { id, label, attributes, defaultValue } ) {
|
|
31
|
+
constructor( { id, label, attributes, classes, styles, defaultValue } ) {
|
|
32
32
|
/**
|
|
33
33
|
* An ID of a manual decorator which is the name of the attribute in the model, for example: 'linkManualDecorator0'.
|
|
34
34
|
*
|
|
@@ -65,6 +65,36 @@ export default class ManualDecorator {
|
|
|
65
65
|
* @type {Object}
|
|
66
66
|
*/
|
|
67
67
|
this.attributes = attributes;
|
|
68
|
+
|
|
69
|
+
/**
|
|
70
|
+
* A set of classes added to downcasted data when the decorator is activated for a specific link.
|
|
71
|
+
* Classes should be added in a form of classes defined in {@link module:engine/view/elementdefinition~ElementDefinition}.
|
|
72
|
+
*
|
|
73
|
+
* @type {Object}
|
|
74
|
+
*/
|
|
75
|
+
this.classes = classes;
|
|
76
|
+
|
|
77
|
+
/**
|
|
78
|
+
* A set of styles added to downcasted data when the decorator is activated for a specific link.
|
|
79
|
+
* Styles should be added in a form of styles defined in {@link module:engine/view/elementdefinition~ElementDefinition}.
|
|
80
|
+
*
|
|
81
|
+
* @type {Object}
|
|
82
|
+
*/
|
|
83
|
+
this.styles = styles;
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
/**
|
|
87
|
+
* Returns {@link module:engine/view/matcher~MatcherPattern} with decorator attributes.
|
|
88
|
+
*
|
|
89
|
+
* @protected
|
|
90
|
+
* @returns {module:engine/view/matcher~MatcherPattern}
|
|
91
|
+
*/
|
|
92
|
+
_createPattern() {
|
|
93
|
+
return {
|
|
94
|
+
attributes: this.attributes,
|
|
95
|
+
classes: this.classes,
|
|
96
|
+
styles: this.styles
|
|
97
|
+
};
|
|
68
98
|
}
|
|
69
99
|
}
|
|
70
100
|
|