Qiita Teams that are logged in
You are not logged in to any team

Log in to Qiita Team
Community
OrganizationEventAdvent CalendarQiitadon (β)
Service
Qiita JobsQiita ZineQiita Blog
103
Help us understand the problem. What are the problem?

More than 3 years have passed since last update.

Organization

Electronでファイルやフォルダの選択

※こちらの記事の内容はElectronの現行のVersion 1.x系では動作しません
http://qiita.com/khirose/items/11dae9f4650767d20c4f
こちらにversion 1.x系でのの焼き直しをしていますので参照ください

はじめに

HTML5/CSS/JavaScriptといったWeb技術でおなじみの技術でネイティブアプリも作れるよ!という触れ込みのElectron
ネイティブアプリなら自分のPCの中にあるファイルやフォルダを扱いたいわけで

普通のHTML + JavaScriptでやろうとしたら失敗した

画面のHTMLに

<input type="file">
<input type="file" webkitdirectory directory>

を書いてこいつのchangeイベントをひっかけて・・・とやったけどダメ
あくまでもChromiumのサンドボックスの世界からは出ないブラウザとしての振る舞いになるので、入ってくるファイル名などは C:\fakeroot\ファイル名 となって、PCのファイルシステム上のパスではないのでそのままファイル名として使えない
ファイル名は重要じゃなく、中身だけが必要だという場合であればここからReader作って...でいいんだけど、今回は必要な要件の中にファイル名もあるのでこの方法は無理筋と判断

そこでプロセス間通信APIを使えばいい

画面提供側(レンダラプロセス)から

var remote = require('remote');

でnode.jsベースで動いているメインプロセスを取得できる
HTML側のclickイベントを補足して、そのハンドラ内でブラウザ側のjsではなくメインプロセス側のAPIを叩けばネイティブのファイルを選ぶダイアログ、フォルダを選ぶダイアログを表示したり、選択内容(PCのファイルシステム上のフルパス名)を引っ張れる
あとはこれをHTML側に統合されているnode.jsのfsモジュールとかで操作すればよい

以下はサンプル(jQueryとBootstrapをローカルに入れて使ってます)

package.json
{
  "name": "example",
  "version": "0.0.0",
  "main": "index.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "author": "",
  "license": "NYSL",
  "keywords": [],
  "description": ""
}
index.js
'use strict';

var app = require('app');
var BrowserWindow = require('browser-window');

require('crash-reporter').start();

var mainWindow = null;

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

app.on('ready', function() {
    mainWindow = new BrowserWindow({width: 1024, height: 768});

    //  ↓を入れるとデフォルトで開発ツールが開いた状態になる
    mainWindow.openDevTools();

    mainWindow.loadUrl('file://' + __dirname + '/index.html');
    mainWindow.on('closed', function() {
        mainWindow = null;
    });
});
index.html
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Example</title>
<link rel="stylesheet" href="./css/bootstrap.min.css">
</head>
<body>
<div class="container">
    <button id="fileSelect" type="button" class="btn btn-primary btn-lg btn-block">ファイル選択</button>
    <button id="folderSelect" type="button" class="btn btn-default btn-lg btn-block">フォルダ選択</button>
</div>

<script>
// node_integrationを行うとmodule.exports関係の事情でjQuery/$がundefinedになるので
// それの回避コード
window.jQuery = window.$ = require('./js/jquery-2.1.4.min.js');
</script>
<script src="./js/bootstrap.min.js"></script>
<script>
/**
* ここからメインディッシュ
*/
var remote = require('remote');
var dialog = remote.require('dialog');
var browserWindow = remote.require('browser-window');

//  以下選択されたファイルをいじりたい場合はnode.jsのfsが使える
var fs = require('fs');

$(function(){
    // ボタンが押されたときの挙動
    $('#fileSelect').on('click', function(){
        var focusedWindow = browserWindow.getFocusedWindow();

        dialog.showOpenDialog(focusedWindow, {
            properties: ['openFile'],
            filters: [{
                name: 'テキストファイル',
                extensions: ['txt']             
            }]
        }, function(files){
            files.forEach(function(file){
                console.log(file);
            });
        });
    });

    $('#folderSelect').on('click', function(){
        var focusedWindow = browserWindow.getFocusedWindow();

        dialog.showOpenDialog(focusedWindow, {
            properties: ['openDirectory']
        }, function(directories){
            directories.forEach(function(directory){
                console.log(directory);
            });
        });
    });
});
</script>
</body>
</html>

ダイアログを出した上で何も選択しないとfilesやdirectoriesがundefinedになり、undefined.forEachを呼ぼうとしてエラーが出るっぽい
しかしクライアントサイドのJavaScriptに何も考えずrequire()書けるのは不思議な感覚

Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
103
Help us understand the problem. What are the problem?