Google elementide loomine ja nende kasutamine oma töös

Prompt:

Kirjuta Google Script
⚙️ Töötamine onEdit päästiku ja LanguageApp klassiga
(reaktsioon tabelis tehtud muudatustele ja teksti tõlkimine Google Sheetsis)
📌 Mida see kood teeb?
See skript töötab automaatselt, kui kasutaja sisestab andmeid Google Sheetsi lahtrisse.
🔄 Koodi tööloogika
🔹 onEdit(e) käivitamine
➡️ Funktsioon käivitub automaatselt, kui kasutaja muudab mõnda lahtrit.
🔹 📄 Lehe kontroll
➡️ Kontrollitakse, millisel lehel muudatus toimus
❗ Kui lehe nimi ei ole “synavara”, siis skript peatub.
🔹 📊 Veeru kontroll
➡️ Kontrollitakse, kas muudatus toimus esimeses veerus
❗ Kui muudatus ei toimunud esimeses veerus, siis skript peatub.
🔹 🌐 Teksti tõlkimine
➡️ Loetakse tekst esimesest veerust
➡️ Kasutatakse Google’i keele API-t LanguageApp.translate()
➡️ Tõlgitakse tekst inglise keelest eesti keelde
🔹 💾 Tulemuse salvestamine
➡️ Tõlgitud tekst salvestatakse teise veergu (samal real)

Iseseisvalt: Optimeeri esialgne onEdit funktsioon ning lisa täiendatud versioon, mis tõlgib teksti veel kolme keelde. (nt prantsuse (fr), jaapani (ja) ja läti (lv) keelde)
Ülesanne:
Kasuta antud Google Scripti koodinäidiseid ja vii need tööle, et saada korrektne tulemus.
Pärast seda optimeeri koodi tehisintellekti abil: lisa uusi võimalusi (nt valideerimine, andmete või tausta kontroll).
Koodis on kommentaarid, mis selgitavad, mida iga osa teeb.

Kood:

/**
 * Funktsioon käivitub automaatselt andmete sisestamisel.
 * Tõlgib veerus A oleva teksti nelja erinevasse keelde (B, C, D, E veerud).
 */
function onEdit(e) {
  // 1. Kontrollime, et sündmus eksisteerib
  if (!e) return;

  var range = e.range;
  var sheet = range.getSheet();

  // 2. FILTRID: Töötame ainult lehel "synavara" ja veerus 1 (A)
  // Samuti väldime päiserea (rida 1) muutmist
  if (sheet.getName() !== "synavara" || range.getColumn() !== 1 || range.getRow() === 1) return;

  var startRow = range.getRow();
  var numRows = range.getNumRows();
  
  // Võtame kõik muudetud lahtrite väärtused korraga
  var values = range.getValues();

  // Käime läbi kõik muudetud read (juhuks, kui kopeeriti mitu rida korraga)
  for (var i = 0; i < numRows; i++) {
    var textToTranslate = values[i][0];
    var currentRow = startRow + i;

    // 3. VALIDEERIMINE: Kui lahter on tühi või liiga lühike, puhastame tõlked ja liigume edasi
    if (!textToTranslate || textToTranslate.toString().trim().length < 1) {
      sheet.getRange(currentRow, 2, 1, 4).clearContent().setBackground(null);
      continue;
    }

    try {
      // 4. TÕLKIMINE: Kasutame LanguageApp teenust
      var tEesti = LanguageApp.translate(textToTranslate, 'en', 'et');
      var tPrantsuse = LanguageApp.translate(textToTranslate, 'en', 'fr');
      var tJaapani = LanguageApp.translate(textToTranslate, 'en', 'ja');
      var tLati = LanguageApp.translate(textToTranslate, 'en', 'lv');

      // 5. SALVESTAMINE: Kirjutame tulemused veergudesse B, C, D ja E
      var results = [[tEesti, tPrantsuse, tJaapani, tLati]];
      var targetRange = sheet.getRange(currentRow, 2, 1, 4);
      
      targetRange.setValues(results);
      
      // 6. VISUAALNE TAGASISIDE: Muudame taustavärvi korraks helehalliks/roheliseks
      targetRange.setBackground("#e8f0fe"); 
      
    } catch (error) {
      Logger.log("Viga tõlkimisel real " + currentRow + ": " + error.message);
    }
  }
}

Kuidas töötab:

Koodi uuendamine:

Prompt: “Kopeerisin kõik koodid” kirjuta uus versioon uute funktsioonidega, näiteks lisa mingisugune andmekontroll

1. Google Drive haldamine:

Vana kood:

 function createFolder() {
     const folder = DriveApp.createFolder("Uus kaust");
     Logger.log("Kaust on loodud: " + folder.getName());
   }

Uus kood:

/**
 * Funktsioon loob Google Drive'i uue kausta, 
 * küsides kasutajalt nime ja kontrollides duplikaate.
 */
function createFolderImproved() {
  // Loome ühenduse Google Sheetsi kasutajaliidesega (UI)
  const ui = SpreadsheetApp.getUi();
  
  // 1. KÜSIME KASUTAJALT SISENDIT
  // Kuvatakse dialoogiaken, kus kasutaja saab sisestada kausta nime
  const response = ui.prompt('Kausta loomine', 'Sisesta uue kausta nimi:', ui.ButtonSet.OK_CANCEL);
  
  // Kontrollime, kas kasutaja vajutas "OK" nuppu
  if (response.getSelectedButton() == ui.Button.OK) {
    const folderName = response.getResponseText();
    
    // Kontrollime, et nimi ei oleks tühi
    if (!folderName || folderName.trim() === "") {
      ui.alert('Viga: Kausta nimi ei tohi olla tühi!');
      return;
    }

    // 2. KONTROLLIME DUPLIKAATE
    // Otsime Drive'ist kaustu, millel on juba sama nimi
    const existingFolders = DriveApp.getFoldersByName(folderName);
    
    if (existingFolders.hasNext()) {
      // Kui selline kaust on juba olemas, teavitame kasutajat ja katkestame töö
      ui.alert('Viga: Kaust nimega "' + folderName + '" on juba olemas!');
    } else {
      
      // 3. LOOME KAUSTA
      // Kui nimi on unikaalne, loome uue kausta Google Drive'i juurkataloogi
      const newFolder = DriveApp.createFolder(folderName);
      const folderUrl = newFolder.getUrl(); // Saame loodud kausta otselingi
      
      // 4. TAGASISIDE KASUTAJALE
      // Teavitame kasutajat edukast loomisest ja näitame linki
      ui.alert('Edu! Kaust "' + folderName + '" on loodud.\nLink: ' + folderUrl);
      
      // 5. ANDMETE SALVESTAMINE TABELISSE
      // Kirjutame loodud kausta lingi aktiivsesse lahtrisse, et seda oleks mugav avada
      SpreadsheetApp.getActiveRange().setValue(folderUrl);
      
      // Logime tegevuse ka skripti konsooli
      Logger.log("Loodi uus kaust: " + folderName + " asukohaga " + folderUrl);
    }
  } else {
    // Kui kasutaja vajutas "Cancel" või pani ak

Näide:

Lisatud: Kontroll, kas samanimeline kaust on juba olemas (et vältida duplikaate).

Lisatud: Kasutajale kuvatakse pärast loomist kohe kausta otselink.

Lisatud: Kausta link kirjutatakse automaatselt tabelisse valitud lahtrisse.

2. Calendar

Vana kood:

function createCalendarEvent() {
  const calendar = CalendarApp.getDefaultCalendar();
  calendar.createEvent("Koosolek", new Date(), new Date(new Date().getTime() + 60 * 60 * 1000));
  Logger.log("Sündmus on loodud");
}

Uus kood:

/**
 * 2. FUNKTSIOON: Kalendrisündmuse loomine (CalendarApp)
 * * Muudatused:
 * 1. Lisatud kasutajalt pealkirja küsimine.
 * 2. Lisatud ajakonflikti kontroll (kas aeg on vaba?).
 * 3. PARANDATUD: ui.alert meetod, et vältida "Parameters don't match" viga.
 */
function createMeetingEventImproved() {
  const ui = SpreadsheetApp.getUi();
  const calendar = CalendarApp.getDefaultCalendar();
  
  // 1. KÜSIME SÜNDMUSE PEALKIRJA
  const titleResponse = ui.prompt('Uus sündmus', 'Sisesta koosoleku pealkiri:', ui.ButtonSet.OK_CANCEL);
  
  // Kui kasutaja vajutab "Cancel" või paneb akna kinni, siis lõpetame töö
  if (titleResponse.getSelectedButton() !== ui.Button.OK) {
    return;
  }
  
  const title = titleResponse.getResponseText();

  // 2. MÄÄRAME AJA
  // Näidisena: sündmus algab 1 tunni pärast ja kestab 1 tund
  const startTime = new Date(new Date().getTime() + 1 * 60 * 60 * 1000); 
  const endTime = new Date(startTime.getTime() + 60 * 60 * 1000);

  // 3. KONTROLLIME KONFLIKTE
  // getEvents tagastab massiivi sündmustega, mis on juba selles ajavahemikus
  const conflictEvents = calendar.getEvents(startTime, endTime);
  
  if (conflictEvents.length > 0) {
    // PARANDUS SIIN: Lisatud ui.ButtonSet.YES_NO, et vältida koodi viga
    const proceed = ui.alert(
      'Hoiatus: Aeg on hõivatud', 
      'Sellel ajal on sul juba ' + conflictEvents.length + ' sündmus(t). Kas soovid siiski jätkata?', 
      ui.ButtonSet.YES_NO
    );
    
    // Kui kasutaja vastab "No", siis katkestame sündmuse loomise
    if (proceed !== ui.Button.YES) {
      Logger.log("Kasutaja tühistas sündmuse loomise ajakonflikti tõttu.");
      return;
    }
  }

  // 4. LOOME SÜNDMUSE
  const event = calendar.createEvent(title, startTime, endTime, {
    description: 'Loodud automaatselt Google Apps Scripti abil.',
    location: 'Veebikoosolek'
  });

  // 5. TEAVITAME KASUTAJAT
  ui.alert('Edu!', 'Sündmus "' + title + '" on kalendrisse lisatud.', ui.ButtonSet.OK);
  
  Logger.log('Sündmus loodud: ' + title + ' (ID: ' + event.getId() + ')');
}

Näide:

Lisatud: Sündmuse pealkirja küsimine interaktiivse akna kaudu.

Lisatud: Nutikas kontroll – skript vaatab, kas valitud aeg on kalendris juba hõivatud, ja hoiatab sind.

Lisatud: Lisainfo (asukoht “Veebis” ja kirjeldus) lisamine sündmusele.

3. DocumentApp

Vana kood:

function createDocument() {
     const doc = DocumentApp.create("Uus dokument");
     const body = doc.getBody();
     body.appendParagraph("Tere, maailm!");
     Logger.log("Dokument on loodud nimega: " + doc.getName());
   }

Uus kood:

/**
 * 3. FUNKTSIOON: Google Docs dokumendi loomine ja haldamine.
 * Lisatud: kasutaja sisend, teksti vormindamine ja sisu asendamine.
 */
function createProjectDocumentImproved() {
  const ui = SpreadsheetApp.getUi();

  // 1. KÜSIME DOKUMENDI PEALKIRJA
  const nameResponse = ui.prompt('Uus dokument', 'Sisesta dokumendi nimi:', ui.ButtonSet.OK_CANCEL);
  if (nameResponse.getSelectedButton() !== ui.Button.OK) return;
  const docName = nameResponse.getResponseText();

  // 2. LOOME DOKUMENDI
  const doc = DocumentApp.create(docName);
  const body = doc.getBody();

  // 3. LISAME SISU JA VORMISTAME (HALDUS)
  // Lisame pealkirja
  const header = body.insertParagraph(0, docName);
  header.setHeading(DocumentApp.ParagraphHeading.HEADING1);
  header.setAlignment(DocumentApp.HorizontalAlignment.CENTER);

  // Küsime kasutajalt põhiteksti
  const textResponse = ui.prompt('Dokumendi sisu', 'Kirjuta siia dokumendi tekst:', ui.ButtonSet.OK_CANCEL);
  const content = textResponse.getSelectedButton() == ui.Button.OK ? textResponse.getResponseText() : "Tekst puudub.";

  body.appendParagraph("\nKoostaja: " + Session.getActiveUser().getEmail());
  body.appendParagraph("Kuupäev: " + new Date().toLocaleDateString());
  
  const mainPara = body.appendParagraph("\n" + content);
  mainPara.setFontSize(12);
  mainPara.setItalic(true);

  // 4. NÄIDE HALDUSEST: Teksti asendamine
  // Kui tekstis on sõna "viga", asendame selle automaatselt sõnaga "PARANDUS"
  body.replaceText("viga", "PARANDUS");

  // 5. TEAVITUS JA LINK
  const docUrl = doc.getUrl();
  ui.alert('Edu!', 'Dokument "' + docName + '" on loodud.\nLink: ' + docUrl, ui.ButtonSet.OK);
  
  // Kirjutame lingi tabelisse, et see ära ei kaoks
  SpreadsheetApp.getActiveRange().setValue(docUrl);
}

Näide:

Lisatud: Dokumendi nime küsimine kasutajalt.

Lisatud: Automaatne kujundamine – pealkiri tehakse suureks (Heading 1) ja kuupäev kaldkirja (Italic).

Lisatud: Teavitusaken koos uue dokumendi lingiga.

4. SpreadsheetApp

Vana kood:

   function addSheet() {
     const spreadsheet = SpreadsheetApp.getActiveSpreadsheet();
     spreadsheet.insertSheet("Uus leht");
     Logger.log("Leht on lisatud");
   }

Uus kood:

/**
 * 4. FUNKTSIOON: Uue töölehe loomine ja andmete haldamine.
 * Lisatud: kontroll, kas leht on olemas, andmete lisamine ja tabeli kujundamine.
 */
function createDataSheetImproved() {
  const ss = SpreadsheetApp.getActiveSpreadsheet();
  const ui = SpreadsheetApp.getUi();
  const sheetName = "Projekt_Andmed";

  // 1. KONTROLL: Kas sellise nimega leht on juba olemas?
  let sheet = ss.getSheetByName(sheetName);
  
  if (sheet) {
    const response = ui.alert('Hoiatus', 'Leht "' + sheetName + '" on juba olemas. Kas soovid selle tühjendada ja uuesti täita?', ui.ButtonSet.YES_NO);
    if (response !== ui.Button.YES) return;
    sheet.clear(); // Puhastame vana sisu ja kujunduse
  } else {
    // Kui lehte pole, loome uue
    sheet = ss.insertSheet(sheetName);
  }

  // 2. ANDMETE LISAMINE (HALDUS)
  // Lisame päiserea
  const headers = [["ID", "Tegevus", "Tähtaeg", "Staatus"]];
  sheet.getRange(1, 1, 1, 4).setValues(headers);

  // Lisame näidisandmed
  const sampleData = [
    ["1", "Kausta loomine", new Date(), "Tehtud"],
    ["2", "Kalendri sündmus", new Date(), "Ootel"],
    ["3", "Dokumendi koostamine", new Date(), "Töös"]
  ];
  sheet.getRange(2, 1, sampleData.length, 4).setValues(sampleData);

  // 3. KUJUNDAMINE (HALDUS)
  // Muudame päise stiili
  const headerRange = sheet.getRange("A1:D1");
  headerRange.setBackground("#45818e") // Tumesinine taust
             .setFontColor("white")    // Valge tekst
             .setFontWeight("bold")    // Paks kiri
             .setHorizontalAlignment("center");

  // Külmutame päiserea, et see kerimisel ei kaoks
  sheet.setFrozenRows(1);

  // Automaatne veergude laiuse reguleerimine
  sheet.autoResizeColumns(1, 4);

  // 4. TEAVITUS
  ui.alert('Edu!', 'Tööleht "' + sheetName + '" on ette valmistatud ja andmetega täidetud.', ui.ButtonSet.OK);
  
  // Aktiveerime uue lehe, et kasutaja näeks tulemust
  sheet.activate();
}

Näide:

Lisatud: Kontroll, et ei loodaks uut lehte, kui “Andmed” nimeline leht on juba olemas.

Lisatud: Tabeli päise automaatne loomine, teksti paksuks muutmine ja tausta värvimine.

Lisatud: Veergude laiuse automaatne kohandamine vastavalt teksti pikkusele.

5. FormsApp

Vana kood:

function createForm() {
     const form = FormApp.create("Küsitlus");
     form.addMultipleChoiceItem()
         .setTitle("Mis on sinu lemmikvärv?")
         .setChoiceValues(["Punane", "Roheline", "Sinine"]);
     Logger.log("Vorm on loodud: " + form.getTitle());
   }

Uus kood:

/**
 * 5. FUNKTSIOON: Google Forms küsitluse loomine ja haldamine.
 * Lisatud: kontroll nime põhjal, erinevad küsimuste tüübid ja seadistamine.
 */
function createSurveyFormImproved() {
  const ui = SpreadsheetApp.getUi();
  const formTitle = "Kliendirahulolu küsitlus";

  // 1. KONTROLL: Kas sellise nimega vorm on juba Drive'is olemas?
  const files = DriveApp.getFilesByName(formTitle);
  if (files.hasNext()) {
    ui.alert('Teavitus', 'Vorm nimega "' + formTitle + '" on juba olemas. Loome uue koopia või muuda olemasolevat Drive-is.', ui.ButtonSet.OK);
    // Me ei peata protsessi, aga anname märku
  }

  // 2. LOOME VORMI
  const form = FormApp.create(formTitle);
  
  // Seadistame vormi (HALDUS)
  form.setDescription('Palun täitke see lühike küsitlus meie teenuse kohta.')
      .setConfirmationMessage('Aitäh vastamast!')
      .setAllowResponseEdits(true)
      .setLimitOneResponsePerUser(false);

  // 3. LISAME ERINEVAID KÜSIMUSI (HALDUS)
  
  // A. Valikvastustega küsimus (Multiple Choice)
  form.addMultipleChoiceItem()
      .setTitle('Kuidas hindate meie teenuse kiirust?')
      .setChoiceValues(['Väga hea', 'Hea', 'Rahuldav', 'Halb'])
      .setRequired(true); // Teeme küsimuse kohustuslikuks

  // B. Märkeruudud (Checkboxes) - Kasutaja saab valida mitu
  form.addCheckboxItem()
      .setTitle('Milliseid meie teenuseid te kasutate?')
      .setChoiceValues(['Konsultatsioon', 'Hooldus', 'Paigaldus', 'Koolitus']);

  // C. Tekstiküsimus (Text Item) - Lühike vastus
  form.addTextItem()
      .setTitle('Mis on teie e-posti aadress?')
      .setHelpText('Sisestage kehtiv e-post.');

  // D. Skaala küsimus (Scale Item) - 1 kuni 5
  form.addScaleItem()
      .setTitle('Kui tõenäoliselt soovitate meid sõbrale?')
      .setBounds(1, 5)
      .setLabels('Kindlasti mitte', 'Kindlasti jah');

  // 4. TEAVITUS JA LINK
  const formUrl = form.getEditUrl();
  const publishedUrl = form.getPublishedUrl();
  
  ui.alert('Edu!', 'Küsitlus on loodud!\n\nMuutmislink: ' + formUrl + '\n\nVastamislink: ' + publishedUrl, ui.ButtonSet.OK);
  
  // Salvestame vastamislingi tabelisse
  SpreadsheetApp.getActiveRange().setValue(publishedUrl);
  
  Logger.log("Loodi vorm: " + formTitle + " (URL: " + publishedUrl + ")");
}

Näide:

Lisatud: Rohkem küsimustüüpe (lisaks valikvastustele ka 1–5 palli skaala).

Lisatud: Vormi seadistus, mis määrab, mis teade ilmub kasutajale pärast vastamist.

Lisatud: Vormi avaliku (vastamis-) lingi kuvamine ekraanil.

6. PropertiesService

Vana kood:

function setProperty() {
     const userProperties = PropertiesService.getUserProperties();
     userProperties.setProperty("username", "admin");
     Logger.log("Atribuut on seadistatud");
   }

Uus kood:

/**
 * 6. FUNKTSIOON: Seadete ja andmete salvestamine (PropertiesService).
 * Lisatud: loendur, andmete lugemine, muutuja kontroll ja kustutamine.
 */
function manageUserPropertiesImproved() {
  const ui = SpreadsheetApp.getUi();
  const props = PropertiesService.getUserProperties();
  
  // 1. LUGEMINE: Võtame olemasoleva loenduri väärtuse (või määrame 0, kui seda pole)
  let count = props.getProperty('runCount');
  count = count ? parseInt(count) : 0;
  
  // 2. MUUTMINE: Suurendame loendurit
  count++;
  
  // 3. SALVESTAMINE: Salvestame uue numbri ja kellaaja
  const now = new Date().toLocaleString();
  props.setProperty('runCount', count.toString());
  props.setProperty('lastRun', now);
  
  // 4. KONTROLL: Küsime kasutajalt, kas ta soovib andmeid näha või hoopis "mälu" tühjendada
  const response = ui.alert(
    'Skripti mälu', 
    'Seda skripti on käivitatud ' + count + ' korda.\nViimane kord oli: ' + now + '\n\nKas soovid seaded tühjendada (Reset)?', 
    ui.ButtonSet.YES_NO
  );
  
  // 5. HALDUS: Andmete kustutamine
  if (response === ui.Button.YES) {
    props.deleteAllProperties();
    ui.alert('Mälu on tühjendatud!');
  }
}

Lisatud: Skripti “mälu” – see loendab nüüd, mitu korda sa oled funktsiooni käivitanud.

Lisatud: Viimase käivitusaja salvestamine ja kuvamine.

Lisatud: Funktsionaalsus, mis võimaldab salvestatud andmeid vajadusel kustutada.

7. UrlFetchApp

Vana kood:

function fetchData() {
     const response = UrlFetchApp.fetch("https://api.example.com/data");
     const data = JSON.parse(response.getContentText());
     Logger.log("Andmed on saadud: " + data);
   }

Uus kood:

/**
 * 7. FUNKTSIOON: Avab akna nalja seadete valimiseks.
 */
function showJokeSettings() {
  const html = HtmlService.createHtmlOutputFromFile('JokeDialog')
      .setWidth(350)
      .setHeight(400);
  SpreadsheetApp.getUi().showModalDialog(html, 'Naljade seadistamine');
}

/**
 * Funktsioon, mida kutsutakse välja HTML-aknast pärast nupule vajutamist.
 */
function fetchCustomJoke(categories, blacklist) {
  const ss = SpreadsheetApp.getActiveSpreadsheet();
  const sheetName = "Jokes";
  
  // Kontrollime/loome lehe
  let sheet = ss.getSheetByName(sheetName);
  if (!sheet) {
    sheet = ss.insertSheet(sheetName);
    sheet.appendRow(["Kuupäev", "Nalja tüüp", "Sisu"]);
    sheet.getRange("A1:C1").setBackground("#cfe2f3").setFontWeight("bold");
  }

  // Koostame URL-i vastavalt valitud checkboxidele
  const catParam = categories.length &gt; 0 ? categories.join(',') : 'Any';
  const blackParam = blacklist.length &gt; 0 ? '&amp;blacklistFlags=' + blacklist.join(',') : '';
  const url = `https://v2.jokeapi.dev/joke/${catParam}?lang=en${blackParam}`;

  try {
    const response = UrlFetchApp.fetch(url);
    const data = JSON.parse(response.getContentText());
    
    if (data.error) throw new Error("Nalja ei leitud valitud kriteeriumitega.");

    const nextRow = sheet.getLastRow() + 1;
    const timeStamp = new Date().toLocaleString();

    if (data.type === "single") {
      sheet.getRange(nextRow, 1, 1, 3).setValues([[timeStamp, "Single", data.joke]]);
    } else {
      sheet.getRange(nextRow, 1, 1, 3).setValues([[timeStamp, "Setup", data.setup]]);
      sheet.getRange(nextRow + 1, 1, 1, 3).setValues([[timeStamp, "Delivery", data.delivery]]);
    }
    
    sheet.autoResizeColumns(1, 3);
    return "Nali on lisatud lehele Jokes!";
  } catch (e) {
    return "Viga: " + e.message;
  }
}
<!DOCTYPE html>
<html>
  <head>
    <base target="_top">
    <style>
      body { font-family: Arial; padding: 10px; line-height: 1.5; }
      h3 { color: #2c3e50; }
      .section { margin-bottom: 15px; border-bottom: 1px solid #eee; padding-bottom: 10px; }
      button { background: #4285f4; color: white; border: none; padding: 10px; width: 100%; cursor: pointer; border-radius: 4px; }
    </style>
  </head>
  <body>
    <h3>Vali kategooriad:</h3>
    <div class="section">
      <input type="checkbox" id="Programming" value="Programming" checked> <label>Programmeerimine</label><br>
      <input type="checkbox" id="Misc" value="Misc"> <label>Muu (Misc)</label><br>
      <input type="checkbox" id="Pun" value="Pun"> <label>Sõnamängud (Pun)</label>
    </div>

    <h3>Filtreeri välja (Blacklist):</h3>
    <div class="section">
      <input type="checkbox" id="nsfw" value="nsfw"> <label>NSFW</label><br>
      <input type="checkbox" id="political" value="political"> <label>Poliitika</label><br>
      <input type="checkbox" id="racist" value="racist"> <label>Rassistlik</label>
    </div>

    <button onclick="sendSettings()">Võta nali!</button>

    <script>
      function sendSettings() {
        const categories = [];
        ['Programming', 'Misc', 'Pun'].forEach(id => {
          if(document.getElementById(id).checked) categories.push(id);
        });

        const blacklist = [];
        ['nsfw', 'political', 'racist'].forEach(id => {
          if(document.getElementById(id).checked) blacklist.push(id);
        });

        google.script.run
          .withSuccessHandler(msg => { google.script.host.close(); })
          .fetchCustomJoke(categories, blacklist);
      }
    </script>
  </body>
</html>

Näide:

8. Utilities

Vana kood:

function encodeText() {
     const text = "Tere, maailm!";
     const encoded = Utilities.base64Encode(text);
     Logger.log("Kodeeritud tekst: " + encoded);
   }

Uus kood:

/**
 * 8. FUNKTSIOON: Teksti kodeerimine ja dekodeerimine (Utilities).
 * Lisatud: dekodeerimise loogika, kasutaja sisend ja valikute haldus.
 */
function manageEncodingImproved() {
  const ui = SpreadsheetApp.getUi();
  
  // 1. KASUTAJA SISEND: Küsime teksti, mida on vaja töödelda
  const textResponse = ui.prompt('Utilities: Kodeerimine', 'Sisesta tekst või Base64 kood:', ui.ButtonSet.OK_CANCEL);
  if (textResponse.getSelectedButton() !== ui.Button.OK) return;
  
  const inputText = textResponse.getResponseText();
  
  // 2. VALIK: Kas kasutaja soovitab kodeerida või dekodeerida?
  const actionResponse = ui.alert('Vali tegevus', 'JAH - Kodeeri Base64-ks\nEI - Dekodeeri Base64-st', ui.ButtonSet.YES_NO);
  
  try {
    if (actionResponse === ui.Button.YES) {
      // 3. KODEERIMINE (Encryption/Encoding)
      const encoded = Utilities.base64Encode(inputText, Utilities.Charset.UTF_8);
      ui.alert('Tulemus (Kodeeritud):', encoded, ui.ButtonSet.OK);
      SpreadsheetApp.getActiveRange().setValue(encoded);
      
    } else {
      // 4. DEKODEERIMINE (Decryption/Decoding)
      const decodedBytes = Utilities.base64Decode(inputText, Utilities.Charset.UTF_8);
      const decodedString = Utilities.newBlob(decodedBytes).getDataAsString();
      
      ui.alert('Tulemus (Dekodeeritud):', decodedString, ui.ButtonSet.OK);
      SpreadsheetApp.getActiveRange().setValue(decodedString);
    }
  } catch (error) {
    // 5. HALDUS: Vigade kontroll (nt kui proovitakse dekodeerida vigast koodi)
    ui.alert('Viga!', 'Tegevus ebaõnnestus. Kontrolli, kas sisend on korrektne Base64 formaat.', ui.ButtonSet.OK);
    Logger.log("Utilities viga: " + error.message);
  }
}

Näide:

Lisatud: Võimalus tekst ise sisestada (mitte koodi sisse kirjutada).

Lisatud: Dekodeerimise funktsioon – saad muuta Base64 koodi tagasi loetavaks tekstiks.

Lisatud: Toetus erimärkidele (UTF-8), et täpitähed kaduma ei läheks.

9. HtmlService

Vana kood:

function showDialog() {
     const html = HtmlService.createHtmlOutput("<p>Tere, maailm!</p>");
     SpreadsheetApp.getUi().showModalDialog(html, "Dialoog");
   }

Uus kood:

/**
 * 9. FUNKTSIOON: HTML-põhise dialoogiakna kuvamine (HtmlService).
 * Lisatud: CSS stiilid, dünaamiline sisu ja suurem aken.
 */
function showHtmlDialogImproved() {
  const ui = SpreadsheetApp.getUi();
  
  // 1. SISU HALDUS: Loome HTML-i koos CSS stiilidega
  // Kasutame muutujaid, et sisu oleks kergesti muudetav
  const pealkiri = "Tervitus skriptilt!";
  const luuletus = `
    <div style="font-family: Arial, sans-serif; padding: 20px; background-color: #f4f4f9; border-radius: 10px;">
      <h2 style="color: #2c3e50;">${pealkiri}</h2>
      <p style="font-style: italic; color: #34495e;">
        Kood on pikk ja kood on lai,<br>
        skriptis valmis suur ja pai.<br>
        Andmed ritta seame me,<br>
        töö siis kiirelt teeme me!
      </p>
      <hr>
      <button onclick="google.script.host.close()" 
              style="background-color: #45818e; color: white; border: none; padding: 10px 20px; border-radius: 5px; cursor: pointer;">
        Sule aken
      </button>
    </div>
  `;

  // 2. HTML-I LOOMINE: Kasutame HtmlService-it
  const htmlOutput = HtmlService.createHtmlOutput(luuletus)
      .setWidth(400)   // Määrame akna laiuse
      .setHeight(300); // Määrame akna kõrguse

  // 3. KUVAMINE: Avame akna Google Sheetsis
  ui.showModalDialog(htmlOutput, "Projekti teavitus");
}

Näide:

Lisatud: CSS-stiilide lisamine (värvid, fondid), et aken näeks professionaalne välja.

Lisatud: Dünaamiline tekst – sisu saab muuta muutujate abil.

Lisatud: Akna suuruse (laius ja kõrgus) täpne paika panemine.

10. ContactsApp

Vana kood:

function createContact() {
     const contact = ContactsApp.createContact("Jaan", "Jaanov", "jaanov@example.com");
     Logger.log("Kontakt on loodud: " + contact.getFullName());
   }

Uus kood:

/**
 * 10. FUNKTSIOON: Google'i kontakti loomine.
 * Küsime nime ja e-posti eraldi akendes ja kontrollime andmeid.
 */
function manageContactsImproved() {
  const ui = SpreadsheetApp.getUi();

  // 1. KÜSIME NIMI
  const nameResponse = ui.prompt("Uus kontakt", "Sisesta eesnimi ja perekonnanimi:", ui.ButtonSet.OK_CANCEL);
  if (nameResponse.getSelectedButton() !== ui.Button.OK) return;
  const fullName = nameResponse.getResponseText().trim();

  if (!fullName) {
    ui.alert("Viga", "Nimi ei tohi olla tühi!", ui.ButtonSet.OK);
    return;
  }

  // 2. KÜSIME E-POSTI
  const emailResponse = ui.prompt("Uus kontakt", "Sisesta kasutaja e-posti aadress:", ui.ButtonSet.OK_CANCEL);
  if (emailResponse.getSelectedButton() !== ui.Button.OK) return;
  const email = emailResponse.getResponseText().trim();

  // Kontrollime, kas e-posti märk (@) on olemas
  if (email.indexOf("@") === -1) {
    ui.alert("Viga", "Palun sisesta korrektne e-posti aadress!", ui.ButtonSet.OK);
    return;
  }

  try {
    // 3. KONTROLLIME DUPLIKAATE
    // Märkus: ContactsApp võib mõnes regioonis vajada teenuse lubamist
    const existingContacts = ContactsApp.getContactsByEmailAddress(email);

    if (existingContacts.length > 0) {
      ui.alert("Hoiatus", "Kontakt e-postiga " + email + " on juba olemas!", ui.ButtonSet.OK);
      return;
    }

    // 4. LOOME KONTAKTI
    const names = fullName.split(" ");
    const firstName = names[0];
    const lastName = names.length > 1 ? names.slice(1).join(" ") : "";

    const contact = ContactsApp.createContact(firstName, lastName, email);
    
    // Lisame lisainfo (Haldus)
    contact.setNotes("Loodud Google Sheetsi kaudu: " + new Date().toLocaleDateString());
    
    ui.alert("Edu!", "Kontakt " + fullName + " on edukalt lisatud.", ui.ButtonSet.OK);
    Logger.log("Loodi kontakt: " + fullName);

  } catch (e) {
    // Kui ContactsApp on tõesti kättesaamatu, anname sellest teada
    ui.alert("Süsteemi viga", "Viga ContactsApp teenusega: " + e.message, ui.ButtonSet.OK);
    Logger.log("Viga: " + e.toString());
  }
}

Näide:

Lisatud: Nime ja e-posti küsimine eraldi akendes (mugavam sisestus).

Lisatud: E-posti aadressi kontroll (kas @ märk on olemas), et vältida tühje kirju.

Lisatud: Automaatse tervitusmeili saatmine (asendab vananenud ContactsApp teenust).

11. Session

Vana kood:

function getUserEmail() {
     const email = Session.getActiveUser().getEmail();
     Logger.log("Kasutaja e-post: " + email);
   }

Uus kood:

/**
 * Tuvastab aktiivse kasutaja e-posti, kuvab selle teavitusaknana
 * ja pakub võimalust salvestada see aktiivsesse lahtrisse.
 */
function getUserEmailImproved() {
  const ui = SpreadsheetApp.getUi();
  
  try {
    // 1. Hankige e-posti aadress
    const email = Session.getActiveUser().getEmail();
    
    // Kontroll, kas e-post on kättesaadav (mõnikord privaatsusseadete tõttu tühi)
    if (!email) {
      ui.alert("Teave puudub", "Sinu e-posti aadress pole skriptile kättesaadav (piiratud õigused).", ui.ButtonSet.OK);
      return;
    }

    // 2. Logi konsooli (arendajale)
    Logger.log("Tuvastatud kasutaja: " + email);

    // 3. Küsi kasutajalt, kas ta soovib e-posti tabelisse lisada
    const response = ui.alert(
      "Kasutaja tuvastatud", 
      "Sinu e-posti aadress on: " + email + "\n\nKas soovid selle lisada valitud lahtrisse?", 
      ui.ButtonSet.YES_NO
    );

    // 4. Tegevus vastavalt valikule
    if (response == ui.Button.YES) {
      const sheet = SpreadsheetApp.getActiveSheet();
      sheet.getActiveCell().setValue(email);
      ui.alert("Tehtud!", "E-post on tabelisse sisestatud.", ui.ButtonSet.OK);
    }

  } catch (error) {
    // Vigade haldus (nt kui skriptil pole üldse õigusi kasutaja info nägemiseks)
    ui.alert("Viga", "Kasutaja info hankimine ebaõnnestus: " + error.toString(), ui.ButtonSet.OK);
  }
}

Näide:

Lisatud: E-posti kuvamine otse teavitusaknas (ei pea logisid vaatama).

Lisatud: “Salvesta” nupp – saad oma e-posti aadressi ühe klõpsuga tabelisse kirjutada.

Lisatud: Turvakontroll juhuks, kui skriptil puudub ligipääs kasutaja andmetele.

Menüü

Kood:

function onOpen() {
  const ui = SpreadsheetApp.getUi();
  
  ui.createMenu('🚀 Admin Paneel')
      .addItem('1. Loo projektikaust (Drive)', 'createNewFolderImproved')
      .addItem('2. Lisa sündmus (Calendar)', 'createMeetingEventImproved')
      .addItem('3. Koosta dokument (Docs)', 'createProjectDocumentImproved')
      .addItem('4. Valmista andmetabel (Sheets)', 'createDataSheetImproved')
      .addSeparator()
      .addItem('5. Loo kohandatud küsitlus (Forms)', 'createSurveyFormImproved')
      .addItem('6. Vaata skripti loendurit (Properties)', 'manageUserPropertiesImproved')
      .addItem('7. Võta nali (JokeAPI Seaded)', 'showJokeSettings')
      .addItem('8. Kodeeri tekst (Utilities)', 'manageEncodingImproved')
      .addSeparator()
      .addItem('9. Näita tervitusakent (HTML)', 'showHtmlDialogImproved')
      .addItem('10. Saada tervitusmeil (Gmail)', 'manageContactsImproved')
      .addItem('11. Tuvasta minu e-post (Session)', 'logUserEmailImproved')
      .addToUi();
}