Przejdź do głównej treści
INF.03-02-24.06-SGCzerwiec 2024 · 54 kroki · ok. 92 min · 40 kryteriów z klucza

Rozwiązanie krok po kroku: Prototyp front-endu chatu (Wersja podstawowa)

Prototyp chatu to baza chat (uczestnicy i dane logowania) z pięcioma zapytaniami - INSERT z identyfikatorem wziętym z relacji, średnia AVG zaokrąglona w dół FLOOR z aliasem, JOIN z LIKE, a na koniec CREATE USER i GRANT - oraz zdjęcie przycięte w edytorze grafiki i strona chat.html z oknem rozmowy. Skrypt JavaScript dokłada do okna wiadomość wpisaną w pole (jako wypowiedź Jolanty) albo losową odpowiedź Krzysztofa z tablicy dziewięciu tekstów i przewija okno do nowej wypowiedzi.

Kroki idą zdanie po zdaniu za treścią arkusza - przy każdym jest polecenie z arkusza, a kod pokazuje dokładnie te linie, które je spełniają. Skrypt jest najpierw napisany najprościej, funkcjami z tabel 1 i 2 arkusza (createElement, classList.add, innerText, appendChild, scrollIntoView, zdarzenie onclick), a na końcu przerobiony na wersję z prawdziwych projektów: jedna wspólna funkcja zamiast dwóch kopii, pomijanie pustych wiadomości, wysyłanie klawiszem Enter i nasłuchiwacze zdarzeń.

To jest wersja podstawowa. W zakładce „Nowoczesny kod (grid, addEventListener)” jest drugi sposób rozwiązania tego samego arkusza: bloki na siatce CSS, formularz z obsługą klawisza Enter i jedna funkcja tworząca wypowiedź od początku, zdarzenia podpięte przez addEventListener - obie wersje są zgodne z kluczem.

Baza, zdjęcia i teksty odpowiedzi pochodzą z prawdziwego archiwum pliki2 (załącznik do arkusza, hasło w treści zadania). Zrzuty wyników zapytań są odtworzone z tej bazy - na egzaminie robisz je sam, z całego ekranu. Działanie skryptu jest sprawdzone w prawdziwej przeglądarce Chrome.

Jak liczą się punkty. Klucz ma 40 kryteriów (R.1.1 - R.5.9), każde za 1 punkt. Próg zdania części praktycznej to 75%, czyli 30 punktów - można stracić 10 kryteriów i nadal zdać. Przy każdym kroku jest napisane, które kryteria spełnia; egzaminator ocenia spełnienie kryteriów z klucza, nie zgodność z tym kodem.

  1. Etap 1: Baza danych

    Kroki 1-8 · po tym etapie masz 7 z 40 kryteriów (pkt)

    Krok 1: Baza danych chat

    ok. 2 min
    Polecenie z arkusza

    Utwórz bazę danych o nazwie chat, z zestawem polskich znaków (np. utf8_unicode_ci)

    Najpierw archiwum pliki2.zip z pulpitu (hasło ChaT_Ch@t, wielkość liter ma znaczenie) i folder z numerem zdającego - arkusz każe umieścić w nim rozpakowane pliki. W phpMyAdmin: Nowa, nazwa chat, porównywanie utf8_unicode_ci.

  2. Krok 2: Import tabel z pliku baza.sql

    ok. 2 min
    Polecenie z arkusza

    Do bazy zaimportuj tabele z pliku baza.sql z rozpakowanego archiwum

    Zaznaczona baza chat, potem Import → baza.sql → Wykonaj. Powstają dwie tabele z obrazu 1: logowanie (nick i hasło, na razie 2 wiersze) i uczestnicy (3 osoby). Pole logowanie_id uczestnika wskazuje jego wiersz w tabeli logowanie - Jeremi Kowalski ma już logowanie_id = 3, choć wiersza o tym identyfikatorze jeszcze nie ma.

  3. Krok 3: Zrzut ekranu import.png

    Kryteria:

    R.1.1 Wykonano import tabel do bazy danych chat czynność udokumentowano plikiem o nazwie import w formacie PNG

    ok. 2 min
    Polecenie z arkusza

    Wykonaj zrzut ekranu po imporcie. Zrzut zapisz w formacie PNG i nazwij import. Nie kadruj zrzutu. Powinien on obejmować cały ekran monitora, z widocznym paskiem zadań. Na zrzucie powinny być widoczne elementy wskazujące na poprawnie wykonany import tabel.

    Print Screen, wklejenie do edytora grafiki i zapis jako import.png. Uwaga na formaty: import idzie do PNG, a zrzuty zapytań do JPEG.

    Typowe błędy

    Wykadrowany zrzut albo zrzut bez paska zadań nie jest oceniany (uwaga w kluczu przy R.1).

  4. Krok 4: Zapytanie 1: dane logowania Jeremiego

    Kryteria: ,

    R.1.2 Zapisano plik kwerendy.txt zawierający co najmniej jedno zapytanie SQL, wynikające z treści zadania

    R.1.3 Wykonano zapytanie 1 wstawiające do tabeli logowanie nick "Jeremi" z hasłem „Jer123” o id=3. W pliku z kwerendami lub na zrzucie istnieje zapis np.: INSERT INTO `logowanie`(`id`, `nick`, `haslo`) VALUES (3, 'Jeremi','Jer123'); oraz wynik działania udokumentowano zrzutem, na którym jest widoczne pomyślnie wykonane zapytanie lub tabela ze wstawionym wierszem o id=3

    ok. 2 min
    Polecenie z arkusza

    Zapytanie 1: wstawiające do tabeli logowanie nick „Jeremi” z hasłem „Jer123”. Wstawianemu wierszowi należy nadać identyfikator, odpowiadający wartości klucza obcego dla wiersza z danymi „Jeremi Kowalski” z tabeli uczestnicy

    • INSERT INTO logowanie (id, nick, haslo) - tym razem identyfikator podaje się sam, bo musi pasować do relacji,
    • VALUES (3, 'Jeremi', 'Jer123') - trójka to wartość logowanie_id w wierszu Jeremiego Kowalskiego w tabeli uczestnicy (wystarczy ją odczytać w phpMyAdmin).

    Tabela logowanie nie ma w tym dumpie AUTO_INCREMENT, więc bez podanego id wiersz dostałby zero. Zapytania trafiają do kwerendy.txt, zrzut z komunikatem albo z wstawionym wierszem do kw1.jpg.

    kwerendy.txt Tekst nowy plik
    -- Zapytanie 1
    INSERT INTO logowanie (id, nick, haslo) VALUES (3, 'Jeremi', 'Jer123');
    Podgląd strony po tym kroku
    Podgląd strony po kroku 4
  5. Krok 5: Zapytanie 2: średni rok urodzenia zaokrąglony w dół

    Kryteria:

    R.1.4 Wykonano zapytanie 2 obliczające średni rok urodzenia uczestników. Wybrana kolumna powinna nosić nazwę "Średni rok urodzenia", a obliczony wynik powinien być zaokrąglony do najbliższej mniejszej liczby całkowitej. W pliku z kwerendami lub na zrzucie istnieje zapis np.: SELECT FLOOR(AVG(rokUr)) AS "Średni rok urodzenia" FROM uczestnicy; oraz wynik działania udokumentowano zrzutem, na którym jest widoczna wartość całkowita 2001, nazwa kolumny (alias) "Średni rok urodzenia"

    ok. 2 min
    Polecenie z arkusza

    Zapytanie 2: obliczające średni rok urodzenia uczestników. Wybrana kolumna powinna mieć nazwę (alias) „Średni rok urodzenia”, a obliczony wynik powinien być zaokrąglony w dół do liczby całkowitej

    • AVG(rokUr) - średnia z kolumny rokUr wszystkich uczestników,
    • FLOOR(AVG(rokUr)) - zaokrąglenie średniej w dół do liczby całkowitej (tabela 3 arkusza; ROUND zaokrągla do najbliższej, CEIL w górę),
    • AS `Średni rok urodzenia` - alias ze spacjami trzeba ująć w lewe apostrofy albo w cudzysłów.

    Wynik: 2001. Zrzut: kw2.jpg.

    Typowe błędy

    Alias bez cudzysłowu (AS Średni rok urodzenia) to błąd składni - po pierwszym słowie MySQL oczekuje słowa FROM.

    kwerendy.txt Tekst zmienione: 3 linie
    -- Zapytanie 1
    INSERT INTO logowanie (id, nick, haslo) VALUES (3, 'Jeremi', 'Jer123');
    
    -- Zapytanie 2
    SELECT FLOOR(AVG(rokUr)) AS `Średni rok urodzenia` FROM uczestnicy;
    Podgląd strony po tym kroku
    Podgląd strony po kroku 5
  6. Krok 6: Zapytanie 3: uczestnicy na J z danymi logowania

    Kryteria:

    R.1.5 Wykonano zapytanie 3 wybierające jedynie imię i nazwisko uczestnika oraz odpowiadające mu nick i hasło dla imion rozpoczynających się literą J. W pliku z kwerendami lub na zrzucie istnieje zapis np.: SELECT imie, nazwisko, nick, haslo FROM uczestnicy JOIN logowanie ON logowanie_id = logowanie.id WHERE imie LIKE "J%"; (możliwe również INNER JOIN lub bez JOIN i porównanie kluczy po WHERE) oraz wynik działania udokumentowano zrzutem, na którym są widoczne dokładnie 2 rekordy: Jolanta Nowak Jolka Jol123; Jeremi Kowalski Jeremi Jer123. Jeżeli nie wykonano R.1.3 jest widoczny dokładnie 1 rekord dla Jolanty

    ok. 2 min
    Polecenie z arkusza

    Zapytanie 3: wybierające jedynie imię i nazwisko uczestnika oraz odpowiadające mu nick i hasło dla imion rozpoczynających się literą J. Należy posłużyć się relacją

    • SELECT imie, nazwisko, nick, haslo - dwa pola z uczestnicy, dwa z logowanie,
    • FROM uczestnicy JOIN logowanie - złączenie,
    • ON uczestnicy.logowanie_id = logowanie.id - relacja z obrazu 1,
    • WHERE imie LIKE 'J%' - % zastępuje dowolny ciąg znaków, więc wzorzec łapie każde imię zaczynające się od „J”.

    Wynik: Jolanta Nowak Jolka Jol123 i Jeremi Kowalski Jeremi Jer123 - Jeremi jest w wyniku tylko dzięki zapytaniu 1 (bez niego złączenie nie znalazłoby pary). Zrzut: kw3.jpg.

    kwerendy.txt Tekst zmienione: 3 linie
    -- Zapytanie 1
    INSERT INTO logowanie (id, nick, haslo) VALUES (3, 'Jeremi', 'Jer123');
    
    -- Zapytanie 2
    SELECT FLOOR(AVG(rokUr)) AS `Średni rok urodzenia` FROM uczestnicy;
    
    -- Zapytanie 3
    SELECT imie, nazwisko, nick, haslo FROM uczestnicy JOIN logowanie ON uczestnicy.logowanie_id = logowanie.id WHERE imie LIKE 'J%';
    Podgląd strony po tym kroku
    Podgląd strony po kroku 6
  7. Krok 7: Zapytanie 4: użytkownik uczestnik

    Kryteria:

    R.1.6 Wykonano zapytanie 4 tworzące użytkownika uczestnik na localhost z hasłem Ucz123& W pliku z kwerendami lub na zrzucie istnieje zapis np.: CREATE USER uczestnik@localhost IDENTIFIED BY "Ucz123&" oraz wynik działania udokumentowano zrzutem, na którym widoczne jest poprawnie wykonane zapytanie

    ok. 2 min
    Polecenie z arkusza

    Zapytanie 4: tworzące użytkownika uczestnik na localhost z hasłem Ucz123&

    • CREATE USER 'uczestnik'@'localhost' - konto serwera MySQL (nie wiersz tabeli): nazwa i host, z którego wolno się logować,
    • IDENTIFIED BY 'Ucz123&' - hasło w apostrofach.

    Zapytanie nie zwraca wierszy - na zrzucie kw4.jpg widać komunikat o poprawnym wykonaniu. Zapytania 4 i 5 wpisuje się w zakładce SQL serwera albo bazy - działają w obu miejscach.

    kwerendy.txt Tekst zmienione: 3 linie
    -- Zapytanie 1
    INSERT INTO logowanie (id, nick, haslo) VALUES (3, 'Jeremi', 'Jer123');
    
    -- Zapytanie 2
    SELECT FLOOR(AVG(rokUr)) AS `Średni rok urodzenia` FROM uczestnicy;
    
    -- Zapytanie 3
    SELECT imie, nazwisko, nick, haslo FROM uczestnicy JOIN logowanie ON uczestnicy.logowanie_id = logowanie.id WHERE imie LIKE 'J%';
    
    -- Zapytanie 4
    CREATE USER 'uczestnik'@'localhost' IDENTIFIED BY 'Ucz123&';
    Podgląd strony po tym kroku
    Podgląd strony po kroku 7
  8. Krok 8: Zapytanie 5: prawa SELECT i UPDATE do tabeli uczestnicy

    Kryteria:

    R.1.7 Wykonano zapytanie 5 nadające utworzonemu użytkownikowi prawa do wybierania i aktualizacji danych jedynie dla tabeli uczestnicy . W pliku z kwerendami lub na zrzucie istnieje zapis np.: GRANT SELECT, UPDATE ON chat.uczestnicy TO uczestnik@localhost; oraz wynik działania udokumentowano zrzutem, na którym widoczne jest poprawnie wykonane zapytanie lub użytkownik z przydzielonymi prawami SELECT, UPDATE

    ok. 2 min
    Polecenie z arkusza

    Zapytanie 5: nadające utworzonemu użytkownikowi prawa do wybierania i aktualizacji danych jedynie dla tabeli uczestnicy

    • GRANT SELECT, UPDATE - wybieranie i aktualizacja danych,
    • ON chat.uczestnicy - tylko ta jedna tabela tej bazy (chat.* dałoby prawa do wszystkich tabel),
    • TO 'uczestnik'@'localhost'.

    Sprawdzone: SHOW GRANTS pokazuje GRANT SELECT, UPDATE ON chat.uczestnicy, a po zalogowaniu jako uczestnik zapytanie do tabeli uczestnicy działa, a do logowanie kończy się odmową („SELECT command denied”). Zrzut: kw5.jpg.

    kwerendy.txt Tekst zmienione: 3 linie
    -- Zapytanie 1
    INSERT INTO logowanie (id, nick, haslo) VALUES (3, 'Jeremi', 'Jer123');
    
    -- Zapytanie 2
    SELECT FLOOR(AVG(rokUr)) AS `Średni rok urodzenia` FROM uczestnicy;
    
    -- Zapytanie 3
    SELECT imie, nazwisko, nick, haslo FROM uczestnicy JOIN logowanie ON uczestnicy.logowanie_id = logowanie.id WHERE imie LIKE 'J%';
    
    -- Zapytanie 4
    CREATE USER 'uczestnik'@'localhost' IDENTIFIED BY 'Ucz123&';
    
    -- Zapytanie 5
    GRANT SELECT, UPDATE ON chat.uczestnicy TO 'uczestnik'@'localhost';
    Podgląd strony po tym kroku
    Podgląd strony po kroku 8
  9. Etap 2: Grafika i strona HTML

    Kroki 9-30 · po tym etapie masz 19 z 40 kryteriów (pkt)

    Krok 9: Jolka.jpg: kadr do kwadratu z całą twarzą

    ok. 3 min
    Polecenie z arkusza

    Grafika Jolka.jpg przygotowana, podobnie jak Krzysiek.jpg. Grafikę Jolka.jpg należy wykadrować do kwadratu tak, aby była widoczna tylko cała twarz. Następnie należy przeskalować dokładnie do rozmiaru 70 px na 70 px.

    Wzorem jest Krzysiek.jpg z archiwum: sama twarz, 70 × 70 pikseli. Oryginał Jolka.jpg ma 640 × 427 i pokazuje całą postać na tle drzew. W GIMP-ie: narzędzie Zaznaczanie prostokątne z opcją Stałe: Proporcje 1:1 (zaznaczenie zawsze kwadratowe), obrys od czoła do brody i od policzka do policzka, potem Obraz → Przytnij do zaznaczenia. W tym rozwiązaniu kwadrat ma 180 × 180 pikseli i zaczyna się w punkcie (165, 70) - widać całą twarz, a tło prawie znika.

    Podgląd strony po tym kroku
    Podgląd strony po kroku 9
  10. Krok 10: Jolka.jpg: skala do 70 × 70 px

    Kryteria:

    R.2.1 Plik Jolka.jpg wykadrowano do kwadratu, tak, aby była widoczna cała twarz. Wymiary grafiki to 70 px na 70 px

    ok. 2 min
    Polecenie z arkusza

    Grafika Jolka.jpg przygotowana, podobnie jak Krzysiek.jpg. Grafikę Jolka.jpg należy wykadrować do kwadratu tak, aby była widoczna tylko cała twarz. Następnie należy przeskalować dokładnie do rozmiaru 70 px na 70 px.

    Obraz → Skaluj obraz, szerokość i wysokość 70 px. Kadr jest kwadratem, więc proporcje się nie zmieniają i twarz nie jest spłaszczona. Eksport pod tą samą nazwą: Plik → Nadpisz Jolka.jpg (albo Wyeksportuj jako). Teraz oba zdjęcia mają ten sam rozmiar, co przyda się w blokach wypowiedzi wysokich na 70 px.

    Typowe błędy

    Skalowanie całego zdjęcia 640 × 427 do 70 × 70 bez kadrowania spłaszcza postać i nie pokazuje „tylko twarzy”.

    Podgląd strony po tym kroku
    Podgląd strony po kroku 10
  11. Krok 11: Plik chat.html w HTML5

    ok. 1 min
    Polecenie z arkusza

    Składa się ze strony o nazwie chat.html zapisanej w języku HTML5

    Deklaracja <!DOCTYPE html>, sekcje head i body. Strona nie ma skryptów PHP, więc wystarczy rozszerzenie .html - plik otwiera się w przeglądarce prosto z folderu.

    chat.html HTML nowy plik
    <!DOCTYPE html>
    <html>
    <head>
    </head>
    <body>
    </body>
    </html>
    Podgląd strony po tym kroku (chat.html)
  12. Krok 12: Język strony

    ok. 1 min
    Polecenie z arkusza

    Ustawiony język zawartości strony na polski

    Atrybut lang="pl" w znaczniku <html>.

    chat.html HTML zmienione: 1 linia
    <!DOCTYPE html>
    <html lang="pl">
    <head>
    </head>
    <body>
    </body>
    </html>
    Podgląd strony po tym kroku (chat.html)
  13. Krok 13: Kodowanie polskich znaków

    Kryteria:

    R.2.2 Witrynę internetową zapisano w pliku chat.html oraz zapisano jawnie standard kodowania polskich znaków i deklarację HTML5 <!DOCTYPE HTML> i zadeklarowano język witryny polski np.<HTML lang="pl">. Strona zawiera sekcje head i body

    ok. 1 min
    Polecenie z arkusza

    Jawnie zastosowany właściwy standard kodowania polskich znaków

    <meta charset="UTF-8"> jako pierwszy element <head>. Ten krok zamyka kryterium R.2.2: nazwa pliku, deklaracja HTML5, język i kodowanie.

    chat.html HTML zmienione: 1 linia
    <!DOCTYPE html>
    <html lang="pl">
    <head>
        <meta charset="UTF-8">
    </head>
    <body>
    </body>
    </html>
    Podgląd strony po tym kroku (chat.html)
  14. Krok 14: Tytuł strony

    Kryteria:

    R.2.3 Nadano tytuł stronie: Chat

    ok. 1 min
    Polecenie z arkusza

    Tytuł strony widoczny na karcie przeglądarki: „Chat”

    <title> w <head>.

    chat.html HTML zmienione: 1 linia
    <!DOCTYPE html>
    <html lang="pl">
    <head>
        <meta charset="UTF-8">
        <title>Chat</title>
    </head>
    <body>
    </body>
    </html>
    Podgląd strony po tym kroku (chat.html)
  15. Krok 15: Podpięcie arkusza stylów

    Kryteria:

    R.3.5 Strona zawiera działające połączenie z zewnętrznym arkuszem stylów o nazwie styl.css , formatowanie CSS pochodzi jedynie z tego arkusza Uwaga: kryterium to nie jest spełnione również, gdy zdający źle przypisał co najmniej jeden selektor do bloku (np. kropka zamiast #)

    ok. 1 min
    Polecenie z arkusza

    Arkusz stylów w pliku o nazwie styl.css prawidłowo połączony z kodem strony

    Nazwa pliku: styl.css (nie style.css). Klucz przypomina, że R.3.5 przepada także wtedy, gdy któryś selektor jest źle zapisany, np. kropka zamiast # przy identyfikatorze.

    chat.html HTML zmienione: 1 linia
    <!DOCTYPE html>
    <html lang="pl">
    <head>
        <meta charset="UTF-8">
        <title>Chat</title>
        <link rel="stylesheet" href="styl.css">
    </head>
    <body>
    </body>
    </html>
    Podgląd strony po tym kroku (chat.html)
  16. Krok 16: Bloki: baner, boczny, główny, stopka

    Kryteria:

    R.2.4 Układ strony zdefiniowano dzieląc ją na bloki: banera, boczny, główny oraz stopkę. Zastosowano semantyczne znaczniki sekcji HTML5 zgodnie z ich znaczeniem, w tym do części nagłówkowej - header, stopki - footer, dopuszcza się zagnieżdżenie bloków div w znacznikach semantycznych

    ok. 2 min
    Polecenie z arkusza

    Podział strony na baner i pod nim blok główny, obok obu bloków blok boczny oraz na dole stopka. Podział zrealizowany wyłącznie za pomocą semantycznych znaczników sekcji języka HTML5 tak, aby po uruchomieniu w przeglądarce wygląd układu bloków był zgodny z obrazem 2

    Baner to header, stopka footer (klucz wymienia je wprost), blok boczny aside, główny main (R.2.4). Kolejność w kodzie - baner, boczny, główny, stopka - jest taka jak kolejność opisu zawartości bloków w arkuszu i ułatwi ułożenie bloków w CSS: blok boczny musi stanąć obok banera, więc w kodzie stoi tuż za nim.

    chat.html HTML zmienione: 8 linii
    <!DOCTYPE html>
    <html lang="pl">
    <head>
        <meta charset="UTF-8">
        <title>Chat</title>
        <link rel="stylesheet" href="styl.css">
    </head>
    <body>
        <header>
        </header>
        <aside>
        </aside>
        <main>
        </main>
        <footer>
        </footer>
    </body>
    </html>
    Podgląd strony po tym kroku (chat.html)
  17. Krok 17: Baner: nagłówek

    ok. 1 min
    Polecenie z arkusza

    Zawartość banera: nagłówek drugiego stopnia o treści „Chat”

    <h2> w banerze.

    chat.html HTML zmienione: 1 linia
    <!DOCTYPE html>
    <html lang="pl">
    <head>
        <meta charset="UTF-8">
        <title>Chat</title>
        <link rel="stylesheet" href="styl.css">
    </head>
    <body>
        <header>
            <h2>Chat</h2>
        </header>
        <aside>
        </aside>
        <main>
        </main>
        <footer>
        </footer>
    </body>
    </html>
    Podgląd strony po tym kroku (chat.html)
  18. Krok 18: Blok boczny: nagłówek „Chaty”

    ok. 1 min
    Polecenie z arkusza

    Zawartość bloku bocznego: Nagłówek trzeciego stopnia o treści „Chaty”

    <h3> na początku bloku bocznego.

    chat.html HTML zmienione: 1 linia
    <!DOCTYPE html>
    <html lang="pl">
    <head>
        <meta charset="UTF-8">
        <title>Chat</title>
        <link rel="stylesheet" href="styl.css">
    </head>
    <body>
        <header>
            <h2>Chat</h2>
        </header>
        <aside>
            <h3>Chaty</h3>
        </aside>
        <main>
        </main>
        <footer>
        </footer>
    </body>
    </html>
    Podgląd strony po tym kroku (chat.html)
  19. Krok 19: Lista punktowana: Ogólny, Tematyczne

    ok. 1 min
    Polecenie z arkusza

    Lista punktowana z elementami: „Ogólny” , „Tematyczne”.

    Lista punktowana to <ul>, każdy element w <li>.

    chat.html HTML zmienione: 4 linie
    <!DOCTYPE html>
    <html lang="pl">
    <head>
        <meta charset="UTF-8">
        <title>Chat</title>
        <link rel="stylesheet" href="styl.css">
    </head>
    <body>
        <header>
            <h2>Chat</h2>
        </header>
        <aside>
            <h3>Chaty</h3>
            <ul>
                <li>Ogólny</li>
                <li>Tematyczne</li>
            </ul>
        </aside>
        <main>
        </main>
        <footer>
        </footer>
    </body>
    </html>
    Podgląd strony po tym kroku (chat.html)
  20. Krok 20: Lista numerowana zagnieżdżona w drugim elemencie

    Kryteria:

    R.2.8 W bloku bocznym umieszczono jedną listę punktowaną o dwóch elementach, z czego drugi zagnieżdża jedną listę numerowaną o czterech elementach. Zastosowano znaczniki <ul>, <ol>, <li>, zagnieżdżenie wewnątrz znacznika <li>

    ok. 2 min
    Polecenie z arkusza

    Drugi element zagnieżdża listę numerowaną z elementami „Turystyczny”, „Żeglarski”, „Filatelistyczny”, „Hodowla zwierzątek domowych”

    „Zagnieżdża” znaczy: lista <ol> stoi wewnątrz elementu <li> z tekstem „Tematyczne”, przed jego zamykającym znacznikiem </li> - klucz sprawdza to wprost (R.2.8). Lista numerowana obok <ul> (po </li>) byłaby błędem składni HTML, bo w <ul> mogą stać tylko elementy <li>.

    chat.html HTML zmienione: 8 linii
    <!DOCTYPE html>
    <html lang="pl">
    <head>
        <meta charset="UTF-8">
        <title>Chat</title>
        <link rel="stylesheet" href="styl.css">
    </head>
    <body>
        <header>
            <h2>Chat</h2>
        </header>
        <aside>
            <h3>Chaty</h3>
            <ul>
                <li>Ogólny</li>
                <li>Tematyczne
                    <ol>
                        <li>Turystyczny</li>
                        <li>Żeglarski</li>
                        <li>Filatelistyczny</li>
                        <li>Hodowla zwierzątek domowych</li>
                    </ol>
                </li>
            </ul>
        </aside>
        <main>
        </main>
        <footer>
        </footer>
    </body>
    </html>
    Podgląd strony po tym kroku (chat.html)
  21. Krok 21: Blok boczny: nagłówek „Uczestnicy”

    ok. 1 min
    Polecenie z arkusza

    Nagłówek trzeciego stopnia o treści „Uczestnicy”

    Drugi <h3>, pod listą.

    chat.html HTML zmienione: 1 linia
    <!DOCTYPE html>
    <html lang="pl">
    <head>
        <meta charset="UTF-8">
        <title>Chat</title>
        <link rel="stylesheet" href="styl.css">
    </head>
    <body>
        <header>
            <h2>Chat</h2>
        </header>
        <aside>
            <h3>Chaty</h3>
            <ul>
                <li>Ogólny</li>
                <li>Tematyczne
                    <ol>
                        <li>Turystyczny</li>
                        <li>Żeglarski</li>
                        <li>Filatelistyczny</li>
                        <li>Hodowla zwierzątek domowych</li>
                    </ol>
                </li>
            </ul>
            <h3>Uczestnicy</h3>
        </aside>
        <main>
        </main>
        <footer>
        </footer>
    </body>
    </html>
    Podgląd strony po tym kroku (chat.html)
  22. Krok 22: Paragraf „Jolanta Nowak”

    ok. 1 min
    Polecenie z arkusza

    Paragraf (akapit) o treści „Jolanta Nowak”

    <p> z imieniem i nazwiskiem.

    chat.html HTML zmienione: 1 linia
    <!DOCTYPE html>
    <html lang="pl">
    <head>
        <meta charset="UTF-8">
        <title>Chat</title>
        <link rel="stylesheet" href="styl.css">
    </head>
    <body>
        <header>
            <h2>Chat</h2>
        </header>
        <aside>
            <h3>Chaty</h3>
            <ul>
                <li>Ogólny</li>
                <li>Tematyczne
                    <ol>
                        <li>Turystyczny</li>
                        <li>Żeglarski</li>
                        <li>Filatelistyczny</li>
                        <li>Hodowla zwierzątek domowych</li>
                    </ol>
                </li>
            </ul>
            <h3>Uczestnicy</h3>
            <p>Jolanta Nowak</p>
        </aside>
        <main>
        </main>
        <footer>
        </footer>
    </body>
    </html>
    Podgląd strony po tym kroku (chat.html)
  23. Krok 23: Obraz Jolka.jpg z tekstem alternatywnym

    ok. 1 min
    Polecenie z arkusza

    Obraz Jolka.jpg z tekstem alternatywnym "Jolanta Nowak"

    Przycięte i przeskalowane zdjęcie z etapu grafiki. Nazwa pliku z wielką literą, jak w archiwum - na serwerze wielkość liter w nazwach plików ma znaczenie.

    chat.html HTML zmienione: 1 linia
    <!DOCTYPE html>
    <html lang="pl">
    <head>
        <meta charset="UTF-8">
        <title>Chat</title>
        <link rel="stylesheet" href="styl.css">
    </head>
    <body>
        <header>
            <h2>Chat</h2>
        </header>
        <aside>
            <h3>Chaty</h3>
            <ul>
                <li>Ogólny</li>
                <li>Tematyczne
                    <ol>
                        <li>Turystyczny</li>
                        <li>Żeglarski</li>
                        <li>Filatelistyczny</li>
                        <li>Hodowla zwierzątek domowych</li>
                    </ol>
                </li>
            </ul>
            <h3>Uczestnicy</h3>
            <p>Jolanta Nowak</p>
            <img src="Jolka.jpg" alt="Jolanta Nowak">
        </aside>
        <main>
        </main>
        <footer>
        </footer>
    </body>
    </html>
    Podgląd strony po tym kroku (chat.html)
  24. Krok 24: Paragraf „Krzysztof Łukasiński”

    ok. 1 min
    Polecenie z arkusza

    Paragraf o treści „Krzysztof Łukasiński”

    Drugi <p> w bloku bocznym.

    chat.html HTML zmienione: 1 linia
    <!DOCTYPE html>
    <html lang="pl">
    <head>
        <meta charset="UTF-8">
        <title>Chat</title>
        <link rel="stylesheet" href="styl.css">
    </head>
    <body>
        <header>
            <h2>Chat</h2>
        </header>
        <aside>
            <h3>Chaty</h3>
            <ul>
                <li>Ogólny</li>
                <li>Tematyczne
                    <ol>
                        <li>Turystyczny</li>
                        <li>Żeglarski</li>
                        <li>Filatelistyczny</li>
                        <li>Hodowla zwierzątek domowych</li>
                    </ol>
                </li>
            </ul>
            <h3>Uczestnicy</h3>
            <p>Jolanta Nowak</p>
            <img src="Jolka.jpg" alt="Jolanta Nowak">
            <p>Krzysztof Łukasiński</p>
        </aside>
        <main>
        </main>
        <footer>
        </footer>
    </body>
    </html>
    Podgląd strony po tym kroku (chat.html)
  25. Krok 25: Obraz Krzysiek.jpg z tekstem alternatywnym

    Kryteria:

    R.2.7 W bloku bocznym obraz Jolka.jpg ma tekst alternatywny Jolanta Nowak a obraz Krzysiek.jpg ma tekst alternatywny Krzysztof Łukasiński

    ok. 1 min
    Polecenie z arkusza

    Obraz Krzysiek.jpg z tekstem alternatywnym "Krzysztof Łukasiński"

    Obaj uczestnicy mają w bloku bocznym zdjęcie z tekstem alternatywnym (R.2.7).

    chat.html HTML zmienione: 1 linia
    <!DOCTYPE html>
    <html lang="pl">
    <head>
        <meta charset="UTF-8">
        <title>Chat</title>
        <link rel="stylesheet" href="styl.css">
    </head>
    <body>
        <header>
            <h2>Chat</h2>
        </header>
        <aside>
            <h3>Chaty</h3>
            <ul>
                <li>Ogólny</li>
                <li>Tematyczne
                    <ol>
                        <li>Turystyczny</li>
                        <li>Żeglarski</li>
                        <li>Filatelistyczny</li>
                        <li>Hodowla zwierzątek domowych</li>
                    </ol>
                </li>
            </ul>
            <h3>Uczestnicy</h3>
            <p>Jolanta Nowak</p>
            <img src="Jolka.jpg" alt="Jolanta Nowak">
            <p>Krzysztof Łukasiński</p>
            <img src="Krzysiek.jpg" alt="Krzysztof Łukasiński">
        </aside>
        <main>
        </main>
        <footer>
        </footer>
    </body>
    </html>
    Podgląd strony po tym kroku (chat.html)
  26. Krok 26: Blok chatu z wypowiedzią Jolanty

    ok. 2 min
    Polecenie z arkusza

    Zawartość bloku głównego: Blok chatu zawierający: Jeden blok z wypowiedzią Jolanty: Obraz Jolka.jpg i paragraf: „Cześć idziesz jutro do kina?”

    Blok chatu to <div id="chat"> - jeden na stronie, więc identyfikator (po nim skrypt znajdzie okno rozmowy). Wypowiedź to <div> z dwiema klasami naraz, rozdzielonymi spacją: message (wspólny wygląd wszystkich wypowiedzi) i jolanta (kolor tła i obraz po lewej). Klucz wymaga, żeby wspólny styl był nadany klasą - identyfikator byłby błędem (R.4.9), bo wypowiedzi będzie wiele.

    chat.html HTML zmienione: 6 linii
    <!DOCTYPE html>
    <html lang="pl">
    <head>
        <meta charset="UTF-8">
        <title>Chat</title>
        <link rel="stylesheet" href="styl.css">
    </head>
    <body>
        <header>
            <h2>Chat</h2>
        </header>
        <aside>
            <h3>Chaty</h3>
            <ul>
                <li>Ogólny</li>
                <li>Tematyczne
                    <ol>
                        <li>Turystyczny</li>
                        <li>Żeglarski</li>
                        <li>Filatelistyczny</li>
                        <li>Hodowla zwierzątek domowych</li>
                    </ol>
                </li>
            </ul>
            <h3>Uczestnicy</h3>
            <p>Jolanta Nowak</p>
            <img src="Jolka.jpg" alt="Jolanta Nowak">
            <p>Krzysztof Łukasiński</p>
            <img src="Krzysiek.jpg" alt="Krzysztof Łukasiński">
        </aside>
        <main>
            <div id="chat">
                <div class="message jolanta">
                    <img src="Jolka.jpg" alt="Jolanta Nowak">
                    <p>Cześć idziesz jutro do kina?</p>
                </div>
            </div>
        </main>
        <footer>
        </footer>
    </body>
    </html>
    Podgląd strony po tym kroku (chat.html)
  27. Krok 27: Wypowiedź Krzysztofa

    Kryteria: ,

    R.3.2 W bloku głównym zdefiniowano blok okna chatu zawierający dwa bloki

    R.2.6 W oknie chatu oraz bloku bocznym umieszczono dwa obrazy Jolka.jpg i Krzysiek.jpg

    ok. 1 min
    Polecenie z arkusza

    Jeden blok z wypowiedzią Krzysztofa: Obraz Krzysiek.jpg i paragraf: „Tak! A ty?”

    Ta sama budowa z klasą krzysztof. Obraz stoi w kodzie przed paragrafem także tutaj - na prawą stronę przeniesie go CSS. Okno chatu zawiera teraz dwa bloki (R.3.2), a zdjęcia obojga uczestników są i w oknie chatu, i w bloku bocznym (R.2.6).

    chat.html HTML zmienione: 4 linie
    <!DOCTYPE html>
    <html lang="pl">
    <head>
        <meta charset="UTF-8">
        <title>Chat</title>
        <link rel="stylesheet" href="styl.css">
    </head>
    <body>
        <header>
            <h2>Chat</h2>
        </header>
        <aside>
            <h3>Chaty</h3>
            <ul>
                <li>Ogólny</li>
                <li>Tematyczne
                    <ol>
                        <li>Turystyczny</li>
                        <li>Żeglarski</li>
                        <li>Filatelistyczny</li>
                        <li>Hodowla zwierzątek domowych</li>
                    </ol>
                </li>
            </ul>
            <h3>Uczestnicy</h3>
            <p>Jolanta Nowak</p>
            <img src="Jolka.jpg" alt="Jolanta Nowak">
            <p>Krzysztof Łukasiński</p>
            <img src="Krzysiek.jpg" alt="Krzysztof Łukasiński">
        </aside>
        <main>
            <div id="chat">
                <div class="message jolanta">
                    <img src="Jolka.jpg" alt="Jolanta Nowak">
                    <p>Cześć idziesz jutro do kina?</p>
                </div>
                <div class="message krzysztof">
                    <img src="Krzysiek.jpg" alt="Krzysztof Łukasiński">
                    <p>Tak! A ty?</p>
                </div>
            </div>
        </main>
        <footer>
        </footer>
    </body>
    </html>
    Podgląd strony po tym kroku (chat.html)
  28. Krok 28: Napis, pole edycyjne i przycisk „Wyślij”

    Kryteria:

    R.3.4 Dla dowolnego przycisku zdefiniowano zdarzenie związane z jego kliknięciem, które odwołuje się do funkcji w skrypcie (atrybut onClick lub słuchacz zdarzenia click lub właściwość onclick obiektu DOM)

    ok. 2 min
    Polecenie z arkusza

    Obok siebie: napis „Wpisz wiadomość:”, pole edycyjne, przycisk o treści „Wyślij”. Kliknięcie przycisku powoduje wywołanie funkcji skryptu

    Napis to <label> powiązany z polem przez for/id - kliknięcie w niego ustawia kursor w polu. Etykieta, pole i przycisk są elementami liniowymi, więc stoją obok siebie bez żadnego CSS. Atrybut onclick wywołuje funkcję sendMessage, którą napisze etap JavaScript. <br> przenosi kolejny przycisk do nowej linii („poniżej”).

    chat.html HTML zmienione: 3 linie
    <!DOCTYPE html>
    <html lang="pl">
    <head>
        <meta charset="UTF-8">
        <title>Chat</title>
        <link rel="stylesheet" href="styl.css">
    </head>
    <body>
        <header>
            <h2>Chat</h2>
        </header>
        <aside>
            <h3>Chaty</h3>
            <ul>
                <li>Ogólny</li>
                <li>Tematyczne
                    <ol>
                        <li>Turystyczny</li>
                        <li>Żeglarski</li>
                        <li>Filatelistyczny</li>
                        <li>Hodowla zwierzątek domowych</li>
                    </ol>
                </li>
            </ul>
            <h3>Uczestnicy</h3>
            <p>Jolanta Nowak</p>
            <img src="Jolka.jpg" alt="Jolanta Nowak">
            <p>Krzysztof Łukasiński</p>
            <img src="Krzysiek.jpg" alt="Krzysztof Łukasiński">
        </aside>
        <main>
            <div id="chat">
                <div class="message jolanta">
                    <img src="Jolka.jpg" alt="Jolanta Nowak">
                    <p>Cześć idziesz jutro do kina?</p>
                </div>
                <div class="message krzysztof">
                    <img src="Krzysiek.jpg" alt="Krzysztof Łukasiński">
                    <p>Tak! A ty?</p>
                </div>
            </div>
            <label for="text">Wpisz wiadomość:</label>
            <input type="text" id="text">
            <button onclick="sendMessage()">Wyślij</button><br>
        </main>
        <footer>
        </footer>
    </body>
    </html>
    Podgląd strony po tym kroku (chat.html)
  29. Krok 29: Przycisk „Generuj losową odpowiedź”

    Kryteria:

    R.2.9 W bloku głównym umieszczono pole edycyjne oraz przyciski: "Wyślij" i "Generuj losową odpowiedź"

    ok. 1 min
    Polecenie z arkusza

    Poniżej: przycisk o treści: „Generuj losową odpowiedź”. Kliknięcie przycisku powoduje wywołanie funkcji skryptu

    Drugi przycisk wywołuje funkcję generateReply. Blok główny ma już pole edycyjne i oba przyciski (R.2.9).

    chat.html HTML zmienione: 1 linia
    <!DOCTYPE html>
    <html lang="pl">
    <head>
        <meta charset="UTF-8">
        <title>Chat</title>
        <link rel="stylesheet" href="styl.css">
    </head>
    <body>
        <header>
            <h2>Chat</h2>
        </header>
        <aside>
            <h3>Chaty</h3>
            <ul>
                <li>Ogólny</li>
                <li>Tematyczne
                    <ol>
                        <li>Turystyczny</li>
                        <li>Żeglarski</li>
                        <li>Filatelistyczny</li>
                        <li>Hodowla zwierzątek domowych</li>
                    </ol>
                </li>
            </ul>
            <h3>Uczestnicy</h3>
            <p>Jolanta Nowak</p>
            <img src="Jolka.jpg" alt="Jolanta Nowak">
            <p>Krzysztof Łukasiński</p>
            <img src="Krzysiek.jpg" alt="Krzysztof Łukasiński">
        </aside>
        <main>
            <div id="chat">
                <div class="message jolanta">
                    <img src="Jolka.jpg" alt="Jolanta Nowak">
                    <p>Cześć idziesz jutro do kina?</p>
                </div>
                <div class="message krzysztof">
                    <img src="Krzysiek.jpg" alt="Krzysztof Łukasiński">
                    <p>Tak! A ty?</p>
                </div>
            </div>
            <label for="text">Wpisz wiadomość:</label>
            <input type="text" id="text">
            <button onclick="sendMessage()">Wyślij</button><br>
            <button onclick="generateReply()">Generuj losową odpowiedź</button>
        </main>
        <footer>
        </footer>
    </body>
    </html>
    Podgląd strony po tym kroku (chat.html)
  30. Krok 30: Stopka z autorem

    Kryteria:

    R.2.5 W bloku banera zapisano nagłówek h2 "Chat", w bloku bocznym h3: "Chaty" i "Uczestnicy", poniżej dwa paragrafy, w bloku stopki nagłówek h5: "Chat wykonał: " z numerem zdającego. W oknie chatu zapisano dwa paragrafy

    ok. 1 min
    Polecenie z arkusza

    Zawartość stopki: nagłówek piątego stopnia o treści: „Chat wykonał: ”, dalej wstawiony numer zdającego.

    Tym razem nie paragraf, a nagłówek <h5>. Na egzaminie w miejscu imienia i nazwiska wpisuje się numer zdającego, czyli PESEL; w tym rozwiązaniu stoi tam „Bartosz Bryniarski”. Strona ma już wszystkie nagłówki i paragrafy z klucza (R.2.5).

    chat.html HTML zmienione: 1 linia
    <!DOCTYPE html>
    <html lang="pl">
    <head>
        <meta charset="UTF-8">
        <title>Chat</title>
        <link rel="stylesheet" href="styl.css">
    </head>
    <body>
        <header>
            <h2>Chat</h2>
        </header>
        <aside>
            <h3>Chaty</h3>
            <ul>
                <li>Ogólny</li>
                <li>Tematyczne
                    <ol>
                        <li>Turystyczny</li>
                        <li>Żeglarski</li>
                        <li>Filatelistyczny</li>
                        <li>Hodowla zwierzątek domowych</li>
                    </ol>
                </li>
            </ul>
            <h3>Uczestnicy</h3>
            <p>Jolanta Nowak</p>
            <img src="Jolka.jpg" alt="Jolanta Nowak">
            <p>Krzysztof Łukasiński</p>
            <img src="Krzysiek.jpg" alt="Krzysztof Łukasiński">
        </aside>
        <main>
            <div id="chat">
                <div class="message jolanta">
                    <img src="Jolka.jpg" alt="Jolanta Nowak">
                    <p>Cześć idziesz jutro do kina?</p>
                </div>
                <div class="message krzysztof">
                    <img src="Krzysiek.jpg" alt="Krzysztof Łukasiński">
                    <p>Tak! A ty?</p>
                </div>
            </div>
            <label for="text">Wpisz wiadomość:</label>
            <input type="text" id="text">
            <button onclick="sendMessage()">Wyślij</button><br>
            <button onclick="generateReply()">Generuj losową odpowiedź</button>
        </main>
        <footer>
            <h5>Chat wykonał: Bartosz Bryniarski</h5>
        </footer>
    </body>
    </html>
    Podgląd strony po tym kroku (chat.html)
  31. Etap 3: Styl CSS

    Kroki 31-43 · po tym etapie masz 31 z 40 kryteriów (pkt)

    Krok 31: Krój Garamond dla wszystkich elementów

    Kryteria:

    R.4.1 Ustawiono domyślne formatowanie wszystkich selektorów (dla *): krój czcionki Garamond

    ok. 1 min
    Polecenie z arkusza

    Domyślne formatowanie wszystkich selektorów: krój czcionki Garamond

    Selektor uniwersalny * - krój dostają też przyciski i pole edycyjne, które nie dziedziczą czcionki po body.

    styl.css CSS nowy plik
    * {
        font-family: Garamond;
    }
    Podgląd strony po tym kroku (chat.html)
  32. Krok 32: Baner: kolory, wyśrodkowanie, wymiary

    ok. 1 min
    Polecenie z arkusza

    Dla banera: kolor tła Tomato, biały kolor czcionki, wyrównanie tekstu do środka, szerokość 80%, wysokość 80 px

    Pięć właściwości z arkusza w jednej regule header. Tomato to nazwana barwa CSS (pomidorowa czerwień).

    styl.css CSS zmienione: 7 linii
    * {
        font-family: Garamond;
    }
    header {
        background-color: Tomato;
        color: white;
        text-align: center;
        width: 80%;
        height: 80px;
    }
    Podgląd strony po tym kroku (chat.html)
  33. Krok 33: Blok główny: wymiary

    ok. 1 min
    Polecenie z arkusza

    Dla bloku głównego: szerokość 80%, wysokość 600 px

    Baner i blok główny mają po 80% - zostaje 20% na blok boczny.

    styl.css CSS zmienione: 4 linie
    * {
        font-family: Garamond;
    }
    header {
        background-color: Tomato;
        color: white;
        text-align: center;
        width: 80%;
        height: 80px;
    }
    main {
        width: 80%;
        height: 600px;
    }
    Podgląd strony po tym kroku (chat.html)
  34. Krok 34: Blok boczny: tło i wymiary

    ok. 1 min
    Polecenie z arkusza

    Dla bloku bocznego: kolor tła Coral, szerokość 20%, wysokość 680 px

    680 px = 80 px banera + 600 px bloku głównego: blok boczny sięga dokładnie od góry banera do dołu bloku głównego.

    styl.css CSS zmienione: 5 linii
    * {
        font-family: Garamond;
    }
    header {
        background-color: Tomato;
        color: white;
        text-align: center;
        width: 80%;
        height: 80px;
    }
    main {
        width: 80%;
        height: 600px;
    }
    aside {
        background-color: Coral;
        width: 20%;
        height: 680px;
    }
    Podgląd strony po tym kroku (chat.html)
  35. Krok 35: Stopka: kolory i wyśrodkowanie

    ok. 1 min
    Polecenie z arkusza

    Dla stopki: kolor tła Tomato, biały kolor czcionki, wyrównanie tekstu do środka

    Te same kolory co baner, bez wymiarów - stopka zajmie całą szerokość strony.

    styl.css CSS zmienione: 5 linii
    * {
        font-family: Garamond;
    }
    header {
        background-color: Tomato;
        color: white;
        text-align: center;
        width: 80%;
        height: 80px;
    }
    main {
        width: 80%;
        height: 600px;
    }
    aside {
        background-color: Coral;
        width: 20%;
        height: 680px;
    }
    footer {
        background-color: Tomato;
        color: white;
        text-align: center;
    }
    Podgląd strony po tym kroku (chat.html)
  36. Krok 36: Układ bloków zgodny z obrazem 2

    Kryteria:

    R.3.1 Układ bloków po uruchomieniu strony w przeglądarce jest zgodny z obrazem 2 w arkuszu egzaminacyjnym, nie należy brać pod uwagę zawartości bloku głównego (prawidłowo zastosowano właściwości CSS decydujące o układzie strony, np. float i clear albo display flex albo grid)

    ok. 3 min
    Polecenie z arkusza

    Podział strony na baner i pod nim blok główny, obok obu bloków blok boczny oraz na dole stopka. Podział zrealizowany wyłącznie za pomocą semantycznych znaczników sekcji języka HTML5 tak, aby po uruchomieniu w przeglądarce wygląd układu bloków był zgodny z obrazem 2

    Baner float: left staje w lewym górnym rogu, blok boczny float: right - w prawym, obok niego (80% + 20%). Blok główny też płynie w lewo, ale obok banera nie ma już miejsca, więc schodzi pod niego - a blok boczny sięga po prawej przez całą wysokość obu bloków. Stopka z clear: both zaczyna się pod pływającymi blokami. Dlatego aside stoi w kodzie przed main: pływający blok nie może zacząć się wyżej niż blok wcześniejszy w kodzie, więc blok boczny zapisany po bloku głównym spadłby pod baner.

    styl.css CSS zmienione: 9 linii
    * {
        font-family: Garamond;
    }
    header {
        background-color: Tomato;
        color: white;
        text-align: center;
        width: 80%;
        height: 80px;
    }
    main {
        width: 80%;
        height: 600px;
    }
    aside {
        background-color: Coral;
        width: 20%;
        height: 680px;
    }
    footer {
        background-color: Tomato;
        color: white;
        text-align: center;
    }
    header, main {
        float: left;
    }
    aside {
        float: right;
    }
    footer {
        clear: both;
    }
    Podgląd strony po tym kroku (chat.html)
  37. Krok 37: Obrazy: koło i odstępy po bokach

    Kryteria:

    R.4.8 Ustawiono zaokrąglenie rogów 50% dla obrazu

    ok. 1 min
    Polecenie z arkusza

    Dla selektora obrazu: zaokrąglenie rogów 50%, marginesy wewnętrzne lewy i prawy 10 px

    border-radius: 50% robi z kwadratowego zdjęcia koło. Skrót padding: 0 10px - górny i dolny 0, lewy i prawy 10 px. Zgodnie z uwagą arkusza selektor to sam znacznik img (klasa nie spełniłaby R.4.6).

    styl.css CSS zmienione: 4 linie
    * {
        font-family: Garamond;
    }
    header {
        background-color: Tomato;
        color: white;
        text-align: center;
        width: 80%;
        height: 80px;
    }
    main {
        width: 80%;
        height: 600px;
    }
    aside {
        background-color: Coral;
        width: 20%;
        height: 680px;
    }
    footer {
        background-color: Tomato;
        color: white;
        text-align: center;
    }
    header, main {
        float: left;
    }
    aside {
        float: right;
    }
    footer {
        clear: both;
    }
    img {
        border-radius: 50%;
        padding: 0 10px;
    }
    Podgląd strony po tym kroku (chat.html)
  38. Krok 38: Blok chatu: ramka, margines, wysokość, przewijanie

    Kryteria:

    R.4.3 Ustawiono wysokość bloków banera 80px, głównego 600px i bocznego 680px oraz bloku chatu 470px

    ok. 2 min
    Polecenie z arkusza

    Dla bloku chatu: obramowanie linią ciągłą o szerokości 1 px i kolorze Tomato, marginesy zewnętrzne 15 px, wysokość 470 px, paski przewijania zawsze widoczne na stronie

    Skrót border: 1px solid Tomato - grubość, styl (solid - linia ciągła), kolor. „Paski przewijania zawsze widoczne” to overflow: scroll: paski są od początku, choć dwie wypowiedzi mieszczą się w oknie (obraz 2). Okno ma stałą wysokość 470 px, więc kolejne wypowiedzi nie rozciągną strony - pojawi się przewijanie. Ustawione są już wszystkie wysokości z klucza (R.4.3).

    styl.css CSS zmienione: 6 linii
    * {
        font-family: Garamond;
    }
    header {
        background-color: Tomato;
        color: white;
        text-align: center;
        width: 80%;
        height: 80px;
    }
    main {
        width: 80%;
        height: 600px;
    }
    aside {
        background-color: Coral;
        width: 20%;
        height: 680px;
    }
    footer {
        background-color: Tomato;
        color: white;
        text-align: center;
    }
    header, main {
        float: left;
    }
    aside {
        float: right;
    }
    footer {
        clear: both;
    }
    img {
        border-radius: 50%;
        padding: 0 10px;
    }
    #chat {
        border: 1px solid Tomato;
        margin: 15px;
        height: 470px;
        overflow: scroll;
    }
    Podgląd strony po tym kroku (chat.html)
  39. Krok 39: Wspólny wygląd wypowiedzi

    Kryteria:

    R.4.9 Ustawiono styl dla obu bloków z wypowiedziami: zaokrąglenie rogów 5px, szerokość 90%, wysokość 70px, marginesy zewnętrzne 2%, marginesy wewnętrzne 3px (np. za pomocą klasy, id jest błędem)

    ok. 1 min
    Polecenie z arkusza

    Wspólne dla bloków z wypowiedziami: zaokrąglenie rogów 5 px, szerokość 90%, wysokość 70 px, marginesy zewnętrzne 2%, marginesy wewnętrzne 3 px

    Klasa message jest przy każdej wypowiedzi, także dokładanej przez skrypt. Wysokość 70 px to dokładnie wysokość zdjęć.

    styl.css CSS zmienione: 7 linii
    * {
        font-family: Garamond;
    }
    header {
        background-color: Tomato;
        color: white;
        text-align: center;
        width: 80%;
        height: 80px;
    }
    main {
        width: 80%;
        height: 600px;
    }
    aside {
        background-color: Coral;
        width: 20%;
        height: 680px;
    }
    footer {
        background-color: Tomato;
        color: white;
        text-align: center;
    }
    header, main {
        float: left;
    }
    aside {
        float: right;
    }
    footer {
        clear: both;
    }
    img {
        border-radius: 50%;
        padding: 0 10px;
    }
    #chat {
        border: 1px solid Tomato;
        margin: 15px;
        height: 470px;
        overflow: scroll;
    }
    .message {
        border-radius: 5px;
        width: 90%;
        height: 70px;
        margin: 2%;
        padding: 3px;
    }
    Podgląd strony po tym kroku (chat.html)
  40. Krok 40: Wypowiedź Jolanty: tło i obraz po lewej

    ok. 2 min
    Polecenie z arkusza

    Dodatkowo dla bloków z wypowiedziami Jolanty: kolor tła #EEE, obraz opływany tekstem z prawej strony (obraz po lewej stronie)

    #EEE to skrót od #EEEEEE - jasnoszary. Obraz z float: left przesuwa się do lewej krawędzi bloku, a tekst paragrafu opływa go z prawej. Selektor .jolanta img wskazuje tylko zdjęcia wewnątrz wypowiedzi Jolanty - zdjęcia w bloku bocznym nie zmieniają ułożenia.

    styl.css CSS zmienione: 6 linii
    * {
        font-family: Garamond;
    }
    header {
        background-color: Tomato;
        color: white;
        text-align: center;
        width: 80%;
        height: 80px;
    }
    main {
        width: 80%;
        height: 600px;
    }
    aside {
        background-color: Coral;
        width: 20%;
        height: 680px;
    }
    footer {
        background-color: Tomato;
        color: white;
        text-align: center;
    }
    header, main {
        float: left;
    }
    aside {
        float: right;
    }
    footer {
        clear: both;
    }
    img {
        border-radius: 50%;
        padding: 0 10px;
    }
    #chat {
        border: 1px solid Tomato;
        margin: 15px;
        height: 470px;
        overflow: scroll;
    }
    .message {
        border-radius: 5px;
        width: 90%;
        height: 70px;
        margin: 2%;
        padding: 3px;
    }
    .jolanta {
        background-color: #EEE;
    }
    .jolanta img {
        float: left;
    }
    Podgląd strony po tym kroku (chat.html)
  41. Krok 41: Wypowiedź Krzysztofa: tło, tekst do prawej, obraz po prawej

    Kryteria: ,

    R.3.3 W bloku z wypowiedziami Jolanty obraz jest opływany tekstem po prawej stronie a z wypowiedziami Krzysztofa po stronie lewej

    R.4.10 Ustawiono kolor tła bloku wypowiedzi Jolanty #EEE oraz wypowiedzi Krzysztofa #CCC, wypowiedzi Krzysztofa są wyrównane do prawej strony

    ok. 2 min
    Polecenie z arkusza

    Dodatkowo dla bloków z wypowiedziami Krzysztofa: kolor tła #CCC, wyrównanie tekstu do prawej strony, obraz opływany tekstem z lewej strony (obraz po prawej stronie)

    Ciemniejsze tło, tekst dosunięty do prawej i obraz z float: right - tekst opływa go z lewej. Okno chatu wygląda już jak na obrazie 2: wypowiedzi na zmianę z lewej i z prawej (R.3.3, R.4.10).

    styl.css CSS zmienione: 7 linii
    * {
        font-family: Garamond;
    }
    header {
        background-color: Tomato;
        color: white;
        text-align: center;
        width: 80%;
        height: 80px;
    }
    main {
        width: 80%;
        height: 600px;
    }
    aside {
        background-color: Coral;
        width: 20%;
        height: 680px;
    }
    footer {
        background-color: Tomato;
        color: white;
        text-align: center;
    }
    header, main {
        float: left;
    }
    aside {
        float: right;
    }
    footer {
        clear: both;
    }
    img {
        border-radius: 50%;
        padding: 0 10px;
    }
    #chat {
        border: 1px solid Tomato;
        margin: 15px;
        height: 470px;
        overflow: scroll;
    }
    .message {
        border-radius: 5px;
        width: 90%;
        height: 70px;
        margin: 2%;
        padding: 3px;
    }
    .jolanta {
        background-color: #EEE;
    }
    .jolanta img {
        float: left;
    }
    .krzysztof {
        background-color: #CCC;
        text-align: right;
    }
    .krzysztof img {
        float: right;
    }
    Podgląd strony po tym kroku (chat.html)
  42. Krok 42: Przyciski: tło, ramka, odstęp, pogrubienie

    Kryteria: , , ,

    R.4.2 Ustawiono kolor tła Tomato dla bloków banera, stopki i przycisków; Coral dla bloku bocznego oraz biały kolor czcionki dla banera i stopki

    R.4.5 Ustawiono wyrównanie tekstu do środka dla banera i stopki oraz czcionkę pogrubioną dla przycisków

    R.4.6 Ustawiono marginesy wewnętrzne (padding) lewy i prawy 10px dla selektora img, 5px dla przycisków oraz marginesy zewnętrzne (margin) dla bloku chatu 15px

    R.4.7 Ustawiono obramowanie linią ciągłą o szerokości 1px i kolorze Tomato dla bloku chatu oraz obramowanie linią ciągłą o szerokości 1px i kolorze DarkRed dla przycisków oraz paski przewijania zawsze widoczne na stronie (overflow: scroll;) dla bloku chatu

    ok. 2 min
    Polecenie z arkusza

    Dla obu przycisków: kolor tła Tomato, obramowanie linią ciągłą o szerokości 1 px i kolorze DarkRed, marginesy wewnętrzne 5 px, czcionka pogrubiona

    Selektor button obejmuje oba przyciski. Ta reguła domyka kilka kryteriów naraz: kolory tła (R.4.2), pogrubienie obok wyśrodkowania banera i stopki (R.4.5), marginesy wewnętrzne i zewnętrzne (R.4.6) oraz obramowania razem z przewijaniem chatu (R.4.7).

    styl.css CSS zmienione: 6 linii
    * {
        font-family: Garamond;
    }
    header {
        background-color: Tomato;
        color: white;
        text-align: center;
        width: 80%;
        height: 80px;
    }
    main {
        width: 80%;
        height: 600px;
    }
    aside {
        background-color: Coral;
        width: 20%;
        height: 680px;
    }
    footer {
        background-color: Tomato;
        color: white;
        text-align: center;
    }
    header, main {
        float: left;
    }
    aside {
        float: right;
    }
    footer {
        clear: both;
    }
    img {
        border-radius: 50%;
        padding: 0 10px;
    }
    #chat {
        border: 1px solid Tomato;
        margin: 15px;
        height: 470px;
        overflow: scroll;
    }
    .message {
        border-radius: 5px;
        width: 90%;
        height: 70px;
        margin: 2%;
        padding: 3px;
    }
    .jolanta {
        background-color: #EEE;
    }
    .jolanta img {
        float: left;
    }
    .krzysztof {
        background-color: #CCC;
        text-align: right;
    }
    .krzysztof img {
        float: right;
    }
    button {
        background-color: Tomato;
        border: 1px solid DarkRed;
        padding: 5px;
        font-weight: bold;
    }
    Podgląd strony po tym kroku (chat.html)
  43. Krok 43: Pole edycyjne: szerokość

    Kryteria:

    R.4.4 Ustawiono szerokość bloków banera i głównego 80%, bloku bocznego 20% (width lub grid- template-columns lub flex) oraz pola edycyjnego 500px

    ok. 1 min
    Polecenie z arkusza

    Dla pola edycyjnego tekstowego: szerokość 500 px

    Selektor identyfikatora pola. Z szerokościami bloków to kryterium R.4.4.

    styl.css CSS zmienione: 3 linie
    * {
        font-family: Garamond;
    }
    header {
        background-color: Tomato;
        color: white;
        text-align: center;
        width: 80%;
        height: 80px;
    }
    main {
        width: 80%;
        height: 600px;
    }
    aside {
        background-color: Coral;
        width: 20%;
        height: 680px;
    }
    footer {
        background-color: Tomato;
        color: white;
        text-align: center;
    }
    header, main {
        float: left;
    }
    aside {
        float: right;
    }
    footer {
        clear: both;
    }
    img {
        border-radius: 50%;
        padding: 0 10px;
    }
    #chat {
        border: 1px solid Tomato;
        margin: 15px;
        height: 470px;
        overflow: scroll;
    }
    .message {
        border-radius: 5px;
        width: 90%;
        height: 70px;
        margin: 2%;
        padding: 3px;
    }
    .jolanta {
        background-color: #EEE;
    }
    .jolanta img {
        float: left;
    }
    .krzysztof {
        background-color: #CCC;
        text-align: right;
    }
    .krzysztof img {
        float: right;
    }
    button {
        background-color: Tomato;
        border: 1px solid DarkRed;
        padding: 5px;
        font-weight: bold;
    }
    #text {
        width: 500px;
    }
    Podgląd strony po tym kroku (chat.html)
  44. Etap 4: JavaScript

    Kroki 44-50 · po tym etapie masz 40 z 40 kryteriów (pkt)

    Krok 44: Wyślij: tekst z pola na końcu okna chatu

    Kryteria: , ,

    R.5.1 Skrypt zapisano w języku JavaScript i zawiera on przynajmniej jedną instrukcję zapisaną zgodnie ze składnią

    R.5.2 Funkcja wywoływana przyciskiem Wyślij pobiera dane z pola edycyjnego

    R.5.3 Dane z pola edycyjnego są wyświetlane w oknie chatu

    ok. 2 min
    Polecenie z arkusza

    Działanie funkcji wywoływanej po kliknięciu przycisku Wyślij: Pobierany jest tekst z pola edycyjnego i umieszczany w oknie chatu jako ostatni

    Skrypt w znaczniku <script> na końcu <body>. Funkcja sendMessage (tę nazwę wywołuje onclick) odczytuje pole przez getElementById("text").value, tworzy nowy paragraf (createElement("p") z tabeli 2), wpisuje do niego tekst przez innerText i dokłada go na koniec okna chatu - appendChild zawsze wstawia element jako ostatni. Na razie tekst pojawia się bez tła i zdjęcia; wygląd wypowiedzi dojdzie w następnym kroku.

    chat.html HTML zmienione: 8 linii
    <!DOCTYPE html>
    <html lang="pl">
    <head>
        <meta charset="UTF-8">
        <title>Chat</title>
        <link rel="stylesheet" href="styl.css">
    </head>
    <body>
        <header>
            <h2>Chat</h2>
        </header>
        <aside>
            <h3>Chaty</h3>
            <ul>
                <li>Ogólny</li>
                <li>Tematyczne
                    <ol>
                        <li>Turystyczny</li>
                        <li>Żeglarski</li>
                        <li>Filatelistyczny</li>
                        <li>Hodowla zwierzątek domowych</li>
                    </ol>
                </li>
            </ul>
            <h3>Uczestnicy</h3>
            <p>Jolanta Nowak</p>
            <img src="Jolka.jpg" alt="Jolanta Nowak">
            <p>Krzysztof Łukasiński</p>
            <img src="Krzysiek.jpg" alt="Krzysztof Łukasiński">
        </aside>
        <main>
            <div id="chat">
                <div class="message jolanta">
                    <img src="Jolka.jpg" alt="Jolanta Nowak">
                    <p>Cześć idziesz jutro do kina?</p>
                </div>
                <div class="message krzysztof">
                    <img src="Krzysiek.jpg" alt="Krzysztof Łukasiński">
                    <p>Tak! A ty?</p>
                </div>
            </div>
            <label for="text">Wpisz wiadomość:</label>
            <input type="text" id="text">
            <button onclick="sendMessage()">Wyślij</button><br>
            <button onclick="generateReply()">Generuj losową odpowiedź</button>
        </main>
        <footer>
            <h5>Chat wykonał: Bartosz Bryniarski</h5>
        </footer>
        <script>
            function sendMessage() {
                let text = document.getElementById("text").value;
                let paragraph = document.createElement("p");
                paragraph.innerText = text;
                document.getElementById("chat").appendChild(paragraph);
            }
        </script>
    </body>
    </html>
    Podgląd strony po tym kroku (chat.html)
  45. Krok 45: Wyślij: blok wypowiedzi Jolanty

    Kryteria:

    R.5.4 Dane z funkcji związanej z przyciskiem Wyślij są formatowane jako wypowiedzi Jolanty (tak samo jak pierwsza wypowiedź w chacie)

    ok. 3 min
    Polecenie z arkusza

    Tekst jest formatowany jako wypowiedź Jolanty, zgodnie z obrazem 3, czyli utworzony jest blok z wypowiedzią zawierający obraz Jolka.jpg i paragraf zgodny z tekstem wpisanym do pola edycyjnego

    Skrypt buduje dokładnie taki sam kawałek drzewa dokumentu jak pierwsza wypowiedź w HTML-u: div z klasami message i jolanta (classList.add z tabeli 2), a w nim obraz i paragraf. Kolejność appendChild ma znaczenie - obraz przed paragrafem, jak w kodzie HTML, bo float działa na tekst stojący za obrazem. Do okna chatu trafia dopiero gotowy blok. Sprawdzone w Chrome: wiadomość „Ok, cieszę się” dostaje ten sam wygląd co „Cześć idziesz jutro do kina?” (obraz 3).

    chat.html HTML zmienione: 9 linii
    <!DOCTYPE html>
    <html lang="pl">
    <head>
        <meta charset="UTF-8">
        <title>Chat</title>
        <link rel="stylesheet" href="styl.css">
    </head>
    <body>
        <header>
            <h2>Chat</h2>
        </header>
        <aside>
            <h3>Chaty</h3>
            <ul>
                <li>Ogólny</li>
                <li>Tematyczne
                    <ol>
                        <li>Turystyczny</li>
                        <li>Żeglarski</li>
                        <li>Filatelistyczny</li>
                        <li>Hodowla zwierzątek domowych</li>
                    </ol>
                </li>
            </ul>
            <h3>Uczestnicy</h3>
            <p>Jolanta Nowak</p>
            <img src="Jolka.jpg" alt="Jolanta Nowak">
            <p>Krzysztof Łukasiński</p>
            <img src="Krzysiek.jpg" alt="Krzysztof Łukasiński">
        </aside>
        <main>
            <div id="chat">
                <div class="message jolanta">
                    <img src="Jolka.jpg" alt="Jolanta Nowak">
                    <p>Cześć idziesz jutro do kina?</p>
                </div>
                <div class="message krzysztof">
                    <img src="Krzysiek.jpg" alt="Krzysztof Łukasiński">
                    <p>Tak! A ty?</p>
                </div>
            </div>
            <label for="text">Wpisz wiadomość:</label>
            <input type="text" id="text">
            <button onclick="sendMessage()">Wyślij</button><br>
            <button onclick="generateReply()">Generuj losową odpowiedź</button>
        </main>
        <footer>
            <h5>Chat wykonał: Bartosz Bryniarski</h5>
        </footer>
        <script>
            function sendMessage() {
                let text = document.getElementById("text").value;
                let block = document.createElement("div");
                block.classList.add("message");
                block.classList.add("jolanta");
                let image = document.createElement("img");
                image.src = "Jolka.jpg";
                image.alt = "Jolanta Nowak";
                let paragraph = document.createElement("p");
                paragraph.innerText = text;
                block.appendChild(image);
                block.appendChild(paragraph);
                document.getElementById("chat").appendChild(block);
            }
        </script>
    </body>
    </html>
    Podgląd strony po tym kroku (chat.html)
  46. Krok 46: Wyślij: przewinięcie do nowej wypowiedzi

    Kryteria:

    R.5.5 Po zapełnieniu bloku chatu następuje przewinięcie do nowo wstawionej wypowiedzi dla przynajmniej jednej funkcji.

    ok. 1 min
    Polecenie z arkusza

    Jeśli blok chatu jest cały wypełniony, powinien być przewinięty do nowo wstawionej wypowiedzi

    scrollIntoView() (tabela 2) przewija okno chatu tak, żeby nowy blok był widoczny. Gdy okno nie jest jeszcze pełne, nic się nie dzieje - warunek „jeśli wypełniony” spełnia się sam. Sprawdzone w Chrome: po kilkunastu wiadomościach okno jest przewinięte do ostatniej.

    chat.html HTML zmienione: 1 linia
    <!DOCTYPE html>
    <html lang="pl">
    <head>
        <meta charset="UTF-8">
        <title>Chat</title>
        <link rel="stylesheet" href="styl.css">
    </head>
    <body>
        <header>
            <h2>Chat</h2>
        </header>
        <aside>
            <h3>Chaty</h3>
            <ul>
                <li>Ogólny</li>
                <li>Tematyczne
                    <ol>
                        <li>Turystyczny</li>
                        <li>Żeglarski</li>
                        <li>Filatelistyczny</li>
                        <li>Hodowla zwierzątek domowych</li>
                    </ol>
                </li>
            </ul>
            <h3>Uczestnicy</h3>
            <p>Jolanta Nowak</p>
            <img src="Jolka.jpg" alt="Jolanta Nowak">
            <p>Krzysztof Łukasiński</p>
            <img src="Krzysiek.jpg" alt="Krzysztof Łukasiński">
        </aside>
        <main>
            <div id="chat">
                <div class="message jolanta">
                    <img src="Jolka.jpg" alt="Jolanta Nowak">
                    <p>Cześć idziesz jutro do kina?</p>
                </div>
                <div class="message krzysztof">
                    <img src="Krzysiek.jpg" alt="Krzysztof Łukasiński">
                    <p>Tak! A ty?</p>
                </div>
            </div>
            <label for="text">Wpisz wiadomość:</label>
            <input type="text" id="text">
            <button onclick="sendMessage()">Wyślij</button><br>
            <button onclick="generateReply()">Generuj losową odpowiedź</button>
        </main>
        <footer>
            <h5>Chat wykonał: Bartosz Bryniarski</h5>
        </footer>
        <script>
            function sendMessage() {
                let text = document.getElementById("text").value;
                let block = document.createElement("div");
                block.classList.add("message");
                block.classList.add("jolanta");
                let image = document.createElement("img");
                image.src = "Jolka.jpg";
                image.alt = "Jolanta Nowak";
                let paragraph = document.createElement("p");
                paragraph.innerText = text;
                block.appendChild(image);
                block.appendChild(paragraph);
                document.getElementById("chat").appendChild(block);
                block.scrollIntoView();
            }
        </script>
    </body>
    </html>
    Podgląd strony po tym kroku (chat.html)
  47. Krok 47: Tablica dziewięciu odpowiedzi Krzysztofa

    Kryteria:

    R.5.6 W kodzie zdefiniowano tablicę z dziewięcioma wypowiedziami Krzysztofa

    ok. 2 min
    Polecenie z arkusza

    Losowana jest wypowiedź Krzysztofa z wcześniej zadeklarowanej tablicy. Tablica zawiera 9 elementów, którymi są wypowiedzi. Należy je skopiować z pliku pomocniczego tekstyDoChatu.txt rozpakowanego z archiwum

    Plik tekstyDoChatu.txt jest przygotowany do wklejenia: każdy tekst w cudzysłowie, z przecinkiem na końcu linii. Wystarczy go objąć nawiasami kwadratowymi i nazwać tablicę - replies. Tablica stoi poza funkcją, więc powstaje raz, przy wczytaniu strony („wcześniej zadeklarowana”), a nie przy każdym kliknięciu.

    chat.html HTML zmienione: 12 linii
    <!DOCTYPE html>
    <html lang="pl">
    <head>
        <meta charset="UTF-8">
        <title>Chat</title>
        <link rel="stylesheet" href="styl.css">
    </head>
    <body>
        <header>
            <h2>Chat</h2>
        </header>
        <aside>
            <h3>Chaty</h3>
            <ul>
                <li>Ogólny</li>
                <li>Tematyczne
                    <ol>
                        <li>Turystyczny</li>
                        <li>Żeglarski</li>
                        <li>Filatelistyczny</li>
                        <li>Hodowla zwierzątek domowych</li>
                    </ol>
                </li>
            </ul>
            <h3>Uczestnicy</h3>
            <p>Jolanta Nowak</p>
            <img src="Jolka.jpg" alt="Jolanta Nowak">
            <p>Krzysztof Łukasiński</p>
            <img src="Krzysiek.jpg" alt="Krzysztof Łukasiński">
        </aside>
        <main>
            <div id="chat">
                <div class="message jolanta">
                    <img src="Jolka.jpg" alt="Jolanta Nowak">
                    <p>Cześć idziesz jutro do kina?</p>
                </div>
                <div class="message krzysztof">
                    <img src="Krzysiek.jpg" alt="Krzysztof Łukasiński">
                    <p>Tak! A ty?</p>
                </div>
            </div>
            <label for="text">Wpisz wiadomość:</label>
            <input type="text" id="text">
            <button onclick="sendMessage()">Wyślij</button><br>
            <button onclick="generateReply()">Generuj losową odpowiedź</button>
        </main>
        <footer>
            <h5>Chat wykonał: Bartosz Bryniarski</h5>
        </footer>
        <script>
            let replies = [
                "Świetnie!",
                "Kto gra główną rolę?",
                "Lubisz filmy Tego reżysera?",
                "Będę 10 minut wcześniej",
                "Może kupimy sobie popcorn?",
                "Ja wolę Colę",
                "Zaproszę jeszcze Grześka",
                "Tydzień temu też byłem w kinie na Diunie",
                "Ja funduję bilety"
            ];
    
            function sendMessage() {
                let text = document.getElementById("text").value;
                let block = document.createElement("div");
                block.classList.add("message");
                block.classList.add("jolanta");
                let image = document.createElement("img");
                image.src = "Jolka.jpg";
                image.alt = "Jolanta Nowak";
                let paragraph = document.createElement("p");
                paragraph.innerText = text;
                block.appendChild(image);
                block.appendChild(paragraph);
                document.getElementById("chat").appendChild(block);
                block.scrollIntoView();
            }
        </script>
    </body>
    </html>
    Podgląd strony po tym kroku (chat.html)
  48. Krok 48: Generuj: losowy indeks 0-8 i tekst na końcu chatu

    Kryteria:

    R.5.7 Funkcja wywoływana przyciskiem Generuj… losuje index tablicy z wypowiedziami Krzysztofa (liczba od 0 do 8), wypowiedź o tym indeksie jest wyświetlana w oknie chatu (sprawdzić w kodzie i w przeglądarce)

    ok. 2 min
    Polecenie z arkusza

    Losowana liczba z przedziału od 0 do 8 jest indeksem tablicy. Wypowiedź jest umieszczana w oknie chatu jako ostatnia

    Math.random() zwraca ułamek od 0 (włącznie) do 1 (bez jedynki), po pomnożeniu przez 9 - od 0 do prawie 9, a Math.floor obcina część ułamkową: wychodzi liczba całkowita od 0 do 8, czyli poprawny indeks tablicy dziewięcioelementowej. replies[index] to wylosowany tekst; trafia na koniec okna tak samo jak wiadomość z pola.

    chat.html HTML zmienione: 7 linii
    <!DOCTYPE html>
    <html lang="pl">
    <head>
        <meta charset="UTF-8">
        <title>Chat</title>
        <link rel="stylesheet" href="styl.css">
    </head>
    <body>
        <header>
            <h2>Chat</h2>
        </header>
        <aside>
            <h3>Chaty</h3>
            <ul>
                <li>Ogólny</li>
                <li>Tematyczne
                    <ol>
                        <li>Turystyczny</li>
                        <li>Żeglarski</li>
                        <li>Filatelistyczny</li>
                        <li>Hodowla zwierzątek domowych</li>
                    </ol>
                </li>
            </ul>
            <h3>Uczestnicy</h3>
            <p>Jolanta Nowak</p>
            <img src="Jolka.jpg" alt="Jolanta Nowak">
            <p>Krzysztof Łukasiński</p>
            <img src="Krzysiek.jpg" alt="Krzysztof Łukasiński">
        </aside>
        <main>
            <div id="chat">
                <div class="message jolanta">
                    <img src="Jolka.jpg" alt="Jolanta Nowak">
                    <p>Cześć idziesz jutro do kina?</p>
                </div>
                <div class="message krzysztof">
                    <img src="Krzysiek.jpg" alt="Krzysztof Łukasiński">
                    <p>Tak! A ty?</p>
                </div>
            </div>
            <label for="text">Wpisz wiadomość:</label>
            <input type="text" id="text">
            <button onclick="sendMessage()">Wyślij</button><br>
            <button onclick="generateReply()">Generuj losową odpowiedź</button>
        </main>
        <footer>
            <h5>Chat wykonał: Bartosz Bryniarski</h5>
        </footer>
        <script>
            let replies = [
                "Świetnie!",
                "Kto gra główną rolę?",
                "Lubisz filmy Tego reżysera?",
                "Będę 10 minut wcześniej",
                "Może kupimy sobie popcorn?",
                "Ja wolę Colę",
                "Zaproszę jeszcze Grześka",
                "Tydzień temu też byłem w kinie na Diunie",
                "Ja funduję bilety"
            ];
    
            function sendMessage() {
                let text = document.getElementById("text").value;
                let block = document.createElement("div");
                block.classList.add("message");
                block.classList.add("jolanta");
                let image = document.createElement("img");
                image.src = "Jolka.jpg";
                image.alt = "Jolanta Nowak";
                let paragraph = document.createElement("p");
                paragraph.innerText = text;
                block.appendChild(image);
                block.appendChild(paragraph);
                document.getElementById("chat").appendChild(block);
                block.scrollIntoView();
            }
    
            function generateReply() {
                let index = Math.floor(Math.random() * 9);
                let paragraph = document.createElement("p");
                paragraph.innerText = replies[index];
                document.getElementById("chat").appendChild(paragraph);
            }
        </script>
    </body>
    </html>
    Podgląd strony po tym kroku (chat.html)
  49. Krok 49: Generuj: blok wypowiedzi Krzysztofa

    Kryteria:

    R.5.8 Dane z funkcji związanej z przyciskiem Generuj... są formatowane jako wypowiedzi Krzysztofa (tak samo jak druga wypowiedź w chacie)

    ok. 2 min
    Polecenie z arkusza

    Tekst jest formatowany jako wypowiedź Krzysztofa, zgodnie z obrazem 4, czyli utworzony jest blok z wypowiedzią zawierający obraz Krzysiek.jpg i paragraf zgodny z wylosowanym tekstem

    Ta sama budowa co w sendMessage, ale z klasą krzysztof i zdjęciem Krzysiek.jpg - odpowiedź ląduje po prawej, na ciemniejszym tle (obraz 4).

    chat.html HTML zmienione: 9 linii
    <!DOCTYPE html>
    <html lang="pl">
    <head>
        <meta charset="UTF-8">
        <title>Chat</title>
        <link rel="stylesheet" href="styl.css">
    </head>
    <body>
        <header>
            <h2>Chat</h2>
        </header>
        <aside>
            <h3>Chaty</h3>
            <ul>
                <li>Ogólny</li>
                <li>Tematyczne
                    <ol>
                        <li>Turystyczny</li>
                        <li>Żeglarski</li>
                        <li>Filatelistyczny</li>
                        <li>Hodowla zwierzątek domowych</li>
                    </ol>
                </li>
            </ul>
            <h3>Uczestnicy</h3>
            <p>Jolanta Nowak</p>
            <img src="Jolka.jpg" alt="Jolanta Nowak">
            <p>Krzysztof Łukasiński</p>
            <img src="Krzysiek.jpg" alt="Krzysztof Łukasiński">
        </aside>
        <main>
            <div id="chat">
                <div class="message jolanta">
                    <img src="Jolka.jpg" alt="Jolanta Nowak">
                    <p>Cześć idziesz jutro do kina?</p>
                </div>
                <div class="message krzysztof">
                    <img src="Krzysiek.jpg" alt="Krzysztof Łukasiński">
                    <p>Tak! A ty?</p>
                </div>
            </div>
            <label for="text">Wpisz wiadomość:</label>
            <input type="text" id="text">
            <button onclick="sendMessage()">Wyślij</button><br>
            <button onclick="generateReply()">Generuj losową odpowiedź</button>
        </main>
        <footer>
            <h5>Chat wykonał: Bartosz Bryniarski</h5>
        </footer>
        <script>
            let replies = [
                "Świetnie!",
                "Kto gra główną rolę?",
                "Lubisz filmy Tego reżysera?",
                "Będę 10 minut wcześniej",
                "Może kupimy sobie popcorn?",
                "Ja wolę Colę",
                "Zaproszę jeszcze Grześka",
                "Tydzień temu też byłem w kinie na Diunie",
                "Ja funduję bilety"
            ];
    
            function sendMessage() {
                let text = document.getElementById("text").value;
                let block = document.createElement("div");
                block.classList.add("message");
                block.classList.add("jolanta");
                let image = document.createElement("img");
                image.src = "Jolka.jpg";
                image.alt = "Jolanta Nowak";
                let paragraph = document.createElement("p");
                paragraph.innerText = text;
                block.appendChild(image);
                block.appendChild(paragraph);
                document.getElementById("chat").appendChild(block);
                block.scrollIntoView();
            }
    
            function generateReply() {
                let index = Math.floor(Math.random() * 9);
                let block = document.createElement("div");
                block.classList.add("message");
                block.classList.add("krzysztof");
                let image = document.createElement("img");
                image.src = "Krzysiek.jpg";
                image.alt = "Krzysztof Łukasiński";
                let paragraph = document.createElement("p");
                paragraph.innerText = replies[index];
                block.appendChild(image);
                block.appendChild(paragraph);
                document.getElementById("chat").appendChild(block);
            }
        </script>
    </body>
    </html>
    Podgląd strony po tym kroku (chat.html)
  50. Krok 50: Generuj: przewinięcie do nowej wypowiedzi

    Kryteria:

    R.5.9 Zastosowano znaczące nazewnictwo dla wszystkich zmiennych i funkcji w języku polskim lub angielskim. Nazwy odzwierciedlają cel zastosowania.

    ok. 1 min
    Polecenie z arkusza

    Jeśli blok chatu jest cały wypełniony, powinien być przewinięty do nowo wstawionej wypowiedzi

    To samo scrollIntoView() na końcu drugiej funkcji. Wszystkie nazwy mówią, do czego służą: sendMessage, generateReply, replies, text, index, block, image, paragraph (R.5.9).

    chat.html HTML zmienione: 1 linia
    <!DOCTYPE html>
    <html lang="pl">
    <head>
        <meta charset="UTF-8">
        <title>Chat</title>
        <link rel="stylesheet" href="styl.css">
    </head>
    <body>
        <header>
            <h2>Chat</h2>
        </header>
        <aside>
            <h3>Chaty</h3>
            <ul>
                <li>Ogólny</li>
                <li>Tematyczne
                    <ol>
                        <li>Turystyczny</li>
                        <li>Żeglarski</li>
                        <li>Filatelistyczny</li>
                        <li>Hodowla zwierzątek domowych</li>
                    </ol>
                </li>
            </ul>
            <h3>Uczestnicy</h3>
            <p>Jolanta Nowak</p>
            <img src="Jolka.jpg" alt="Jolanta Nowak">
            <p>Krzysztof Łukasiński</p>
            <img src="Krzysiek.jpg" alt="Krzysztof Łukasiński">
        </aside>
        <main>
            <div id="chat">
                <div class="message jolanta">
                    <img src="Jolka.jpg" alt="Jolanta Nowak">
                    <p>Cześć idziesz jutro do kina?</p>
                </div>
                <div class="message krzysztof">
                    <img src="Krzysiek.jpg" alt="Krzysztof Łukasiński">
                    <p>Tak! A ty?</p>
                </div>
            </div>
            <label for="text">Wpisz wiadomość:</label>
            <input type="text" id="text">
            <button onclick="sendMessage()">Wyślij</button><br>
            <button onclick="generateReply()">Generuj losową odpowiedź</button>
        </main>
        <footer>
            <h5>Chat wykonał: Bartosz Bryniarski</h5>
        </footer>
        <script>
            let replies = [
                "Świetnie!",
                "Kto gra główną rolę?",
                "Lubisz filmy Tego reżysera?",
                "Będę 10 minut wcześniej",
                "Może kupimy sobie popcorn?",
                "Ja wolę Colę",
                "Zaproszę jeszcze Grześka",
                "Tydzień temu też byłem w kinie na Diunie",
                "Ja funduję bilety"
            ];
    
            function sendMessage() {
                let text = document.getElementById("text").value;
                let block = document.createElement("div");
                block.classList.add("message");
                block.classList.add("jolanta");
                let image = document.createElement("img");
                image.src = "Jolka.jpg";
                image.alt = "Jolanta Nowak";
                let paragraph = document.createElement("p");
                paragraph.innerText = text;
                block.appendChild(image);
                block.appendChild(paragraph);
                document.getElementById("chat").appendChild(block);
                block.scrollIntoView();
            }
    
            function generateReply() {
                let index = Math.floor(Math.random() * 9);
                let block = document.createElement("div");
                block.classList.add("message");
                block.classList.add("krzysztof");
                let image = document.createElement("img");
                image.src = "Krzysiek.jpg";
                image.alt = "Krzysztof Łukasiński";
                let paragraph = document.createElement("p");
                paragraph.innerText = replies[index];
                block.appendChild(image);
                block.appendChild(paragraph);
                document.getElementById("chat").appendChild(block);
                block.scrollIntoView();
            }
        </script>
    </body>
    </html>
    Podgląd strony po tym kroku (chat.html)
  51. Etap 5: Dobre praktyki (poza kluczem)

    Kroki 51-53 · po tym etapie masz 40 z 40 kryteriów (pkt)

    Krok 51: Jedna funkcja addMessage zamiast dwóch kopii

    ok. 4 min
    Polecenie z arkusza

    Należy stosować znaczące nazewnictwo wszystkich zmiennych i funkcji

    Obie funkcje egzaminacyjne różnią się tylko czterema wartościami: tekstem, plikiem zdjęcia, podpisem i klasą. W prawdziwym projekcie tworzenie bloku wypowiedzi jest jedną funkcją addMessage z czterema parametrami, a sendMessage i generateReply tylko ją wywołują - poprawka wyglądu wypowiedzi jest wtedy w jednym miejscu. Przy okazji: classList.add przyjmuje kilka klas naraz, append - kilka elementów, liczba odpowiedzi bierze się z replies.length (dopisanie dziesiątego tekstu nie wymaga zmiany losowania), a okno przewija scrollTop = scrollHeight. Sprawdzone w Chrome: scrollIntoView przewijało nie tylko okno chatu, ale i całą stronę (na niskim ekranie strona „podskakiwała” o 257 px), a scrollTop przewija tylko okno chatu. Na egzaminie wystarczy wersja wcześniejsza - klucz tego nie sprawdza.

    chat.html HTML zmienione: 18 linii
    <!DOCTYPE html>
    <html lang="pl">
    <head>
        <meta charset="UTF-8">
        <title>Chat</title>
        <link rel="stylesheet" href="styl.css">
    </head>
    <body>
        <header>
            <h2>Chat</h2>
        </header>
        <aside>
            <h3>Chaty</h3>
            <ul>
                <li>Ogólny</li>
                <li>Tematyczne
                    <ol>
                        <li>Turystyczny</li>
                        <li>Żeglarski</li>
                        <li>Filatelistyczny</li>
                        <li>Hodowla zwierzątek domowych</li>
                    </ol>
                </li>
            </ul>
            <h3>Uczestnicy</h3>
            <p>Jolanta Nowak</p>
            <img src="Jolka.jpg" alt="Jolanta Nowak">
            <p>Krzysztof Łukasiński</p>
            <img src="Krzysiek.jpg" alt="Krzysztof Łukasiński">
        </aside>
        <main>
            <div id="chat">
                <div class="message jolanta">
                    <img src="Jolka.jpg" alt="Jolanta Nowak">
                    <p>Cześć idziesz jutro do kina?</p>
                </div>
                <div class="message krzysztof">
                    <img src="Krzysiek.jpg" alt="Krzysztof Łukasiński">
                    <p>Tak! A ty?</p>
                </div>
            </div>
            <label for="text">Wpisz wiadomość:</label>
            <input type="text" id="text">
            <button onclick="sendMessage()">Wyślij</button><br>
            <button onclick="generateReply()">Generuj losową odpowiedź</button>
        </main>
        <footer>
            <h5>Chat wykonał: Bartosz Bryniarski</h5>
        </footer>
        <script>
            let replies = [
                "Świetnie!",
                "Kto gra główną rolę?",
                "Lubisz filmy Tego reżysera?",
                "Będę 10 minut wcześniej",
                "Może kupimy sobie popcorn?",
                "Ja wolę Colę",
                "Zaproszę jeszcze Grześka",
                "Tydzień temu też byłem w kinie na Diunie",
                "Ja funduję bilety"
            ];
            let chatWindow = document.getElementById("chat");
            let textField = document.getElementById("text");
    
            function addMessage(text, imageFile, author, cssClass) {
                let block = document.createElement("div");
                block.classList.add("message", cssClass);
                let image = document.createElement("img");
                image.src = imageFile;
                image.alt = author;
                let paragraph = document.createElement("p");
                paragraph.innerText = text;
                block.append(image, paragraph);
                chatWindow.appendChild(block);
                chatWindow.scrollTop = chatWindow.scrollHeight;   // było: block.scrollIntoView();
            }
    
            function sendMessage() {
                addMessage(textField.value, "Jolka.jpg", "Jolanta Nowak", "jolanta");
            }
    
            function generateReply() {
                let index = Math.floor(Math.random() * replies.length);   // było: Math.random() * 9
                addMessage(replies[index], "Krzysiek.jpg", "Krzysztof Łukasiński", "krzysztof");
            }
        </script>
    </body>
    </html>
    Podgląd strony po tym kroku (chat.html)
  52. Krok 52: Pusta wiadomość pominięta, pole czyszczone po wysłaniu

    ok. 3 min
    Polecenie z arkusza

    Pobierany jest tekst z pola edycyjnego i umieszczany w oknie chatu jako ostatni

    Wersja egzaminacyjna sprawdzona w Chrome z pustym polem: kliknięcie „Wyślij” dokłada pustą wypowiedź - samo zdjęcie Jolanty w szarym prostokącie. Tak samo przy tekście złożonym z samych spacji. Poprawka: trim() obcina spacje z początku i końca, a dla pustego napisu funkcja kończy się od razu (return). Po wysłaniu pole jest czyszczone i dostaje kursor (focus()) - można pisać kolejną wiadomość bez klikania w pole. Na egzaminie wystarczy wersja wcześniejsza - klucz tego nie sprawdza.

    chat.html HTML zmienione: 7 linii
    <!DOCTYPE html>
    <html lang="pl">
    <head>
        <meta charset="UTF-8">
        <title>Chat</title>
        <link rel="stylesheet" href="styl.css">
    </head>
    <body>
        <header>
            <h2>Chat</h2>
        </header>
        <aside>
            <h3>Chaty</h3>
            <ul>
                <li>Ogólny</li>
                <li>Tematyczne
                    <ol>
                        <li>Turystyczny</li>
                        <li>Żeglarski</li>
                        <li>Filatelistyczny</li>
                        <li>Hodowla zwierzątek domowych</li>
                    </ol>
                </li>
            </ul>
            <h3>Uczestnicy</h3>
            <p>Jolanta Nowak</p>
            <img src="Jolka.jpg" alt="Jolanta Nowak">
            <p>Krzysztof Łukasiński</p>
            <img src="Krzysiek.jpg" alt="Krzysztof Łukasiński">
        </aside>
        <main>
            <div id="chat">
                <div class="message jolanta">
                    <img src="Jolka.jpg" alt="Jolanta Nowak">
                    <p>Cześć idziesz jutro do kina?</p>
                </div>
                <div class="message krzysztof">
                    <img src="Krzysiek.jpg" alt="Krzysztof Łukasiński">
                    <p>Tak! A ty?</p>
                </div>
            </div>
            <label for="text">Wpisz wiadomość:</label>
            <input type="text" id="text">
            <button onclick="sendMessage()">Wyślij</button><br>
            <button onclick="generateReply()">Generuj losową odpowiedź</button>
        </main>
        <footer>
            <h5>Chat wykonał: Bartosz Bryniarski</h5>
        </footer>
        <script>
            let replies = [
                "Świetnie!",
                "Kto gra główną rolę?",
                "Lubisz filmy Tego reżysera?",
                "Będę 10 minut wcześniej",
                "Może kupimy sobie popcorn?",
                "Ja wolę Colę",
                "Zaproszę jeszcze Grześka",
                "Tydzień temu też byłem w kinie na Diunie",
                "Ja funduję bilety"
            ];
            let chatWindow = document.getElementById("chat");
            let textField = document.getElementById("text");
    
            function addMessage(text, imageFile, author, cssClass) {
                let block = document.createElement("div");
                block.classList.add("message", cssClass);
                let image = document.createElement("img");
                image.src = imageFile;
                image.alt = author;
                let paragraph = document.createElement("p");
                paragraph.innerText = text;
                block.append(image, paragraph);
                chatWindow.appendChild(block);
                chatWindow.scrollTop = chatWindow.scrollHeight;   // było: block.scrollIntoView();
            }
    
            function sendMessage() {
                let text = textField.value.trim();
                if (text == "") {
                    return;
                }
                addMessage(text, "Jolka.jpg", "Jolanta Nowak", "jolanta");
                textField.value = "";
                textField.focus();
            }
    
            function generateReply() {
                let index = Math.floor(Math.random() * replies.length);   // było: Math.random() * 9
                addMessage(replies[index], "Krzysiek.jpg", "Krzysztof Łukasiński", "krzysztof");
            }
        </script>
    </body>
    </html>
    Podgląd strony po tym kroku (chat.html)
  53. Krok 53: Nasłuchiwacze zdarzeń i wysyłanie klawiszem Enter

    ok. 3 min
    Polecenie z arkusza

    Działanie funkcji wywoływanej po kliknięciu przycisku Wyślij

    Przyciski dostają identyfikatory, a zdarzenia podpina skrypt przez addEventListener - HTML zostaje bez kodu JavaScript. W każdym komunikatorze wiadomość wysyła się też klawiszem Enter: nasłuchiwacz zdarzenia keydown na polu sprawdza, który klawisz naciśnięto (event.key), i dla Entera wywołuje tę samą funkcję co przycisk. Na egzaminie wystarczy wersja wcześniejsza - klucz uznaje oba sposoby podpięcia zdarzenia (R.3.4).

    chat.html HTML zmienione: 11 linii
    <!DOCTYPE html>
    <html lang="pl">
    <head>
        <meta charset="UTF-8">
        <title>Chat</title>
        <link rel="stylesheet" href="styl.css">
    </head>
    <body>
        <header>
            <h2>Chat</h2>
        </header>
        <aside>
            <h3>Chaty</h3>
            <ul>
                <li>Ogólny</li>
                <li>Tematyczne
                    <ol>
                        <li>Turystyczny</li>
                        <li>Żeglarski</li>
                        <li>Filatelistyczny</li>
                        <li>Hodowla zwierzątek domowych</li>
                    </ol>
                </li>
            </ul>
            <h3>Uczestnicy</h3>
            <p>Jolanta Nowak</p>
            <img src="Jolka.jpg" alt="Jolanta Nowak">
            <p>Krzysztof Łukasiński</p>
            <img src="Krzysiek.jpg" alt="Krzysztof Łukasiński">
        </aside>
        <main>
            <div id="chat">
                <div class="message jolanta">
                    <img src="Jolka.jpg" alt="Jolanta Nowak">
                    <p>Cześć idziesz jutro do kina?</p>
                </div>
                <div class="message krzysztof">
                    <img src="Krzysiek.jpg" alt="Krzysztof Łukasiński">
                    <p>Tak! A ty?</p>
                </div>
            </div>
            <label for="text">Wpisz wiadomość:</label>
            <input type="text" id="text">
            <button id="send">Wyślij</button><br>
            <button id="generate">Generuj losową odpowiedź</button>
        </main>
        <footer>
            <h5>Chat wykonał: Bartosz Bryniarski</h5>
        </footer>
        <script>
            let replies = [
                "Świetnie!",
                "Kto gra główną rolę?",
                "Lubisz filmy Tego reżysera?",
                "Będę 10 minut wcześniej",
                "Może kupimy sobie popcorn?",
                "Ja wolę Colę",
                "Zaproszę jeszcze Grześka",
                "Tydzień temu też byłem w kinie na Diunie",
                "Ja funduję bilety"
            ];
            let chatWindow = document.getElementById("chat");
            let textField = document.getElementById("text");
    
            function addMessage(text, imageFile, author, cssClass) {
                let block = document.createElement("div");
                block.classList.add("message", cssClass);
                let image = document.createElement("img");
                image.src = imageFile;
                image.alt = author;
                let paragraph = document.createElement("p");
                paragraph.innerText = text;
                block.append(image, paragraph);
                chatWindow.appendChild(block);
                chatWindow.scrollTop = chatWindow.scrollHeight;   // było: block.scrollIntoView();
            }
    
            function sendMessage() {
                let text = textField.value.trim();
                if (text == "") {
                    return;
                }
                addMessage(text, "Jolka.jpg", "Jolanta Nowak", "jolanta");
                textField.value = "";
                textField.focus();
            }
    
            function generateReply() {
                let index = Math.floor(Math.random() * replies.length);   // było: Math.random() * 9
                addMessage(replies[index], "Krzysiek.jpg", "Krzysztof Łukasiński", "krzysztof");
            }
    
            // <button onclick="..."> zastąpione nasłuchiwaczami zdarzeń
            document.getElementById("send").addEventListener("click", sendMessage);
            document.getElementById("generate").addEventListener("click", generateReply);
            textField.addEventListener("keydown", function (event) {
                if (event.key == "Enter") {
                    sendMessage();
                }
            });
        </script>
    </body>
    </html>
    Podgląd strony po tym kroku (chat.html)
  54. Etap 6: Oddanie pracy

    Krok 54 · po tym etapie masz 40 z 40 kryteriów (pkt)

    Krok 54: Plik przeglądarka.txt i nagranie płyty

    ok. 5 min
    Polecenie z arkusza

    Po zakończeniu pracy utwórz plik tekstowy o nazwie przeglądarka.txt. Zapisz w nim nazwę przeglądarki internetowej, w której weryfikowana była poprawność działania witryny. Umieść go w folderze z numerem zdającego. Nagraj płytę z rezultatami pracy.

    W przeglądarka.txt wystarczy nazwa przeglądarki, w której była sprawdzana strona.

    W folderze z numerem zdającego: rozpakowane pliki z archiwum (baza.sql, Jolka.jpg - już przycięta, Krzysiek.jpg, tekstyDoChatu.txt), chat.html, import.png, kw1.jpg - kw5.jpg, kwerendy.txt, przeglądarka.txt i styl.css. Po nagraniu płyty trzeba sprawdzić jej odczyt i opisać ją numerem zdającego.

    przeglądarka.txt Tekst nowy plik
    Google Chrome

    Podgląd strony bez zmian - taki jak po kroku 53.

Podgląd

To jedno z możliwych rozwiązań. Egzaminator ocenia spełnienie kryteriów z klucza odpowiedzi, a nie zgodność z tym kodem - inna, poprawna droga też daje punkty.

Autor rozwiązania: . Licencja CC BY-NC 4.0 - kopiowanie i przeróbki do celów niekomercyjnych, z podaniem autora i źródła (link do tej strony) (zasady wykorzystania). Treść arkusza i klucza oceniania pochodzi z CKE.