LANG SELRCT

Apps Script Reference  (Create: Create new Spreadsheet | Create new Apps Script

Sunday, September 30, 2018

claspでpullとpushができなくなった時にlogoutしてloginし直すと解決した話


結論から言うと、タイトルに書いてあるように
$ clasp logout
してから

$ clasp login
すると解決しました


つまづいたことと試したことを備忘録で書き残しておきます。

今回つまづいたこと

$ clasp pull
$ clasp push
ができなくなった


pullの場合
$ clasp pull
Error: Permission denied. Enable the Apps Script API:
https://script.google.com/home/usersettings

と言われたので
https://script.google.com/home/usersettings
にアクセスしてみると「オン」になっているのでEnabledにはなっている
Permission denied.は別の原因っぽい。


pushの場合
$ clasp push
Push failed. Errors:
Requested entity was not found.

こう返ってきてしまう。


試したこと


その1
$ clasp open
でスクリプトエディタを開くことはできる


その2
$ clasp login
You seem to already be logged in. Did you mean to 'logout'?
と返ってくるのでログインはできている


いろいろとググってみても解決策が見つからない…


その3
以下のコンソールにアクセスしてみると
https://console.cloud.google.com/apis/library/script.googleapis.com?project=SCRIPT ID


自分がオーナーのはずが「有効にする」権限がないらしい


その4
リソース > Googleの拡張サービスで
下部にあるリンク「Google Cloud Platform API Dashboard」をクリックして

左サイドのメニューで「ライブラリ」をクリックして


「Apps Script」で検索

ここで「有効にする」をクリック

$ clasp push
Push failed. Errors:
The caller does not have permission

pushで返ってくるメッセージは変わったけれど
やはり権限がないらしい


その5
もはやどうすればいいのかわからないので
一度ログアウトしてログインしてみようとふと思った

といわけで
$ clasp logout
してから

$ clasp login
すると解決しました


キーを押して放したことを検知したい(シンプル版)


キーを押して放したことを検知したい
をシンプルにしたくて書きました

  • キーを押したら
    テキストエリアにそのキーコードを入れる

  • キーを放したら
    テキストエリアからそのキーコードを消す

ここで対象にするキーは以下4つの装飾キーです
“command”: 91
“shift”: 16
“control”: 17
“option”: 18


デモ





コード.gs
function doGet() {
  return HtmlService.createHtmlOutputFromFile("index");
}
意訳
この機能がやること
指定したHTMLファイルを表示する




index.html
<!DOCTYPE html>
<html>
<body>
  <textarea id="key_down_ta"  disabled></textarea>
  <script>
  /************************************
グローバル
************************************/
var key_down_ta = elem("key_down_ta");

/************************************
イベント
************************************/
document.onkeydown = function(e) { down_up_keycode(e, "down") };
document.onkeyup = function(e) { down_up_keycode(e, "up") };

/************************************
elem(id)
************************************/
function elem(id) {
  return document.getElementById(id);
}


/************************************
装飾キー
“command”: 91
“shift”: 16
“control”: 17
“option”: 18
************************************/
var modifier_key = /91|16|17|18/;

/************************************
down_up_keycode
************************************/
function down_up_keycode(e, flag) {
  var keycode = get_keycode(e);
  var is_modifier_key = modifier_key.test(keycode.toString());
  if (is_modifier_key === true) {
    var down_value = key_down_ta.value;
    switch (flag) {
      case "down":
        key_down_ta.value = "";
        key_down_ta.value += down_value + keycode + ",";
        break;
      case "up":
        var result = down_value.replace(keycode + ",", "");
        key_down_ta.value = result;
        break;
    }
  }
}

/************************************
get_keycode
************************************/
function get_keycode(e) {
  var keycode = e.keyCode;
  return keycode;
}
  </script>
</body>
</html>


Saturday, September 29, 2018

sublime textでインデントを設定したい(HTML-CSS-JS Prettify)


Sublime Textでインデントの設定をしたくて調べた備忘録



HTML-CSS-JS Prettifyのインストール方法
  1. Sublime Textを開く
  2. 上部メニューのToolsをクリック
  3. Command Paletteを選択
  4. installと入力
  5. 「install Package Control」 という選択肢を選択
  6. Package Control was successfully installed
    Use the Command Palette and type "Install Package" to get started
    というメッセージが表示される
  7. 再度Command Paletteを選択
  8. installで検索
  9. 「Package Control: Install Package」という選択肢を選択
  10. HTML-CSSで検索
  11. HTML-CSS-JS Prettifyを選択
  12. 再度Toolsを開くと「HTML/CSS/JS Prettify」が選択できる



使い方
  1. 「HTML/CSS/JS Prettify」を選択
  2. Prettify Code



インデントのサイズ設定
  1. 「HTML/CSS/JS Prettify」を選択
  2. 「Prettify Preferences - Default」を選択
  3. indent_size: 4, になっているコードを 2 など任意に設定



いろいろ調べてこちらの記事を参考にさせていただきました
https://suppon.innovator.jp.net/entry/sublimetextprettify

Wednesday, September 26, 2018

今日は今年の何日目で何週目かを知りたい


2018-01-01から今日までの経過日数に+1して今日が何日目かを導いて
それを7(1週間の日数)で割った余りをMath.ceilで切り上げて何週目かを導いてみる



コード.gs
function get_days(){
  var start_date = new Date("2018-01-01");
  var target_date = new Date();
  var days = get_elapsed_days(start_date, target_date);
  Logger.log("今日は今年の " + days + " 日目"); 
}

function get_weeks(){
  var start_date = new Date("2018-01-01");
  var target_date = new Date();
  var days = get_elapsed_days(start_date, target_date);
  var weeks = Math.ceil(days / 7);
  Logger.log("今日は今年の " + weeks + " 週目");
}

function get_elapsed_days(start_date, target_date){
  var sec = target_date.getTime() - start_date.getTime();
  var days = Math.floor(sec / (1000 * 60 * 60 * 24));
  days = parseInt(days) + 1;
  return days;
}



Friday, September 21, 2018

.replace()で文字列を置換する


.replace()で置換するときに
何度か同じ失敗をしてしまったので備忘録として


以下の myFunction() を実行するとエラーが出て置換できない

myFunction2() や myFunction3() のように数値を文字列にしてから実行すると置換できる



コード.gs
//エラーが出て変換できない
function myFunction() {
  var value = 123;
  var result = value.replace(/123/, "abc");
  Logger.log(result);
}

//123がabcに変換される
function myFunction2() {
  var value = "123";
  var result = value.replace(/123/, "abc");
  Logger.log(result);
}

//123がabcに変換される
function myFunction3() {
  var value = 123;
  var result = value.toString().replace(/123/, "abc");
  Logger.log(result);
}


Tuesday, September 18, 2018

指定した文字列の前後に特定の文字列を追加したい


指定した文字列の前後に
特定の文字列を足したい
そして末尾が特定の文字列の場合に削除したい

と言語化してもよくわからないのでもう少し具体的な例を以下に書きます



以下のような正規表現を作りたい
["aaa", "bbb"]
から

/^aaa$|^bbb$/
を作りたい


作る手順


このような配列を用意して
["aaa", "bbb"]


それぞれの前後に ^ と $| を追加して

このような文字列を作って
^aaa$|^bbb$|

末尾の | を削除して
^aaa$|^bbb$


このような正規表現をつくる
/^aaa$|^bbb$/


ということを実現するコードです。


コード.gs
function get_regexp(){
  var array = ["aaa", "bbb"];
  var front = "^";
  var rear = "$|";
  var tail = "|";
  var str = get_str_sandwich(array, front, rear, tail);
  Logger.log(str);
  var regexp = new RegExp(str);
  Logger.log(regexp);
}

function get_str_sandwich(array, front, rear, tail) {
  var str = "";
  for(var i = 0; i < array.length; i++){
    str += front + array[i] + rear;
  }
  Logger.log(str);
  if(str.slice(-1) === tail){
    str = str.slice(0,  -1);
  }
  return str;
}



Monday, September 17, 2018

累乗の計算をする


累乗の計算をしたくて書いたコードです。


デモ
乗は




コード.gs
function get_exponentiation() {
  var radix = 2;
  var exponent = 3;
  var result = 1;
  for(var i = 0; i < exponent; i++){
    result = result * radix;
  }
  Logger.log(result);
}
意訳
この機能がやること
基数
指数
結果の初期値に1を入れておく
指数の数だけ繰り返す
結果*基数

出来上がった結果をログに出す




実行結果



HTML Serviceで書いてみる

コード.gs
function doGet() {
  return HtmlService.createHtmlOutputFromFile("index");
}




index.html
<!DOCTYPE html>
<html>
  <body>
    <input type="text" id="radix_tb">の 
    <input type="text" id="exponent_tb">乗は 
    <input type="text" id="result_tb">
<script>
    function elem(id) {
        return document.getElementById(id);
    }

    var radix_tb = elem("radix_tb");
    var exponent_tb = elem("exponent_tb");
    var result_tb = elem("result_tb");

    radix_tb.onkeyup = get_exponentiation;
    exponent_tb.onkeyup = get_exponentiation;

    function get_exponentiation() {
        var radix = radix_tb.value;
        var exponent = exponent_tb.value;
        var result = 1;
        for (var i = 0; i < exponent; i++) {
            result = result * radix;
        }
        result_tb.value = result;
    }
</script>
  </body>
</html>



キーを押して放したことを検知したい


デモ command, shift, control, 4に対応

左からtrue/false キー キーコードの順

command:91
shift:16
control:17
num4:52

4以外のキーの同時押しには反応する
最後に4を加えると反応しなくなる(ここは未解決)


関連記事


前提
command + shift + control + 4
を同時に押して
選択した範囲をスクリーンショットに撮ると
クリップボードに保存される
Macでスクリーンショットを撮ってクリップボードに保存する


やりたいこと(未完)
command + shift + control + 4を同時に押して放した時に
クリップボードのデータを取得したい

と思って作ってみたらできなかったという話。
おそらく方法はあるのだろうけど、深そうなので追うのはやめました。


できたところまでのコードを残しておきます。

最後の「4」を押した時にkeydownで検知できないという壁がありました。
「4」単体であれば押した時に検知できるが上記でのキーを組み合わせたときには検知できなくなる。




コード.gs
function doGet() {
  return HtmlService.createHtmlOutputFromFile("index");
}
意訳
この機能がやること
指定したHTMLファイルを表示する




index.html
<!DOCTYPE html>
<html>
  <body>
    <label id="cmd">false</label>command:91
    <br>
    <label id="sht">false</label>shift:16
    <br>
    <label id="ctrl">false</label>control:17
    <br>
    <label id="num4">false</label>num4:52
    <br>
    <script>
/************************************
イベント
************************************/
document.onkeydown = function(e) { down_up_keycode(e,"down")};
document.onkeyup = function(e) { down_up_keycode(e, "up")};
document.onmouseup = mouse_up;

/************************************
mouse_up
************************************/
function mouse_up(){
  var ids = get_key_values();
  var result = get_text_content(ids)
}

function get_text_content(ids){
  var result;
  for(var i = 0; i < ids.length; i++){
    result = elem(ids[i]).textContent;
    if(result !== "true"){
      break;
    }
  }
}

/************************************
down_up_keycodey
************************************/
function down_up_keycode(e, flag){
  var keycode = get_keycode(e);
  switch(flag){
    case "down":
      down_case(keycode);
      break;
    case "up":
      up_case(keycode);
      break;
  }
}

/************************************
down_case
************************************/
function down_case(keycode){
  elem(key_obj[keycode]).textContent = true;
}

/************************************
up_case
************************************/
function up_case(keycode){
  elem(key_obj[keycode]).textContent = false;
    if(keycode === 52){
    alert("4が押されました");
  }
}

/************************************
key_obj
************************************/
var key_obj = {
  91: "cmd",
  16: "sht",
  17: "ctrl",
  52: "num4"
}

/************************************
elem
************************************/
function elem(id){
  return document.getElementById(id);
}

/************************************
get_keycode
************************************/
function get_keycode(e){
  var keycode = e.keyCode;
  return keycode;
}

/************************************
get_key_values
************************************/
function get_key_values() {
  var keys = Object.keys(key_obj);
  var values = [];
  for (var i = 0; i < keys.length; i++) {
    var value = key_obj[keys[i]];
    values.push(value);
  }
  return values;
}
</script>
  </body>
</html>



クリップボードにコピーする document.execCommand("copy")


※この記事で使っているDocument.execCommand()は廃止されたようです。

FYI




選択した範囲のテキストをクリップボードにコピーする。

このページ内で任意のテキストを選択すると クリップボードにコピーされます
そしてcommand + vで貼り付けることができる


つまりこのページ内で選択されたテキストは
command + cでコピーしなくても
自動でクリップボードにコピーされるので
「コピペ」の「コピー」を手動でせずとも「ースト」ができる


window.getSelection()
で選択テキストを取得して

document.execCommand("copy")
でクリップボードにコピーする




コード.gs
function doGet() {
  return HtmlService.createHtmlOutputFromFile("index");
}
意訳
この機能がやること
指定したHTMLファイルを表示する




index.html
<!DOCTYPE html>
<html>
<body>
選択した範囲のテキストをクリップボードにコピーする。
<script>
document.onmouseup = on_mouseup;

function on_mouseup() {
  var text = window.getSelection();
  document.execCommand("copy");
  alert(text);
}
</script>
</body>
</html>
意訳
 


テキストを置いておく

マウスのクリック操作が終わったらon_mouseupを実行する

この機能がやること
選択されている文字列を取得して
クリップボードにコピーして(command + c)
アラートに出す






Saturday, September 8, 2018

セレクトボックスの選択肢に応じて指定した要素をスクロールさせたい


selectの選択肢に応じてdiv要素をスクロールしたい

ついでに上下ボタンでもスクロールさせてみる



Bloggerの記事の中ではうまく動作しなかったのでデモアプリを用意しました

デモ
https://script.google.com/macros/s/AKfycbxMlOTqLMMfUmC0Ink4SU9jNl7mpNJzoawJcKh1tQrF1bcs3uw/exec



コード.gs
function doGet() {
  return HtmlService.createHtmlOutputFromFile("index");
}
意訳
この機能がやること
指定したHTMLファイルを表示する




index.html
<html>
<head>
  <style>
    #overflow_scroll {
      width: 240px;
      height: 40px;
      overflow: scroll;
      border: solid 1px lightgray;
    }
  </style>
</head>
<body>
  <div id="overflow_scroll">
    <div id="a">あいうえお</div>
    <div id="ka">かきくけこ</div>
    <div id="sa">さしすせそ</div>
    <div id="ta">たちつてと</div>
    <div id="na">なにぬねの</div>
  </div>
  <select id="akasatana">
    <option value="a">あいうえお</option>
    <option value="ka">かきくけこ</option>
    <option value="sa">さしすせそ</option>
    <option value="ta">たちつてと</option>
    <option value="na">なにぬねの</option>
  </select>
  <button id="prev_bt">▲</button>
  <button id="next_bt">▼</button>
  <script>
    var akasatana = elem("akasatana");
    var overflow_scroll = elem("overflow_scroll");

    akasatana.onchange = akasatana_onchange;
    prev_bt.onclick = function() {prev_next_click(-1)};
    next_bt.onclick = function() {prev_next_click(1)};

    function elem(id) {
      return document.getElementById(id);
    }

    function prev_next_click(add) {
      var index = akasatana.selectedIndex;
      akasatana.selectedIndex = index + add;
      var value = akasatana[index + add].value;
      div_scroll(value);
    }

    function akasatana_onchange() {
      var selected_index = akasatana.selectedIndex;
      var target_value = akasatana[selected_index].value;
      div_scroll(target_value);
    }

    function div_scroll(target_value) {
      var target = elem(target_value);
      var abs_pos = target.getBoundingClientRect().top - 5;
      overflow_scroll.scrollBy(0, abs_pos);
    }
  </script>
</body>
</html>


補足

window.scrollTo ではうまく行かなかったので window.scrollBy を使いました


Friday, September 7, 2018

毎週特定の日時ちょうどに実行するトリガーを作る


毎日特定の日時ちょうどに実行するトリガーを作る
とほぼ同じですが、毎日ではなく毎週設定したい場合のコードを別途書きました


この例では、毎週月曜日に実行するため以下のように設定します

  .everyWeeks(1)
  .onWeekDay(ScriptApp.WeekDay.MONDAY)



やりたいこと
  • 毎週月曜日の18時ちょうどに send_mail を実行したい(自動で)



コード.gs
function set_project_trigger(){
  ScriptApp.newTrigger("add_temp_trigger")
  .timeBased()
  .everyWeeks(1)
  .onWeekDay(ScriptApp.WeekDay.MONDAY)
  .atHour(6)
  .create();
}

function add_temp_trigger() {
  delete_temp_trigger();
  var date = new Date();
  date.setHours(18);
  date.setMinutes(00);
  var trigger = ScriptApp.newTrigger("send_mail")
    .timeBased()
    .at(date)
    .create();
}   

function send_mail(){
  var mail_address = Session.getActiveUser().getEmail();
  MailApp.sendEmail(mail_address, "実行したスクリプトID", ScriptApp.getScriptId());
}

function delete_temp_trigger() {
  var allTriggers = ScriptApp.getProjectTriggers();
  for (var i = 0; i < allTriggers.length; i++) {
    if (allTriggers[i].getHandlerFunction() == "send_mail") {
      ScriptApp.deleteTrigger(allTriggers[i]);
      break;
    }
  }
}


関連記事

選択したテキストをアラートに出す


テキストエリア内で選択したテキストを取得したくて書いたコードです

window.getSelection() と onmouseup を使って、テキストを選択した時に
そのテキストを取得してアラートに出してみます


デモ


入力したテキストを選択するとアラートに表示します



コード.gs
function doGet() {
  return HtmlService.createHtmlOutputFromFile("index");
}
意訳
この機能がやること
指定したHTMLファイルを表示する




index.html
<!DOCTYPE html>
<html>
  <body>
  <textarea id="ta"></textarea>
    <script>
    var ta = document.getElementById("ta");
    ta.onmouseup = ta_onmouseup;
    
    function ta_onmouseup(){
      var selection = window.getSelection();
      alert(selection);
    }
    </script>
  </body>
</html>


Thursday, September 6, 2018

フォーカスされている要素を取得したい


現在フォーカスされている要素は

document.activeElement

で取得できる



画面上で何かキーを押した時に
bodyがフォーカスされているかどうかを返したくて
以下のコードを書きました




デモ




コード.gs
function doGet() {
  return HtmlService.createHtmlOutputFromFile("index");
}
意訳
この機能がやること
指定したHTMLファイルを表示する




index.html
<!DOCTYPE html>
<html>
<body>
    <textarea></textarea>
    <script>
        window.onkeyup = window_keyup;

        function window_keyup(e) {
            var focused = document.activeElement;
            var if_body = get_if_body(focused);
            alert(if_body);
        }

        function get_if_body(focused) {
            if (focused == "[object HTMLBodyElement]") {
                return true;
            } else {
                return false;
            }
        }
    </script>
</body>
</html>
意訳
 


テキストエリア

画面上でキーが上がったら

この機能がやること
フォーカスされている要素を取得して
bodyかどうか判定して
アラートに出す


この機能がやること
フォーカスされているのがbodyなら
trueを返す
そうでなければ
falseを返す







Wednesday, September 5, 2018

スプレッドシート内のシート名とインデックスを取得したい


このようなスプレッドシートがある時に


このように [インデックス, シート名]を取得したい
 [[1, シート1], [2, シート2], [3, シート3]]


ということを実現するコードを書きました


コード.gs
function set_indexes_names(){
  var ss = SpreadsheetApp.getActiveSpreadsheet();
  var shs = ss.getSheets();
  var sh_indexes_names = [];
  for(var i = 0; i < shs.length; i++){
    sh_indexes_names.push([shs[i].getIndex(), shs[i].getName()])
  }
  Logger.log(sh_indexes_names);
}



複数のシートをスクリプトで挿入したい


このような配列を用意して
["1月", "2月", "3月", "4月", "5月", "6月", "7月", "8月", "9月", "10月", "11月", "12月"]


このようにシートを自動で作りたい

ということを実現するコードを書きました


コード.gs
function insert_sheets() {
  var months = ["1月", "2月", "3月", "4月", "5月", "6月", "7月", "8月", "9月", "10月", "11月", "12月"];
  var ss = SpreadsheetApp.getActiveSpreadsheet();
  for(var i = 0; i < months.length; i++){
    ss.insertSheet(months[i]);
  }
}
意訳
この機能がやること
シート名の配列を用意する
アクティブスプレッドシートを取得する
配列の要素の数だけ以下を繰り返す
一つずつ名前をつけてシートを挿入する




参考

insertSheet(sheetName)
https://developers.google.com/apps-script/reference/spreadsheet/spreadsheet#insertsheetsheetname

Monday, September 3, 2018

スプレッドシートのURLからスプレッドシートIDとシートIDを取り出したい

スプレッドシートのURLはこのようになっている
var ss_url = "https://docs.google.com/spreadsheets/d/スプレッドシートID/edit#gid=シートID";


スプレッドシートIDを取得したい場合はこんな感じでsplitしてやる
var ss_id = ss_url.split("/d/")[1].split("/edit")[0];


シートIDを取得したい場合はこんな感じでsplitしてやる
var sh_id = ss_url = ss_url.split("#gid=")[1];



コード.gs
function get_id_from_url(){
  var ss_url = "https://docs.google.com/spreadsheets/d/スプレッドシートID/edit#gid=シートID";
  var ss_id = ss_url.split("/d/")[1].split("/edit")[0];
  var sh_id = ss_url.split("#gid=")[1]; 
  Logger.log([ss_id, sh_id]);
}


実行結果


スクロールを最上部に戻したい ELEMENT.scrollTop = 0


ELEMENT.scrollTop でスクロールされたピクセル数を取得できる

ELEMENT.scrollTop = 0
で実現できたので書き残しておこう


デモ

あいうえお
かきくけこ
さしすせそ
たちつてと
なにぬねの
はひふへほ
まみむめも
やゆよ
らりるれろ
わをん




コード.gs
function doGet() {
  return HtmlService.createHtmlOutputFromFile("index");
}
意訳
この機能がやること
指定したHTMLファイルを表示する




index.html
<!DOCTYPE html>
<html>
<head>
    <style>
        #main {
            height: 120px;
            width: 240px;
            overflow: scroll;
            border: solid 1px lightgray;
        }
    </style>
</head>
<body>
    <div id="main">
        あいうえお<br />
        かきくけこ<br />
        さしすせそ<br />
        たちつてと<br />
        なにぬねの<br />
        はひふへほ<br />
        まみむめも<br />
        やゆよ<br />
        らりるれろ<br />
        わをん</div>
    <button id="bt_top">TOP</button>
    <script>
        document.getElementById("bt_top").onclick = bt_top_click;

        function bt_top_click() {
            document.getElementById("main").scrollTop = 0;
        }
    </script>
</body>
</html>
意訳
 



idがmainのスタイル
高さ
幅
スクロールする
枠線




idがmainのdiv
あ行
か行
さ行
た行
な行
は行
ま行
や行
ら行
わ行
最上部に戻るボタン

最上部に戻るボタンをクリックしたらbt_top_clickを実行する

この機能がやること
idがmainの要素のスクロールするピクセル数を決める






Latest post

Extracting data from Google Sheets with regular expressions

Introduction Regular expressions are a powerful tool that can be used to extract data from text.  In Google Sheets, regular expressions ca...