Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

CKEditor 4.5 drag and drop image upload - how to return new dimensions in json response?

Tags:

ckeditor

I have drag and drop image uploads working using CKEditor 4.5.1. Very nice feature! On the server side I am resizing large images. My JSON response returns the resized image url (set by 'url' in the response) and that is the image that is shown in the CKEditor window after the successful file upload. But the img tag inserted has the height and width attributes set with the values from the original image, not my resized image. Is there a way to return the new height and width values? Or does anyone have an idea of how to hack around this?

And more generally, is there any resource which describes all possible values in the JSON response? I saw it mentioned somewhere that it wasn't documented yet but hopefully someone might know and take the time to share.

like image 768
jimb Avatar asked Jul 02 '15 18:07

jimb


1 Answers

When uploading an image finishes, CKEditor replaces an upload widget (which contains an image with Base64 data in the source) with the final HTML. The uploaded image has the same dimensions as the one being uploaded to prevent from blinking during this replacement. Here are the lines that do this replacement.

If blinking when an image is uploaded is not a problem for you, then you can simple overwrite this method:

editor.on( 'instanceReady', function() {
    editor.widgets.registered.uploadimage.onUploaded = function ( upload ) {
        this.replaceWith( '<img src="' + upload.url + '">' );
    }
} );

Now, where can we get the image dimensions from?

One option is to load the image (upload.url) and read its dimensions in the browser. However, this is an asynchronous operation, so it may affect the undo manager and I would not recommend it.

Therefore, if you know the new dimensions you can send then in the server response. If you put them in your JSON response like this:

{
    "uploaded": 1,
    "fileName": "foo.jpg",
    "url": "/files/foo.jpg",
    "width:" 300,
    "height:" 200
}

You need to handle them in the response (we'll most likely simplify this bit soon):

editor.on( 'fileUploadResponse', function( evt ) {
    var fileLoader = evt.data.fileLoader,
        xhr = fileLoader.xhr,
        data = evt.data;

    try {
        var response = JSON.parse( xhr.responseText );

        // Error message does not need to mean that upload finished unsuccessfully.
        // It could mean that ex. file name was changes during upload due to naming collision.
        if ( response.error && response.error.message ) {
            data.message = response.error.message;
        }

        // But !uploaded means error.
        if ( !response.uploaded ) {
            evt.cancel();
        } else {
            data.fileName = response.fileName;
            data.url = response.url;
            data.width = response.width;
            data.height = response.height;

            // Do not call the default listener.
            evt.stop();
        }
    } catch ( err ) {
        // Response parsing error.
        data.message = fileLoader.lang.filetools.responseError;
        window.console && window.console.log( xhr.responseText );

        evt.cancel();
    }
} );

To learn more check the editor#fileUploadResponse event and the Uploading Dropped or Pasted Files guide.

Then you can use them in the upload widget:

editor.on( 'instanceReady', function() {
    editor.widgets.registered.uploadimage.onUploaded = function( upload ) {
        this.replaceWith( '<img src="' + upload.url + '" ' +
            'width="' + upload.width + '" ' +
            'height="' + upload.height + '">' );
    }
} );

PS. We were considering including such a feature in the core, but because the release was huge we had to limit it at some point to bring it finally to life. There is a great chance that such a feature will be included in the core soon, and only configuration will be needed.

like image 194
Piotr Jasiun Avatar answered Oct 23 '22 02:10

Piotr Jasiun