tinyMCEでローカルで動作するHTML用WYSWYGエディタ作ってみた

 tinyMCEというライブラリがあったので、それを使ってWordPressみたいなエディタを作成してみました。JavaScriptオンリーで作成しています。あとライブラリ類は全部ローカルに落とし込んでいるのでネットにつながらない環境でも利用することができます。

簡易な検索機能と、その他ファイルの閲覧のみの機能も備えてみました。

javascriptはシロート並みなので当然ながらChatGPTにほとんど作成してもらってます。まぁ弱っちいのでそうなります。そのうち淘汰されるんだろうなと感じながら日々生きてます。


tinyMCEを制御している主要なjsのみ掲載しときます。後はGitHubのコード見てください。弱っちいのでもっといい書き方あるよとか教えていただけると幸いです。


// オリジナルHTMLを保持する
let originHtml = '';

const initialConfig = {
    selector: '#editor',
    language: 'ja',
    language_url: './langs/ja.js',
    branding: false,
    plugins: 'link image code codesample table lists media visualblocks wordcount preview save textpattern',
    textpattern_patterns: [
        { start: '*', end: '*', format: 'italic' },
        { start: '**', end: '**', format: 'bold' },
        { start: '#', format: 'h1' },
        { start: '##', format: 'h2' },
        { start: '###', format: 'h3' },
        { start: '####', format: 'h4' },
        { start: '#####', format: 'h5' },
        { start: '######', format: 'h6' },
        { start: '1. ', cmd: 'InsertOrderedList' },
        { start: '* ', cmd: 'InsertUnorderedList' },
        { start: '- ', cmd: 'InsertUnorderedList' },
        { start: '//brb', replacement: 'Be Right Back' }
    ],
    codesample_languages: [
        { text: 'HTML/XML', value: 'markup' },
        { text: 'JavaScript', value: 'javascript' },
        { text: 'CSS', value: 'css' },
        { text: 'PHP', value: 'php' },
        { text: 'Ruby', value: 'ruby' },
        { text: 'Python', value: 'python' },
        { text: 'Java', value: 'java' },
        { text: 'C', value: 'c' },
        { text: 'C#', value: 'csharp' },
        { text: 'C++', value: 'cpp' }
    ],
    save_onsavecallback: () => {
        contentsSave();
    },
    menu: {
        file: {
            title: 'ファイル',
            items: 'newdocument preview print | save clearheader', // 既存の新規ドキュメントメニューとカスタムメニューを含める
        },
    },
    setup: (editor) => {
        editor.ui.registry.addButton('custom-preview', {
            icon: 'preview',
            tooltip: 'fullscreen preview',
            onAction: () => {
                contentsPreview();
            }
        });

        editor.ui.registry.addToggleButton('save', {
            icon: 'save',
            onAction: () => {
                contentsSave(); // 保存ボタンの処理を呼び出し
            },
        });

        editor.ui.registry.addMenuItem('clearheader', {
            text: 'ヘッダーのクリア',
            onAction: () => {
                clearHeader(); // ヘッダーをクリアする関数を呼び出し
            },
        });

        editor.ui.registry.addMenuItem('save', {
            text: 'save',
            onAction: () => {
                contentsSave(); // 保存ボタンの処理を呼び出し
            },
        });


    },
    toolbar: 'save custom-preview undo redo | blocks fontfamily fontsize | bold italic strikethrough forecolor backcolor | alignleft aligncenter alignright alignjustify | bullist numlist outdent indent | link image | media | code | codesample | table | visualblocks',
    menubar: 'file edit view insert format tools table help',
    height: 600
};


// TinyMCEを初期化
tinymce.init(initialConfig);

// エディタにコンテンツを表示
function setTinyMCEContent(content) {
    originHtml = content
    tinymce.get('editor').setContent(content);
}

// HTML生成
function editorContent() {
    //タイトル


    const titleText = document.getElementById('title').textContent;

    const content = tinymce.activeEditor.getContent();
    const indentedContent = content.split('\n').map(line => '    ' + line).join('\n');

    // 既存HTML読込時
    const existingHeader = getHeaderFromHTML(originHtml);
    const existingFooter = getFooterFromHTML(originHtml);
    let htmlContent = `${existingHeader}\n${indentedContent}\n${existingFooter}`;

    if (originHtml === '') {
        htmlContent = `<!DOCTYPE html>
<html lang="ja">
<head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>${titleText}</title>
</head>
<body>
${indentedContent}
</body>
</html>`;
    }
    return htmlContent
}

// オリジナルHTMLからヘッダーを取得する関数
function getHeaderFromHTML(htmlContent) {
    const match = htmlContent.match(/<!DOCTYPE[\s\S]*?<\/head>/i);
    return match ? match[0] : '';
}

// オリジナルHTMLからフッターを取得する関数
function getFooterFromHTML(htmlContent) {
    const match = htmlContent.match(/<\/body>[\s\S]*?<\/html>/i);
    return match ? match[0] : '';
}

// プレビューボタンのクリックイベントハンドラ
function contentsPreview() {
    const htmlContent = editorContent();

    // プレビューウィンドウにHTMLコンテンツを表示
    const previewWindow = window.open('', '_blank');
    previewWindow.document.open();
    previewWindow.document.write(htmlContent);
    previewWindow.document.close();
}

// 保存
function contentsSave() {
    const htmlContent = editorContent();

    const blob = new Blob([htmlContent], { type: 'text/html' });
    const fileName = 'document.html';

    // ダウンロード
    const downloadLink = document.createElement('a');
    downloadLink.href = URL.createObjectURL(blob);
    downloadLink.download = fileName;
    downloadLink.click();
    URL.revokeObjectURL(blob);
}

//ヘッダークリア
function clearHeader() {
    originHtml = '';
}

GitHubっす

https://github.com/Otazoman/tinyMCEEditorSample


◆参照サイト

・tinyMCE

https://oxynotes.com/?p=11177

https://qiita.com/nissuk/items/e31bdfa858d6c5c018c2

https://www.keicode.com/script/how-to-use-tinymce.php

https://gitlab.raisound.com:9443/webs/smart_party/tree/ef29d4366d9d17fbd7a57adfb47939a1c3e1d9fa/tinymce/plugins/textpattern

・awesome

https://tech-blog.rakus.co.jp/entry/20220127/fontawesome

https://www.sungrove.co.jp/font-awesome/

https://webdesign-trends.net/entry/14327

・FileAPI

https://qiita.com/wada1355/items/8028d87d8d2bc6c00e69

https://developer.mozilla.org/ja/docs/Web/API/File

https://www.tohoho-web.com/html5/file_api.html

https://atmarkit.itmedia.co.jp/ait/articles/1112/16/news135.html

コメント

このブログの人気の投稿

証券外務員1種勉強(計算式暗記用メモ)

GASでGoogleDriveのサブフォルダとファイル一覧を出力する

マクロ経済学(IS-LM分析)