WEB上のソースコードに、シンタックスハイライトを導入(highlight.js)

目的
読みやすさ向上のため、記事内に書くプログラムコード等に、シンタックスハイライトをつけたい。
導入するライブラリ
highlight.jsを導入します。
ダウンロード
TOPページのGet version XX.XX.XXをクリックします。

移動先のページで、
- CDNを利用する
- ダウンロードする
- npmからインストールする
についての説明があります。
今回は、ダウンロードで利用しますので、「Custom package」のところまでスクロールします。

ここで、必要な言語を含めた分でダウンロードできます。
必要最小限に絞ることで、容量を減らすことにも繋がります。
(追加する時は、選択を増やして改めてダウンロードすれば良いので)
チェックできたら、ダウンロードボタンを押して、zipファイルを取得。
解凍後、任意の場所に設置します。

例:Laravelを利用して作った当ブログの場合
+ public
+ js
+ highlight
+ styles
+ atom-one-dark-reasonable.min.css
+ highlight.min.js
テーマの選択
スタイルを選択します。
デモページがあるので、確認して使用するテーマを決めます。

HTML側の対応
HTML側で、jsとテーマCSSを読み込みます。
以下は、このブログにて実装した際の記述です。
{{-- コードハイライト --}}
<link rel="stylesheet" href="{{ asset('/js/highlight/styles/atom-one-dark-reasonable.min.css') }}">
<script type="text/javascript" src="{{ asset('/js/highlight/highlight.min.js') }}" charset="UTF-8"></script>
<script>hljs.highlightAll();</script>
Laravelでブログサイトを作る 21. 管理画面・記事のプレビュー機能

目的
記事編集途中に、プレビュー表示して確認したい。
ルーティング
routes/web.php
プレビュー用のルーティングを追加します。更新と同様に、入力値をPOST送信する予定です。
// ...省略...
Route::group(['prefix' => 'admin', 'middleware' => 'auth', 'namespace' => 'App\\Http\\Controllers\\'], function() {
// ...省略...
Route::post('articlePreview', 'ArticleController@preview')->name('admin_article_preview'); // プレビュー
// ...省略...
});
テンプレート
resources/views/admin/articleEdit.blade.php
プレビューボタンを設置します。
更新する時と同じく、入力内容をsubmitします。
{{-- 省略 --}}
<form method="post">
{{-- 省略 --}}
<input type="button" id="preview" value="プレビュー" />
<input type="button" id="update" value="{{ isset($articleData->id) ? '更新' : '登録' }}" />
</form>
{{-- 省略 --}}
<script>
$(document)
.on('click', '#preview', function(){
$(this).parents('form').attr('action', '{{ route('admin_article_preview') }}').attr('target', '_blank');
$(this).parents('form').submit();
})
.on('click', '#update', function(){
$(this).parents('form').attr('action', '{{ route('admin_article_update') }}').attr('target', '');
$(this).parents('form').submit();
})
;
</script>
Controller
app/Http/Controllers/ArticleController.php
記事詳細表示の共通化
フロントの記事詳細画面と、プレビュー表示で共通化できる部分が多いので、先に対応します。
(記事の詳細表示するcontent()の一部分を抜き出す。抜き出した箇所にはreturn $this->articleView($articleData, $articleChildrenData);を記述する)
/**
* 記事1件分のページ表示(フロントの記事詳細と、管理画面のプレビュー機能から)
* @param $articleData
* @param $articleChildrenData
* @return mixed
*/
private function articleView($articleData, $articleChildrenData) {
// 親カテゴリを取得
$parentCategoryList = $this->parentCategory->orderBy('number', 'asc')->orderBy('id', 'asc')->get();
// 子カテゴリは、キーを親カテゴリIDにした連想配列にする
$data = $this->childCategory->orderBy('number', 'asc')->orderBy('id', 'asc')->get();
$childCategoryList = [];
foreach ($data as $item) {
$childCategoryList[$item->parent][] = $item;
}
// 目次対応
$articleData->body = $this->makeIndex($articleData->body);
return view('front.article', [
'articleData' => $articleData,
'articleChildrenData' => $articleChildrenData,
'parentCategoryList' => $parentCategoryList,
'childCategoryList' => $childCategoryList,
'parentNum' => $this->getParentArticleNum(),
'childNum' => $this->getChildArticleNum(),
'newArticleData' => $this->getNewArticleList(),
]);
}
プレビュー表示
内容はシンプルで、
- 入力値を取得して変数に格納する
- 本来はDBから取得する記事データを、入力値にする
- JOINで取得する親カテゴリ名を別途取得してセットする
- 記事と関連付けられている子カテゴリは、入力値から子カテゴリのリストとして取得する
という感じです。
これらの情報を、先程の共通化メソッドに渡してやれば、ページ表示できます。
/**
* プレビュー表示更新
*
* @param Request $request
* @return mixed
*/
public function preview(Request $request)
{
// 入力値取得
$id = $request['id'];
$tiitle = $request['title'];
$body = $request['body'];
$parent = $request['parent'];
$childList = $request['child'];
$open = $request['open'];
$private = $request['private'];
$description = $request['description'];
// 記事取得
$articleData = new Article();
$articleData->title = $tiitle;
$articleData->body = $body;
$articleData->parent = $parent;
$articleData->open = $open;
$articleData->private = $private;
$articleData->description = $description;
// 親カテゴリ名を保持させる
$parentData = $this->parentCategory->where('id', $parent)->first();
$articleData->name = $parentData->name;
// 記事と関連付けられている子カテゴリの情報を取得
$articleChildrenData = null;
if (is_array($childList)) {
$articleChildrenData = $this->childCategory->whereIn('id', array_keys($childList))->get();
}
return $this->articleView($articleData, $articleChildrenData);
}
Laravelでブログサイトを作る 20. DBに後からカラムを追加する

目的
記事に、Meta用の項目"Description"を設定できるようにしたい。
(設計する時に考慮しきれなかった部分に対応する)
migration
migrationファイルの作成
サーバに入り、コマンドを実行します。
- meta情報を追加するので、ファイルの名前は"add_meta_to_article"にします。
--table=で、追加するテーブルを指定します。
php artisan make:migration add_meta_to_article --table=articles
migrationファイルの内容を記述
database/migrations/XXXX_XX_XX_XXXXXX_add_meta_to_article.php
テーブル作成の時と同様に、up()に追加する項目を記述します。
// ...省略...
public function up()
{
Schema::table('articles', function (Blueprint $table) {
$table->text('description'); // 追加:ディスクリプション
});
}
// ...省略...
migration実行
php artisan migrate
これで、テーブルにカラムが追加されました。
テンプレートの修正
記事編集画面
resources/views/admin/articleEdit.blade.php
編集画面に、それぞれの入力欄を設置します。
// ...省略...
<form action="{{ route('admin_article_update') }}" method="post">
// ...省略...
<h3>Description</h3>
<input type="text" name="description" value="{{ $articleData->description ?? '' }}" />
// ...省略...
</form>
// ...省略...
共通テンプレート
resources/views/app.blade.php
headタグ内に、@yield('meta')だけ記載することで、各テンプレートでMetaタグを自在に設定できるようになります。
存在しない場合は、何も表示されませんので、既存のテンプレートを修正しなくてもエラーが出たりはしないので、必要な箇所にのみ記述するだけで良いのです。
<head>
// ...省略...
@yield('meta')
// ...省略...
</head>
記事の表示画面
resources/views/front/article.blade.php
// ...省略...
@section('meta')
<meta name="description" content="{{ $articleData->description }}" />
@endsection
// ...省略...
Controller
記事編集
app/Http/Controllers/ArticleController.php
入力されたDescriptionを取得して、テーブルに保存します。
なお、未入力であれば、記事の冒頭100文字を抽出して保存するようにします。
/**
* 記事情報更新
*
* @param Request $request
* @return mixed
*/
public function update(Request $request)
{
// 入力値取得
$id = $request['id'];
$tiitle = $request['title'];
$body = $request['body'];
$parent = $request['parent'];
$childList = $request['child'];
$open = $request['open'];
$private = $request['private'];
$description = $request['description'] ?? mb_substr(strip_tags($body), 0, 100);
// ...省略...
// トランザクション開始
DB::beginTransaction();
try {
// 記事データ保存
$articleData = $this->article->withTrashed()->where('id', $id)->first();
if ($articleData === null) {
$articleData = new Article();
}
$articleData->title = $tiitle;
$articleData->body = $body;
$articleData->parent = $parent;
$articleData->open = $open;
$articleData->private = $private;
$articleData->description = $description;
$articleData->save();
// ...省略...
} catch (\Exception $e) {
// ...省略...
}
}
Laravelでブログサイトを作る 19. 管理画面・記事編集の時に、画像をアップロードできるように(TinyMCE)

はじめに
前回にて実装したTinyMCEの機能を利用して、記事の編集中に画像をアップロードする仕組みを用意します。
サーバー側での対応
Laravelのディレクトリ構造から考えまして、画像は、storageディレクトリ(storage/app/public)に保存するべきと考えました。
しかし、このディレクトリを参照することはできません。
そこで、以下のコマンドを実行しておきます。
$ php artisan storage:link
これで、public/storageにシンボリックリンクが作成されますので、storage/***.jpgのようにして画像を表示できます。
$ ls -l public/
(省略) storage -> /home/vagrant/blog/storage/app/public
TinyMCEでアップロードできるようにする
resources/views/admin/articleEdit.blade.php
前回実装したTinyMCSの記述を修正します。
<script src="{{ asset('/js/tinymce/tinymce.min.js') }}"></script>
<script>
tinymce.init({
selector:'textarea',
language: "ja", // 日本語対応(https://qiita.com/nissuk/items/e31bdfa858d6c5c018c2)
// ▼画像アップロード対応(https://www.tiny.cloud/docs/configure/file-image-upload/)
plugins: 'image code',
toolbar: 'undo redo | link image | code',
image_title: true, // イメージダイアログのタイトルフィールドを有効にする
automatic_uploads: true, // ブロブやデータのURIで表現された画像の自動アップロードを可能にする
images_upload_url: '{{ route('admin_article_image_upload') }}?_token={{ csrf_token() }}',
file_picker_types: 'image',
relative_urls : false, // 画像やリンクのパスが相対パスに変換されるのを防ぐ
convert_urls: false,
/* カスタムイメージピッカー */
file_picker_callback: function (cb, value, meta) {
var input = document.createElement('input');
input.setAttribute('type', 'file');
input.setAttribute('accept', 'image/*');
input.onchange = function () {
var file = this.files[0];
var reader = new FileReader();
reader.onload = function () {
var id = 'blobid' + (new Date()).getTime();
var blobCache = tinymce.activeEditor.editorUpload.blobCache;
var base64 = reader.result.split(',')[1];
var blobInfo = blobCache.create(id, file, base64);
blobCache.add(blobInfo);
cb(blobInfo.blobUri(), { title: file.name });
};
reader.readAsDataURL(file);
};
input.click();
},
content_style: 'body { font-family:Helvetica,Arial,sans-serif; font-size:14px }'
});
</script>
アップロードされた画像を保存する
ルーティング
routes/web.php
アップロードするルーティングを追加します。
Route::group(['prefix' => 'admin', 'middleware' => 'auth', 'namespace' => 'App\\Http\\Controllers\\'], function() {
// ...省略...
Route::post('articleImageUpload', 'ArticleController@image')->name('admin_article_image_upload'); // 画像アップロード
// ...省略...
});
Controller
app/Http/Controllers/ArticleController.php
アップロードされた画像を保存し、パスを返却します。
/**
* 画像アップロード
*
* @param Request $request
* @return false|string
*/
public function image(Request $request) {
// ファイルの保存(戻り値はファイル名)
$imgpath = request()->file('file')->store('', 'public');
// 画像パスを返却
return json_encode(['location' => '/storage/' . $imgpath]);
}
参考文献
https://www.tiny.cloud/docs/configure/file-image-upload/
https://qiita.com/kawa_matsu/items/50306befb7a5f879e38e
https://readouble.com/laravel/7.x/ja/structure.html
Laravelでブログサイトを作る 18. 管理画面・記事編集の際に入力補助を(TinyMCE)

はじめに
記事を編集する際に、HTMLの入力補助を行えるようにします。
様々なライブラリが存在しますが、TinyMCEを使用します。
画像のアップロード機能を組み込むことができるので(次回解説予定)、という理由で
選定しました。
導入方法
- JSファイルをダウンロードし、
public/jsに配置する- CDNを使うと、日本語化で手こずる懸念と、バージョンアップに引きずられて問題が発生する可能性があるため、ファイルをダウンロードします。
- テンプレートファイルに、JSの読み込みと初期化構文を記述する
1. JSファイルのダウンロード
ダウンロードは、コチラから可能です。
ページ中程にある「Download TinyMCE Community」から本体を、「Download Language Pack」から日本語パックをダウンロードし、解凍します。
本体は、public/jsに配置します。
その後、langディレクトリに日本語パックのja.jsを移動します。
最終的には、以下のような形です。
public/
└ js/
└ tinymce/
├ lang
| └ ja.js ←日本語パックから移動
└ その他、jquery.tinymce.min.js など
テンプレート
resources/views/admin/articleEdit.blade.php
JSファイルの読み込みと、初期化についての記述を追加するだけで、便利なTinyMCEが使えるようになります。
日本語化せずにCDNを使う場合は、前述のダウンロード云々もスキップできるので、非常に簡単です。
@section('adminMain')
{{-- 省略 --}}
<h3>記事本文</h3>
<textarea name="body">{{ $articleData->body ?? '' }}</textarea>
{{-- 省略 --}}
<script src="{{ asset('/js/tinymce/tinymce.min.js') }}"></script>
<script>
tinymce.init({
selector:'textarea',
language: "ja"
});
</script>
@endsection
参考文献
TinyMCEを設置する
https://qiita.com/nissuk/items/e31bdfa858d6c5c018c2
