Atom Shellでファイルを選択ボタンが使えない件

# input type="file"が使えない
Atom Shellで[前回の記事でkoaが使える](http://qiita.com/kjunichi/items/f4f5b75686f26d1bc18c)ようになったので、[express4のアップロード](http://qiita.com/kjunichi/items/fe33b6a4e82ac944b487)のkoa版を作ろうとしたらハマった。

何と、input type="file"が使えない。


# 何とかAtom Shellでファイルを選択ボタンを作る方法

幸い、Atom Shellにはファイルダイアログを開くAPIは用意されているので、これを使う。しかし、これはmain.js側のために用意されているもので、index.html側（レンダラー側）では直接扱えない模様。そこでIPCを使ってmain.js側と.html側で内部通信させて、ダイアログの表示要求とファイルの選択結果の受け渡しを行うことで、ファイルを選択ボタンの代替実装が行えた。

```json:package.json
{
  "name"    : "your-app",
  "version" : "0.1.0",
  "main"    : "main.js"
}
```

```js:main.js
var app = require('app'); // Module to control application life.
var BrowserWindow = require('browser-window'); // Module to create native browser window.
var dialog = require('dialog');
var ipc = require('ipc');

// Report crashes to our server.
require('crash-reporter').start();

// Keep a global reference of the window object, if you don't, the window will
// be closed automatically when the javascript object is GCed.
var mainWindow = null;

// Quit when all windows are closed.
app.on('window-all-closed', function() {
  if (process.platform != 'darwin')
    app.quit();
});

// This method will be called when atom-shell has done everything
// initialization and ready for creating browser windows.
app.on('ready', function() {
  // Create the browser window.
  mainWindow = new BrowserWindow({
    width: 800,
    height: 600
  });

  ipc.on('openFileDialog', function(event, arg) {
    // レンダラー側からのファイルオープンダイアログ表示要求イベント受信時の処理
    dialog.showOpenDialog({
      properties: ['openFile', 'multiSelections']
    }, function(filePath) {
      console.log("filePath = " + filePath);
      event.sender.send('asynchronous-reply', filePath);
    });
    event.returnValue = "OK";
  });

  // and load the index.html of the app.
  mainWindow.loadUrl('file://' + __dirname + '/index.html');

  // Emitted when the window is closed.
  mainWindow.on('closed', function() {
    // Dereference the window object, usually you would store windows
    // in an array if your app supports multi windows, this is the time
    // when you should delete the corresponding element.
    mainWindow = null;
  });
});
```

```html:index.html
<!DOCTYPE html>
<html>

<head>
  <meta charset="UTF-8">
  <title>Hello World!</title>
</head>

<body>
  <h1>Hello World!</h1>
  We are using node.js
  <script>
    document.write(process.version)
  </script>
  and atom-shell
  <script>
    document.write(process.versions['atom-shell'])
  </script>.
  <button id="fileOpenBtn">ファイルを選択</button>
  <div id="out"></div>
  <!-- 以下のフォームはAtom Shellでは利用できない模様 -->
  <form method="post" enctype="multipart/form-data" action="http://localhost:3000/">
    <input type="file" name="fileName">
    <input type="submit" name="upload">
  </form>
  <script>
    var ipc = require('ipc');

    ipc.on('asynchronous-reply', function(arg) {
      // main.jsでファイルオープンダイアログでファイル選択後に呼ばれる。
      // argにmain.jsでセットしたファイルパスが入っている。
      console.log("fileName = " + arg);
      var out = document.getElementById("out");
      out.innerHTML = "fileName = " + arg;
    });

    var fileOpenBtn = document.getElementById("fileOpenBtn");
    fileOpenBtn.addEventListener("click", function() {
      // main.js側に同期イベントを送る。
      ipc.sendSync('openFileDialog');
    });
  </script>

</body>

</html>
```

# まとめ

Atom Shellで簡単にHTML5でデスクトップアプリを実装できると思いきや、
Atom Shell固有の実装が必要な事がわかった。