-
-
Notifications
You must be signed in to change notification settings - Fork 3.7k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Support setting data attributes on image from upload adapters #5204
Comments
cc @oleq |
Can you share some code? Because I'm at a loss for what you use, what you want to do and what is the actual issue here. |
Here's the workaround we are now using in production, which we derived from the ImageUpload plugin I believe. But if you look at the code (marked), it relies on parsing the CDN url, making it a roundabout method of deriving the original values.
For an example use case, please see medium.com's CMS. When you upload an image, it inserts a CDN url with resize query parameters. But there are additional attributes that are also set, which can then be used to do other stuff, for example, generating more thumbnails using different size configurations.
Not an issue. Proposal. |
@mlewand WDYT? |
This would be a nice feature, something similar was also mentioned in #8192. @darylteo suggestion to allow an
The workaround code here only works if the property can be derived from the path, and won't help for other arbitrary values that the server could provide. It's still necessary to add any custom attributes in Allowing other attributes in the server response would require a change in both the upload adapter and in the For example in the
This line would need to be changed to include And in ckeditor5/packages/ckeditor5-image/src/imageupload/imageuploadediting.js Lines 254 to 257 in bcfb8fe
There would need to be another line or helper function here to |
I don't like the idea of an ckeditor5/packages/ckeditor5-image/src/imageupload/imageuploadediting.js Lines 261 to 265 in 5cbb625
model.enqueueChange( 'transparent', writer => {
writer.setAttribute( 'uploadStatus', 'complete', imageElement );
this.fire( 'uploadComplete', { imageElement, data } );
} ); Note that this event would be fired by the I'd also move the editor.plugins.get( 'ImageUploadEditing' ).on( 'uploadComplete', ( evt, { imageElement, data } ) => {
editor.model.change( writer => {
writer.setAttribute( 'src', data.default, imageElement );
} );
} ); |
We discussed this f2f and ClipboardPipeline is part of the essential features. This is a different layer than image upload. I'd say they layer like this:
The question is whether One new idea, though, is to move the default listener to |
Feature (image): Introduced the `uploadComplete` event in `ImageUploadEditing` that allows customizing the image element (e.g. setting custom attributes) based on data retrieved from the upload adapter. Closes #5204. Feature (upload): Upload adapters' async `upload` method can now resolve to an object with additional properties along with the `urls` hash. See more in #5204. MINOR BREAKING CHANGE (upload): The async `SimpleUploadAdapter#upload()` resolves to an object with normalized data including the `urls` object, which was only returned before. This may affect all integrations depending on the `SimpleUploadAdapter` uploading mechanism.
Hi there, this feature seems like impIemented but I couldn't make it work in anyway. I couldn't find a way to add custom attributes.
|
Hi @datasoysa, Could you open a new issue as this one is closed? |
For anyone interested, it's working fine providing that you extend the @datasoysa in your example Here's some code that works for me: editor.plugins.get( 'ImageUploadEditing' ).on( 'uploadComplete', ( evt, { data, imageElement } ) => {
editor.model.change( writer => {
writer.setAttribute( 'dataReference', data.reference, imageElement );
} ); } );
editor.model.schema.extend( 'imageBlock', { allowAttributes: 'dataReference' } );
editor.conversion.for( 'upcast' ).attributeToAttribute( {
view: 'data-reference',
model: 'dataReference'
} );
editor.conversion.for( 'downcast' ).add( dispatcher => {
dispatcher.on( 'attribute:dataReference:imageBlock', ( evt, data, conversionApi ) => {
if ( !conversionApi.consumable.consume( data.item, evt.name ) ) {
return;
}
const viewWriter = conversionApi.writer;
const figure = conversionApi.mapper.toViewElement( data.item );
const img = figure.getChild( 0 );
if ( data.attributeNewValue !== null ) {
viewWriter.setAttribute( 'data-reference', data.attributeNewValue, img );
} else {
viewWriter.removeAttribute( 'data-reference', img );
}
} );
} ); |
@testinfected could you help me, your code example works pretty well, but I have an issue with the edit form. When I have a |
@solilin most likely you need to swap the |
no, in my case, I have |
@solilin It’s been a long time, I don’t remember the details. Maybe CKEditor treats |
Could you elaborate @solilin? |
@Witoso I have a scenario where a user can both create and edit a post using the CKEditor content field. The above code works perfectly for creating posts. When a user uploads images, the required |
Gotcha, most likely because the snippet above only extends the schema after image upload: editor.plugins.get( 'ImageUploadEditing' ).on( 'uploadComplete', ( evt, { data, imageElement } ) => {
// ^^^^^^^^^
// Extending happens only on uploadComplete
} When the content is loaded, the editor doesn't know this attribute can be stored on an image. What you need to do is to create your plugin and add it to the editor so that it works in every case. With a quick glance, copying and pasting should work: function imageDataIdPlugin( editor ) {
editor.model.schema.extend( 'imageBlock', { allowAttributes: 'dataId' } );
editor.conversion.for( 'upcast' ).attributeToAttribute( {
view: 'data-id',
model: 'dataId'
} );
editor.conversion.for( 'downcast' ).add( dispatcher => {
dispatcher.on( 'attribute:dataReference:imageBlock', ( evt, data, conversionApi ) => {
if ( !conversionApi.consumable.consume( data.item, evt.name ) ) {
return;
}
const viewWriter = conversionApi.writer;
const figure = conversionApi.mapper.toViewElement( data.item );
const img = figure.getChild( 0 );
if ( data.attributeNewValue !== null ) {
viewWriter.setAttribute( 'data-id', data.attributeNewValue, img );
} else {
viewWriter.removeAttribute( 'data-id', img );
}
} );
} Add it to the plugins lists of the editor, and in the |
It works, @Witoso you’re a lifesaver. I spent almost 1 day with this problem. |
Hi guys, I get totally stuck in same issue, I'm trying the upper solution, but got |
@godofevil could you share your plugins lists, looks like |
@Witoso Does this work if any text is also typed? I've used and it worked, but only when the ckeditor contains only the image. As soon as I type anything and try uploading it, the data-attribute is not set. The ImageAttribute function contains exactly what you posted above. Not currently using it as a plugin. Editor.ClassicEditor.create(
document.querySelector("#input_" + this.input.alias),
this.config
)
.then((editor) => {
// ------- Sets editor's height -----------
editor.editing.view.change((writer) => {
let height = this.input.height ?? "280px";
writer.setStyle("height", height, editor.editing.view.document.getRoot());
writer.setStyle("color", "#71748d", editor.editing.view.document.getRoot());
});
// Hides the toolbar when in read only mode.
const toolbarElement = editor.ui.view.toolbar.element;
editor.on("change:isReadOnly", (evt, propertyName, isReadOnly) => {
if (isReadOnly) {
toolbarElement.style.display = "none";
} else {
toolbarElement.style.display = "flex";
}
});
// ------- Sets editor's content when it changes -----------
editor.model.document.on("change:data", () => {
this.formData[this.input.name] = editor.getData();
});
// ------- Deals with midia upload -----------
editor.plugins.get("FileRepository").createUploadAdapter = (loader) => {
return new CKEditorUploadAdapter(loader, this.$route.params.route);
};
ImageAttributes(editor);
// ------- Make editor's instance available after mounted -----------
window[this.input.alias + "_editor"] = editor;
})
.catch((err) => {
console.error(err.stack);
this.$notify({
type: "error",
text: "Houve algum erro no carregamento do formulário.",
});
}); EDIT: import { Plugin } from "ckeditor5-custom-build/build/ckeditor";
export default class ImgIdAttributePlugin extends Plugin {
init() {
const editor = this.editor;
editor.plugins.get("ImageUploadEditing").on("uploadComplete", (evt, { data, imageElement }) => {
editor.model.change((writer) => {
writer.setAttribute("dataFileid", data.fileid, imageElement);
});
});
editor.model.schema.extend("imageBlock", { allowAttributes: "dataFileid" });
editor.model.schema.extend("imageInline", { allowAttributes: "dataFileid" });
editor.conversion.for("upcast").attributeToAttribute({
view: "data-fileid",
model: "dataFileid",
});
editor.conversion.for("downcast").add((dispatcher) => {
dispatcher.on("attribute:dataFileid:imageBlock", (evt, data, conversionApi) => {
this._setAttribute(evt, data, conversionApi, "imageBlock");
});
dispatcher.on("attribute:dataFileid:imageInline", (evt, data, conversionApi) => {
this._setAttribute(evt, data, conversionApi, "imageInline");
});
});
}
_setAttribute(evt, data, conversionApi, type) {
if (!conversionApi.consumable.consume(data.item, evt.name)) {
return;
}
const viewWriter = conversionApi.writer;
let figure = null;
let img = conversionApi.mapper.toViewElement(data.item);
if (type == "imageBlock") {
figure = img;
img = figure.getChild(0);
}
if (data.attributeNewValue !== null) {
viewWriter.setAttribute("data-fileid", data.attributeNewValue, img);
} else {
viewWriter.removeAttribute("data-fileid", img);
}
}
} |
Current
upload()
returnWe currently have a situation where I would like to save the original path of the uploaded image, but the images have to be served through a CDN.
It would be nice if I could save the original path as a data attribute. I've had a look at https://github.com/ckeditor/ckeditor5-image/blob/8fa4acf7850e958526d0f049899f88cb91282a74/src/imageupload/imageuploadediting.js to find the relevant code and it comes down to the
_parseAndSetSrcsetAttributeOnImage
function which sets the srcset attributes for numeric keys.If we could have support another
attributes
property where this information could be passed through, allowing the Custom Upload Adapter to supply any number of attributes to save, that would be very handy. Could be used to set thesizes
attribute, for example, which this plugin currently does not do.Proposed
upload()
returnMy current work around is to use downcast/upcast to parse the
src
and reverse engineer the path that way, which is slightly annoying but not impossible, I suppose. Just feels easier to get it from the horse's mouth.Thank you very much!
The text was updated successfully, but these errors were encountered: