Funkce vyšších řádů, události

Funkce vyšších řádů, události

1. Hesla

Stáhněte si JavaScriptový program, který obsahuje tři různé funkce na generování hesel. Každá funkce vygeneruje heslo zadané délky s určitou bezpečnostní silou. Kód funkcí zkoumat nemusíte, obsahuje věci, které jsme zatím neprobírali. Vyzkoušejte si však funkce zavolat z konzole a prohlédněte si, jaká hesla generují.

Napište funkci createAccount, která se bude tvářit, že zakládá nový uživatelský účet. Funkce bude mít dva parametry. První bude uživatelské jméno a druhý bude funkce, pomocí které se má vygenerovat heslo pro tento účet. Funkce createAccount vrátí řetězec, který bude obsahovat jméno uživatele a heslo vygenerovaní voláním funkce obdržené jaké druhý parametr. Například

Založen nový uživatel honza s heslem 123456

Vyzkoušejte v konzoli založit více různých účtů s různými typy hesel.

Řešení

const weakPassword = (len) => {
  let result = '';
  for (let i = 0; i < len; i++) {
    result += String(i % 10);
  }

  return result;
};

const mediumPassword = (len) => {
  let result = '';
  for (let i = 0; i < len; i++) {
    const digit = Math.floor(Math.random() * 10);
    result += String(digit);
  }

  return result;
};

const strongPassword = (len) => {
  const chars = 'abcdefghijklmnopqrstuvwxyz0123456789_-/?';
  let result = '';
  for (let i = 0; i < len; i++) {
    const charIndex = Math.floor(Math.random() * chars.length);
    result += chars[charIndex];
  }

  return result;
};

const createAccount = (jmeno, generujHeslo) => {
  return `${jmeno}: ${generujHeslo(8)}`;
};

console.log(createAccount('mujUcet', mediumPassword));

2. E-mail podruhé

  1. Stáhněte si řešení příkladu E-mail z předchozí lekce.
  2. Všimněte si funkce goodbye, která generuje pozdrav na konec e-mailu. Přidejte alespoň dvě další funkce, kde každá generuje k zadanému jménu jiný typ pozdravu. Například formalGoodbye pro velmi formální pozdravy, nebo rudeGoodbye, pokud se chcete rozloučit naštvaně.
  3. Udělejte z funkce fillBody funkci vyššího řádu. Přidejte jí třetí parametr goodbyeFunc, který představuje funkci, pomocí které se má vygenerovat závěrečný pozdrav. Vyzkoušejte zavolat funkci fillBody postupně s každou z vašich zdravících funkcí a ověřte, že vše správně funguje.

Řešení

'use strict';

const goodbye = (name) => {
  return 'S pozdravem ' + name;
};

const formalGoodbye = (name) => {
  return 'S přáním hezkého dne ' + name;
};

const rudeGoodbye = (name) => {
  return 'S neúctou ' + name;
};

const fillSubject = (subject) => {
  document.querySelector('.email__subject').textContent = subject;
};

const fillBody = (body, name, goodbyeFunc) => {
  const bodyElm = document.querySelector('.email__body');
  bodyElm.textContent = body + ' ' + goodbyeFunc(name);
};

fillBody('Test 1', 'Jan N', rudeGoodbye);
<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <link rel="stylesheet" href="index.css" />
    <title>E-mail</title>
  </head>
  <body>
    <div class="container">
      <div class="email">
        <div class="email__subject">Hokus pokus</div>
        <div class="email__body">
          Lorem ipsum dolor sit, amet consectetur adipisicing elit. Molestiae
          omnis distinctio nisi earum. Veritatis facilis tempore ea doloribus,
          pariatur culpa!
        </div>
      </div>
    </div>
    <script src="index.js"></script>
  </body>
</html>
* {
  box-sizing: border-box;
}

html {
  font-family: sans-serif;
  font-size: 16px;
}

.container {
  max-width: 40rem;
  margin-left: auto;
  margin-right: auto;
}

.email__subject,
.email__body {
  background-color: #efefef;
  margin: 1rem;
  color: #555;
}

.email__subject {
  padding: 1rem 2rem;
}

.email__body {
  padding: 2rem;
}

3. Objednávka

Stáhněte si základ stránky obsahující jedno tlačítko.

  1. Doplňte JavaScriptový program, který zařídí, že po stisknutí tlačítka se do konzole vypíše text
    Objednáno
  2. Pozměňte program tak, že text se nevypíše do konzole, ale zobrazí se na samotném tlačítku.
  3. Pozměňte program tak, že akce objednání se vykoná při kliknutí kamkoliv na stránku, nikoliv pouze na tlačítko.

Řešení

'use strict';
const tlacitko = document.querySelector('#btn-order');

tlacitko.addEventListener('click', () => {
  // 1
  console.log('Objednáno');
  // 2
  tlacitko.textContent = 'Objednáno';
});

// 3

document.addEventListener('click', () => {
  tlacitko.textContent = 'Objednáno';
});
<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8" />
  <meta name="viewport" content="width=device-width, initial-scale=1.0" />
  <title>Objednávka</title>
</head>

<body>
  <button id="btn-order">Objednat</button>
  <div id="vysledek"></div>

  <script src="index.js"></script>
</body>

</html>

4. Kontrola dostupnosti

Vyjděte z řešení předchozího příkladu, kdy se objednává při kliknutí na tlačítko.

  1. Zařiďte, aby při načtení stránky tlačítko obsahovalo zprávu Kontroluji dostupnost...
  2. Přidejte do stránky zpoždění pomocí funkce setTimeout, která zařídí, že 8 vteřin po načtení stránky se zpráva na tlačítku změní na Objednat.
  3. Tlačítka mají speciální HTML atribut s názvem disabled. Pokud je tento atribut přítomen, na tlačítko se nedá kliknout. Přidejte tento atribut do HTML kódu tlačítka, aby tlačítko bylo při načtení stránky nedostupné. Až po uplynutí časovače jej zpřístupněte nastavením vlastnosti disabled na false.

Řešení

'use strict';

setTimeout(() => {
  const tlacitko = document.querySelector('#btn-order');
  // 2
  tlacitko.textContent = 'Objednat';

  //3
  tlacitko.disabled = false;
}, 8000);
<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8" />
  <meta name="viewport" content="width=device-width, initial-scale=1.0" />
  <title>Objednávka</title>
</head>

<body>
  <button id="btn-order" disabled>Kontroluji dostupnost…</button>
  <div id="vysledek"></div>

  <script src="index.js"></script>
</body>

</html>

5. Žárovka

Stáhněte si základ stránky, která zobrazuje obyčejnou žárovku.

  1. Pomocí JavaScriptu zařiďte, aby se při stisknutí libovolné klávesy na stránce přidala k elementu žárovky CSS třída bulb--on. Žárovka by se takto měla rozsvítit.
  2. Vylepšete program tak, aby na následné stisknutí libovolné klávesy žárovka opět zhasnula. Opakovaným mačkávním kláves ji tak můžeme rozsvěcovat a zhasínat.

Řešení

'use strict';

const zarovka = document.querySelector('.bulb');

document.addEventListener('keypress', () => {
  // 1
  // zarovka.classList.add('bulb--on');
  // 2
  zarovka.classList.toggle('bulb--on');
});
<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <link rel="stylesheet" href="style.css" />
    <title>Žárovka</title>
  </head>
  <body>
    <div class="bulb"></div>

    <script src="index.js"></script>
  </body>
</html>
* {
  box-sizing: border-box;
}

html {
  font-family: sans-serif;
  font-size: 15px;
}

body {
  display: flex;
  justify-content: center;
  align-items: center;

  height: 100vh;
}

.bulb {
  width: 250px;
  height: 450px;
  background-size: contain;
  background-image: url('img/bulb-off.png');
}

.bulb--on {
  background-image: url('img/bulb-on.png');
}

6. Na doma | Catering

Mějme tři cateringové společnosti dodávají občerstvení na různé akce. Jsou to

Just Food
Dodává levné jídlo vyrobené z nepříliš kvalitních surovin.
Your Mama
Dodává středně drahé jídlo vyrobené z lepších surovin.
Flavour Haven
Dodává drahé jídlo z kvalitních surovin.

Napište pro každou z těcho společností funkci s jedním parametrem, který udává, pro kolik lidí se catering objednává. Funkce pak vrátí řetězec obsahující zprávu o tom že catering byl dodán a za jakou cenu. Například

catering od Flavour Haven pro 100 lidí za 300 000 kč

Vyzkoušjte si vaše funkce v konzoli. Poté napište funkci createEvent, která představuje vytvoření nějaké události s cateringem. Funkce na vstupu obdrží název události, počet lidí a funkci, pomocí které se má provést catering. Funkce createEvent pak vypíše zprávu ve smyslu

Událost Inaugurace prezidenta s catering od Flavour Haven pro 100 lidí za 300 000 kč

Řešení

'use strict';

const justFood = (boardersCount) => {
  const pricePerBoarder = 500;
  const totalPrice = pricePerBoarder * boardersCount;
  return `catering od Just Food pro ${boardersCount} lidí za ${totalPrice} kč`;
};

const yourMama = (boardersCount) => {
  const pricePerBoarder = 1000;
  const totalPrice = pricePerBoarder * boardersCount;
  return `catering od Your Mama pro ${boardersCount} lidí za ${totalPrice} kč`;
};

const flavourHaven = (boardersCount) => {
  const pricePerBoarder = 3000;
  const totalPrice = pricePerBoarder * boardersCount;
  return `catering od Flavour Haven pro ${boardersCount} lidí za ${totalPrice} kč`;
};

const createEvent = (eventName, participantsCount, cateringFunc) => {
  return `Událost ${eventName} s ${cateringFunc(participantsCount)}`;
};

// použití funkce např:
// createEvent('Inaugurace prezidenta', 100, flavourHaven)

7. Na doma | Kostka

Stáhněte si základ stránky, která zobrazuje hrací kostku. Doplňte do stránky JavaScriptový program, který zařídí, že když uživatel zmáčkne na stránce libovolnou klávesu, na kostce se zobrazí číslo o jedna vyšší. Po šestce zobrazte opět jedničku.

Rozumným postupem je vytvořit si proměnnou side, která bude obsahovat číslo strany kostky. Tuto proměnnou můžete vždy při stisknutí mezerníku navýšit o jedna a z této hodnoty zkonstruovat řetězec pro atribut src.

Řešení

'use strict';

let side = 1;

document.addEventListener('keyup', () => {
  /*
   * nepamatuji si, zda jsme si ukazovali zápis s promenná++,
   * zde konkrétně používám side++, což zajistí
   * zvýšení hodnoty v proměnné side o jedna.
   * Alternativně lze použít zápis:
   * side = side + 1;
   */
  side++;

  if (side > 6) {
    side = 1; // zde zajištuji, že pokud je hodnota side vyšší než 6, tak ji nastaím opět na 1
  }

  const diceElm = document.querySelector('.dice');
  diceElm.src = `img/side${side}.svg`; // zde už pouze nastavím správný obrázek dle hodnoty side
});
<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <link rel="stylesheet" href="style.css" />
    <title>Kostka</title>
  </head>
  <body>
    <img class="dice" src="img/side1.svg" />

    <script src="index.js"></script>
  </body>
</html>

8. Na doma | Minutka

Stáhněte si základ aplikace pro kuchyňskou minutku. Využijte funkci setTimeout ke splnění následujících úkolů.

  1. Zařiďte, aby minutka začala zvonit za pět vteřin po otevření stránky. Zvonění zařídíte tak, že k elementu budíku přídáte CSS třídu alarm--ring.
  2. Nechte uživatele skrze prompt zadat kolik vteřin má uplynout než minutka začne zvonit.
  3. Můžete zařídit i spuštění zvuku. Stačí ze stránky vybrat audio element a zavolat na něm metodu play. Abyste zvuk slyšeli, musíte po zadání času na stránku kliknout. Prohlíč Chrome totiž brání stránkam přehrávat audio či video dokud uživatel se stránkou nějak neinteragoval.
  4. Přidejte na stránku tlačítko, které umožní odpočet minutky zrušit dřív, než začne zvonit.

Řešení

'use strict';

/* první úkol

setTimeout(() => {
  const minutkaElm = document.querySelector('.alarm');
  minutkaElm.classList.add('alarm--ring');
}, 5000);

*/

/*
// druhý úkol
const vteriny = Number(prompt('Za jak dlouho začne minutka zvonit (vteřiny):'));

setTimeout(() => {
  const minutkaElm = document.querySelector('.alarm');
  minutkaElm.classList.add('alarm--ring');

  // třetí úkol
  const audioElm = document.querySelector('audio');
  audioElm.play();
}, vteriny * 1000);
*/

// čtvrtý úkol
// pro splnění čtvrtého úkolu si musíte nastudovat rušení časovačů:
// https://kodim.cz/czechitas/daweb/zaklady-js/hof-udalosti/#povinne-cteni-na-doma

const vteriny = Number(prompt('Za jak dlouho začne minutka zvonit (vteřiny):'));

const timerID = setTimeout(() => {
  const minutkaElm = document.querySelector('.alarm');
  minutkaElm.classList.add('alarm--ring');
  const audioElm = document.querySelector('audio');
  audioElm.play();
}, vteriny * 1000);

const stopTimerButton = document.querySelector('#stopTimer');
stopTimerButton.addEventListener('click', () => {
  clearTimeout(timerID);
});
<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <link rel="stylesheet" href="style.css" />
    <title>Minutka</title>
  </head>
  <body>
    <audio>
      <source src="assets/alarm.mp3" type="audio/mpeg" />
    </audio>
    <div class="container">
      <div class="alarm"></div>
      <button id="stopTimer" class="button">Zastavit časovač</button>
    </div>
    <script src="index.js"></script>
  </body>
</html>
@import url('https://fonts.googleapis.com/css?family=Roboto:100,400,700&display=swap');

* {
  box-sizing: border-box;
}

html {
  font-family: 'Roboto', sans-serif;
  font-size: 15px;
}

body {
  display: flex;
  background-color: #4ecdc4;
}

.container {
  width: 30rem;
  margin-left: auto;
  margin-right: auto;
  text-align: center;
}

.alarm {
  width: 30rem;
  height: 30rem;
  background-size: contain;
  background-image: url('assets/alarm.svg');
}

@keyframes ring {
  0% {
    transform: rotateZ(0deg);
  }
  25% {
    transform: rotateZ(5deg);
  }
  50% {
    transform: rotateZ(0deg);
  }
  75% {
    transform: rotateZ(-5deg);
  }
  100% {
    transform: rotateZ(0deg);
  }
}

.alarm--ring {
  animation: ring 100ms 50;
}

.button {
  background-color: #f11827;
  color: white;
  cursor: pointer;
  padding: 10px 20px;
  margin: 0 auto;
  border: none;
  border-radius: 5px;
  font-weight: 700;
  font-size: 2em;
}

.button:hover {
  background-color: #9e0f19;
}