propellerkitでリストのアコーディオン実装

はじめに

アコーディオンとは、クリックすると隠れていたコンテンツがずる〜っと現れるアレです。
今回はこのアコーディオンを作成していきます。

完成形はこちらです。
f:id:haruka-i1997:20170830151519g:plain


利用するもの

・propellerkit Accordion
 propeller.in

リストデザイン

まずはリストのデザインを見ていきましょう。

以下の記事を参考にさせていただきました。
weboook.blog22.fc2.com


main.html

<div>
  <ul class="menu">
     <li>
        <a>メニュー1</a>
     </li>
     <ul>
         <li><a>メニュー1-A</a></li>
         <li><a>メニュー1-B</a></li>
         <li><a>メニュー1-C</a></li>
     </ul>
     <li>
         <a>メニュー2</a>
     </li>
     <ul>
         <li><a>メニュー2-A</a></li>
         <li><a>メニュー2-B</a></li>
         <li><a>メニュー2-C</a></li>
     </ul>
     <li>
        <a>メニュー3</a>
     </li>
     <ul>
        <li><a>メニュー3-A</a></li>
        <li><a>メニュー3-B</a></li>
        <li><a>メニュー3-C</a></li>
     </ul>
  </ul>
</div>


main.css

.menu {
    width: 500px;
    padding: 0;
    margin: 30px;
}
.menu li {
    overflow: hidden;
    border-bottom: 1px solid #fff;
    cursor: pointer;
}

.menu li a {
    display: block;
    position: relative;
    padding: 0px 10px 0px 50px;
    background: #f2f2f2;
    color: #494949;
    font-size: 14px;
    line-height: 40px;
}

.menu li a:before {
    display: block;
    content: "";
    position: absolute;
    top: 50%;
    left: 25px;
    width: 8px;
    height: 8px;
    margin-top: -4px;
    border-radius: 50%;
    background: #457B9D;
    transition-property:all;
    transition: 0.2s linear;
    color: #494949;
}
.menu li a:hover:before {
    left: -16px;
    width: 50px;
    height: 50px;
    margin-top: -25px;
    transition-property:all;
    transition: 0.2s linear;
    color: #494949;
}


まだアコーディオンは実装していないのでこんな感じです。
クリックしても変化はありません。
f:id:haruka-i1997:20170830153330p:plain


それでは、これからアコーディオンの実装をしていきます。

main.html

<div>
  <ul class="menu">
     <li href="#/main#menu1" data-toggle="collapse">
        <a>メニュー1</a>
     </li>
     <ul id="menu1"class="panel-collapse collapse">
         <li><a>メニュー1-A</a></li>
         <li><a>メニュー1-B</a></li>
         <li><a>メニュー1-C</a></li>
     </ul>
     <li href="#/main#menu2" data-toggle="collapse">
         <a>メニュー2</a>
     </li>
     <ul id="menu2"class="panel-collapse collapse">
         <li><a>メニュー2-A</a></li>
         <li><a>メニュー2-B</a></li>
         <li><a>メニュー2-C</a></li>
     </ul>
     <li href="#/main#menu3" data-toggle="collapse">
        <a>メニュー3</a>
     </li>
     <ul id="menu3"class="panel-collapse collapse">
        <li><a>メニュー3-A</a></li>
        <li><a>メニュー3-B</a></li>
        <li><a>メニュー3-C</a></li>
     </ul>
  </ul>
</div>


大体は上記URLにあるpropellerkitサイトの通りです。
が、説明のため必要でない箇所は極力省いています。


ポイント解説

liタグにある

data-toggle="collapse"

これはアコーディオンコンポーネント
この一文がなければ開閉の動作ができません。

同じくulタグにある

class="panel-collapse collapse"

これもアコーディオンの実装に大切なコードです。
なくても開閉動作はできますが若干挙動がおかしくなります。
安定した動作のためにも書いておく方が良いですね。

ちなみに

class="panel-collapse collapse in"

最後に「in」を入れると、開いた状態が初期状態となります。


liタグにある

href="#/main#menu1"

ここで、親リストをクリックした際に、どの子リストを開閉するのかを決定します。

「#/main」がhtmlのページの名前です。
「#menu1」が子リストの名前です。

子リストの名前は、ulタグにある

id="menu1"

このようにidで指定します。

こうすることで、親リストと子リストが結びつき、
クリックした親リストに結びついている子リストのみが開閉されます。

因みに上記で書いた「#/main」の部分ですが、
これはAngularJSで$routeProviderを使用している時のみ必要となります。

$routeProviderを使用しているときは、
定義しているhtmlの名前をhrefに含めないと
全く違うページに飛ばされてしまう場合があるからです。


さいごに

これでリストのアコーディオン実装は終了です。
ごく基本の形しか書いていないので、色々オプションをつけたいときは上記URLの公式ページで見てください。

以上です。

自作Markdown記法とプレビュー機能の作り方



Markdown記法とは

はてなブログやQiitaなど様々なところで使われている記法です。

Markdown(マークダウン)は、文書を記述するための軽量マークアップ言語のひとつである。本来はプレーンテキスト形式で手軽に書いた文書からHTMLを生成するために開発されたものである。 (wikipedia引用)

例えば、「*タイトル*」と書くと「タイトル」と表示されるような感じです。

今回は、Markdown記法で書かれた文章をhtmlに変換し、
プレビュー機能で文章を表示するところまでを紹介します。



利用するもの

・AngularJS
 プレビュー機能の作成に利用します。
 ※当記事ではAngularJSの知識をある程度持っていることを前提で進めていきます。
 AngularJS — Superheroic JavaScript MVW Framework

・propellerkit
 プレビュー機能の作成に利用します。
 propeller.in




MarkdownをHTMLに変換

今回考えたMarkdown記法は以下の通りです。

Markdown記法 表示結果
#titleタイトル#
タイトル
%red赤い文字% 赤い文字
*bold太い文字* 太い文字
_under下線_ 下線
※あくまで分かりやすさ優先で考えたのでhtmlで書くより面倒なものもあります^^;

さっそくMarkdownで入力された文章をhtmlに変換する処理を作成していきます。
ここでは仮処理として、ボタンが押されたらMarkdownをhtmlに変換するようにします。

ここからAngularJSを利用していきます。

htmlはこちら

<textarea type="text" cols="120" rows="20"ng-model="content"></textarea>
<button type="button" ng-click="convert();"> 変換 </button >


Javascriptはこちら

$scope.content = "";
function convert(){
 var convertContent = $scope.content;
 console.log(convertContent) //変換処理前
 /*変換処理*/
  //タイトル
   convertContent = convertContent.split('#title').join("<div style='font-size:20px;font-weight:bold;'>");
    convertContent = convertContent.split('#').join("</div>");
  //赤い文字
    convertContent = convertContent.split('%red').join("<span style='color:red;'>");
    convertContent = convertContent.split('%').join("</span>");
  //太文字
    convertContent = convertContent.split('*bold').join("<b>");
    convertContent = convertContent.split('*').join("</b>");
  //下線
    convertContent = convertContent.split('_under').join("<u>");
    convertContent = convertContent.split('_').join("</u>");
 
  console.log(convertContent) //変換処理後
}

※AngularJSの基本的な部分は省略しています。


単純なので簡単に説明します。

まず変換ボタンが押されると、「ng-click」にある「convert」関数が動作され、
変換処理がはじまります。

変換処理ではjavascriptの「split」メソッドと「join」メソッドを利用しています。

例えば、入力されたMarkdownの中に「#title」という文字列が含まれていた場合。
まずは「split」メソッドを使って、この文字列を除去します。
次に「join」メソッドを使って、除去した箇所に対応するhtmlを追加します。

このようにすることで、Markdownをhtmlの形に変換することができます。
(だいぶんゴリ押しですが...)

実際にコンソールを使って、変換処理前と変換処理後の文章を比べてみましょう。

例えば、以下のような文章をフォームに入力したとします。

#titleタイトルです#

%red赤い文字です%

*bold太い文字です*

_under下線付きです_


コンソール結果は以下の通りです。

【変換前】

#titleタイトルです#

%red赤い文字です%

*bold太い文字です*

_under下線付きです_

【変換後】

<div style='font-size:20px;font-weight:bold;margin-bottom:-10px;'>タイトルです</div>

<span style='color:red;'>赤い文字です</span>

<b>太い文字です</b>

<u>下線付きです</u>


Markdownの部分がhtmlに変換されていることがわかります。

以上で、Markdownをhtmlに変換する処理が完成しました。
次に、htmlに変換した文章をプレビューで表示する機能を作成していきましょう。



まずはプレビューを表示していきましょう。

上記で仮処理としていた「変換」ボタンを「プレビュー」ボタンに変更し
ボタンが押されたらプレビューのダイアログが表示される機能を作成してきます。

ここでは、propellerkitのModalを利用します。
propeller.in



それでは早速htmlを見ていきましょう。

<textarea type="text" cols="120" rows="20"ng-model="content"></textarea>
<button type="button" data-target="#preview-dialog" data-toggle="modal" ng-click="preview()"> プレビュー </button >
<!--プレビューダイアログ-->
<div tabindex="-1" class="modal fade" id="preview-dialog" aria-hidden="true">
        <div class="modal-dialog modal-lg" >
            <div class="modal-content">
                <div class="modal-header pmd-modal-bordered">
                    <button aria-hidden="true" data-dismiss="modal" class="close"type="button">×</button>
                    <h2 class="pmd-card-title-text">プレビュー</h2>
                </div>
                <p>ここに文章が表示されます</p>
            </div>
        </div>
</div>


ダイアログの表示方法は、上記リンクのpropellerkit公式ページを見ていただいた方が早いかと思います。

実際に「プレビュー」ボタンが押されると、このようなダイアログが表示されます。
f:id:haruka-i1997:20170828145804p:plain


それでは、いよいよhtmlに変換した文章をプレビューで表示していきたいと思います。

htmlは以下の通りです。
1箇所のみ変更しています。

<div tabindex="-1" class="modal fade" id="preview-dialog" aria-hidden="true">
        <div class="modal-dialog modal-lg" >
            <div class="modal-content">
                <div class="modal-header pmd-modal-bordered">
                    <button aria-hidden="true" data-dismiss="modal" class="close"type="button">×</button>
                    <h2 class="pmd-card-title-text">プレビュー</h2>
                </div>
                <p ng-bind-html="previewContent"></p>
            </div>
        </div>
</div>


Javascriptは以下の通りです。
ここも変更点は1箇所のみです。

$scope.content = "";
$scope.previewContent = "";
function preview(){
 var convertContent = $scope.content;
 /*変換処理*/
  //タイトル
   convertContent = convertContent.split('#title').join("<div style='font-size:20px;font-weight:bold;'>");
    convertContent = convertContent.split('#').join("</div>");
  //赤い文字
    convertContent = convertContent.split('%red').join("<span style='color:red;'>");
    convertContent = convertContent.split('%').join("</span>");
  //太文字
    convertContent = convertContent.split('*bold').join("<b>");
    convertContent = convertContent.split('*').join("</b>");
  //下線
    convertContent = convertContent.split('_under').join("<u>");
    convertContent = convertContent.split('_').join("</u>");

   $scope.previewContent= $sce.trustAsHtml(convertContent); 
}


htmlの変更点は

<p ng-bind-html="previewContent"></p>

のみです。
ここでjavascript側で変換したhtmlを反映します。

Javascriptは、最後の

$scope.previewContent= $sce.trustAsHtml(convertContent); 

を追加したのみです。

htmlで「ng-bind-html」を利用する際には、反映したいhtmlを
「$sce.trustAsHtml」を利用してエスケープしてあげる必要があります。
(しなければエラーが出てしまいます)

プレビューの表示結果は以下の通りです。
f:id:haruka-i1997:20170828152459p:plain

無事に表示されました。

しかし、改行や空白がきちんとされていない点が気になります。
ですので、javascriptで以下の処理を追加してみます。

$scope.content = "";
$scope.previewContent = "";
function preview(){
 var convertContent = $scope.content;

 /*改行・空白処理*/
    convertContent = convertContent.replace(/\r?\n/g, "<br>");
    convertContent = convertContent.replace(/\s+$/g,"");

 /*変換処理*/
  //タイトル
   convertContent = convertContent.split('#title').join("<div style='font-size:20px;font-weight:bold;'>");
    convertContent = convertContent.split('#').join("</div>");
  //赤い文字
    convertContent = convertContent.split('%red').join("<span style='color:red;'>");
    convertContent = convertContent.split('%').join("</span>");
  //太文字
    convertContent = convertContent.split('*bold').join("<b>");
    convertContent = convertContent.split('*').join("</b>");
  //下線
    convertContent = convertContent.split('_under').join("<u>");
    convertContent = convertContent.split('_').join("</u>");
    console.log(convertContent)

   $scope.previewContent= $sce.trustAsHtml(convertContent); 
}

改行・空白処理を追加しました。
ここではJavascriptの「replace」メソッドを利用しています。

まず1つめ

convertContent = convertContent.replace(/\r?\n/g, "<br>");

では、改行文字「/\r?\n/g」があれば改行コードに変換しています。

2つめの

convertContent = convertContent.replace(/\s+$/g,"");

では、空白文字「/\s+$/g」があれば空白に変換しています。


コンソールの表示結果は以下の通りです。

<div style='font-size:20px;font-weight:bold;margin-bottom:-10px;'>タイトルです</div><br><br><span style='color:red;'>赤い文字です</span><br><br><b>太い文字です</b><br><br><u>下線付きです</u>

改行している箇所にはしっかりと「br」タグが挿入されていることがわかります。


プレビューでの表示結果は以下の通りです。
f:id:haruka-i1997:20170828154409p:plain

先ほどとは違い、きちんと改行されていることがわかります。

以上でプレビュー機能が完成しました。



おわりに

今回は主にjavascriptのメソッドを使用し、Markdownからhtmlへの変換処理を作成しました。
一度作成してしまえば、少し面倒なhtmlも自作のMarkdown記法でスイスイ書くことができると思います。
ぜひお試しください。

AngularJSでいいねボタン作成


利用するもの


AngularJS
 ボタンクリック時などの各種機能を作る際に利用します。
 ※当記事は、AngularJSをある程度理解していることを前提で書いています。
 AngularJS — Superheroic JavaScript MVW Framework


propellerkit
 いいね数を表示するバッジを作る際に利用します。
 propeller.in 

font awesome icons
 いいねボタンのデザインを作る際に利用します。
 fontawesome.io



ボタンデザイン

 完成形がこちらになります。
 f:id:haruka-i1997:20170827230209p:plain

 早速HTMLを見てみましょう。

<div data-badge=0 class="material-icons pmd-md pmd-badge pmd-badge-overlap">
 <i class="fa fa-thumbs-up fa-lg" aria-hidden="true"></i>
</div>


 単純ですが少し解説してみます。

<i class="fa fa-thumbs-up fa-lg" aria-hidden="true"></i>

 この部分が  にあたります。

<div data-badge=0 class="material-icons pmd-md pmd-badge pmd-badge-overlap">
</div>

 この部分が青色のバッジにあたります。
 バッジをつけたい箇所に囲むかたちで使用します(今回は  ですね)

 「data-badge」の部分でバッジに表示する値を代入します。
 今は仮処理として初期値である「0」を代入しています。

 
 

クリックすると値が増える機能

 例えば
 f:id:haruka-i1997:20170827230209p:plain
 この状態でボタンをクリックすると

  f:id:haruka-i1997:20170827234342p:plain
 こうなる
 要はバッジの数が1つずつ増えていく機能です。

 ここからはAngularJSを利用していきます。
 
 ざざっとコードを見ていきましょう。
 まずはHTMLです。

<div data-badge={{good}} class="material-icons pmd-md pmd-badge pmd-badge-overlap">
<i class="fa fa-thumbs-up fa-lg" aria-hidden="true" ng-click="clickEvalute()"></i>
</div>


 次にJavascriptです。

$scope.good = 0; 
function clickEvalute(){
 $scope.good += 1;
}

 ※AngularJSの基本的なところは省いています。


 こちらも単純ですのでざっくりと解説します。
 
 ポイントは主に2つあります。

 1つ目は「data-badge」の部分です。
 先ほどは仮処理として直接「0」を代入していましたが、これを「{{good}}」におきかえ、
 javascript側で「good」に初期値の「0」をセットしました。
 
 2つ目は「ng-click」の部分です。
 ボタンをクリックするとjavasciptの「clickEvalute」関数が動作し、
 「good」に1が加算されます。
 加算した結果は「data-badge」の部分に反映されます。

 以上で「クリックすると値が増える機能」が完成です。



クリックするとデザインが変わる機能

 例えば
 f:id:haruka-i1997:20170827234342p:plain
 この状態でボタンをクリックすると

  f:id:haruka-i1997:20170828001639p:plain
 色が薄くなります。
 クリックしたかどうかを判別しやすくなります。

 この機能もAngularJSを利用します。

 まずはHTMLです。

<div data-badge={{good}} class="material-icons pmd-md pmd-badge pmd-badge-overlap">
<i class="fa fa-thumbs-up fa-lg" aria-hidden="true" ng-click="clickEvalute()"ng-style="goodStyle"></i>
</div>

 
 次にJavascriptです。

$scope.good = 0; 
$scope.goodStyle = "";
function clickEvalute(){
 $scope.good += 1;
 $scope.goodStyle = {color:'gray'};
}


 変更点は「ng-style」の部分のみです。
 ボタンをクリックして「clickEvalute」関数が動作すると、
 「goodStyle」にクリック後のスタイルが代入されます。
 これが「ng-style」に反映されることで、デザインを変更することができます。 
 
 
 

1度しかクリックできない機能

 一般的な「いいねボタン」は一度に何回もクリックできるものではないので、
 一度クリックすると、その後はバッジの値もデザインも変化しないようにしたいですね。

 色々とやり方はありますが、恐らく一番単純なのがフラグを利用する方法だと思います。

 変更するのはJavascriptのみです。

$scope.good = 0; 
$scope.goodStyle = "";
$scope.goodFlag = false;
function clickEvalute(){
 if(!$scope.goodFlag){
  $scope.good += 1;
  $scope.goodStyle = {color:'gray'};
  $scope.goodFlag = true;
 }
}


 「goodFlag」の初期値をfalseにして、
 「clickEvalute」関数が動作したときに「goodFlag」がfalseならば
 バッジの値とデザインの変更を行います。
 
 最後に、1度クリックした証として「goodFlag」をtrueにすれば
 2度目以降に「clickEvalute」関数が動作したときには、バッジの値やデザインの変更が
 行われない仕組みとなっています。

 
 本当は「ng-disabled」を使った方法を利用したかったのですが、
 調べてみるとbuttonにしか動作しない(?)ようなので、このような方法となりました。


 案外単純で簡潔なコードで作ることができて驚きです。
 ng-styleを使えばもっと色々なデザインが作れそうですね。
 時間があれば他の方法も模索していきたいと思います。
 
 以上です。
 
 

グローバルナビの作り方

こんな感じのやつ

f:id:haruka-i1997:20170717113442p:plain

機能としては

  • クリックしたナビに下線
  • ナビに応じて画面内容も変更
くらいかなあ。
調べてみると色々なやり方があったけど、今回は主にAngularJSのng-styleを使用してみた。
もっと効率の良い方法があると思うので見つけ次第変更していく予定。

 

html

<ul class="globalNav">
  <li ng-click="indexCtrl.method.clickNav(1);"/>
    <a ng-href="./#/introduction" ng-style="indexCtrl.value.style.styleTop">
       <strong>トップ</strong>
       <span>Top</span>
    </a>
  </li>
  <li ng-click="indexCtrl.method.clickNav(2);">
    <a ng-href="./#/main" ng-style="indexCtrl.value.style.styleCourse">
       <strong>コース</strong>
       <span>Course</span>
    </a>
  </li>
  <li ng-click="indexCtrl.method.clickNav(3);" style="margin-left:-5px;">
    <a ng-href="./#/myPage" ng-style="indexCtrl.value.style.styleMyPage">
    <strong>マイページ</strong>
    <span>My Page</span>
    </a>
 </li>
</ul>

クリックしたナビはng-hrefで各画面に遷移できる


javascript

function clickNav(nav){
            if(nav == 1){
                $scope.indexCtrl.value.style.styleTop = {borderBottom:'solid #457B9D'};
                $scope.indexCtrl.value.style.styleCourse = {borderBottom: '#fff'};
                $scope.indexCtrl.value.style.styleMyPage = {borderBottom: '#fff'};
            }else if(nav == 2){
                $scope.indexCtrl.value.style.styleCourse = {borderBottom:'solid #457B9D'};
                $scope.indexCtrl.value.style.styleTop = {borderBottom: '#fff'};
                $scope.indexCtrl.value.style.styleMyPage = {borderBottom: '#fff'};
            }else{
                $scope.indexCtrl.value.style.styleMyPage = {borderBottom:'solid #457B9D'};
                $scope.indexCtrl.value.style.styleTop = {borderBottom: '#fff'};
                $scope.indexCtrl.value.style.styleCourse = {borderBottom: '#fff'};
            }
};

クリックしたナビ番号(仮)をng-clickでjavaScriptに飛ばし、番号に従ってng-styleを設定する。
今回はクリックしたナビに下線を引く処理なので、クリックしたナビには{borderBottom:'solid #457B9D'}のように、下線に色をつけるように設定する。
その他のナビには{borderBottom: '#fff'}で白に初期化する。

まとめると、もっと効率良い方法がある気がしてならん。
時間があったら他の方法も検討していきたい。