スプレッドシートなどに於いて、ファイルの選択が必要なケースは多々あります。それはGoogle Drive上であっても同じです。VBAであればコモンダイアログなどでファイルの選択画面はもはや当たり前の機能なのですが、Google Apps Scriptの場合には少々面倒くさいコードを記述しなければいけません。また、Google Drive自体が非常に特殊な仕様であるため、このファイル選択画面でも不便な点も多々ありますが、これしか方法がないので仕方がありません。
今回は、スプレッドシートに画像を於いて、クリックするとファイル選択の画面が出て、ファイルを選択すると、A1セルにそのファイルの情報を書き込むというスクリプトを記述しました。
今回のスクリプトのサンプルは、下記のスプレッドシートに収めております。が、APIキーは抜いてありますので、コピーして、それぞれの方でAPIキーを取得して使って見てください。
function init() {//アクティブスプレッドシートの取得
var sheet = SpreadsheetApp.getActiveSpreadsheet(); //UiAppでダイアログ作成の準備とサーバーハンドラを準備 var app = UiApp.createApplication().setTitle("ファイルを選択してください"); var doclisthandler = app.createServerHandler('selectionhandler'); //Pickerダイアログを表示する app.createDocsListDialog() .setDialogTitle('MyPicker') .showDocsPicker() .setMultiSelectEnabled(true) .setInitialView(UiApp.FileType.FOLDERS) .addSelectionHandler(doclisthandler); //appの画面サイズを指定 app.setWidth(750).setHeight(500); //スプレッドシートにダイアログを表示 sheet.show(app); } function fileselect() { return init(); } function selectionhandler(e){ var sheet = SpreadsheetApp.getActiveSpreadsheet(); var app = UiApp.getActiveApplication(); //Logger.log(e.parameter.items[0].id); //Logger.log(e.parameter.items[0].name); //Logger.log(e.parameter.items[0].url); //A1セルに取得したファイルのIDを書き込む sheet.getRange('A1').setValue(e.parameter.items[0].id) app.close(); return app;}図:ファイル選択初期画面(フォルダビューで設定した結果)
図:ファイルの複数選択をしている様子(マルチ選択可にしている為)
今回の機能は、UiAppの機能の一つである「DocsListDialog」を用いて実現しています。Google Driveの画面のようなものが利用できるわけです。資料が少ないので実装も甘い部分があるのですが、今回作成するに当って注目すべき点と、利用するに当っての注意点を記述します。
注目すべき点
注意すべき点
その1では、DocsListDialogを用いて、ファイル選択画面を用いて、Google Driveのファイル選択画面を作成しました。しかし、あまり見た目も良くなく、具合も悪い。そこで、Googleの拡張サービスを利用してGoogle Picker APIを用いてファイルの選択画面を作る方法が、Googleにて公開されています。但し、この方法は結構面倒臭いので、テンプレートを自分で用意しておくと良いと思います。また、この手法は、HTML Servicesも利用していますが、その1とは違い、UiInstanceは使用していません。
スクリプト側function showPicker() { var html = HtmlService.createHtmlOutputFromFile('Picker.html') .setWidth(600).setHeight(425); SpreadsheetApp.getUi().showModalDialog(html, 'Select a file');}function getOAuthToken() { DriveApp.getRootFolder(); //なにげにこの部分重要!! return ScriptApp.getOAuthToken();}HTMLファイル側(Picker.html)<link rel="stylesheet" href="https://ssl.gstatic.com/docs/script/css/add-ons.css"><script type="text/javascript"> var DEVELOPER_KEY = 'ここにデベロッパーコンソールで得たPublic API Keyを入れる'; var DIALOG_DIMENSIONS = {width: 600, height: 425}; var pickerApiLoaded = false; //Google Picker API呼び出し gapi.load('picker', {'callback': function() { pickerApiLoaded = true; }}); //OAuthにて認証作業 function getOAuthToken() { google.script.run.withSuccessHandler(createPicker) .withFailureHandler(showError).getOAuthToken(); } //Picker Dialogを表示する function createPicker(token) { if (pickerApiLoaded && token) { var picker = new google.picker.PickerBuilder() .addView(google.picker.ViewId.SPREADSHEETS) .enableFeature(google.picker.Feature.NAV_HIDDEN) .hideTitleBar() .setOAuthToken(token) .setDeveloperKey(DEVELOPER_KEY) .setCallback(pickerCallback) .setSize(DIALOG_DIMENSIONS.width - 2, DIALOG_DIMENSIONS.height - 2) .build(); picker.setVisible(true); } else { showError('Unable to load the file picker.'); } } //Callbackデータを受け取る function pickerCallback(data) { var action = data[google.picker.Response.ACTION]; if (action == google.picker.Action.PICKED) { var doc = data[google.picker.Response.DOCUMENTS][0]; var id = doc[google.picker.Document.ID]; var url = doc[google.picker.Document.URL]; var title = doc[google.picker.Document.NAME]; document.getElementById('result').innerHTML = '<b>You chose:</b><br>Name: <a href="' + url + '">' + title + '</a><br>ID: ' + id; } else if (action == google.picker.Action.CANCEL) { document.getElementById('result').innerHTML = 'Picker canceled.'; } } //エラー表示用 function showError(message) { document.getElementById('result').innerHTML = 'Error: ' + message; }</script><div> <button onclick='getOAuthToken()'>Select a file</button> <p id='result'></p></div>スクリプトエディタから表示させた、Googleの拡張サービス。しかし、ここにはPicker APIはないので、下のデベロッパーコンソールへのリンクを開く
デベロッパーコンソール側でONにした様子
Credentialsにて、Public APIを取得している様子
スプレッドシート上でGoogle Picker APIにて表示させてみた図
選択をした後の画面。IDとファイル名が返ってきた図。
※使用するためには、Googleデベロッパーコンソールが使えるようになっていることが必要です。
選択した結果を受け取ったり、格納して引き続き別のスクリプトへ渡してあげる為には、その為の関数を用意する必要性があります。上記のコードだけでは表示されただけで受け取ることができません。そこで追加の関数と引き渡すメソッドを用意してあげれば、引き続きスクリプト側で、受け取った値を持って作業を続行することができます。
//コードを取得したら次のコードを付け足しておく。(上記ソースならCallbackを受け取るのソースの中)google.script.run.telepon(id);今回は上記ソースでは、var id = doc[google.picker.Document.ID]; で値を1つ受け取っているので、これをgoogle.script.run.telepon(id)という形で、予め用意しておいたtelepon関数に引数で渡してあげています。
function telepon(targetval){ ScriptProperties.setProperty('uid',targetval); Browser.msgBox(targetval);}今回は、上記コードで、受け取った値をsetPropertyにてプロジェクトプロパティに格納した上で、メッセージボックスを表示させています。
こうすることで、HTML Servicesで表示させたダイアログに表示したPicker APIウィンドウでの値を渡すことが可能です。
Picker APIの設定は、上記ソースコードにもあるように、Picker.Builderに対してオプションを渡して上げることで出来ます。主に使用するであろう追加オプションは
これまでは、Google Driveのファイル単位での選択画面を作る方法を紹介しましたが、そうなってくると欲しくなるのが「フォルダの選択画面」です。但し、Google Drive上ではフォルダは通常のPC上のフォルダとはことなり、タグみたいなものを具現化したに過ぎない存在なのでアレなんですが、その方法はないか?と思って探していたのですが、なかなか実現できませんでした。しかし、ようやくやり方がわかったので記録しておこうと思います。この手法は、上記のGoogle Driveのファイルを選択する画面を作りたい - その2を少し改造するだけで作成できます。HTML側のみ編集しますので、スクリプト側の記述は省略します。
リファレンスはここにあるのですが、読んでもさっぱりでした。今回のソースも、フォルダのIDだけを拾って、自前の関数に渡して上げています。こうすることで、フォルダのIDをゲットしてスクリプトプロパティに値を格納することができるので、スクリプト側でそれを元に作業をしやすくなります。
HTML側(Picker.html)<link rel="stylesheet" href="https://ssl.gstatic.com/docs/script/css/add-ons.css"><script type="text/javascript"> var DEVELOPER_KEY = 'ここにデベロッパーコンソールで得たPublic API Keyを入れる'; var DIALOG_DIMENSIONS = {width: 750, height: 480}; var pickerApiLoaded = false; //Google Picker API呼び出し gapi.load('picker', {'callback': function() { pickerApiLoaded = true; }}); //OAuthにて認証作業 function getOAuthToken() { google.script.run.withSuccessHandler(createPicker) .withFailureHandler(showError).getOAuthToken(); } //Picker Dialogを表示する function createPicker(token) { if (pickerApiLoaded && token) { var docsView = new google.picker.DocsView() .setIncludeFolders(true) .setMimeTypes('application/vnd.google-apps.folder') .setSelectFolderEnabled(true); var picker = new google.picker.PickerBuilder() .addView(docsView) .enableFeature(google.picker.Feature.NAV_HIDDEN) .hideTitleBar() .setOAuthToken(token) .setDeveloperKey(DEVELOPER_KEY) .setCallback(pickerCallback) .setSize(DIALOG_DIMENSIONS.width - 2, DIALOG_DIMENSIONS.height - 2) .build(); picker.setVisible(true); } else { showError('Unable to load the file picker.'); } } //Callbackデータを受け取る function pickerCallback(data) { var action = data[google.picker.Response.ACTION]; if (action == google.picker.Action.PICKED) { var doc = data[google.picker.Response.DOCUMENTS][0]; var id = doc[google.picker.Document.ID]; var url = doc[google.picker.Document.URL]; var title = doc[google.picker.Document.NAME]; document.getElementById('result').innerHTML = '<b>You chose:</b><br>Name: <a href="' + url + '">' + title + '</a><br>ID: ' + id; google.script.run.telepon(id); } else if (action == google.picker.Action.CANCEL) { document.getElementById('result').innerHTML = 'Picker canceled.'; } } //エラー表示用 function showError(message) { document.getElementById('result').innerHTML = 'Error: ' + message; }</script><div> <button onclick='getOAuthToken()'>Select a file</button> <p id='result'></p></div>フォルダ選択画面です(フォルダの文字列をクリックすると中に入るが、チェックで選択となる)
var FOLDER_NAME = 'ここにアップロード先フォルダのIDを入れる'; //格納する為のフォルダIDを入れるためのグローバル変数function filegetter(e) { var sheet = SpreadsheetApp.getActiveSpreadsheet(); var app = UiApp.createApplication(); app.add( app.createHorizontalPanel().add(app.createHTML('<h1>' + 'アップローダー' + '</h1>'))); var form = app.createFormPanel() .setEncoding('multipart/form-data'); form.add( app.createHorizontalPanel().add( app.createFileUpload().setName('UploadFile').setId('UploadFile') ).add(app.createSubmitButton('アップロード') )); app.add(form); sheet.show(app);}function doPost(e){ var sheet = SpreadsheetApp.getActiveSpreadsheet(); var uploadflag = 0; //アップロード成功時に使用するフラグ var app = UiApp.getActiveApplication(); try{ if (e.parameter.UploadFile.length > 0){
//アップロード先のフォルダの取得
var targetFolder = DriveApp.getFolderById(FOLDER_NAME); //面倒ならgetRootFolder()で、ルートディレクトリにしてしまっても可 //アップロードしたファイルのIDを取得するために変数に格納しファイルを生成 var pon = targetFolder.createFile(e.parameter.UploadFile); //アップロードフラグを1にする uploadflag = 1; message = 'アップロード完了'; } else { message = 'ファイルが選択されていません'; } } catch (error){ message = 'エラー!' + error.message; } //アップロードファイルのIDを取得し、A1セルに値を書き込む
if(uploadflag == 1){ sheet.getRange('A1').setValue(pon.getId()); } //ダイアログを閉じてメッセージを表示
app.close(); Browser.msgBox(message); return app;}図:ファイル選択中の画面
図:ファイルアップロード選択ダイアログ
図:アップロード後の特定フォルダ内に入ったファイル
今回の機能は、UiAppの機能の一つである「FileUpload」を用いて実現しています。VBAのコモンダイアログの画面のようなものが利用できるわけです。今回このスクリプトは「とまと あんらいぷ…」というサイトに記載されていたものを少々改造して利用しました。今回作成するに当って注目すべき点と、利用するに当っての注意点を記述します。
注意すべき点