勉強したことのメモ

Webエンジニア / プログラマが勉強したことのメモ。

summernoteにギャラリーから画像を挿入する機能を追加する方法

   2026/08/20  jQuery JavaScript

summernoteの画像機能はデフォルトだと「画像ファイルを選ぶ」「URLから画像を挿入する」の2つになるが、WordPressのようにアップロード済みの画像をギャラリー表示し、ギャラリーから画像を選択することで画像挿入可能な機能を新たに追加したい。以下にサンプルと実装方法をメモ。

 

summernoteについて

summernote自体の使用方法については過去記事参照。

 

サンプル

https://taitan916.info/sample/summernote/gallery/

 

実装方法

WYSIWYGエディタ側(index.php)

<style>
.gallery_img{
    cursor: pointer;
    max-width: 22%;
    padding: 5px;
    margin: 2px;

    img{
        width: 100%;
        border: 1px solid #ccc;
        padding: 3px;
        border-radius: 3px;
    }

    img.choice{
        border: 1px solid #000;
    }
}
.gallery_area{
    display: flex;
    flex-wrap: wrap;
    overflow: auto;
    max-height: 200px;
}
</style>

<form action="./" method="post">
    <div>
        <label>
            <input type="radio" value="on" name="switching" checked>On
        </label>
        <label>
            <input type="radio" value="off" name="switching">Off
        </label>
    </div>
    <textarea name="editor" id="editor"></textarea><br>
    <input type="submit" value="送信">
</form>

<script type="text/javascript" src="https://code.jquery.com/jquery-3.7.1.min.js"></script>
<link href="https://cdn.jsdelivr.net/npm/summernote@0.8.18/dist/summernote-lite.min.css" rel="stylesheet">
<script src="https://cdn.jsdelivr.net/npm/summernote@0.8.20/dist/summernote-lite.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/summernote/0.8.20/lang/summernote-ja-JP.min.js" type="text/javascript"></script>

<script>
$(function(){
    const selector = '#editor';

    let gallery_list = [];
    const gallery_limit = 4;
    let gallery_page = 1;

    //summernoteの開始
    startSummernote(selector);

    //summernoteのOn / Off切り替え
    $('input[name="switching"]').on('change', function(){
        if( $(this).val() == 'on' ){

            //summernoteの開始
            startSummernote(selector);
        }else{

            //空の場合はsummernote側で<p><br></p>が挿入されるので削除
            if( $(selector).summernote('code') == '<p><br></p>' ){
                $(selector).val('');
            }

            //summernoteの破棄
            $(selector).summernote('destroy');
        }
    });

    //ギャラリー画像クリック時
    $(document).on(`click`, `.gallery_img`, function(){
        $(`.gallery_img img`).removeClass(`choice`);
        $(this).find(`img`).addClass(`choice`);
        $(`.note-group-image-url .note-input`).val($(this).data(`url`));
        $(`.note-image-btn`).attr(`disabled`, false)
    });

    //画像をさらに読み込むクリック時
    $(document).on(`click`, `#gallery_next_btn`, function(){
        let gallery_list_html = generateGallery();
        $(`.gallery_next_btn`).before(gallery_list_html);
        $('.gallery_area').animate({scrollTop: $('.gallery_area')[0].scrollHeight}, 'fast');
    });

    //ギャラリー用データの取得
    $.ajax({
        url: `./img_list.php?t=${$.now()}`,
        method: `GET`,
    })
    .done(function( result ){
        gallery_list = JSON.parse(result);
    });

    //summernoteの開始用関数
    function startSummernote( selector ){
        if( !selector ) return false;

        //オプション設定
        const summernote_option = {
            lang: 'ja-JP',
            height: 300,
            focus: true,
            callbacks: {
                onDialogShown: function(dialog){

                    //画像挿入用モーダル表示時
                    if( $(`.note-modal.open`).attr(`aria-label`) == '画像挿入' ){

                        //ギャラリー用データがあって初回表示時はギャラリー生成して出力
                        if( gallery_list.length && gallery_page == 1 ){

                            //(必要に応じて)「URLから画像を挿入する」は削除
                            $(`.form-group.note-group-image-url`).hide();

                            let gallery_list_html = generateGallery();

                            let next_btn_html = '';
                            if( gallery_list.length ){
                                next_btn_html += `
                                    <div class="gallery_next_btn">
                                        <a id="gallery_next_btn" class="note-btn note-btn-primary">画像をさらに読み込む</a>
                                    </div>
                                `;
                            }

                            const gallery_modal_content = `
                                <div class="form-group note-group-gallery-url">
                                    <label for="note-dialog-gallery" class="note-form-label">ギャラリーから画像を挿入する</label>
                                    <div class="gallery_area">
                                        ${gallery_list_html}
                                        ${next_btn_html}
                                    </div>
                                </div>
                            `;

                            $(`.note-modal.open`).find('.note-modal-body').append(gallery_modal_content);
                        }

                    }
                }
            }
        }

        $(selector)
            //オプションを指定して初期化
            .summernote(summernote_option)

            //エンタークリック時に<br>タグを挿入
            .on('summernote.enter',
                function(we, e){
                    $(this).summernote('pasteHTML', '<br>&ZeroWidthSpace;');
                    e.preventDefault();
                }
            );
    }

    //ギャラリー生成
    function generateGallery(){
        let gallery_list_html = '';

        for( let i = 0; i < gallery_limit; i++ ){
            if( !gallery_list[0] ) break;
            const tmp_img = gallery_list.shift();
            gallery_list_html += `
                <div class="gallery_img" data-url="${tmp_img}">
                    <img src="${tmp_img}">
                </div>
            `;
        }

        if( !gallery_list.length ){
            $(`#gallery_next_btn`).hide();
        }

        gallery_page++;

        return gallery_list_html;
    }

});
</script>

ギャラリー用の画像検索(img_list.php)

<?php
$pattern = './img/*.*';
$list = [];
foreach ( glob( $pattern ) as $file ){
    $list[] = str_replace('./img/', 'https://test.com/img/', $file);
}
echo json_encode($list);

解説等

img_list.phpは画像ディレクトリにあるファイルをJSONで返すというもので、それをsummernote側で受け取ってギャラリー表示にしている。

また、画像ディレクトリ内に多数のファイルがある場合、全ファイルを一気に読み込むと重くなるため分割で表示。

尚、ギャラリー内の画像を選択した際、「URLから画像を挿入する」のテキストボックスに画像URLを入れている。

ギャラリー画像の表示順

img_list.phpではファイルをglobで検索しているためファイル名のアルファベット順になる。

実際に使用する場合は恐らくファイルの更新日時順で表示する形になると思われるが、そのような場合はfilemtime等を使用してソートしなおす必要あり。

「URLから画像を挿入する」機能も使用する場合

「URLから画像を挿入する」部分は非表示にしているが、表示させたい場合は以下行をコメントアウトもしくは削除する。

$(`.form-group.note-group-image-url`).hide();

 

所感

少々力業な実装方法かもしれないがやりたかったことはできた。過去にメモした画像のアップロードと組み合わせて使っていけそう。

 - jQuery JavaScript

  関連記事

summernoteで画像選択時にサーバにファイルをアップロードする方法
summernoteで画像選択時にサーバにファイルをアップロードする方法

summernoteで画像を選択した際、ファイルはアップロードされずBase64 ...

summernote(WYSIWYGエディタ)の設置方法と日本語化対応
summernote(WYSIWYGエディタ)の設置方法と日本語化対応

あるシステムにWYSIWYGエディタを実装したかった。以前にメモしたCKEdit ...

「emoji-mart」プラグインを利用してsummernoteに絵文字機能を追加する方法
「emoji-mart」プラグインを利用してsummernoteに絵文字機能を追加する方法

summernoteに絵文字機能を追加したい。具体的にはツールバーに新たにボタン ...

summernoteにクリップボードにコピー機能を追加する方法
summernoteにクリップボードにコピー機能を追加する方法

summernoteのツールバーに新たにボタンを設置し、そのボタンをクリックする ...