【Kintone】 IPアドレスでソートしたい

Kintoneの一覧画面で、IPアドレスでソートを行いたい。

# 普通にソートするとどうなるか
下の画像のように、IPアドレスだけを持つアプリを作成した。

![Kintone_IPアドレス1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3477571/2cd92d57-9120-ea1f-569a-ae64b5dda7c3.png)

「IPアドレス」ヘッダーをクリックしてソートすると、

![Kintone_IPアドレス2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3477571/5a0e6d66-ffcc-89f8-1b87-a99e8ba884cf.png)

このようにソートされる。
できれば`192.168.1.1`→`192.168.2.1`→`192.168.10.1`の順でソートする方法が欲しい。

# IPアドレスを0パディングする
足りないケタを0で埋めれば思った通りにソートできそうだ。つまり、
- `192.168.1.1`→`192.168.001.001`
- `192.168.2.1`→`192.168.002.001`
- `192.168.10.1`→`192.168.010.001`

のようにする。

Kintoneアプリに0パディング用のフィールドを新たに追加して、0で埋めた値を保存してみた。

![Kintone_IPアドレス3.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3477571/ab1e64ee-fbbf-484f-1dbc-504f3b60c144.png)

新たに追加した方のフィールドでソートすると、

![Kintone_IPアドレス4.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3477571/46f893b7-aa07-c034-35a9-fdf539a4aec5.png)

期待した通りの順番になった。

:::note warn
IPアドレスを0パディングで表記すると8進数として扱われるケースがあるようです。例えば`192.168.010.001`の第3オクテット`010`は、8進数の`10`、10進数の`8`と解釈されることがあります。0パディングはKintone上のソートでの使用に限った方が良いと思われます。
:::

# 面倒くさい
期待通りのソートは実現できたが、全レコード分、値を更新しなければならない。
元のIPアドレスは自分で入力するとして、0パディングは自動で補完されてほしい。

というわけで、JavaScriptでのカスタマイズを使って、レコードの追加時や編集時に元のIPアドレスを変更したら、0パディング用のフィールドに自動で入力されるようにする。

# (前準備)アプリのフィールドコードを設定
先にJavaScript上で指定できるように、各フィールドにフィールドコードを設定する。

今回は、元のIPアドレスを入力するフィールドには`ip_address`、
0パディングしたIPアドレスが入力されるフィールドには`ip_address_0padding`と設定した。

# 実際のコード
というわけで、全文は下記の通りになった。

``` IPアドレスの0パディング.js
(() => {
  "use strict";

  // 0パディング用のフィールドを自動的に補完する
  kintone.events.on(
    [
      // IPアドレスのフィールドの値が変更されたとき
      "app.record.create.change.ip_address",
      "app.record.edit.change.ip_address",
    ],
    (event) => {
      // レコード
      const record = event.record;

      // 0パディング用のフィールドを初期化
      record.ip_address_0padding.value = "";

      // IPアドレス用のフィールドに今入力された値
      const ip = record.ip_address.value;

      // 今入力されたのが空文字なら終わり
      if (!ip?.trim()) {
        return event;
      }

      // 今の入力されたのがIPアドレスかどうか判定する
      if (ip.match(
        /^((25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9]?[0-9])\.){3}(25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9]?[0-9])$/
      )) {
        // 0埋めに変換する
        record.ip_address_0padding.value = ip.replace(/\d+/g, m => m.padStart(3, '0'));
      }

      return event;
    }
  );

  // 0パディング用のフィールドは編集禁止にする
  kintone.events.on(
    [
      "app.record.create.show",
      "app.record.edit.show",
      "app.record.index.edit.show",
    ],
    (event) => {
      event.record.ip_address_0padding.disabled = true;
      return event;
    }
  );
})();
```

## 解説
レコードの追加画面、編集画面で、IPアドレスのフィールド（フィールドコード：`ip_address`）が更新されたときに実行してほしいので、イベントハンドラを紐づけるイベントのタイプは下記のように記述した。

``` js
kintone.events.on(
  [
    "app.record.create.change.ip_address",
    "app.record.edit.change.ip_address",
  ],
  (event) => {
    // ここに処理を書く
  }
);
```

また、入力されたのがIPアドレスの場合のみ処理したかったので、正規表現を使ってIPアドレスかどうか判断している。正規表現は[こちらを参考にしました](https://www.javadrive.jp/regex-basic/sample/index4.html)。

``` js
if (ip.match(
  /^((25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9]?[0-9])\.){3}(25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9]?[0-9])$/
)) {
  // IPアドレス！
} else {
  // IPアドレスではない
}
```

~~あとはIPアドレスを`.`で区切った配列を取得して、配列の各要素に対して足りない分は0で埋めて、また`.`区切りでくっつける、という処理を行った。~~
あとは`replace()`を使い、IPアドレスの数値部分を0埋めで置き換える。
※コメントで教えていただきました！ありがとうございます！

```js
record.ip_address_0padding.value = ip.replace(/\d+/g, m => m.padStart(3, '0'));
```

<details><summary>当初書いていたコード</summary>

``` js
// IPアドレスを.で区切る
const ip_array = ip.split(".");

// 0埋めした値を入れ直す
for (let i = 0; i < ip_array.length; i++) {
  ip_array[i] = ip_array[i].padStart(3, '0');
}

// .区切りで連結
record.ip_address_0padding.value = ip_array.join(".");
```
↑当初書いていたコード終わり。
</details>

さらに、0パディングしたIPアドレスを入れるフィールド（フィールドコード：`ip_address_0padding`）は自動入力のみ受け付け、人間に編集して欲しくないので、編集禁止にしておく。

``` js
kintone.events.on(
  [
    "app.record.create.show",
    "app.record.edit.show",
    "app.record.index.edit.show",
  ],
  (event) => {
    event.record.ip_address_0padding.disabled = true;
    return event;
  }
);
```

# アプリに適用する
アプリの設定からJavaScriptファイルをアップロードして、レコードを追加してみる。
下の画像のように0パディング用のフィールドは編集できなくなっている。

![Kintone_IPアドレス5.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3477571/f2301984-525d-bcd6-8404-5bf21b775c8a.png)


また、IPアドレスを入力して、フィールド外などをクリックしてフォーカスが外れると、
下の画像のように自動的に0パディング用のフィールドが更新された。

![Kintone_IPアドレス6.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3477571/67bec08c-8351-c6c6-29fb-c0e248bc48fe.png)


# 参考リンク
- [IPアドレス(IPv4)の正規表現 | 正規表現入門](https://www.javadrive.jp/regex-basic/sample/index4.html)
- [String.prototype.padStart() - JavaScript | MDN](https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Global_Objects/String/padStart)
- [JavaScriptやCSSでアプリをカスタマイズする | kintone ヘルプ](https://jp.cybozu.help/k/ja/user/app_settings/js_customize.html)
- [【kintoneカスタマイズ】テーブルの最下行のデータを一覧に表示したい｜OchaDukeNOP](https://note.com/ochadukenop/n/n9f63c1019291)
- [IPアドレスのゼロパディングはNG | MASAのライフスタイル](https://masa-info.com/memorandum/post-2408/)