JavaScriptのみでGoogle Driveに動的にテキストや画像等を保存する

# Save to Drive buttonだとData URIが使えない
つまり、動的にファイル生成して保存が出来ない！
今回の方法ならば、頑張れば、画像イメージでもなんでもJavaScriptのみでサーバサイドに
頼らず、Google Driveに保存可能。タダで永続的なストレージAPIが手に入る！

# 昔からあるJavaScript　APIを使うことで、動的にファイルをGoogle Driveに保存できる

## 準備

[Google Console](https://code.google.com/apis/console/)にログイン
アプリケーションを登録（Webアプリケーション）
※ただし、Redirect URIsは空にして登録すること！

## テキストエリアに入力した内容をテキストファイルとして保存する

拡張子は勝手には付加されないので、「.txt」を付けるなりしないと何のファイルか分からなくなるｗ

```html:
<script type="text/javascript">
    var CLIENT_ID = 'クライアントID';
    var SCOPES = 'https://www.googleapis.com/auth/drive';

    /**
     * Called when the client library is loaded to start the auth flow.
     */
    function handleClientLoad() {
        window.setTimeout(checkAuth, 1);
    }

    /**
     * Check if the current user has authorized the application.
     */
    function checkAuth() {
        gapi.auth.authorize({
            'client_id': CLIENT_ID,
            'scope': SCOPES,
            'immediate': true
        },
        handleAuthResult);
    }

    /**
     * Called when authorization server replies.
     *
     * @param {Object} authResult Authorization result.
     */
    function handleAuthResult(authResult) {
        var authButton = document.getElementById('authorizeButton');
        var main = document.getElementById('main');
        authButton.style.display = 'none';
        main.style.display = 'none';
        if(authResult && !authResult.error) {
            // Access token has been successfully retrieved, requests can be sent to the API.
            main.style.display = 'block';
            var btn = document.getElementById('saveBtn');
            btn.onclick = writeFile;
            //main.onchange = uploadFile;
        } else {
            // No access token could be retrieved, show the button to start the authorization flow.
            authButton.style.display = 'block';
            authButton.onclick = function () {
                gapi.auth.authorize({
                    'client_id': CLIENT_ID,
                    'scope': SCOPES,
                    'immediate': false
                },
                handleAuthResult);
            };
        }
    }

    /**
     * Start the file upload.
     *
     * @param {Object} evt Arguments from the file selector.
     */
    function writeFile(evt) {
        gapi.client.load('drive', 'v2', function () {
            //var file = evt.target.files[0];
            var fileName = document.getElementById("fileName").value;
            var content = document.getElementById("content").value;
            console.log("fileName = "+fileName);
            console.log("content = "+content);
            insertFile(fileName,content);
        });
    }

    /**
     * Insert new file.
     *
     * @param {fileName} 保存するファイル名
     * @param {content} 保存するファイルの内容
     * @param {Function} callback Function to call when the request is complete.
     */
    function insertFile(fileName,content, callback) {
        const boundary = '-------314159265358979323846';
        const delimiter = "\r\n--" + boundary + "\r\n";
        const close_delim = "\r\n--" + boundary + "--";

        var contentType = 'text/plain';
        var metadata = {
                'title': fileName,
                'mimeType': contentType
        };

        var base64Data = utf8_to_b64(content);
        var multipartRequestBody = delimiter +
                'Content-Type: application/json\r\n\r\n' + JSON.stringify(metadata) + delimiter +
                'Content-Type: ' + contentType + '\r\n' +
                'Content-Transfer-Encoding: base64\r\n' +
                '\r\n' + base64Data + close_delim;

        var request = gapi.client.request({
                'path': '/upload/drive/v2/files',
                'method': 'POST',
                'params': {
                    'uploadType': 'multipart'
                 },
                'headers': {
                    'Content-Type': 'multipart/mixed; boundary="' + boundary + '"'
                },
                'body': multipartRequestBody
        });
        if(!callback) {
          callback = function (file) {
              alert("保存しました。");
              console.log(file)
          };
        }
        request.execute(callback);
        
    }
    
    // from http://ecmanaut.blogspot.jp/2006/07/encoding-decoding-utf8-in-javascript.html
    function utf8_to_b64(str) {
  return window.btoa( unescape(encodeURIComponent( str )) );
}
    
</script>
<script type="text/javascript" src="https://apis.google.com/js/client.js?onload=handleClientLoad"></script>
<!--Add a file picker for the user to start the upload process -->
<div id="main" style="display: none">
<p>
<label>ファイル名</label>
<input type="text" id="fileName">
</p>
<p>
<label>内容</label>
<textarea id="content" cols="50" rows="5"></textarea>
</p>
<p>
    <button id="saveBtn">
        保存
    </button>
</p>
<input type="button" id="authorizeButton" style="display: none" value="Authorize" />
</div>
```

上記のコードは、2016年２月現在リンク切れてとなってしまったが、Googleのページあったサンプルをベースに作成。utf8_to_b64関数はオリジナルはコメント通りだが、自分はMozillaのページで解説で知った。

# Jsdo.itにサンプルを置いた
- [JavaScriptでGoogle Driveにテキストエリアの内容を保存](http://jsdo.it/kjunichi/yt3k)
流行りのフラットUI風にしてみたｗ。

# フォルダを指定したいんだけど

そんな場合は、フォルダのIDを取得して、
meta情報に

```js
parents:[{id:直下のID},{id:その上のフォルダID}]
```

## フォルダIDの取得方法
- [Google DriveのフォルダIDを取得する](http://jsdo.it/kjunichi/1N1a)

# Googleの関連APIのリンク 
- [https://developers.google.com/drive/v2/reference/files/insert](https://developers.google.com/drive/v2/reference/files/insert)

# Qiitaの関連投稿

- [Google Calendar APIをJavaScriptで使う](http://qiita.com/kjunichi/items/f8b44fcc0e024dcc97f6)

# CORSによる方法を扱った記事

- [CORSでGoogle Driveにアクセス](https://abrakatabura.hatenablog.com/entry/2013/03/14/065948)