📝
Editor.jsでインラインのマーカーツールで作成する
概要
Editor.jsでインラインのマーカーツールを作成する方法の備忘録です。
参考
以下のページが参考になりました。
TypeScriptでの記述にあたっては、以下が参考になりました。
実装
Nuxtで実装します。以下のmarker.tsを作成します。
/utils/tools/marker.ts
import type { API } from "@editorjs/editorjs";
class MarkerTool {
button: null | HTMLButtonElement;
state: boolean;
api: API;
tag: string;
class: string;
// 静的メソッドで許可されるHTMLタグと属性を指定
static get sanitize() {
return {
mark: {
class: "cdx-marker",
},
};
}
// インラインツールとしての振る舞いを定義
static get isInline() {
return true;
}
constructor({ api }: { api: API }) {
this.api = api;
this.button = null;
this.state = false;
this.tag = "MARK";
this.class = "cdx-marker";
}
// ボタン要素を作成し、SVGアイコンを設定
render() {
this.button = document.createElement("button");
this.button.type = "button";
this.button.innerHTML =
'<svg width="20" height="18"><path d="M10.458 12.04l2.919 1.686-.781 1.417-.984-.03-.974 1.687H8.674l1.49-2.583-.508-.775.802-1.401zm.546-.952l3.624-6.327a1.597 1.597 0 0 1 2.182-.59 1.632 1.632 0 0 1 .615 2.201l-3.519 6.391-2.902-1.675zm-7.73 3.467h3.465a1.123 1.123 0 1 1 0 2.247H3.273a1.123 1.123 0 1 1 0-2.247z"/></svg>';
this.button.classList.add(this.api.styles.inlineToolButton);
return this.button;
}
// 選択されたテキストを <mark> タグで囲む
surround(range: Range) {
if (this.state) {
this.unwrap(range);
return;
}
this.wrap(range);
}
// テキストを <mark> タグでラップ
wrap(range: Range) {
const selectedText = range.extractContents();
const mark = document.createElement(this.tag);
mark.className = this.class; // class 属性の追加
mark.appendChild(selectedText);
range.insertNode(mark);
this.api.selection.expandToTag(mark);
}
// <mark> タグを解除
unwrap(range: Range) {
const mark = this.api.selection.findParentTag(this.tag);
const text = range.extractContents();
mark?.remove();
range.insertNode(text);
}
// ツールの状態をチェック
checkState() {
const mark = this.api.selection.findParentTag(this.tag, this.class);
this.state = !!mark;
if (this.state) {
this.button?.classList.add("cdx-marker--active");
} else {
this.button?.classList.remove("cdx-marker--active");
}
}
}
export default MarkerTool;
上記を以下のように呼び出します。
<script setup lang="ts">
import EditorJS from '@editorjs/editorjs';
import type { OutputData } from '@editorjs/editorjs';
import MarkerTool from '@/utils/tools/marker';
// Editor.jsの初期データを設定
const blocks = ref<OutputData>({
time: new Date().getTime(),
blocks: [
{
type: 'paragraph',
data: {
text: '大明副使蒋 承奉すらく 、 欽差督察総制提督浙江等処軍務各衙門 、近年以来、日本各島小民、仮るに買売を以て名と為し 、 しばしば中国辺境を犯し、居民を刼掠するを因となし、旨を奉じて 、 浙江等処承宣布政使司 に議行し、本職に転行して 、 親しく貴国に詣り面議せしめん等の因あり。',
},
},
],
});
// Editor.jsを初期化し、ページに組み込む
const initEditor = () => {
new EditorJS({
holder: 'editorjs', // Editor.jsを表示する要素のID
data: blocks.value,
onChange: async (api) => {
blocks.value = await api.saver.save(); // 編集内容が変更された時にデータを更新
},
tools: {
Marker: {
class: MarkerTool,
shortcut: 'CMD+SHIFT+M', // マーカーツールのショートカットキー
},
},
});
};
// エディタの初期化を実行
initEditor();
</script>
<template>
<div style="background-color: aliceblue">
<div id="editorjs"></div>
<hljson :content="blocks" />
</div>
</template>
<style>
pre {
background-color: #f4f4f4;
border: 1px solid #ccc;
padding: 10px;
white-space: pre-wrap; /* 自動的に折り返し */
}
/* エディタ関連のスタイリング調整 */
.ce-block__content,
.ce-toolbar__content {
max-width: calc(100% - 80px) !important; /* エディタの最大幅を調整 */
}
.cdx-block {
max-width: 100% !important; /* ブロック要素の最大幅を設定 */
}
/* アクティブなマーカーのスタイル */
.cdx-marker--active {
color: #388ae5;
}
</style>
動作確認
マーカーアイコンをクリックすると、青色に変わり、<mark class=\"cdx-marker\">xxx</mark>
というタグが挿入されます。
まとめ
参考になりましたら幸いです。
Discussion