zaterdag 28 december 2019

Webapp: data from client to server to client with GAS

Finally I understand how to send data from a client to a server and get  (other) data returned from the server at the same time.

At the server side:


function fromAndToClient(dataFromClient){

//do something with dataFromClient

return dataToClient
}

At the client side:


<script>

document.getElementById("button").addEventListener("click",doSomething);

function doSomething(){

var dataFromClient = document.getElementById("idElement").value;
  
google.script.run.withSuccessHandler(fromServer).fromAndToClient(dataFromClient);
    
}
  
  
function fromServer(dataToClient){

  // do something with dataToClient

}
  
</script>

vrijdag 27 december 2019

Inserting an emoji into a Google Spreadsheets sheet with a GAS made custom function

I came across (?) a tweet of @TheSheetsGuy on how to insert an emoji into a Google Spreadsheets sheet using Windows 10.

I don't use Windows so how to insert an emoji into a Google Spreadsheets sheet using Chrome OS?

With a GAS made custom function.


function EMO(number){
var emojies = [[1,"9993"],[2,"9994"],[3,"9995"],[4,"9996"],[5,"9889"]];
  for(var e=0;e<emojies.length;e++){ 
    if(emojies[e][0] == number){
      return String.fromCharCode(emojies[e][1]);
    }
  }
}

Sources:

dinsdag 24 december 2019

Adding new tasks to a Google Tasks list with Google Apps Script

At work all files are send to a central folder named Postbus. In the folder Postbus the files are renamed and send to a folder into which they belong. Almost all done by GAS-script(s).

The new name of the file of a file contains a task if necessary:
case name-yymmdd-letter in tttyymmdd do something
A GAS-script collect the tasks and (1) send  an email once a week with all the tasks and (2) send an email the day before a task has to be done. Since a week or so a GAS-script adds te tasks also to Google Tasks. I now can see the tasks in Google Calender which is very handy.

function tasksToTasksList(){

var bestanden = DriveApp.searchFiles('title contains "ttt"'); 
  while (files.hasNext()){
     var file = files.next();
     var fileName = file.getName();
     var fileDescription = file.getDescription();
      
     if(/ttt\d\d\d\d\d\d/.test(fileName) && /toTasksList/.test(fileDescription) ==false){
      
        var taskDate = YYMMDD_TO_DATE(/\d\d\d\d\d\d/.exec(fileName.split(/ttt/)[1]));
        var caseName = fileName.split(/-\d{6}-/)[0]; 
        var taskWhat =  fileName.split(/ttt\d{6}/)[1].split(".")[0]; 
        var timeZone = Session.getScriptTimeZone();
        
        if(taskDate.getTime() >= (new Date).getTime()){
        
          var task = {
          title: caseName + " " + taskWhat,
          due: Utilities.formatDate(taskDate,timeZone,"yyyy-MM-dd'T'HH:mm:ss'Z'")
          };
          
          Tasks.Tasks.insert(task,hlptasksToTasksList());
          
          file.setDescription("toTasksList_" + DATE_TO_YYMMDD(new Date()));       } 
     } 
  }
}

function hlptasksToTasksList(){

var lists = Tasks.Tasklists.list().items;

  for(var i=0;i<lists.length;i++){
  
    if(lists[i].title == NAME_TASKSLIST){
    
      var idTasksList = lists[i].id;
      
    }
  }
  return idTasksList;
}

function YYMMDD_TO_DATE(yymmdd){
var dateString = yymmdd.toString(); 
var date = new Date(2000 + Number(datumstring.slice(0,2)),Number(dateString.slice(2,4))-1,Number(datumstring.slice(4,6)));
return date;  
}

function DATE_TO_YYMMDD(date){
var timeZone = Session.getScriptTimeZone();
return Utilities.formatDate(new Date(datum),timeZone, "yyMMdd");
}


Sources:

Advancing insight (Adding data from spreadsheet to custom fields in Google Contacts with GAS)

Advancing insight [voortschrijdend inzicht] made me change the script described in Adding data from spreadsheet to custom fields in Google Contacts with GAS.

More efficient.


function zaaknamenNaarContacten(){

  var ss = SpreadsheetApp.openById(ID_SS);
  var sheet = ss.getSheetByName("XXXX");
  var range = sheet.getRange(1,1,sheet.getMaxRows(),sheet.getMaxColumns());
  var data = range.getValues();
  var veldnamen = data[0];
  
  var contacten = ContactsApp.getContactGroup("Clienten").getContacts();
  
  for(var c=0;c<contacten.length;c++){
  
    var contact = contacten[c];
    var alfa = contact.getNickname();
    var zaaknamen = contact.getCustomFields("Zaaknaam").map(function(zaaknaam){return zaaknaam.getValue()});
    
    if(alfa !== ""){
    
     hlpZaaknamenNaarContacten(data,veldnamen,contact,alfa,zaaknamen);
    
    }
  }
}


function hlpZaaknamenNaarContacten(data,veldnamen,contact,alfa,zaaknamen){
  
  for(var d=0;d<data.length;d++){
  
  var row = data[d];
  var zaaknaam = row[veldnamen.indexOf("zaaknaam")];
  var contactidcl = row[veldnamen.indexOf("contactidcl")];
  var alfacl = row[veldnamen.indexOf("zaakalfacl")];
          
  if(contactidcl !== "" && alfacl == alfa && zaaknamen !== undefined && zaaknamen.indexOf(zaaknaam) == -1){  
    contact.addCustomField("Zaaknaam",zaaknaam);  
  }
  else if(contactidcl !== "" && alfacl == alfa && zaaknamen == undefined){  
    contact.addCustomField("Zaaknaam",zaaknaam);  
  }   
 }
}


vrijdag 6 december 2019

Get weekday name from a date in the language of your choice

Until I read this blog  about getting a weekday name from a date, I used a summer time/winter time script I wrote a few months ago.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
var GMT_TIMES = [[2019,[2019,02,31],[2019,9,27]],[2020,[2020,02,29],[2020,9,25]]];

function gmtSummerAndWinterTime(){
  
  var today = new Date(); 
  var thisYear = today.getFullYear(); 
  var todayNumber = today.getTime();
  
  for(var g=0;g<GMT_TIMES.length;g++){
   
    var gmtTijd = GMT_TIMES[g]; 
    var dateSummerTimeNumber = new Date(GMT_TIMES[1][0],GMT_TIMES[1][1],GMT_TIMES[1][2]).getTime(); 
    var dateWinterTimeNumber = new Date(GMT_TIMES[2][0],GMT_TIMES[2][1],GMT_TIMES[2][2]).getTime();
         
    if(GMT_TIMES[0] == thisYear && dateSummerTimeNumber < todayNumber && todayNumber < dateWinterTimeNumber){
      var gmt = "GMT+2"; 
      return gmt;
    }
    else{
    
      gmt = "GMT+1";
      return gmt
    }
  }
}

The Session thing is so much easier.

'Problem' with formatDate(date,timeZone,format)  in combination with  SimpleDateFormat class is that it is in English.  There are people using other languages than English.

The Google Language Service could be used to solve the 'problem'.

I prefer the following 'solution'.


1
2
3
4
5
6
7
8
function getWeekDayName(){
  var weekdayNames = ["zondag","maandag","dinsdag","woensdag","donderdag","vrijdag","zaterdag"];  
  var today = new Date();
  var timeZone = Session.getScriptTimeZone(); 
  var weekdayNumber = Utilities.formatDate(today,timeZone,"u");
  var weekdayName = weekdayNames[weekdayNumber];
  Logger.log('Weekday name is: ' + weekdayName);
}


Resources:
Get weekday name from a date,  Phil Bainbridge, 2 december 2019

Renaming files with Google Apps Script



At my work  files have to be renamed often.

Before I entered the world of GAS webb apps I used a Google Spreadsheet to rename files by combining values from in-cell dropdown listst, in-cell date values etcetera. The only problem was that I (1) had to copy the file name AND (2) paste it into the name of the file that had to be renamed.

This week I made a webb app for renaming files & moving the files to the folder into which they belong.

The format of the file names is:

zaaknaam-jjmmdd-soort document toelichting jjmmdd toelichting taak
case name-yymmdd-document type short description yymmdd short description task


Files are collected in the post box folder (POSTBUS). To rename the proper file it has to have a unique name. GAS takes care of that (11-20).

The following arrays are 'imported' into the html web page via GAS from somewhere else:
  • array with the names of the files in the post box
  • array with case names (names of case folders)
  • array with document 'types' (email to, email from, letter to, letter from, etcetera)

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
function doGet(){
return HtmlService.createHtmlOutputFromFile('html');
}


function toClientPostbusbestanden(){
var postbusbestandenArray = []; 
  
var postbusFiles = DriveApp.getFolderById(ID_POSTBUS).getFiles();
  
while (postbusFiles.hasNext()) {
var postbusFile = postbusFiles.next();
var postbusFileName = postbusFile.getName();
  if(postbusbestandenArray.indexOf(postbusFileName) == -1){
    postbusbestandenArray.push(postbusFileName);
  }
  else{
    postbusFile.setName(postbusFileName + "_" + new Date().getTime())
    postbusbestandenArray.push(postbusFile.getName())
  }
}
if(postbusbestandenArray.length < 1){postbusFileNames.push("dit is geen bestand in de folder Postbus maar een scripthelper")}  
  
return postbusbestandenArray.sort();
}


function toClientZaaknamen(){
  
  var zaaknamenArray = [];
  
  var cache = CacheService.getScriptCache();
  var cached = cache.get("zaaknamenCache");
  if (cached != null) {
    return cached.split(",").sort();
  }
  
  var foldersinFolderZAKEN = DriveApp.getFolderById(ID_ZAKEN).getFolders();
  while (foldersinFolderZAKEN.hasNext()) {
    var folderinFolderZAKEN = foldersinFolderZAKEN.next();
    zaaknamenArray.push(folderinFolderZAKEN.getName())
  }
  
  cache.put("zaaknamen", zaaknamenArray, 1500);
  
  return zaaknamenArray.sort();
}


function toClientSoortDocumenten(){
  
  var soortDocumentenArray = [];
  
  var doc = DocumentApp.openById(ID_HLP_DOCUMENT);
  var tabellen =  doc.getBody().getTables();
  
  var tabel = tabellen[HLP_SOORT_DOCUMENT];
  
  var tabelLengte = tabel.getNumRows();
  
  for(var t=0;t<tabelLengte;t++){
    
    soortDocumentenArray.push(tabel.getCell(t,0).getText());
    
  }
  return soortDocumentenArray
}


I am using (dropdown)  datalists because the arrays are very long.

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
<!DOCTYPE html>
<html>
<head>
<base target="_top">

<link rel="stylesheet" href="https://www.w3schools.com/w3css/4/w3.css">

<script>
function dropDownPostbusbestandenDoc(postbusbestanden) {
for(var i=0;i<postbusbestanden.length;i++){
var option = document.createElement("option");
option.text = postbusbestanden[i];
option.setAttribute("value", option.text);
document.getElementById("datalistpostbusbestanddoc").appendChild(option);
}
}
google.script.run.withSuccessHandler(dropDownPostbusbestandenDoc).toClientPostbusbestanden();

function dropDownZaaknamen(zaaknamen) {
for(var i=0;i<zaaknamen.length;i++){
var option = document.createElement("option");
option.text = zaaknamen[i];
option.setAttribute("value", option.text);
document.getElementById("datalistzaaknaamdoc").appendChild(option);
}
}
google.script.run.withSuccessHandler(dropDownZaaknamen).toClientZaaknamen();

function dropDownSoortDocumenten(soortdocumenten) {
for(var i=0;i<soortdocumenten.length;i++){
var option = document.createElement("option");
option.text = soortdocumenten[i];
option.setAttribute("value", option.text);
document.getElementById("datalistsoortdocument").appendChild(option);
}
}
google.script.run.withSuccessHandler(dropDownSoortDocumenten).toClientSoortDocumenten();

</script>

</head>

<body>

<div class="w3-container w3-margin">

<div class="w3-panel w3-lime">

<div class="w3-xxlarge">
Hernoem document
</div>

<p></p>
<input id="inputpostbusbestanddoc" list="datalistpostbusbestanddoc">
<datalist id="datalistpostbusbestanddoc">
</datalist>
<label for="datalistpostbusbestanddoc">Kies een te hernoemen document</label>

<p></p>
<input id="inputzaaknaamdoc" list="datalistzaaknaamdoc">
<datalist id="datalistzaaknaamdoc">
</datalist>
<label for="datalistzaaknaamdoc">Kies een zaaknaam</label>

<p></p>
<input id="dddocument" type="date">
<label for="dddocument">Dagtekening document</label>

<p></p>
<input id="inputsoortdocument" list="datalistsoortdocument">
<datalist id="datalistsoortdocument">
</datalist>
<label for="datalistsoortdocument">Soort document</label>

<p></p>
<input id= "toelichtingdocument" type="text">
<label for="toelichtingdocument">Toelichting op soort document</label>

<p></p>
<input id="ddtermijnzitting" type="date">
<label for="ddtermijnzitting">Datum termijn of zitting</label>

<p></p>
<input id= "toelichtingtermijnzitting" type="text">
<label for="toelichtingtermijnzitting">Toelichting op termijn of datum strafzaak</label>

<p></p>
<button id="buttondoc" class="w3-button w3-black">Hernoem document</button>

<script>

document.getElementById("buttondoc").addEventListener("click",doSomethingDoc);

function doSomethingDoc() {
  
  var object = {};
  object.postbusbestandsnaam = document.getElementById("inputpostbusbestanddoc").value;
  object.zaaknaam = document.getElementById("inputzaaknaamdoc").value;
  object.datumdocument = document.getElementById("dddocument").value;
  object.soortdocument = document.getElementById("inputsoortdocument").value;
  object.toelichtingdocument = document.getElementById("toelichtingdocument").value;
  object.datumtermijn = document.getElementById("ddtermijnzitting").value;
  object.toelichtingtermijn = document.getElementById("toelichtingtermijnzitting").value;
  
  google.script.run.fromClientObjectDocument(object);
  
  document.getElementById("inputpostbusbestanddoc").value = "";
  document.getElementById("inputzaaknaamdoc").value= "";
  document.getElementById("dddocument").value= "";
  document.getElementById("inputsoortdocument").value= "";
  document.getElementById("toelichtingdocument").value= "";
  document.getElementById("ddtermijnzitting").value= "";
  document.getElementById("toelichtingtermijnzitting").value= "";
}

</script>

</div>
</div>

</body>
</html>

An object with input data is 'exported' from the html page to the apps script.



 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
function fromClientObjectDocument(object){
   
    if(object && object.zaaknaam && object.datumdocument && object.soortdocument){
    
    var timeZone = Session.getScriptTimeZone();
    var jjmmddDagtekening = Utilities.formatDate(new Date(object.datumdocument), timeZone,"yyMMdd");
    
      if(new Date(object.datumtermijn)){
      var jjmmddTermijn = " ttt" + Utilities.formatDate(new Date(object.datumtermijn), timeZone,"yyMMdd");
      var toelichtingTermijn = object.toelichtingtermijn;  
      }
      else{
        var jjmmddTermijn = ""; 
        var toelichtingTermijn = ""; 
      }
      
      var nieuweBestandsnaam = object.zaaknaam + "-" + jjmmddDagtekening + "-"; 
      nieuweBestandsnaam += object.soortdocument + " " + object.toelichtingdocument;
      nieuweBestandsnaam += jjmmddTermijn + " " + toelichtingTermijn + ".pdf"; 
      
      var postbusFiles = DriveApp.getFolderById(ID_POSTBUS).getFiles();
      while (postbusFiles.hasNext()) {
        var postbusFile = postbusFiles.next();
        
        if(postbusFile.getName().indexOf(object.postbusbestandsnaam) !== -1){
        postbusFile.setName(nieuweBestandsnaam);
          
          var zaakFolders = DriveApp.getFoldersByName(object.zaaknaam);
          while (zaakFolders.hasNext()) {
            var zaakFolder = zaakFolders.next();
            var idZaakFolder = zaakFolder.getId();
            DriveApp.getFolderById(idZaakFolder).addFile(postbusFile);
            DriveApp.getFolderById(ID_POSTBUS).removeFile(postbusFile);
          }
        }
      }
    }
  }