Wails＋Webix を使ってみた

# はじめに

デスクトップアプリを作るための開発環境 Wails と、ウェブアプリを作るためのライブラリ Webix を使ってみました。

[Wails を始めてみた #JavaScript - Qiita](https://qiita.com/tinymouse/items/d95029ad20665bdf1128)

[Webix を使ってみた #JavaScript - Qiita](https://qiita.com/tinymouse/items/7ba3a624d53283860e55)

この二つを一緒に使ってみたいと思います。

# Wails＋Webix を使ってみた

## Wails のプロジェクトを新規作成する

まず、Wails のプロジェクトを新規作成します。

プロジェクトを作成したいフォルダに移動してコマンドを実行します。

```shell
wails init -n HelloWebix -t vanilla
```

使用するフレームワークは `Vanilla JS` を指定しました。↑

## Webix のライブラリを組込する

作成したプロジェクトに Webix のライブラリを組込します。

以下のページからダウンロードします。
[Download a JavaScript UI Widgets Library Webix Based on HTML5 and CSS3 Standards](http://webix.com/download/)

以下のファイルをワークスペースにコピーします。

```
codebase
    webix.min.css
    webix.min.js
```

配置するのはプロジェクトの以下のフォルダにしました。

```
frontend
    lib
        webix
            webix.min.css
            webix.min.js
```

`index.html` に以下のコードを追記します。

```html:index.html
    <link rel="stylesheet" href="./src/lib/webix/webix.css" type="text/css"> 
    <script src="./src/lib/webix/webix.js" type="text/javascript"></script>  
```

↑`main.js` で import したかったのですが、上手くいきませんでした。

`style.css` と `app.css` の参照も、`main.js` から `index.html` に移動しておきます。（しなくて構いません）

```html:index.html
    <link rel="stylesheet" href="./src/style.css" type="text/css">
    <link rel="stylesheet" href="./src/app.css" type="text/css">
```

`app.css` の既存の設定は不要になるので削除しておきます。↓

```css:app.css
(空)
```

`style.css` の設定も整理しておきます。（しなくて構いません）

```css:style.css
html {
    background-color: white;
}

body {
    margin: 0; padding: 0;
}

#app {
    height: 100vh; width: 100%;
}
```

`main.js` の既存のコードは削除しておきます。

## アプリの画面を記述する

Webix ライブラリを使ってアプリの画面を記述します。

[Getting Started - Webix Docs](https://docs.webix.com/desktop__getting_started.html)

Webix の UI コンポーネントは JavaScript コードで生成します。`main.js` に記述します。

```js:main.js
    var app = webix.ui({
        container:'app',
        rows:[
            {
                type:'header', view:'template', template:"Try Webix",
            },
            {
                view:'form',
                elements:[
                    {
                        view:'text', id:"name", label:"Name", name:"name"
                    },
                    {
                        view:'button', id:"clickme", value:"Click me.",
                    },
                    {
                        view:'text', id:"message", label:"Message", name:"message"
                    }
                ],
            },
        ],
    });
```

Webix のコンポーネントは基本的に、親要素の領域一杯に表示されます。`container` プロパティに HTML タグを指定して、その領域一杯に表示させることもできます。
プロジェクトを新規作成したときに生成された `index.html` に、`<div id="app"></div>` があって画面一杯に表示されるようになっていたので、これを親要素にすることにします。

あるいは、`<div id="app"></div>` を削除してしまって、上記のコードで `container` の指定をなくしても構いません。コンポーネントはブラウザのウィンドウ一杯に表示されます。

上記のコードは、通常は以下の初期化ブロックに記述します。

```js:main.js
webix.ready(function(){
    var app = webix.ui({
    (以下略)
```

ビルドして実行してみます。

![サンプル.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/114460/3910df4a-1c79-ebb5-3636-fee95a7c85e3.png)

## イベントハンドラを記述する

ボタンをクリックすると実行するイベントハンドラを記述します。↓

```js:main.js
    $$('clickme').attachEvent('onItemClick', function(){
        var name = $$('name').getValue();
        if (name == "") {
            webix.message("Please enter your name.");
            return;
        }
        $$('message').setValue("Hello, " + name);
    });
```

[Event Handling of Guides, Interacting with Users Webix Docs](https://docs.webix.com/desktop__event_handling.html)

Webix コンポーネントのオブジェクト `app` に `container: 'app'` を指定したとき、アプリを起動すると `<div id="app"></div>` に合わせて、コンポーネント `app` はブラウザのウィンドウ一杯に表示されます。
ブラウザのウィンドウのサイズを変更すると、`<div id="app"></div>` はサイズが変わるのですが、Webix コンポーネント `app` はサイズが変わりません。
これでは困るので、以下のコードを追記します。

```js:main.js
    webix.event(window, 'resize', function(){
        app.adjust(); 
    }); 
```

`<div id="app"></div>` を削除してコンポーネント `app` に `container` の指定をしないときは、この処置は必要ありません。

## バックエンドの Go プログラムを呼出する

`app.go` に以下の関数が書かれています。

```go:app.go
// Greet returns a greeting for the given name
func (a *App) Greet(name string) string {
    return fmt.Sprintf("Hello %s, It's show time!", name)
}
```

以下の設定が作成されていることを確認します。作成されていなかったら `wails generate module` を実行します。

```js:frontend/wailsjs/go/main/App.js
export function Greet(arg1) {
  return window['go']['main']['App']['Greet'](arg1);
}
```

この関数をフロントエンドのコードで呼出します。

```js:main.js
import {Greet} from '../wailsjs/go/main/App';

(中略)

    $$('clickme').attachEvent('onItemClick', function(){
        (中略)
     /* $$('message').setValue("Hello, " + name);
        ↓ */
        Greet(name)
        .then(function(result){
            $$('message').setValue(result);
        });
    });
```




Go の関数は返値でエラーを返せます。上記の関数を変えてみます。↓

```go:app.go
// Greet returns a greeting for the given name
func (a *App) Greet(name string) (string, error) {
    if name == "" {
        return "", errors.New("argument 'name' is empty")
    }
    return fmt.Sprintf("Hello %s, It's show time!", name), nil
}
```

呼出する側も変えてみます。↓

```js:main.js
    $$('clickme').attachEvent('onItemClick', function(){
        var name = $$('name').getValue();
        Greet(name)
        .then(function(result){
            $$('message').setValue(result);
        })
        .catch(function(reason){
            webix.message("Function failed: " + reason);
        });
    });
```