DashboardのテンプレートAdminLTEをElectronで動かす（Tablesページの改造）

# 概要
前回「[DashboardのテンプレートAdminLTEをElectronで動かす](https://qiita.com/h6591/items/d0ffb515c35c0b885991)」で無事表示することが出来たので、`Tables`メニューの`Data tables`のページを改造します。テーブルデータはテンプレートで使われている内容をJSONの外部ファイルにして読み込むようにします。実際はMongoDBを使って実装したのですが、MongoDBを知らない人には試せないのでJSONファイルでの投稿にしました。また、テーブル表示には[Tabulator](http://tabulator.info/)を使ます。JSONデータの送受信は**IPC**で行いますので**preload**を使います。

# テーブルデータのJSONファイル化

改造するファイルは`AdminLTE-2.4.10/pages/tables/data.html`で、`<table>`タグで記述されているデータをJSONファイルにします。

1. `data.html`のデータ部分をテキストエディタにコピペする
1. Javascriptのコードを付加してプログラムを作成します
1. **Node.js**で作成したプログラムを実行して`JSONファイル(data.json)`を作成します

まず初めにデータは`data.html`ファイルの`542行目から948行目`までテキストエディタにコピペします。

```html:テキストエディタ
<tr>
  <td>Trident</td>
  <td>Internet
    Explorer 4.0
  </td>
  <td>Win 95+</td>
  <td> 4</td>
  <td>X</td>
</tr>
～省略～
<tr>
  <td>Other browsers</td>
  <td>All others</td>
  <td>-</td>
  <td>-</td>
  <td>U</td>
</tr>
```

次にコピペしたHTMLを`<table> ...  </table>`で挟んでhtml変数にします。そして**cheerio**を使ってHTMLからデータを取り出してJSON化するプログラム`data.js`を作成します。
**cheerio**を使ったプログラムは「[Node.js で html の表の中身を CSV 形式に加工する](https://qiita.com/daktu32/items/f3f31d1691d0f10380ca)」を参考にしました

```javascript:data.js
var html = `
<table>
<tr>
  <td>Trident</td>
  <td>Internet
    Explorer 4.0
  </td>
  <td>Win 95+</td>
  <td> 4</td>
  <td>X</td>
</tr>
                ～省略～
<tr>
  <td>Other browsers</td>
  <td>All others</td>
  <td>-</td>
  <td>-</td>
  <td>U</td>
</tr>
</table>
`
const cheerio = require('cheerio')
$ = cheerio.load(html)
$('tr').each((i,tr)=>{
    let data=[]
    $(tr).children().each((j,td) => {
        data.push($(td).html())
    })
    let json={engine:data[0], browser:data[1], platform:data[2],version:data[3],css:data[4]}
    console.log(JSON.stringify(json))
})
```
**cheerio**をインストール後、`data.js`を実行して`data.json`ファイルを作成します。`data.json`は`AdminLTE-2.4.10`フォルダに作成します。

```shell
npm install cheerio --save-dev
node data.js > data.json
```

実行した結果`data.json`の内容は次のようになります。最初の4件は`browser`のところに改行が入っていますが元のデータに入っているので修正はしていません。

```json:data.json
{"engine":"Trident","browser":"Internet\n    Explorer 4.0\n  ","platform":"Win 95+","version":" 4","css":"X"}
{"engine":"Trident","browser":"Internet\n    Explorer 5.0\n  ","platform":"Win 95+","version":"5","css":"C"}
{"engine":"Trident","browser":"Internet\n    Explorer 5.5\n  ","platform":"Win 95+","version":"5.5","css":"A"}
{"engine":"Trident","browser":"Internet\n    Explorer 6\n  ","platform":"Win 98+","version":"6","css":"A"}
{"engine":"Trident","browser":"Internet Explorer 7","platform":"Win XP SP2+","version":"7","css":"A"}
```

`data.json`は正確にはJSONではありません。一行一行はJSONですが全体としてはJSONではありませんので注意してください。

# Tabulatorのインストール

インストールは次のURLを参照してください
http://tabulator.info/docs/4.2/install

```shell
npm install tabulator-tables --save
```

# main.jsの改造、preload.jsの追加、data.htmlの改造

## main.jsの改造内容

- `preload.js`を作成して`BrowserWindow`のパラメータとして`preload`項目を追加する
- `ipcMain.On`でRendererプロセスからのipc通信で`data.js`を読んでRendererプロセスにデータを渡す

```javascript:main.js
const { app, BrowserWindow } = require('electron')
const path = require('path')
const { ipcMain } = require('electron')
const fs = require('fs')
const readline = require('readline');

// data.htmlのjavascriptからのファイル名を受信してJSONデータを読んで送信
ipcMain.on('ipc-json', (event, file)=>{
  let replyData = []
  let rs = fs.createReadStream(file, 'utf8')
  let reader = readline.createInterface({input: rs})
  reader.on('line', data => {
    replyData.push(JSON.parse(data))
  }).on('close' , () => {
    event.sender.send('ipc-json-reply', replyData)
  })
})

let mainWindow

function createWindow() {
  mainWindow = new BrowserWindow({
    show: false, backgroundColor: '#FFF', width: 1600, height: 1000, frame: true,
    webPreferences: {
      nodeIntegration: false,
     //preload.jsを指定
      preload: path.join(__dirname, 'preload.js')
    }
  })

  mainWindow.loadFile('index.html')

  mainWindow.once('ready-to-show', () => { mainWindow.show() })
  mainWindow.on('closed', function () {
    mainWindow = null
  })
}

app.on('ready', createWindow)

app.on('window-all-closed', function () {
  if (process.platform !== 'darwin') {
    app.quit()
  }
})

app.on('activate', function () {
  if (mainWindow === null) {
    createWindow()
  }
})
```

## preload.jsの追加

Rendererプロセスで`ipcRenderer`を`gIpcRenderer`として使えるようにします。`preload.js`は`AdminLTE-2.4.10`フォルダに作成します。

```javascript:preload.js
gIpcRenderer = require('electron').ipcRenderer
```

## AdminLTE-2.4.10/pages/tables/data.htmlの改造

`530行目から960行目`を次の一行に置き換えます。

```html:AdminLTE-2.4.10/pages/tables/data.html.html
            <!-- /.box-header -->
            <div id="example-tabulator"></div>
            <!-- /.box-body -->
```

次に`Tabulator`用のJavascriptとcssを`<head>`部に指定します。

```html:AdminLTE-2.4.10/pages/tables/data.html.html
  <link href="../../node_modules/tabulator-tables/dist/css/tabulator.min.css" rel="stylesheet">
  <script src="../../node_modules/tabulator-tables/dist/js/tabulator.min.js"></script>
```

次の`<!-- Tabulator用Javascript -->`以降の`<script> ... </script>`を`data.html`の最後のほうに追加します。

```html:AdminLTE-2.4.10/pages/tables/data.html.html
<script>
    $(function () {
      $('#example1').DataTable()
      $('#example2').DataTable({
        'paging'      : true,
        'lengthChange': false,
        'searching'   : false,
        'ordering'    : true,
        'info'        : true,
        'autoWidth'   : false
      })
    })
  </script>

<!-- Tabulator用Javascript -->
  <script>
    gIpcRenderer.on('ipc-json-reply', (event, arg) => {
      let table = new Tabulator("#example-tabulator", {
        data: arg,
        layout: "fitColumns",
        pagination: "local",
        paginationSize: 10,
        columns:[
          {title:"Rendering engine", field: "engine"},
          {title:"Browser", field:"browser"},
          {title:"Platform(s)", field:"platform"},
          {title:"Engine version", field: "version", align:"right"},
          {title: "CSS grade", field: "css", align:"center", formatter:"html"}
        ]
      });
    })
    gIpcRenderer.send('ipc-json', "data.json")
  </script>
</body>

</html>
```

- gIpcRendererは`preload.js`で定義した変数です
- gIpcRenderer.Onで`main.js`が送信したデータを受信します。`arg`にJSONデータの配列が入っています。
- gIpcRenderer.sendでメインプロセスに読み込みたいファイル名を送ります。結果はgIpcRenderer.Onで受信します
- `formatter:"hmtl"`となっているのは`CSS grade`データの中に`C/A<sup>1</sup>`というHTMLデータあり**C/A<sup>1</sup>**と表示させるためです

# 実行画面
![adminlte3.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/258007/ccab5fd9-2f84-881c-6216-1a65b00e9d9f.png)

# 参照リンク
- 前回投稿記事　[DashboardのテンプレートAdminLTEをElectronで動かす](https://qiita.com/h6591/items/d0ffb515c35c0b885991)
- [AdminLTE](https://adminlte.io/)
- [Tabulator](http://tabulator.info/)
- [Node.js で html の表の中身を CSV 形式に加工する](https://qiita.com/daktu32/items/f3f31d1691d0f10380ca)