テキストエディタQuill.jsのカスタマイズで画像保存、POST送信の準備

WYSIWYG(ウィジウィグ)エディタ

What You See Is What You Get (見たままをゲットする)エディタ

テキストエディタ、Quill.jsの画像保存に注意

Quill.js標準の設定の場合は、画像の一時保存の状態は、画像がBase64化された状態でsrc-“”の保存先名が長くなるので注意すること。

参考サイト:https://nebikatsu.com

更新日:

Quill.jsの画像ファイル追加の状態

参考したWEBサイトの説明の補足です。Quill.jsの標準imgアイコンで画像をアップロードすると、inputタグのファイル参照しているのと同じ状態で、WEBサーバー側に保存は行っていない状態。

HTML


<!-- ファイル参照 -->
<input id="img_upload" type="file" />
テキストエディタQuill.jsのカスタマイズで画像保存、POST送信の準備、説明画像1

画像参照後に発火させてjs処理を行う場合はこう記述する。

HTML


<!-- onchangeでファイル参照完了後にjs処理setImage()を実行 -->
<input id="img_upload" type="file" accept="image/gif,image/jpeg,image/jpg,image/png" onchange="setImage()" multiple />

テキストエディタ、Quill.js設置後のPOST送信処理の準備

Quillは、jsでテキスト形成をしてくれるが、FormタグでPOSTで送るための値を含まないので、jsにより<input>タグに内容をセットする処理が必要になる。受取ったPOSTの処理はjsだけで行うよりPHPでは簡単なので、ここではQuill.jsからPOSTを送るまでのjsによる送信準備を記載。

PHP


//POSTデータも配列化すると確認が楽
$post_data = array();//配列初期化
if( isset($_POST)){
	$post_data = $_POST;
}//

js入力したテキスト内容を一時的にCookie保存を行う

単純に文字列をjsで取得してセットするだけで大丈夫だが、POSTエラーなど、DB登録する途中でデータロストするのを防ぎたいので、一時的にCookieに保存するという方法。

リアルタイムでHTML表示する onInput

onInput=””を利用すると、テキストを入力する度にデータを更新できるのでリアルタイム表示に利用できる。

PHP


<?php
// Quill.jsのPOST送信準備 
//	onInput=入力があった時、onClick=クリックされた時、jsでshowPreview1()処理COOKIE["text"]保存
// PHPのnl2br()関数で改行を表示する

	$content ="";//修正更新したいHTML内容

	if($_COOKIE["text"] ==""){
		setcookie('text',$content,time()+60*60*1*0);//60秒x60分
	}//
?>
		<!-- quill-editor  -->
		<div id="app">
			<form method="post" action="" enctype="multipart/form-data" >
				<div id="editor_area" onInput="showPreview1()"><?php  echo nl2br($_COOKIE["text"]); ?></div>
				<input type="hidden" name="main" id="project_contents_inner">
				<button type="submit" name="subbtn" onClick="showPreview1()">一時保存(Cooki)</button>
			</form>
		</div>
		<!-- //quill-editor  -->

		<!-- 表示エリア --->
		<textarea id="editor_area2" name="html_text" ></textarea>		
		<div id="coment_area" ></div>
		<!-- 表示エリア ここまで --->

Java Script


//js
//保存したCookiをキー名ごとに配列化する

//-----------------------
// 	Cookieの全読み込み
//	var cookies = document.cookie;
//	var c_text = decodeURIComponent(cookies); //encodeURIComponentエンコードを戻す
//---------------------

//-----------------------
// Cookieを連想配列に格納
//-----------------------
function getCookieArray(){
	var arr = new Array();
	
	if(document.cookie != ''){
		var tmp = document.cookie.split('; ');
		for(var i=0;i<tmp.length;i++){
			var data = tmp[i].split('=');
			
			arr[data[0]] = decodeURIComponent(data[1]);
		}
	}
	return arr;
}//

記載したHTML内容は、jsの.innerHTMLで取得や表示が可能。

Quillのエディタの内容エリアは(ql-edito)というクラスから取得する。

Java Script


//変数textがDBに保存する内容
var text = document.querySelector('.ql-editor').innerHTML;

取得した(ql-edito)クラスの内容をtype=”hidden”にしているinputタグにjsで表示してformでPOSTとして渡すとDBに保存が可能。

もし本ページのプログラムを参考に、Cookieに一時保存しているなら、そのCookieの内容をそのままDBに保存すればよいので、簡単です。

Quillの内容を、HTML状態で確認する、HTMLコード状態にする。

Cookieに一時保存した内容を、HTML状態で確認するために<div>タグjsで表示している。HTMLコード状態は<textarea>に表示している。textareaにはjsでQuillの内容を表示する部分をコメントアウトしている。

prettyprintを適用した状態で表示

<Code>部分は、prettyprintでコードを装飾して表示したいのでjs文字列を書換ている。

HTML


<!-- prettyprintを適用するときのクラス設定 -->
<pre><code class="prettyprint linenums lang-php">

textareaでの改行方法

<textarea>では、改行がうまく表示出来ない場合があるので、改行コードの「¥n 」へ置き換えて、CSSに「white-space: pre-wrap」設定が必要。ローカル環境の場合、Windowsの改行コードは「¥r¥n」を。Macの改行コードは「¥r」なので注意する。

CSS


/* css */
textarea ,
textarea div ,
textarea div p{
	white-space: pre-wrap;
}

jsで内容を再表示する

jsによるHTML文の取得の違い
.value HTMLタグが有効になり、pタグ内のテキストのみ表示
.innerText サニタイズされHTMLタグ<p>も表示される
.innerHTML サニタイズ後の特殊記号で表示される

Java Script



//-------------------------
//Cookieに一時保存する処理
//-------------------------
function showPreview1(){

	var text = document.querySelector('.ql-editor').innerHTML;

	//cookieが使えるか確認
	if (navigator.cookieEnabled) { 

		//----------------
		//Cookie保存
		//----------------
		document.cookie = "text=" + encodeURIComponent(text);//エンコードして”text”でCookie保存

		//------------------------
		// Cookieのkeyを指定して取得
		// 「 キー名が”text” 」というCookie情報が保存されているとする
		//-----------------------
		var arr = getCookieArray();//functionでCookiの配列読込
		//var c_text = 'textのCookie内容:' + arr['text'];	//キー名['text']の内容をc_textにセット
		var c_text = '' + arr['text'];	//''を足すことで、文字列として認識させる。
		
		//-------------------------------------------
		//表示エリアにCookie保存した内容を表示する
		// ('coment_area')は<div>内に表示
		// ('editor_area2')はtextareaにHTMLコードとして表示
		//-------------------------------------------

		//document.getElementById('editor_area2').innerText = '`'+ t_text  + '`';// <div id="cookie_v"></div>内にサニタイズ後特殊記号でHTMLとして表示

		var c_text  = c_text .replace('<pre>', '<pre><code class="prettyprint linenums lang-php">');
		var c_text  = c_text .replace('</pre>', '</code></pre>');
		document.getElementById('coment_area').innerHTML = c_text;// <div id="cookie_v"></div>内にサニタイズ後特殊記号でHTMLとして表示
	 
	 	//document.getElementById('editor_area2').value = c_text;// <div id="cookie_v"></div>内にテキストとして表示
	 	//document.getElementById('editor_area2').innerText = c_text;//<div id="cookie_v"></div>内にサニタイズされHTML表示
		//document.getElementById('editor_area2').innerHTML = c_text;//<div id="cookie_v"></div>内にサニタイズ後特殊記号でHTMLとして表示

	}//end_if

}//end_function

上記では、textareaに表示する部分をコメントアウトしている。textareaで表示するとHTMLコードは改行なしの連続した内容で生成されている。

テキストエディタQuill.jsのカスタマイズで画像保存、POST送信の準備、説明画像2

jsで文字列を置き換えでもいいですが、Cookieに保存したデータがあるので、ここではPHP処理で改行を追加して整形しています。

PHP


//Cookieの内容をtextarea用に整形する
	$content ="";//修正更新したいHTML内容
	$get_html_data ="";//HTML表示用に訂正後の内容
 
	if($_COOKIE["text"] ==""){
		setcookie('text',$content,time()+60*60*1*0);//60秒x60分
	}else{
		$content = $_COOKIE["text"];
		$content = str_replace("<p><br></p>", "\n\n" ,$content );
		$content = str_replace("<br>", "\n" ,$content );
		$content = str_replace("</p>", "</p>\n" ,$content );
		$content = str_replace("<tr>", "\n<tr>" ,$content );
		$content = str_replace("\n</td>", "</td>" ,$content );
		$content = str_replace("<table>", "\n<table>\n" ,$content );
		$content = str_replace("</table>", "</table>\n\n" ,$content );
		$content = str_replace("</tbody>", "\n</tbody>\n" ,$content );
		$content = str_replace("<h2>", "\n<h2>" ,$content );
		$content = str_replace("</h2>", "</h2>\n" ,$content );
		$content = str_replace("<h3>", "\n<h3>" ,$content );
		$content = str_replace("</h3>", "</h3>\n" ,$content );
		$content = str_replace("</blockquote>", "</blockquote>\n" ,$content );
		
		//コード部分の書き換え
		$content = str_replace('<div class="ql-code-block-container" spellcheck="false"><div class="ql-code-block" data-language="plain">', "\n\n\<pre><code>\n" ,$content );
		$content = str_replace('</div></div>', "\n</code></pre>\n" ,$content );
		
		setcookie('post_data',$content,time()+60*60*1*0);//60秒x60分
	}//end_if

改行コードを追加してHTMLコードの状態でもみやすくした。

テキストエディタQuill.jsのカスタマイズで画像保存、POST送信の準備、説明画像3

更新日:

Quill.jsでテーブルを追加拡張するサンプルコード

テキストエディタQuill.jsのカスタマイズで画像保存、POST送信の準備、説明画像4

面倒なtableを追加してくれる拡張モジュールを作ってくれた方がいますね。quilljs v2.0.0-dev.3が必要です。テーブルモジュールの実装を説明してくれているサイトもあるので参考に。

テーブルの追加参考サイト Quill 2.0 Table Demoプログラムコード

読み込むjsを変更する

せっかくなのでオリジナルアイコンをsvgでつくってみました。

テーブル追加拡張したことでToolの部分が少し変更しているので、コードごとサンプルを参考にどうぞ。

HTML


<head>

	<script src="https://cdnjs.cloudflare.com/ajax/libs/quill/2.0.0-dev.3/quill.min.js" type="text/javascript"></script>
	<link href="https://cdnjs.cloudflare.com/ajax/libs/quill/2.0.0-dev.3/quill.snow.min.css" rel="stylesheet">

	<script src="https://unpkg.com/quill-table-ui@1.0.5/dist/umd/index.js" type="text/javascript"></script>
	<link href="https://unpkg.com/quill-table-ui@1.0.5/dist/index.css" rel="stylesheet">

</hrad>

<body>
	<!-- 内容の全削除ボタン -->
	<button style="float:right;" onClick="Delete()">入力内容を削除</button>

<!-- 独自toolbar -->
<div id="toolbar-container" class="ql-toolbar ql-snow">
	<!-- 画像 -->
	<button id="btn_img_Upload" >
		<svg viewBox="0 0 228 183"><rect x="16" y="25" width="198" height="141" fill="#fff"/>
		<path d="M208,30V160H21V30H208m11-11H10V171H219V19Z"/>
		<polygon points="26 153 64 109 99 134 141 87 199 123 199 153 26 153"/><circle cx="66" cy="73" r="18"/></svg>					
	</button>

	<!-- テーブル -->
	<button id="btnTable">	
		<svg viewBox="0 0 228 183">
		<rect x="22" y="29" width="183" height="133" fill="none" stroke="#000" stroke-miterlimit="10" stroke-width="4"/>
		<line x1="22" y1="75" x2="205" y2="75" fill="none" stroke="#000" stroke-miterlimit="10" stroke-width="2"/>
		<line x1="22" y1="117" x2="205" y2="117" fill="none" stroke="#000" stroke-miterlimit="10" stroke-width="2"/>
		<line x1="82" y1="29" x2="82" y2="162" fill="none" stroke="#000" stroke-miterlimit="10" stroke-width="2"/>
		<line x1="143" y1="29" x2="143" y2="162" fill="none" stroke="#000" stroke-miterlimit="10" stroke-width="2"/></svg>
	</button>
</div>
<!-- 独自toolbar -->


<!-- quill-editor  -->
<div id="app">
	<!-- Quill main -->
	<div id="editor_area" onInput="showPreview1()"></div>
</div>


<script>


/*--- 追加ボタン ---*/

//画像アップ
document.getElementById('btn_img_Upload').addEventListener('click', function() {
  console.log(quill.getContents());
});

//テーブル追加
document.getElementById('btnTable').addEventListener('click', function() {
  let table = quill.getModule('table');
  console.log(table);
  table.insertTable(3, 3);
});


/*---- 公式ツールバー -------*/

//--- Tool設定 ---*/
var toolbarOptions = [
  [{ header: [ 2, 3,false] }],
  ['bold', 'italic', 'underline', 'strike'],        // toggled buttons
  /* [{ 'size': ['small', false, 'large', 'huge'] }],  // custom dropdown*/
  ['blockquote', 'code-block'],
  ['link'],
 /* ['image'],*/
  ['video'],
  [{ 'list': 'ordered' }, { 'list': 'bullet' }],     // superscript/subscript
  [{ 'align': [] }],
  [{ 'color': [] }, { 'background': [] }],          // dropdown with defaults from theme
 /* ['clean']                                         // remove formatting button*/
];

//-- Tool表示 ---*/
Quill.register({
  'modules/tableUI': quillTableUI.default
}, true)

const quill  = new Quill('#editor_area', {
  bounds: '#edito',
  modules: {
	table: true,
	tableUI: true,
	toolbar: this.toolbarOptions,
	history: {
		delay: 10,
		maxStack: 10,
		userOnly: true
	},
  },
  placeholder: 'ここに記事を入力します',
  theme: 'snow'
});


/*---- テーブル追加js ------*/

var bubble = new Quill('#bubble-container', {
  theme: 'bubble',
  modules: {
    table: true,
  }
});
var snow = new Quill('#snow-container', {
  theme: 'snow',
  modules: {
    table: true,
    tableUI: true
  }
});
var output = new Quill('#output-container', {
  theme: 'bubble',
  modules: { table: true },
  readOnly: true,
})
bubble.on('text-change', function(delta, old, source) {
  if (source === 'user') {
    snow.updateContents(delta, 'api');
    updateOutput();
  }
});
const table = snow.getModule('table');
snow.on('text-change', function(delta, old, source) {
  if (source === 'user') {
    bubble.updateContents(delta, 'api');
    updateOutput();
  }
});


function updateOutput() {
  const bubbleContent = bubble.getContents();
  const snowContent = snow.getContents();
  // TODO compare
  output.setContents(bubbleContent);
  const outputContent = output.getContents();
  // TODO compare outputContent
}

document.querySelector('#insert-table').addEventListener('click', function() {
  table.insertTable(3, 3);
});



/*-- Delete()  --*/

function Delete(){
	
	//----------------
	//Cookie削除
	//----------------
	document.cookie =  "text=; expires=0";//Cookieを削除する

	//--------------------
	//エディタを空にする
	//--------------------
	quill.setContents([
		{ insert: '' },//文字列の空をセット
		{ insert: '\n' }//コンテンツに再セットするとき最後に改行をセットする。
	]);
}


</script>




</body>

テーブル拡張を追加したらonchangeが発火しない

quill公式の内容に合わせて発火方法を変更した。

Java Script


//---------------------------------
//Quillエディタに変更があれば発火
//---------------------------------
quill.on('text-change', function(delta, oldDelta, source) {

	//ここに処理を記載する

	//取得したQuillエディタの内容はtext変数にセット
	var text = document.querySelector('.ql-editor').innerHTML;
});

Quill.jsをカスタマイズするためのAPI一覧

最初は複雑そうにみえて、わかってくると、カスタマイズ自由度が高くてQuill用のjsを考えるのがそれなりに楽しい。

さらにカスタマイズするために、Quill.js独自のAPI一覧を紹介したサイトがあったので参考に。

参考https://cly7796.net テキストエディタQuill.jsのカスタマイズで画像保存、POST送信の準備、説明画像5 Quill公式API

更新日:

Quillで画像のWEBサーバー保存方法とalt追加、画像サイズを追加する方法

Quill標準のimageツールバーでは、WEBサーバーに一時保存している状態。ここから、目的のディレクトリに画像を保存する。

独自設置のImgアイコンから画像を保存する

上記のプログラムで画像svgアイコンを設置していました。この独自Imgアイコンをクリックしたときに、画像を追加するなら次のようなQuillのinsertEmbedメソッドで追加が可能。エディタエリアに画像が挿入される。

Java Script


//Quillのエディタエリアに画像を挿入
document.getElementById('btn_img_Upload').addEventListener('click', function() {
	var img_dir = '../img/test_img.png'; //imgの相対ディレクトリ 
	quill.insertEmbed(10, 'image', img_dir );
}, false);

imgタグにalt属性とサイズheight,widthを追加して、画像のwidthとheight値を追加したい。方法はいくつかある。

(1)Quill標準のimageを利用。POSTをSBに保存する際に、画像をサーバーに保存する。

(2)画面移行せずに、Ajaxを使って画像をサーバーに保存する。

(3)サーバーにActive Storageを用意する。

(4)別ウインドウで画像保存する。

結果、別ウインドウで画像を保存する方法を選択。alt文を追加するテキストエリアが必要だったので、ここでは別ウインドウ呼出することにした。別ウインドウの画面を作ることで、Quillに限らず、画像を保存する処理を、色々な箇所で使い回せます。

PHPでサーバー保存するメリットはJSだけのバリテーションチェックするよりもセキュリティ面でも良かったから。

子ウインドウ側でサーバーに画像を保存すれば、親ウインドウにjsの値を受け渡しが簡単に出来るので、エディタに画像を挿入する際も楽です。上記のように、QuillをCookie保存しながら入力できる仕様にしたので、画面移行していたも問題はないのですが。別ウインドウ側もCSSでカラーを変えれば、それなりに、良い感じになります。

別ウインドウ非推奨対策

別ウインドウを読み出しはGoogleChromeでは非推奨なので、予め、PHPで別ウインドウ部分のファイルをPHPでinclude読込にしておいて、通常は非表示にする。別ウインドウ部分は、アラートにしたり、非表示にしていて、onclickで表示に切り替えるという方法が簡単。

テキストエディタQuill.jsのカスタマイズで画像保存、POST送信の準備、説明画像6

imのaltの追加をjsでアラートを呼出て追加する場合

アラートでalt属性を追加する方法は、既に行っている方がいたので、翻訳されたページがあるので参考に。

アラートでalt属性設置の参考

Java Script


//super.createで画像タグを作成
class CustomImage extends BlockEmbed {
  static create (value) {
    let node = super.create()
    let img = document.createElement('img')
    img.setAttribute('alt', value.alt || '')
    img.setAttribute('src', value.url)
    node.appendChild(img)
    return node
  }
static formats (node) {
    let format = {}
    // do something with format for example format.alt = node.setAttribute('alt')
    // it's need to save changes in Delta
    return format
}
// also need to define static value
static value (node) {
    return {
      alt: node.getAttribute('alt'),
      url: node.getAttribute('src')
    }
  }
// and "public" typical method in JS
format (name, value) {
  if (name === 'alt') {
    this.domNode.alt = value
  }
}

imgかどうかのチェックをjsで

Java Script


document.addEventListener('click', e => {
  if (e.target.tagName.toUpperCase() === 'IMG') {
    // just open popup and pass to it all settings from your blot image
    // for get all props from image use let blot = Parchment.find(e.target)
    // read more about this below
  }
}

画像のプロパティを取得して、画像のDOM要素を直接変更せず、ブロット(履歴)を使用し、てalt属性を追加している。

Java Script


import Parchment from 'parchment'
let blot = Parchment.find(this.currentImg)
// blot contain all what you need, all properties
// and you can change them in this way:
blot.format('alt', e.target.value)

DBに保存を読み出し、内容をQuillに再表示する方法

もし、Quillで表示している見た目そのままを表示ページでも使うなら、Quillと同じクラスを用意する。

PHP


<div class="ql-snow">
    <div class="ql-editor">
        <?php echo $dataFromDb; ?>
    </div>
</div>
タイトルとURLをコピーしました