1. HOME
  2. フロントエンド
  3. a-blog cmsで吹き出しを使った会話コンテンツ

a-blog cmsで吹き出しを使った会話コンテンツ

フロントエンド

なぜか偶然にもa-blog cmsを始めて3年弱ですが会話型のコンテンツ?インタビュー的なコンテンツ?のような要は吹き出しでしゃべっている風なコンテンツを作る機会が割と多く、作る度に悩んでいた問題が自分の中である程度完結したのでそのメモです。
もちろんまだまだ改良の余地はたくさんありますが。

今までの実装方法

今までは、カスタムユニットとユニットの拡張機能を使用して
「インタビュアー」「インタビュイー」のような2つのカスタムユニットを作成していました。
これらのデータは各エントリーのカスタムフィールドとして毎回登録をします。
この方法で問題となったのが数点。

  • 3人以上での対話には対応ができない
  • ユニット入力画面で誰の会話を入力しているのは判別しづらい
  • エントリー毎に人の登録が必要

実装方法

今回実装した方法はポイントは3点。

  • 共通項目(画像など)はブログカスタムフィールドなど1箇所にまとめる
  • カスタムユニットは1つ作成
  • 誰の吹き出しのユニットなのかを視認しやすいように

今回は「画像と吹き出しのみ」で会話コンテンツ作って行きます。
もちろん追加で登録をできるようにすれば画像の下に名前を出したりもできます。


入力画面

表示の例


今回の完成目標は上記のようにラジオボタンで視覚的にわかりやすく、選択しやすく入力画面を作成し、吹き出しで会話をしているように表示をすることです。


ブログのカスタムフィールド

人の画像を全てブログのカスタムフィールドに登録をできるようにします。(カテゴリーなどでもOK◎)
ブログのカスタムフィールドで登録した画像をエントリーのユニット入力画面で選択できるようにすることで
見た目にも誰がしゃべっているユニットなのかわかりやすくなります。

カスタムフィールドメーカーのカスタムフィールドグループで画像を登録するフィールドを作成します。

[テーマ] > [admin] > [blog] > [field.html]
に貼り付けます。

<h2 class="acms-admin-admin-title2">人物設定</h2>
<table class="js-fieldgroup-sortable adminTable acms-admin-table-admin-edit">
	<thead class="acms-admin-hide-sp">
	<tr>
		<th class="acms-admin-table-left acms-admin-admin-config-table-item-handle">&nbsp;</th>
		<th class="acms-admin-table-left">人物画像</th>
		<th class="acms-admin-table-left acms-admin-admin-config-table-action">削除</th>
	</tr>
	</thead>
	<tbody>
	<!-- BEGIN person:loop -->
	<tr class="sortable-item">
		<td class="item-handle"><i class="acms-admin-icon-sort"></i></td>
		<td class="js-img_resize_cf">
			<!-- BEGIN_IF [{person_img@path}/nem] -->
			<div>
				<img src="%{ARCHIVES_DIR}{person_img@path}" class="js-img_resize_preview">
			</div>
			<input type="hidden" name="person_img@old[{i}]" value="{person_img@path}" />
			<!-- ELSE -->
			<div>
				<img src="" class="js-img_resize_preview" style="display:none;">
			</div>
			<!-- END_IF -->
			<input type="file" name="person_img[{i}]" class="js-img_resize_input" /><br />
		</td>
		<td><input type="button" class="item-delete acms-admin-btn-admin acms-admin-btn-admin-danger" value="削除" /></td>
	</tr>
	<!-- END person:loop -->
	<tr class="sortable-item item-template">
		<td class="item-handle"><i class="acms-admin-icon-sort"></i></td>
		<td class="js-img_resize_cf">
			<img src="" style="display:none;" class="js-img_resize_preview"/>
			<input type="file" name="person_img[]" class="js-img_resize_input" /><br />
		</td>
		<td><input type="button" class="item-delete acms-admin-btn-admin acms-admin-btn-admin-danger" value="削除" /></td>
	</tr>
	</tbody>
	<tfoot>
	<tr><td colspan="3"><input type="button" class="item-insert acms-admin-btn-admin" value="追加" /></td>
	</tr>
	</tfoot>
</table>
<input type="hidden" name="@person[]" value="person_img@alt" />
<input type="hidden" name="@person[]" value="person_img@path" />
<input type="hidden" name="@person[]" value="person_img@x" />
<input type="hidden" name="@person[]" value="person_img@y" />
<input type="hidden" name="@person[]" value="person_img@edit" />
<input type="hidden" name="@person[]" value="person_img@old" />
<input type="hidden" name="person_img:extension" value="image" />
<input type="hidden" name="@person[]" value="person_img" />
<input type="hidden" name="field[]" value="person_img" />
<input type="hidden" name="field[]" value="@person" />

管理画面の設定


[管理画面] > [コンフィグ] > [編集設定] から下記のように追加をします。


次に [管理画面] > [コンフィグ] > [ユニット設定] から該当ユニット箇所で「吹き出し」というボタンをクリックします。
上記のようにグレーのボックスが追加されたら設定完了です。

カスタムユニット


今回は1つなのでカスタムユニットの作成で可能ですが、普段はユニットの拡張機能のみを使用しています。
普段案件ではカスタムユニットは0か2つ以上のことが多いためユニットの拡張のみで作成しています。
サクッとコピペで使えるようにユニットの拡張機能で実装方法を紹介します。


カスタムユニットでは

  • 人物選択
  • 配置(左・右)
  • 吹き出しの色(赤・青)
  • テキスト

を設定できるようにしています。
人物選択は1つ前の手順で作成したブログのカスタムフィールドに登録した画像を選択できるようラジオボタンで用意します。
a-blog cmsにはラジオボタンを左にアイコン形式ではなくボタンにするスタイルが用意されているため
そちらを使用して画像をクリックして選択できるようにします。

カスタムフィールドメーカーのカスタムユニットでソースを生成します。
今回は下記のようなフィールドにしています。(ラジオボタンは後にカスタマイズするため1つくらいのダミーでOK◎)


入力欄の種類 タイトル フィールド(変数)
ラジオボタン 人物選択 speech_balloon_character
セレクトボックス 配置 speech_balloon_arrangement
セレクトボックス speech_balloon_color
テキストエリア テキスト speech_balloon_text

人物選択ラジオボタン部分をブログのカスタムフィールドの情報が出力できるようカスタマイズを行います。
元のソースはこのような感じ

<div class="acms-admin-form-radio">
    <input type="radio" name="speech_balloon_character{id}" value="personA"{speech_balloon_character:checked#personA} id="input-radio-speech_balloon_character-personA-{id}" />
     <label for="input-radio-speech_balloon_character-personA-{id}"><i class="acms-admin-ico-radio"></i>人物A</label>
</div>
<input type="hidden" name="unit{id}[]" value="speech_balloon_character{id}" />

カスタマイズのポイントは3点のみ!

  • {id}をエスケープする
  • valueとcheckedをブログのカスタムフィールドの変数に
  • idとforに連番を付与する

{id}をエスケープする

{id}を全て【speech_balloon_character\{id\}】のようにエスケープをさせます。
こうすることでブログのカスタムフィールドの変数として解決されてしまうのを防ぎます。

valueとcheckedをブログのカスタムフィールドの変数に

今回ラジオボタンで選択した画像のパスを渡したいため、valueを【{person_img@path}】に変更します。
またcheckedについてもvalueと一致しているかを見るため【{person_img@path}】に変更します。

idとforに連番を付与する

{id}をエスケープ(例:input-radio-speech_balloon_character-\{id\})しただけではloopで表示したラジオボタン全てが同じ画像になってしまうためうまく選択することができません。

loop内では{i}で連番を出力することができるためidとforそれぞれに{i}を記述します。

例:input-radio-speech_balloon_character_{i}-\{id\}

上記のようにカスタマイズをすると下記のようなソースになります。
これを
[テーマ] > [admin] > [entry] > [unit] > [extend.html]
に記述しましょう。

<!-- BEGIN custom_speech_balloon -->
<table class="entryFormTable acms-admin-table-entry">
	<tr>
		<th>人物選択</th>
		<td>
			<!-- BEGIN_MODULE Blog_Field -->
			<!-- BEGIN person:loop -->
			<div class="acms-admin-form-radio">
				<input type="radio" name="speech_balloon_character\{id\}" value="{person_img@path}"\{speech_balloon_character:checked#{person_img@path}\} id="input-radio-speech_balloon_character_{i}_\{id\}" class="acms-admin-btn-radio" />
				<label for="input-radio-speech_balloon_character_{i}_\{id\}"><img src="%{HTTP_ARCHIVES_DIR}{person_img@path}" width="100" /></label>
			</div>
			<!-- END person:loop -->
			<input type="hidden" name="unit\{id\}[]" value="speech_balloon_character\{id\}" />
			<!-- END_MODULE Blog_Field -->
		</td>
	</tr>
	<tr>
		<th>配置</th>
		<td>
			<select name="speech_balloon_arrangement{id}" class="acms-admin-form-width-mini">
				<option value=""> - </option>
				<option value="right"{speech_balloon_arrangement:selected#right}>右</option>
				<option value="left"{speech_balloon_arrangement:selected#left}>左</option>
			</select>
			<input type="hidden" name="unit{id}[]" value="speech_balloon_arrangement{id}" />
		</td>
	</tr>
	<tr>
		<th>色</th>
		<td>
			<select name="speech_balloon_color{id}" class="acms-admin-form-width-mini">
				<option value=""> - </option>
				<option value="blue"{speech_balloon_color:selected#blue}>青</option>
				<option value="red"{speech_balloon_color:selected#red}>赤</option>
			</select>
			<input type="hidden" name="unit{id}[]" value="speech_balloon_color{id}" />
		</td>
	</tr>
	<tr>
		<th>テキスト</th>
		<td>
			<textarea name="speech_balloon_text{id}" class="acms-admin-form-width-full">{speech_balloon_text}</textarea>
			<input type="hidden" name="unit{id}[]" value="speech_balloon_text{id}" />
			<span class="emoji-edit"></span>
		</td>
	</tr>
</table>
<!-- END custom_speech_balloon -->

入力画面は下記のような感じになるはずです。
ラジオボタンが1つ1つ押せるか必ず確認をしてみましょう。ラジオボタンがちゃんと選択できない場合にはidとforの設定がきちんとできていない場合があります。


ラジオボタンをアイコンではなくボタンにすることで、選択したことがわかりやすいようにしています。

表示テンプレート

表示側のテンプレートについては
[テーマ] > [include] > [unit] > [extend.html]
に記述をしてください。
自由にHTMLやCSSをつけて実装ください。
下記のHTMLとCSSで簡単なものはできるようになっていますので、ご利用していただいても大丈夫です!


このようにHTMLとCSSをつけることで会話をしているように表示をしてみます。

<!-- BEGIN unit#custom_speech_balloon -->
<!-- BEGIN custom_unit:veil -->
<div class="speech_balloon {speech_balloon_arrangement} {speech_balloon_color}">
	<!-- BEGIN speech_balloon_character:veil -->
	<div class="speech_balloon__img-wrap"><img src="%{ARCHIVES_DIR}{speech_balloon_person}" class="speech_balloon__img"></div>
	<!-- END speech_balloon_character:veil -->
	<!-- BEGIN speech_balloon_text:veil -->
	<p class="speech_balloon__text">{speech_balloon_text}[nl2br4html|delnl]</p>
	<!-- END speech_balloon_text:veil -->
</div>
<!-- BEGIN custom_unit:veil -->
<!-- END unit#custom_speech_balloon -->
.speech_balloon {
    display: -webkit-box;
    display: -webkit-flex;
    display: -ms-flexbox;
    display: flex;
    -webkit-box-align: center;
    -webkit-align-items: center;
    -ms-flex-align: center;
    align-items: center;
    margin: 0 0 60px;
}
.speech_balloon__img-wrap {
    width: 120px;
    height: 120px;
}
.speech_balloon__img-wrap .speech_balloon__img {
    width: 100%;
    height: auto;
    vertical-align: bottom;
    border-radius: 50%;
}
.speech_balloon__text {
    -webkit-box-flex: 1;
    -webkit-flex: 1;
    -ms-flex: 1;
    flex: 1;
    max-width: 100%;
    position: relative;
    display: inline-block;
    padding: 20px;
    border-radius: 20px;
}
.speech_balloon__text:after {
    content: '';
    position: absolute;
    height: 0;
    top: 0;
    bottom: 0;
    left: 0;
    margin: auto;
    border: 10px solid transparent;
    border-left-width: 16px;
    border-right-width: 16px;
    -webkit-transform: translateX(-100%);
    -ms-transform: translateX(-100%);
    transform: translateX(-100%);
}
.speech_balloon.blue .speech_balloon__text {
    background: #cfdff9;
}
.speech_balloon.blue .speech_balloon__text:after {
    border-right-color: #cfdff9;
}
.speech_balloon.right.blue .speech_balloon__text:after {
    border-left-color: #cfdff9;
}
.speech_balloon.red .speech_balloon__text {
    background: #fce8e8;
}
.speech_balloon.red .speech_balloon__text:after {
    border-right-color: #fce8e8;
}
.speech_balloon.right.red .speech_balloon__text:after {
    border-left-color: #fce8e8;
}
.speech_balloon.right {
    -webkit-box-direction: reverse;
    -webkit-flex-direction: row-reverse;
    -ms-flex-direction: row-reverse;
    flex-direction: row-reverse;
}
.speech_balloon.right .speech_balloon__text {
    margin: 0 20px 0 0;
}
.speech_balloon.left .speech_balloon__text {
    margin: 0 0 0 20px;
}
.speech_balloon.right .speech_balloon__text:after {
    left: auto;
    right: 0;
    border-left-color: transparent;
    border-right-color: transparent;
    -webkit-transform: translateX(100%);
    -ms-transform: translateX(100%);
    transform: translateX(100%);
}

@media screen and (max-width: 479px) {
    .speech_balloon {
        -webkit-box-align: flex-start;
        -webkit-align-items: flex-start;
        -ms-flex-align: flex-start;
        align-items: flex-start;
        margin: 0 auto 30px;
    }
    .speech_balloon__text:before, .speech_balloon__text:after {
        top: 24px;
        bottom: auto;
    }
    .speech_balloon.right {
        text-align: left;
    }
    .speech_balloon__img-wrap {
        width: 90px;
    }
}

他にもできること

機能を最低限に会話コンテンツを実装して見ましたが他にももう少しカスタマイズをすれば、人ごとに固定の色を決めておいたり、人ごとにグループわけをして色や配置を決めたり..........
まだまだできることはたくさんあると思います!
ぜひこうした方がもっと使いやすい!などなどあればお教えください!

下記にまとめたテンプレートをおいておきましたので参考にしたい方はどうぞ。
今回キャプチャで使用したアイコンについても同包しています。ご使用の際にはreadme.txtをお読みください。