django-summernote icon indicating copy to clipboard operation
django-summernote copied to clipboard

Q: Possibility to add class to images?

Open yujinyuz opened this issue 3 years ago • 7 comments

Whenever I attach an image and save it, I want it to have a default class of img img-responsive so that when images are rendered, they would have that class.

Is that possible right now?

If not, are there any workarounds aside from using javascript/jQuery?

yujinyuz avatar Aug 09 '20 14:08 yujinyuz

You could try the plugin Summernote-Classes, which will one configured the classes you want to use the editor on different elements, allow you to add whatever classes you like to elements. https://github.com/DiemenDesign/summernote-classes I made it so the classes need to be added so it's not rigid to a set of classes, seeing as people could use custom, or different frameworks that will have different class names that do similar and or different things.

DennisSuitters avatar Aug 09 '20 15:08 DennisSuitters

@DiemenDesign Thanks! Though this one seems to be an overkill for what I wanted to achieve as I only want to automatically add img img-responsive to images. I don't want users to manually set the class to be used for images

yujinyuz avatar Aug 09 '20 15:08 yujinyuz

no worries, your welcome to take the idea and run with it.

DennisSuitters avatar Aug 09 '20 15:08 DennisSuitters

Actually, if your overriding the insertion so images are uploaded to the server rather than using the Base 64 encoding when they are inserted, you could add an extra bit of script that also adds the classes you want to the element.

DennisSuitters avatar Aug 09 '20 15:08 DennisSuitters

@DiemenDesign yeah. That's kindas what I want. Do you have any ideas on how?

yujinyuz avatar Aug 09 '20 15:08 yujinyuz

Look up elFinder, they have a small bit of javascript for using their media browser with Summernote, it opens a modal with the media browser, then returns the url of the image and inserts it into Summernote, you could see how they are doing it, and attach the classes to the image as you would have the object and could do something like $(imageelement).addClass('img-reposonsive'); with imageelement being the reference to the image element that was inserted.

DennisSuitters avatar Aug 10 '20 02:08 DennisSuitters

I have found a way but it's somewhat hacky. The idea is to use the summernote.change event to update the editor, if necessary. However, summernote.change is fired on every keystroke, so that would lead to excessive parsing if used standalone. To avoid that, I process the content only after bs.modal.hidden is fired.

Put the following code into a static file, for example summernote/custom.js, and have it added through settings.py:

# settings.py
SUMMERNOTE_CONFIG = {
    'js': (
        '/static/summernote/custom.js',
    )
}

Here's the code for Bootstrap 4. It adds the necessary classes to every <img> and also wraps videos in <div class="embed-responsive ">. Note that this works only in iframe mode because it uses global $('#summernote').


$(document).on('hidden.bs.modal', function() {
    // remember that a dialog has been closed recently, so we must inspect the next change event
    $('#summernote').data('dialogClosed', true);
});

$(document).on('summernote.change', function(evt, content, editor) {
    const $summernote = $('#summernote');
    // has the dialog been closed recently ?
    if ($summernote.data('dialogClosed')=== true) {
        
        // let the browser parse the content (html string)
        const $el = $('<div/>');
        $el.html(content);

        // add  img-thumbnail class to each image
        $el.find('img').addClass('mx-auto d-block img-thumbnail');

        // wrap videos into .embed-responsive instead of <p>
        $el.find('iframe.note-video-clip').each(function () {
            const $video = $(this),
                $parent = $video.parent();

            if ($parent[0].tagName === 'P') {
                $parent.replaceWith($video);
                $video.addClass('embed-responsive-item');
                $video.wrap('<div class="embed-responsive embed-responsive-16by9" />');
            }
        });
        
        // retrieve the updated content as HTML string
        const newContent = $el.html();
        if (newContent !== content) {
            // update editor content with our changes
            $summernote.summernote('code', newContent);
        }
        // delete dialogClosed flag
        $summernote.data('dialogClosed', false);
    }
});

chrisv2 avatar Sep 17 '20 16:09 chrisv2