Sencha Ext JS 6 のツリーリスト その2

Sencha Advent Calendar 2015 23日目
http://www.adventar.org/calendars/1041

## ツリーリストをいじってみる

こんにちは。xenophyの菅井です。
昨日ぶりです。今日も昨日に引き続きツリーリストについて書いていきます。

前回まではツリーリストの表示と「micro」モードとの切り替えまでできていました。
今日はツリーリストの仕上げとして下記の改造をしていきます。

* ツリーリストのベースの色を設定する
* 通常モードと「micro」モードを切り替えた時のガタガタを無くす

## ツリーリストのベースの色を設定する

今日はツリーリストの見た目の部分を主に修正していきます。
ExtJSのスタイルはsassで書かれているのでツリーリスト用にsassファイルを作成し
そこにスタイルを追記していきます。

sassのファイルは下記のディレクトリに配置します。
`~/extjs-6-treelist/classic/sass/src/view/navigation/Main.scss`

sassファイルはViewが置かれているディレクトリに対応していて
今回は下記のツリーリストのViewがあるディレクトリに`sass`を追加した感じですね。
`~/extjs-6-treelist/classic/src/view/navigation/Main.js`

#### 変数

それでは早速sassを書いていきましょう。
まずはツリーリストのベースとなる色を決めます。

下記のファイルを作成しsassで利用する変数を宣言します。
今回はツリーリストでベースになる色とテキストの色を宣言しました。
ファイル名： `~/extjs-6-treelist/classic/sass/var/Application.scss`
ソース:

```
  // ツリーリストのベースになる色
  $navigation-base-color: #242925;
  
  // ツリーリストのテキストの色
  $navigation-text-color: #32e53b;
```

#### サイドバーパネルの色

次に昨日空にした下記のsassの中にサイドバーパネルの色の設定を追記します。
サイドバーの色はツリーリストのベースの色と同じにしています。
ファイル名：`~/extjs-6-treelist/classic/sass/src/view/main/Main.scss`
ソース:

```
  .sidebar > .x-panel-body {
  	background-color: $navigation-base-color;
  }
```

* 本来ならツリーリストのViewとこのサイドバーのパネルは
同じファイルにまとめて`ui`を作るべきでしたが、気づいた時にはもう遅かったのです。

#### ツリーリストの色

次に先ほど作成したツリーリストのsassファイルに下記の追記をします。
それぞれどの部分の指定かはざっくりコメントに書いているので確認してみてください。
細かい変数の意味はだいたいベースになる色と`over`と付く奴はマウスオーバー時の色
`selected`は選択時の色といった形になっています。
今回はベースの色に上記で設定した変数の色を指定し、選択時はそこから少し明るく
マウスオーバー時はさらに明るく、ツリーの階層を開けているときは逆に
ベースから暗い色にしています。
ファイル名：`~/extjs-6-treelist/classic/sass/src/view/navigation/Main.scss`
ソース:

```
  @include treelist-ui(
    $ui: 'navigation',
  
    // 通常モードの設定
    $background-color: $navigation-base-color,
    $row-over-background-color: lighten($navigation-base-color, 20%),
    $row-selected-background-color: lighten($navigation-base-color, 10%),
  
    // microモードの設定
    $toolstrip-background-color: $navigation-base-color,
    $tool-selected-background-color: lighten($navigation-base-color, 10%),
  
    // 階層を開けている時の背景色
    $item-expanded-background-color: darken($navigation-base-color, 10%),
  
    // リスト内の項目
    $item-text-color: $navigation-text-color,
    $item-text-over-color: lighten($navigation-text-color, 20%),
  
    // リストアイコン
    $item-icon-color: $navigation-text-color,
    $item-icon-over-color: lighten($navigation-text-color, 20%),
  
    // 開閉アイコン
    $item-expander-color: $navigation-text-color,
    $item-expander-over-color: lighten($navigation-text-color, 20%)
  );
```
#### Viewへの適用

sassを書いたらそのクラス名やui名をViewに指定します。
それぞれ下記のように設定していきます。

サイドバーパネルには下記のように`cls`を設定

    {
        // サイドバー部分のパネル
        xtype   : 'panel',
            region  : 'west',
        width   : 300,
        name    : 'sidebar',
        cls     : 'sidebar',
        items   : [{
            xtype: 'navigation'
        }]
    });

ツリーリストには下記のように`ui`を設定

    Ext.define('ExtJs6TreeList.view.navigation.Main', {
        extend: 'Ext.list.Tree',
        xtype: 'navigation',
    
        requires: [
            'ExtJs6TreeList.view.navigation.MainController',
            'ExtJs6TreeList.view.navigation.MainModel',
    
            'ExtJs6TreeList.store.Navigation'
        ],
    
        store: {
            type: 'navigation'
        },
    
        ui: 'navigation'
    });


#### ビルド

sassを修正した後はビルドが必要なので下記のコマンドを叩きます。
この後のsass編集後の画面確認の前には毎回行って下さい。
> % `sencha app build`

#### 画面表示

ここまでできたら一旦画面で確認します。
sassで設定した結果こんな感じでカラーリングされました。
初期状態よりもだいぶモード同士の統一感と動きのメリハリが付いています。

![micromode](https://i.gyazo.com/a270a16c74b1c2bf8207e76158dd052b.png)

## 通常モードと「micro」モードを切り替えた時のガタガタを無くす

上記の画像を見てもらってもわかりますが現在それぞれのモードを切り替えた時
シームレスに表示が入れ替わっているように見えません。
理由としては通常モード時に左側に階層の開閉アイコンが表示されているため
その分リストが右に寄っているので左側にぴったり付いている「micro」モードと
リスト表示の位置が違うせいですね。

#### 開閉アイコンを右に寄せる

まず位置をずらさなければならない理由になっている開閉アイコンを右に寄せます。
下記のようにツリーリストのsassにスタイルを追記します。
`ui`の変数ではそのような設定は見当たらなかったので普通のsassの形で書きます。
ちなみに下記のセレクタですが`ui`で`navigation`という名前を付けているので
ツリーリストには`x-treelist-navigation`という名前のクラスが自動で当たっています。

```
  @include treelist-ui(
    $ui: 'navigation',
  ~省略~
  );

  .x-treelist-navigation {
    // 開閉アイコンの位置を左から右へ
    .x-treelist-item-expander {
      left: auto;
      right: 0;
    }
  }
```

するとまず開閉アイコンが右に寄りました。

![micromode](https://i.gyazo.com/0aed33b18df2f415c1846be032e20e50.png)

#### アイコンとテキストを左に寄せる

開閉アイコンを右に寄せたのでリストの左側に余白ができました。
ここを詰めて「micro」モードの位置と合わせたいと思います。
sassにアイコンとテキストの表示位置を変更する設定を追記します。

```
  .x-treelist-navigation {
    // 開閉アイコンの位置を左から右へ
    .x-treelist-item-expander {
      left: auto;
      right: 0;
    }
  
    // テキストを左に寄せる 40pxから25pxへ
    .x-treelist-item-text {
      margin-left: 25px;
    }
  
    // リストアイコンの余白を無くす
    .x-treelist-item-icon {
      left: 0;
    }
  }
```

ここで再度モード同士を並べてみます。
通常モードのリストが左によったおかげで
アイコンの位置が同じになり切り替えがシームレスに見えるようになりました！

![micromode](https://i.gyazo.com/69a68b5aa01065c5342d70bc5ad0cf9e.png)

## おまけ

ここまでできたら既にだいぶ完成しているんですが、最後にもう少しだけ見栄えがよくなるよう
ちょっとだけいじっていきます。

修正する点としてはリストのレコードが狭いのでもう少し高くしてあげるのと
選択されているレコードがよりわかりやすくなるよう横にラインを出してあげます。

ツリーリストの`ui`にそれぞれ下記の変数を追記します。

```
  @include treelist-ui(
    $ui: 'navigation',
  ~省略~
    // 操作しやすくなるようレコードを高くする
    $item-line-height: 50px,
  
    // 通常モードのマウスオーバー時と選択時に横にラインを出す
    $row-indicator-width: 3px,
    $row-indicator-selected-color: $navigation-text-color,
    $row-indicator-over-color: lighten($navigation-text-color, 10%),
  
    // microモードのマウスオーバー時と選択時に横にラインを出す
    $tool-float-indicator-width: 3px,
    $tool-float-indicator-color: lighten($navigation-text-color, 10%),
    $tool-indicator-selected-width: 3px,
    $tool-indicator-selected-color: $navigation-text-color
  );
```

表示すると以下のようになります。
さっきよりも若干見栄えがいい感じになったと思います。
どうでしょうか。ナビゲーションぽくなったでしょうか。

* 高さはもう少しあったほうがかっこいいかもしれないですね。

![micromode](https://i.gyazo.com/aa2f57053c894accac72b715bbd65dbb.png)

## さいごに

昨日今日と２日かけてツリーリストについて書いてきましたが
今回触ってみた部分以外にもまだ色々やれることがあるので
興味が湧いたという方は触って頂いて色々実験してみてもらえると幸いです。

ちなみにExt JS 6 の`Ext.list.Tree`のドキュメントには上記で紹介したcss-mixinの記述が無いので
私はSDKのソースを見ながら触っていました。
今回のアプリケーションの中だと下記ファイルの`treelist-ui`の部分になります。
`~/extjs-6-treelist/ext/packages/core/sass/src/list/TreeItem.scss`

あと今回は使っていませんがドキュメントの「Events」の中にはなぜか高さと幅が変わった時のイベントしか書いてなくて
リストを選択したときのイベントってどうするんだろうと思ってはまっていたんですが
これもSDKのjsのソースをみたら`'selectionchange'`を`fireEvent`していたので
下記のようにリッスンしてあげたらうまく動きました。

    listeners: {
    	selectionchange: 'onSelectionChange'
    }

まとめなんだか、なんだかよくわからなくなりましたが
ツリーリストについては以上になります。
読んで頂きありがとうございました。
それではまた来年（？）メリークリスマス！よいお年を！！:)