Skip to content

Commit

Permalink
IBX-6889: Added custom attributes to links
Browse files Browse the repository at this point in the history
  • Loading branch information
dew326 committed Nov 14, 2023
1 parent cbae649 commit 3b951eb
Show file tree
Hide file tree
Showing 6 changed files with 346 additions and 53 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -52,12 +52,20 @@ class IbexaCustomAttributesEditing extends Plugin {
const elementsWithCustomClasses = Object.keys(customClassesConfig);

elementsWithCustomAttributes.forEach((element) => {
if (element === 'link') {
return;
}

const customAttributes = Object.keys(customAttributesConfig[element]);

this.extendSchema(model.schema, element, { allowAttributes: customAttributes });
});

elementsWithCustomClasses.forEach((element) => {
if (element === 'link') {
return;
}

this.extendSchema(model.schema, element, { allowAttributes: 'custom-classes' });
});

Expand Down
10 changes: 10 additions & 0 deletions src/bundle/Resources/public/js/CKEditor/link/link-command.js
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,16 @@ class IbexaLinkCommand extends Command {
writer.setAttribute('ibexaLinkHref', linkData.href, element);
writer.setAttribute('ibexaLinkTitle', linkData.title, element);
writer.setAttribute('ibexaLinkTarget', linkData.target, element);

if (!!linkData.ibexaLinkClasses) {
writer.setAttribute('ibexaLinkClasses', linkData.ibexaLinkClasses, element);
}

if (linkData.ibexaLinkAttributes) {
Object.entries(linkData.ibexaLinkAttributes).forEach(([name, value]) => {
writer.setAttribute(name, value, element);
});
}
}
}

Expand Down
110 changes: 81 additions & 29 deletions src/bundle/Resources/public/js/CKEditor/link/link-editing.js
Original file line number Diff line number Diff line change
@@ -1,13 +1,14 @@
import Plugin from '@ckeditor/ckeditor5-core/src/plugin';

import IbexaLinkCommand from './link-command';
import { getCustomAttributesConfig, getCustomClassesConfig } from '../custom-attributes/helpers/config-helper';

class IbexaCustomTagEditing extends Plugin {
static get requires() {
return [];
}

defineConverters() {
defineConverters(customAttributesLinkConfig, customClassesLinkConfig) {
const { conversion } = this.editor;

conversion.for('editingDowncast').attributeToElement({
Expand Down Expand Up @@ -40,42 +41,93 @@ class IbexaCustomTagEditing extends Plugin {
view: (target, { writer: downcastWriter }) => downcastWriter.createAttributeElement('a', { target }),
});

conversion.for('upcast').elementToAttribute({
view: {
name: 'a',
attributes: {
href: true,
},
},
model: {
key: 'ibexaLinkHref',
value: (viewElement) => viewElement.getAttribute('href'),
},
});

conversion.for('upcast').attributeToAttribute({
view: {
name: 'a',
key: 'title',
},
model: 'ibexaLinkTitle',
});

conversion.for('upcast').attributeToAttribute({
view: {
name: 'a',
key: 'target',
},
model: 'ibexaLinkTarget',
if (customClassesLinkConfig) {
conversion.for('editingDowncast').attributeToElement({
model: 'ibexaLinkClasses',
view: (classes, { writer: downcastWriter }) => downcastWriter.createAttributeElement('a', { class: classes }),
});

conversion.for('dataDowncast').attributeToElement({
model: 'ibexaLinkClasses',
view: (classes, { writer: downcastWriter }) => downcastWriter.createAttributeElement('a', { class: classes }),
});
}

if (customAttributesLinkConfig) {
Object.keys(customAttributesLinkConfig).forEach((customAttributeName) => {
conversion.for('editingDowncast').attributeToElement({
model: `ibexaLink${customAttributeName}`,
view: (attr, { writer: downcastWriter }) =>
downcastWriter.createAttributeElement('a', { [`data-ezattribute-${customAttributeName}`]: attr }),
});

conversion.for('dataDowncast').attributeToElement({
model: `ibexaLink${customAttributeName}`,
view: (attr, { writer: downcastWriter }) =>
downcastWriter.createAttributeElement('a', { [`data-ezattribute-${customAttributeName}`]: attr }),
});
});
}

conversion.for('upcast').add((dispatcher) => {
dispatcher.on('element:a', (evt, data, conversionApi) => {
if (conversionApi.consumable.consume(data.viewItem, { attributes: ['href'] })) {
const { modelRange } = conversionApi.convertChildren(data.viewItem, data.modelCursor);
const ibexaLinkHref = data.viewItem.getAttribute('href');
const ibexaLinkTitle = data.viewItem.getAttribute('title');
const ibexaLinkTarget = data.viewItem.getAttribute('target');
const classes = data.viewItem.getAttribute('class');

conversionApi.writer.setAttributes(
{
ibexaLinkHref,
ibexaLinkTitle,
ibexaLinkTarget,
},
modelRange,
);

if (classes && customClassesLinkConfig) {
conversionApi.writer.setAttribute('ibexaLinkClasses', classes, modelRange);
}

if (customAttributesLinkConfig) {
Object.keys(customAttributesLinkConfig).forEach((customAttributeName) => {
const customAttributeValue = data.viewItem.getAttribute(`data-ezattribute-${customAttributeName}`);

if (customAttributeValue) {
conversionApi.writer.setAttribute(`ibexaLink${customAttributeName}`, customAttributeValue, modelRange);
}
});
}
}
});
});
}

init() {
const customAttributesConfig = getCustomAttributesConfig();
const customClassesConfig = getCustomClassesConfig();
const customAttributesLinkConfig = customAttributesConfig.link;
const customClassesLinkConfig = customClassesConfig.link;

this.editor.model.schema.extend('$text', { allowAttributes: 'ibexaLinkHref' });
this.editor.model.schema.extend('$text', { allowAttributes: 'ibexaLinkTitle' });
this.editor.model.schema.extend('$text', { allowAttributes: 'ibexaLinkTarget' });

this.defineConverters();
if (customAttributesLinkConfig) {
const attributes = Object.keys(customAttributesLinkConfig);

attributes.forEach((attribute) => {
this.editor.model.schema.extend('$text', { allowAttributes: `ibexaLink${attribute}` });
});
}

if (customClassesLinkConfig) {
this.editor.model.schema.extend('$text', { allowAttributes: 'ibexaLinkClasses' });
}

this.defineConverters(customAttributesLinkConfig, customClassesLinkConfig);

this.editor.commands.add('insertIbexaLink', new IbexaLinkCommand(this.editor));
}
Expand Down
26 changes: 24 additions & 2 deletions src/bundle/Resources/public/js/CKEditor/link/link-ui.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import findAttributeRange from '@ckeditor/ckeditor5-typing/src/utils/findattribu

import IbexaLinkFormView from './ui/link-form-view';
import IbexaButtonView from '../common/button-view/button-view';
import { getCustomAttributesConfig, getCustomClassesConfig } from '../custom-attributes/helpers/config-helper';

const { Translator } = window;

Expand Down Expand Up @@ -35,7 +36,7 @@ class IbexaLinkUI extends Plugin {
const formView = new IbexaLinkFormView({ locale: this.editor.locale, editor: this.editor });

this.listenTo(formView, 'save-link', () => {
const { url, title, target } = this.formView.getValues();
const { url, title, target, ibexaLinkClasses, ibexaLinkAttributes } = this.formView.getValues();
const { path: firstPosition } = this.editor.model.document.selection.getFirstPosition();
const { path: lastPosition } = this.editor.model.document.selection.getLastPosition();
const noRangeSelection = firstPosition[0] === lastPosition[0] && firstPosition[1] === lastPosition[1];
Expand All @@ -50,7 +51,7 @@ class IbexaLinkUI extends Plugin {

this.isNew = false;

this.editor.execute('insertIbexaLink', { href: url, title: title, target: target });
this.editor.execute('insertIbexaLink', { href: url, title, target, ibexaLinkClasses, ibexaLinkAttributes });
this.hideForm();
});

Expand Down Expand Up @@ -88,13 +89,34 @@ class IbexaLinkUI extends Plugin {
}

showForm() {
const customAttributesConfig = getCustomAttributesConfig();
const customClassesConfig = getCustomClassesConfig();
const customAttributesLinkConfig = customAttributesConfig.link;
const customClassesLinkConfig = customClassesConfig.link;
const link = this.findLinkElement();
const values = {
url: link ? link.getAttribute('href') : '',
title: link ? link.getAttribute('title') : '',
target: link ? link.getAttribute('target') : '',
};

if (customClassesLinkConfig) {
const defaultCustomClasses = customClassesLinkConfig?.defaultValue ?? '';
const classesValue = link?.getAttribute('class') ?? defaultCustomClasses;

values.ibexaLinkClasses = classesValue;
}

if (customAttributesLinkConfig) {
const attributesValues = Object.entries(customAttributesLinkConfig).reduce((output, [name, config]) => {
output[name] = link?.getAttribute(`data-ezattribute-${name}`) ?? config.defaultValue;

return output;
}, {});

values.ibexaLinkAttributes = attributesValues;
}

this.formView.setValues(values);

this.balloon.add({
Expand Down
Loading

0 comments on commit 3b951eb

Please sign in to comment.