INF.03-09-26.06-SGCzerwiec 2026 · 47 kroków · ok. 79 min · 35 kryteriów z klucza
Rozwiązanie krok po kroku: Aplikacja internetowa restauracji (Nowoczesny kod (grid, zdarzenia))
To drugi sposób rozwiązania tego samego arkusza. Wynik jest ten sam - baza restauracja z pięcioma zapytaniami i strona index.html z sześcioma klikanymi potrawami, listą zamówienia i dwoma przyciskami - i tak samo spełnia każde kryterium klucza. Inna jest droga:
zmienne CSS: zieleń #778A35 pojawia się w arkuszu pięć razy, w kodzie jest wpisana raz,
bloki potraw na siatce CSS (display: grid na sekcji potraw) zamiast display: inline-block na każdym bloku,
skrypt w osobnym plikuskrypt.js z atrybutem defer: jeden nasłuchiwacz zdarzeń na całej sekcji potraw zamiast sześciu atrybutów onclick, nazwa potrawy czytana z jej podpisu, textContent zamiast innerHTML, potrawę można dodać także klawiaturą,
zapytania z aliasami i warunkiem na przedział dat zamiast funkcji DATE().
Na końcu krótkie porównanie z wersją podstawową (zakładka obok). Baza, zdjęcia i logo pochodzą z prawdziwego archiwum pliki19, zapytania zostały wykonane na tej bazie w MariaDB z XAMPP-a, a skrypty sprawdzone w prawdziwej przeglądarce. Strona w podglądzie działa - od kroków ze skryptem można klikać potrawy i przyciski.
Jak liczą się punkty. Klucz ma 35 kryteriów (R.1.1 - R.5.7), każde za 1 punkt. Próg zdania to 75%, czyli 27 punktów. Przy każdym kroku jest napisane, które kryteria spełnia.
Suwak i strzałki obok niego - albo ←→ na klawiaturze - przechodzą krok po kroku; wyjaśnienie, pliki i podgląd zmieniają się razem z krokiem.
Lista „Etap” przenosi od razu do wybranego etapu.
„Rozwiązuję samodzielnie” chowa rozwiązanie kroku - najpierw własna próba, potem odsłonięcie.
„Tryb prezentacji” pokazuje same kroki, bez menu strony - na rzutnik.
Etap 1: Baza danych
Kroki 1-8 · po tym etapie masz 7 z 35 kryteriów (pkt)
Krok 1: Baza danych restauracja
ok. 2 min
Polecenie z arkusza
Utwórz bazę danych o nazwie restauracja, z zestawem polskich znaków (np. utf8_polish_ci).
Archiwum pliki19.7z rozpakuj hasłem ReStAuRac1a (wielkość liter ma znaczenie, przed ostatnią literą jest cyfra 1). W phpMyAdmin Nowa → restauracja, porównywanie utf8_polish_ci - albo jednym poleceniem:
CREATE DATABASE restauracja CHARACTER SET utf8 COLLATE utf8_polish_ci;
Krok 2: Import tabel z pliku restauracja.sql
ok. 2 min
Polecenie z arkusza
Do utworzonej bazy zaimportuj tabele z pliku restauracja.sql.
Import → restauracja.sql → Wykonaj. Pięć tabel z ilustracji 1: Kelnerzy, Stoliki, Zamowienia, Potrawy i tabela łącząca ZamowieniaPotrawy (jedno zamówienie ma wiele potraw, jedna potrawa trafia do wielu zamówień - relacja wiele do wielu zawsze potrzebuje takiej trzeciej tabeli).
Krok 3: Zrzut ekranu import.png
Kryteria:
R.1.1 Wykonany import tabel do bazy danych restauracja - plik import.png
ok. 2 min
Polecenie z arkusza
Wykonaj zrzut ekranu po imporcie. Zapisz zrzut w formacie PNG pod nazwą 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.
Cały ekran z paskiem zadań, zapis jako import.png (w tym arkuszu wszystkie zrzuty są w PNG).
Typowe błędy
Wykadrowany zrzut albo zrzut bez paska zadań nie jest oceniany (uwaga w kluczu przy R.1).
Krok 4: Zapytanie 1: kelnerzy malejąco po nazwisku
Kryteria: ,
R.1.2 W pliku kwerendy.txt zapisane co najmniej jedno zapytanie SQL, wynikające z treści zadania
R.1.3 Wykonane zapytanie 1 wybierające jedynie imię i nazwisko kelnera z tabeli Kelnerzy. Wyniki posortowane są malejąco według nazwiska. W pliku z kwerendami lub na zrzucie istnieje zapis np. SELECT imie, nazwisko FROM Kelnerzy ORDER BY nazwisko DESC; oraz na zrzucie widoczne są dokładnie 3 rekordy (dla Piotra, Anny i Jana)
ok. 1 min
Polecenie z arkusza
Zapytanie 1: wybierające jedynie imiona i nazwiska kelnerów posortowane malejąco według nazwiska.
Każda klauzula w osobnej linii - tak zapytanie czyta się od góry: co (SELECT imie, nazwisko), skąd (FROM Kelnerzy), w jakiej kolejności (ORDER BY nazwisko DESC - malejąco, od Z do A).
Wynik: 3 wiersze - Piotr Wiśniewski, Anna Nowak, Jan Kowalski, jak w kluczu. Zapytania zapisuj w kwerendy.txt, zrzut jako kw1.png.
kwerendy.txtTekstnowy plik
-- Zapytanie 1SELECT imie, nazwiskoFROM KelnerzyORDER BY nazwisko DESC;
Podgląd strony po tym kroku
Krok 5: Zapytanie 2: zamówienia przy stoliku 3 w sali 1
Kryteria:
R.1.4 Wykonane zapytanie 2 zliczające jedynie liczbę zamówień, które zostały złożone dla stolika numer 3 w sali numer 1. W pliku z kwerendami lub na zrzucie istnieje zapis np. SELECT COUNT(*) FROM Zamowienia JOIN Stoliki ON Stoliki.id = idStolika WHERE numerStolika = 3 AND sala = 1; (możliwe również porównanie kluczy po WHERE) oraz na zrzucie widoczny jest jeden wiersz z wartością 2
ok. 2 min
Polecenie z arkusza
Zapytanie 2: zliczające jedynie liczbę zamówień, które zostały złożone dla stolika numer 3 w sali numer 1. Należy posłużyć się relacją.
FROM Zamowienia AS z JOIN Stoliki AS s - aliasyz i s to krótkie nazwy tabel na czas zapytania; zamiast Stoliki.numerStolika piszesz s.numerStolika,
ON s.id = z.idStolika - warunek złączenia stoi przy JOIN, a nie w WHERE: od razu widać, którą parą kluczy łączą się tabele, a WHERE zostaje na warunki z treści zadania,
WHERE s.numerStolika = 3 AND s.sala = 1 - stolik numer 3 jest w obu salach, więc potrzebne są oba warunki,
COUNT(*) AS liczba_zamowien - jedna liczba z czytelnym nagłówkiem kolumny zamiast COUNT(*).
Wynik: jeden wiersz z wartością 2 (zamówienia 3 i 4). Zrzut: kw2.png.
Typowe błędy
WHERE idStolika = 3 bez złączenia porównuje identyfikator stolika, a nie jego numer. W tej bazie trafia przypadkiem (stolik o id 3 to stolik nr 3 w sali 1), ale klucz wymaga relacji i zapytania uniwersalnego.
kwerendy.txtTekstzmienione: 7 linii
-- Zapytanie 1SELECT imie, nazwiskoFROM KelnerzyORDER BY nazwisko DESC;-- Zapytanie 2SELECT COUNT(*) AS liczba_zamowienFROM Zamowienia AS zJOIN Stoliki AS s ON s.id = z.idStolikaWHERE s.numerStolika = 3 AND s.sala = 1;
Podgląd strony po tym kroku
Krok 6: Zapytanie 3: potrawy zamówione 9 czerwca 2024
Kryteria:
R.1.5 Wykonane zapytanie 3 wybierające jedynie nazwy potraw, które zostały zamówione dnia 9 czerwca 2024. W pliku z kwerendami lub na zrzucie istnieje zapis np. SELECT nazwa FROM Potrawy JOIN ZamowieniaPotrawy ON idPotrawy = Potrawy.id JOIN Zamowienia ON idZamowienia = Zamowienia.id WHERE DATE(Zamowienia.dataZlozenia)='2024-06-09'; (możliwe również porównanie kluczy po WHERE) oraz na zrzucie widoczny jest jedynie jeden rekord o treści Spaghetti bolognese
ok. 3 min
Polecenie z arkusza
Zapytanie 3: wybierające jedynie nazwy potraw, które zostały zamówione dnia 9 czerwca 2024. Należy posłużyć się relacją.
Od potrawy do daty prowadzi droga przez tabelę łączącą: Potrawy → ZamowieniaPotrawy (pozycje zamówień) → Zamowienia (data). Dwa JOIN, każdy ze swoim ON.
Pole dataZlozenia przechowuje datę i godzinę (2024-06-09 14:30:00). Zamiast odcinać godzinę funkcją DATE() (jak w przykładzie z klucza), warunek opisuje przedział: od północy 9 czerwca włącznie do północy 10 czerwca wyłącznie. Wynik jest ten sam, a różnica wychodzi przy dużych tabelach: na samej kolumnie serwer może użyć indeksu, a na DATE(kolumna) musi przeliczyć funkcję dla każdego wiersza.
Wynik: jeden wiersz - Spaghetti bolognese (sprawdzone na tej bazie, z DATE() wychodzi to samo). Zrzut: kw3.png.
Typowe błędy
WHERE z.dataZlozenia = '2024-06-09' daje pusty wynik - serwer porównuje z północą, a zamówienie złożono o 14:30. <= '2024-06-09 23:59:59' gubi ułamki sekund; bezpieczny jest warunek < '2024-06-10'.
kwerendy.txtTekstzmienione: 8 linii
-- Zapytanie 1SELECT imie, nazwiskoFROM KelnerzyORDER BY nazwisko DESC;-- Zapytanie 2SELECT COUNT(*) AS liczba_zamowienFROM Zamowienia AS zJOIN Stoliki AS s ON s.id = z.idStolikaWHERE s.numerStolika = 3 AND s.sala = 1;-- Zapytanie 3SELECT p.nazwaFROM Potrawy AS pJOIN ZamowieniaPotrawy AS zp ON zp.idPotrawy = p.idJOIN Zamowienia AS z ON z.id = zp.idZamowieniaWHERE z.dataZlozenia >= '2024-06-09' AND z.dataZlozenia < '2024-06-10';
Podgląd strony po tym kroku
Krok 7: Zapytanie 4: użytkownik administrator
Kryteria:
R.1.6 Wykonane zapytanie 4 tworzące konto użytkownika lokalnego o nazwie administrator i haśle boss123!. W pliku z kwerendami lub na zrzucie istnieje zapis np. CREATE USER administator@localhost IDENTIFIED BY 'boss123!'; oraz na zrzucie jest widoczny komunikat o poprawnie wykonanym zapytaniu. (dopuszczalny jest błąd informujący o niewybraniu bazy, @localhost wymagany)
ok. 2 min
Polecenie z arkusza
Zapytanie 4: tworzące nowego użytkownika lokalnego o nazwie administrator i haśle boss123!
'administrator'@'localhost' - konto to para nazwa + host; „lokalny” oznacza localhost, czyli logowanie tylko z komputera, na którym działa serwer (klucz R.1.6 wymaga @localhost),
IDENTIFIED BY 'boss123!' - hasło w apostrofach; serwer zapisze z niego tylko skrót, nie sam tekst.
Nowe konto nie ma żadnych uprawnień - nadaje się je osobno poleceniem GRANT (arkusz tego nie wymaga). Zrzut kw4.png: konto na liście użytkowników.
Typowe błędy
Przykład w kluczu ma literówkę („administator”) - nazwa z arkusza to administrator. Bez @'localhost' powstaje konto 'administrator'@'%' (dowolny host), czyli nie lokalne.
kwerendy.txtTekstzmienione: 4 linie
-- Zapytanie 1SELECT imie, nazwiskoFROM KelnerzyORDER BY nazwisko DESC;-- Zapytanie 2SELECT COUNT(*) AS liczba_zamowienFROM Zamowienia AS zJOIN Stoliki AS s ON s.id = z.idStolikaWHERE s.numerStolika = 3 AND s.sala = 1;-- Zapytanie 3SELECT p.nazwaFROM Potrawy AS pJOIN ZamowieniaPotrawy AS zp ON zp.idPotrawy = p.idJOIN Zamowienia AS z ON z.id = zp.idZamowieniaWHERE z.dataZlozenia >= '2024-06-09' AND z.dataZlozenia < '2024-06-10';-- Zapytanie 4CREATE USER 'administrator'@'localhost' IDENTIFIED BY 'boss123!';
Podgląd strony po tym kroku
Krok 8: Zapytanie 5: cena jako DECIMAL(6,2)
Kryteria:
R.1.7 Wykonane zapytanie 5 zmieniające strukturę tabeli Potrawy poprzez modyfikację typu kolumny cena na decimal(6,2), przy jednoczesnym zachowaniu ograniczenia NOT NULL. W pliku z kwerendami lub na zrzucie istnieje zapis np. ALTER TABLE Potrawy MODIFY cena DECIMAL(6,2) NOT NULL; (zastosowanie CHANGE zamiast MODIFY wymaga dwukrotnego podania kolumny; możliwy też typ numeric) oraz na zrzucie jest widoczny komunikat o poprawnie wykonanym zapytaniu lub zmieniona struktura tabeli
ok. 3 min
Polecenie z arkusza
Zapytanie 5: zmieniające strukturę tabeli Potrawy poprzez zmianę typu kolumny cena w taki sposób, aby przechowywała ona liczby rzeczywiste składające się z maksimum 4 cyfr w części całkowitej (przed przecinkiem) i 2 cyfr w części ułamkowej (po przecinku). Typ ten powinien przechowywać dane w zapisie stałoprzecinkowym. Należy zachować wszystkie dotychczasowe ograniczenia nałożone na kolumnę.
Typ stałoprzecinkowy to DECIMAL(M, D): M - liczba wszystkich cyfr, D - cyfr po przecinku. 4 + 2 = DECIMAL(6,2), największa wartość 9999.99. Dotąd kolumna miała DECIMAL(5,2) i NOT NULL.
MODIFY podaje całą nową definicję kolumny - czego nie napiszesz, tego kolumna nie będzie miała. Dlatego NOT NULL trzeba powtórzyć (bez niego kolumna zaczęłaby przyjmować NULL - sprawdzone na kopii tabeli w wersji podstawowej). Zrzut kw5.png: struktura po zmianie.
Typowe błędy
FLOAT i DOUBLE są zmiennoprzecinkowe - przy kwotach dają błędy zaokrągleń (0.1 + 0.2 to nie dokładnie 0.3), a arkusz żąda zapisu stałoprzecinkowego.
kwerendy.txtTekstzmienione: 4 linie
-- Zapytanie 1SELECT imie, nazwiskoFROM KelnerzyORDER BY nazwisko DESC;-- Zapytanie 2SELECT COUNT(*) AS liczba_zamowienFROM Zamowienia AS zJOIN Stoliki AS s ON s.id = z.idStolikaWHERE s.numerStolika = 3 AND s.sala = 1;-- Zapytanie 3SELECT p.nazwaFROM Potrawy AS pJOIN ZamowieniaPotrawy AS zp ON zp.idPotrawy = p.idJOIN Zamowienia AS z ON z.id = zp.idZamowieniaWHERE z.dataZlozenia >= '2024-06-09' AND z.dataZlozenia < '2024-06-10';-- Zapytanie 4CREATE USER 'administrator'@'localhost' IDENTIFIED BY 'boss123!';-- Zapytanie 5ALTER TABLE PotrawyMODIFY cena DECIMAL(6,2) NOT NULL;
Podgląd strony po tym kroku
Etap 2: Strona HTML
Kroki 9-24 · po tym etapie masz 16 z 35 kryteriów (pkt)
Krok 9: Plik index.html w HTML5
ok. 1 min
Polecenie z arkusza
Zapisana w języku HTML5.
Pierwsza linia <!DOCTYPE html> - przeglądarka renderuje stronę według standardu, a nie w trybie zgodności ze starymi stronami. Plik index.html zapisz w folderze z numerem zdającego, obok zdjęć i logo.
R.2.1 W pliku index.html znajduje się deklaracja HTML5 <!DOCTYPE HTML>, deklaracja języka zawartości: polski np. <html lang="pl">
ok. 1 min
Polecenie z arkusza
Zadeklarowany polski język zawartości witryny.
lang="pl" w <html> - czytnik ekranu czyta tekst z polską wymową, a przeglądarka dzieli wyrazy według polskich reguł. Razem z deklaracją HTML5 to R.2.1.
R.2.2 W sekcji head znajduje się jawnie podany standard kodowania polskich znaków i tytuł strony "Restauracja Marchewka"
ok. 1 min
Polecenie z arkusza
Tytuł strony widoczny na karcie przeglądarki: „Restauracja Marchewka”.
<title> z treścią z arkusza; kodowanie i tytuł razem to R.2.2. Dodatkowo <meta name="viewport"> - bez niej telefon udaje ekran szeroki na ok. 980 px i pomniejsza stronę. Arkusz tego nie wymaga, ale to stały element każdego współczesnego szablonu.
R.3.2 Strona zawiera działające połączenie z zewnętrznym arkuszem stylów o nazwie styl.css formatowanie CSS pochodzi jedynie z tego arkusza
ok. 1 min
Polecenie z arkusza
Arkusz stylów w pliku o nazwie styl.css prawidłowo połączony z kodem strony.
<link rel="stylesheet" href="styl.css"> - bez ukośnika na końcu (w HTML5 <link> jest elementem pustym i nie potrzebuje />). Całe formatowanie ma pochodzić z tego pliku, bez atrybutów style w HTML-u (R.3.2).
Krok 14: Bloki: nagłówek i blok główny po dwie sekcje, stopka
Kryteria:
R.2.3 W sekcji body zdefiniowany jest podział na bloki za pomocą semantycznych znaczników HTML 5: header -> section + section, main -> section + section, footer (dopuszcza się stosowanie bloków pomocniczych)
ok. 2 min
Polecenie z arkusza
Podział strony na bloki: blok nagłówkowy zawierający dwie sekcje, blok główny zawierający dwie sekcje, blok stopki. Podział zrealizowany za pomocą semantycznych znaczników języka HTML5 tak, aby po uruchomieniu w przeglądarce układ bloków był zgodny z ilustracją 3.
Struktura z klucza R.2.3: header z dwiema section, main z dwiema section, footer. Znaczniki semantyczne mówią, czym jest blok (nagłówek strony, treść główna, stopka), a nie tylko jak wygląda - korzystają z tego czytniki ekranu (skok do treści głównej) i wyszukiwarki.
Identyfikatory po angielsku: header-left, header-right, order (zamówienie) i dishes (potrawy). Każda sekcja ma inny styl, a skrypt sięgnie do dwóch ostatnich.
R.2.6 W lewej sekcji głównej znajduje się lista punktowana. W stanie początkowym lista nie zawiera elementów (znacznik <ul> - sprawdzić w kodzie)
ok. 1 min
Polecenie z arkusza
Lista punktowana (nieuporządkowana) - lista w stanie początkowym jest pusta.
<ul id="order-list"></ul> bez żadnego <li> (R.2.6) - pozycje dołoży skrypt. Atrybut aria-live="polite" to obietnica dla czytnika ekranu: gdy zawartość listy się zmieni, czytnik przeczyta nową pozycję (osoba niewidoma dowie się, że potrawa trafiła do zamówienia). Na wygląd nie wpływa.
Przycisk o treści „Wyczyść”, którego kliknięcie powoduje wykonanie skryptu 2.
<button type="button"> - przycisk, który niczego nie wysyła. Domyślny typ to submit: tu nie ma formularza, więc nic by się nie stało, ale gdy ktoś kiedyś otoczy listę <form>, przycisk bez typu zacząłby przeładowywać stronę. Identyfikator clear-order posłuży skryptowi do podpięcia zdarzenia - HTML nie zawiera wywołania funkcji.
Zawartość prawej sekcji głównej: 6 bloków z potrawami zawierających obraz oraz paragraf. Obraz nalesniki.webp z tekstem alternatywnym „Naleśniki” i paragraf o treści „Naleśniki”.
Blok potrawy: <div class="dish"> z obrazem i akapitem. Klasa, bo bloków jest sześć i mają wspólny styl. Atrybut tabindex="0" dodaje blok do kolejności klawisza Tab - <div> sam z siebie nie przyjmuje fokusu, a ktoś, kto nie używa myszy, też powinien móc zamówić naleśniki. Obsługę Entera dopisze skrypt.
Zdjęcia są w formacie WebP - przeglądarki wyświetlają go jak JPEG czy PNG, a pliki są mniejsze.
R.2.8 Prawa sekcja główna składa się z 6 bloków z potrawami. Każdy z bloków zawiera zdjęcie wraz z tekstem alternatywnym oraz akapit z podpisem potrawy
ok. 3 min
Polecenie z arkusza
Obraz lasagne.webp z tekstem alternatywnym „Lasagne szpinakowa” i paragraf o treści „Lasagne szpinakowa”. Obraz marchewka.webp z tekstem alternatywnym „Pieczona marchewka” i paragraf o treści „Pieczona marchewka”. Obraz rosol.webp z tekstem alternatywnym „Wege rosół” i paragraf o treści „Wege rosół”. Obraz tarta.webp z tekstem alternatywnym „Tarta szparagowa” i paragraf o treści „Tarta szparagowa”. Obraz kompot.webp z tekstem alternatywnym „Kompot” i paragraf o treści „Kompot”.
Pięć kopii pierwszego bloku w kolejności z arkusza. Nazwy plików bez polskich znaków (rosol.webp), teksty na stronie z nimi („Wege rosół”). Nazwa potrawy stoi w bloku tylko w akapicie (i w tekście alternatywnym) - skrypt przeczyta ją stamtąd, więc nie trzeba jej powtarzać w wywołaniu funkcji (R.2.8).
R.2.4 W lewej sekcji nagłówkowej znajduje się <h1> :"Restauracja Marchewka" oraz <h3> : "Twoje wegetariańskie miejsce na mapie miasta", w lewej sekcji głównej <h4> : "Twoje zamówienie", w stopce <p> zawierający numer zdającego
ok. 1 min
Polecenie z arkusza
Zawartość stopki: paragraf o treści „Wykonał:”, dalej wstawiony numer zdającego.
Akapit w <footer>. Na egzaminie po dwukropku wpisujesz swój numer zdającego (PESEL) - tutaj stoi imię i nazwisko autora rozwiązania. Ten akapit domyka R.2.4: <h1> i <h3> w nagłówku, <h4> w sekcji zamówienia i <p> w stopce.
Domyślnie, dla wszystkich selektorów: krój czcionki „Verdana”, zaokrąglenie obramowania 5 px.
Plik styl.css zaczyna się od zmiennych CSS w :root (to element <html>, więc zmienne są widoczne w całym dokumencie). Zieleń #778A35 arkusz każe ustawić pięć razy - wpisana raz, w regułach jest var(--green). Zmiana odcienia to jedna linia, a nie pięć miejsc, z których jedno łatwo pominąć. Inspektor przeglądarki pokazuje obliczony kolor, więc egzaminator sprawdza go tak samo.
Selektor * (R.4.1): krój Verdana z rodziną zastępczą sans-serif (gdy Verdany nie ma, przeglądarka weźmie inny krój bezszeryfowy, a nie domyślny szeryfowy) i zaokrąglenie 5 px - widoczne tylko tam, gdzie jest tło: sekcje, bloki potraw, przyciski.
Dla lewej sekcji nagłówkowej: szerokość 80%, kolor tła #778A35, wysokość 200 px.
Właściwości w stałej kolejności: wymiary, potem kolory - łatwiej porównać reguły między sobą. Sekcje stoją jeszcze jedna pod drugą; obok siebie ustawi je krok z układem.
Dla nagłówka pierwszego stopnia: rozmiar czcionki 50 px, margines wewnętrzny lewy 200 px.
padding-left - tylko lewy margines wewnętrzny; klucz (R.4.8) sprawdza, że jedynie lewy, więc skrót padding: 0 0 0 200px też by przeszedł, ale wyzerowałby pozostałe.
R.3.1 Układ bloków po uruchomieniu strony w przeglądarce jest zgodny z ilustracją 3 w arkuszu egzaminacyjnym (prawidłowo zastosowane właściwości CSS decydujące o układzie bloków na stronie, np. float i clear albo display flex albo grid albo position; żaden blok nie zachodzi na inne bloki - sprawdzić w inspektorze)
ok. 3 min
Polecenie z arkusza
Podział zrealizowany za pomocą semantycznych znaczników języka HTML5 tak, aby po uruchomieniu w przeglądarce układ bloków był zgodny z ilustracją 3.
Sekcje nagłówka i bloku głównego stają obok siebie dzięki display: flex na rodzicu; align-items: flex-start w bloku głównym zostawia sekcję zamówienia niską, przy górze, jak na ilustracji 2 (R.3.1).
Dlaczego tu nie siatka? Arkusz i klucz (R.4.6) ustawiają szerokości na samych sekcjach (width: 80%). W siatce procent szerokości elementu liczy się od jego kolumny, a nie od rodzica: sprawdzone w Chrome - sekcja z width: 80% w kolumnie auto nagłówka szerokiego na 1000 px miała 400 px. Flex liczy procenty od rodzica, więc szerokości z arkusza działają bez zmian. Siatka przyda się za chwilę tam, gdzie arkusz nie podaje szerokości - przy blokach potraw.
R.4.9 wyświetlanie bloków z potrawami obok siebie (ilustracja 2)
ok. 3 min
Polecenie z arkusza
Dla bloków z potrawami: kolor tła #778A35, tekst wyrównany do środka, marginesy zewnętrzne 20 px, wyświetlanie elementów blokowych obok siebie zgodnie z ilustracją 2.
Reguła .dish: margines 20 px, tło ze zmiennej, tekst do środka. „Obok siebie” ustawia rodzic - sekcja potraw staje się siatką:
display: grid - dzieci sekcji (bloki potraw) trafiają do komórek siatki,
grid-template-columns: repeat(auto-fill, 220px) - tyle kolumn po 220 px, ile się zmieści; gdy okno się zwęża, kolumn ubywa, a bloki przechodzą do kolejnego wiersza. Arkusz o tym uprzedza („układ bloków z potrawami może się różnić”),
220 px to szerokość bloku z marginesami: zdjęcie 150 px + 2 × 15 px jego marginesu + 2 × 20 px marginesu bloku.
W wersji podstawowej każdy blok miał display: inline-block i zachowywał się jak wyraz w zdaniu - z odstępem po spacji między znacznikami i wyrównaniem do linii tekstu. Siatka nie ma tych efektów: wszystkie bloki w wierszu mają tę samą wysokość, a odstępy wynikają tylko z marginesów (R.4.9).
Typowe błędy
repeat(auto-fill, 1fr) jest błędem składni - przy auto-fill kolumna musi mieć stałą szerokość albo minmax() ze stałym minimum (np. minmax(220px, 1fr) rozciągnęłoby bloki na całą szerokość sekcji).
R.4.5 wysokość: obie sekcje nagłówkowe - 200px, selektor img, znajdujący się w bloku z potrawą - 150px
ok. 1 min
Polecenie z arkusza
Dla selektora obrazu znajdującego się w bloku z potrawą: marginesy zewnętrzne 15 px, wysokość 150 px.
Selektor potomka .dish img kończy się selektorem znacznika img (tego wymaga uwaga arkusza) i dotyczy tylko zdjęć w blokach potraw - logo zostaje w spokoju. Szerokość przeliczy się z proporcji: zdjęcia są kwadratowe, więc mają 150 × 150 px. Wysokości sekcji nagłówka (200 px) i zdjęcia (150 px) to R.4.5.
Typowe błędy
Sam selektor img zmniejszyłby także logo do 150 px.
R.4.10 gdy kursor znajdzie się na bloku z potrawą ustawiany jest obrys outline: 2px white, dowolna pojedyncza linia ciągła
ok. 2 min
Polecenie z arkusza
Gdy kursor znajdzie się na bloku z potrawą pojawia się obrys (outline) linią ciągłą, o szerokości 2 px i kolorze białym.
outline: 2px solid white po najechaniu (R.4.10). Obrys rysuje się poza blokiem i nie zajmuje miejsca, więc nic się nie przesuwa.
Ta sama reguła obsługuje :focus-visible - blok wybrany klawiszem Tab dostaje identyczny obrys, czyli użytkownik klawiatury widzi, gdzie jest. cursor: pointer (rączka) podpowiada, że blok da się kliknąć.
R.4.3 kolor tła: obie sekcje nagłówkowe, blok z potrawami, stopka i przyciski - #778A35 lewa sekcja główna - #EBEBE8
R.4.8 marginesy wewnętrzne (padding): stopka - 10px, przyciski - 5px, nagłówki pierwszego i trzeciego stopnia - jedynie lewy 200px marginesy zewnętrzne (margin): bloki z potrawami - 20px, obraz znajdujący się w bloku z potrawami - 15px, stopka - jedynie górny 10px
ok. 1 min
Polecenie z arkusza
Dla przycisków: kolor tła #778A35, marginesy wewnętrzne 5px.
Selektor znacznika button. Tu domykają się dwa kryteria zbierane przez kilka reguł: kolory tła - wszystkie z var(--green) oraz var(--order) w sekcji zamówienia (R.4.3), i marginesy - stopka, przyciski, nagłówki, bloki potraw i ich zdjęcia (R.4.8).
Kroki 39-45 · po tym etapie masz 35 z 35 kryteriów (pkt)
Krok 39: Plik skrypt.js: jeden nasłuchiwacz dla sześciu potraw
Kryteria:
R.5.2 Zastosowana przynajmniej jedna zmienna lub funkcja oraz nazewnictwo jest w języku polskim lub angielskim i odzwierciedla cel zastosowania
ok. 4 min
Polecenie z arkusza
Skrypt 1: Wywoływany jest po kliknięciu na blok z potrawą. Kliknięcie każdego z bloków powoduje wykonanie skryptu 1.
Skrypt w osobnym pliku skrypt.js, podpięty w <head> z atrybutem defer: przeglądarka pobiera go równolegle ze stroną, a wykonuje dopiero po wczytaniu całego HTML-u - lista i bloki już istnieją, choć znacznik stoi przed nimi.
const orderList, const dishes - dwa elementy, do których skrypt będzie sięgał; const, bo zmienna zawsze wskazuje ten sam element,
delegacja zdarzeń: zamiast sześciu nasłuchiwaczy jeden, na całej sekcji potraw. Kliknięcie w zdjęcie „wędruje” w górę drzewa dokumentu aż do sekcji, a event.target mówi, w co dokładnie kliknięto,
event.target.closest('.dish') - najbliższy przodek z klasą dish (albo sam element); kliknięcie w odstęp między blokami daje null i if je pomija,
nazwę potrawy funkcja addDish dostaje z akapitu bloku (textContent) - zapisana raz w HTML-u.
Funkcja addDish(name) jest jeszcze pusta (nazwa po angielsku i mówi, co robi - R.5.2).
Typowe błędy
Bez defer (i ze znacznikiem w <head>) skrypt wykona się przed powstaniem sekcji - querySelector('#dishes') zwróci null, a addEventListener rzuci błąd i nic nie zadziała.
Krok 40: Skrypt 1: nowa pozycja na liście zamówienia
Kryteria: ,
R.5.1 Skrypt w języku JavaScript zawiera przynajmniej jedną poprawną składniowo instrukcję wynikającą z treści zadania
R.5.3 Po kliknięciu na blok z potrawą zostaje dodany nowy element <li> do listy w lewej sekcji głównej. Element ten zawiera nazwę klikniętej potrawy (działa dla więcej niż jednego bloku)
ok. 3 min
Polecenie z arkusza
Dodaje nowy element do listy w lewej sekcji głównej. Element ten zawiera nazwę klikniętej potrawy (ilustracja 4).
document.createElement('li') - nowy element listy, na razie poza stroną,
item.textContent = name - wstawia tekst. innerHTML potraktowałby nazwę jak kod HTML: gdyby w nazwie potrawy znalazł się znak <, przeglądarka próbowałaby z niego zrobić znacznik,
orderList.append(item) - dokłada pozycję na koniec listy.
Kliknij kilka potraw w podglądzie - każde kliknięcie dopisuje pozycję jak na ilustracji 4 (R.5.1, R.5.3).
Typowe błędy
orderList.textContent = namezastępuje całą zawartość listy zwykłym tekstem - zamiast nowej pozycji <li> zostaje jeden napis.
Kliknięcie każdego z bloków powoduje wykonanie skryptu 1.
Blok z tabindex="0" przyjmuje fokus, ale <div> nie zamienia Entera na kliknięcie (robi to tylko <button> i odnośnik). Drugi nasłuchiwacz, też na sekcji: zdarzenie keydown, a event.key mówi, który klawisz naciśnięto - Enter albo spacja dodają potrawę. preventDefault() przy spacji powstrzymuje przewinięcie strony.
Klucz tego nie ocenia, ale arkusz mówi o „kliknięciu” bloku, a dla użytkownika klawiatury Enter jest kliknięciem. Spróbuj w podglądzie: Tab do potrawy, Enter.
Krok 42: Skrypt 2: czyszczenie listy przyciskiem „Wyczyść”
Kryteria: ,
R.3.3 Zdefiniowano dla minimum jednego przycisku zdarzenie związane z jego wciśnięciem, które uruchamia funkcję skryptu
R.5.4 Po kliknięciu na przycisk Wyczyść zawartość listy jest czyszczona
ok. 2 min
Polecenie z arkusza
Skrypt 2: Wywoływany jest po kliknięciu na przycisk Wyczyść. Czyści zawartość listy lewej sekcji głównej.
orderList.replaceChildren() bez argumentów usuwa wszystkie dzieci elementu - nazwa mówi wprost, co się dzieje, zamiast podstawiania pustego HTML-u (innerHTML = ''),
addEventListener('click', clearOrder) - funkcję przekazujesz bez nawiasów: przeglądarka wywoła ją sama przy kliknięciu.
To zdarzenie wciśnięcia przycisku, które uruchamia funkcję (R.3.3, R.5.4). Dodaj w podglądzie kilka potraw i wyczyść listę.
Typowe błędy
addEventListener('click', clearOrder()) z nawiasami wywołuje funkcję od razu przy wczytaniu, a jako obsługę zdarzenia przekazuje jej wynik (undefined) - przycisk przestaje działać.
R.5.5 Po kliknięciu na przycisk Zatwierdź pojawia się alert o treści "Zamówienie zostało przekazane do realizacji"
ok. 2 min
Polecenie z arkusza
Skrypt 3: Wywoływany jest po kliknięciu na przycisk Zatwierdź. Na stronie pojawia się alert z informacją „Zamówienie zostało przekazane do realizacji” (ilustracja 5).
alert(komunikat) - okienko z tekstem z arkusza i przyciskiem OK (R.5.5). Przycisk dostaje nasłuchiwacz tak samo jak „Wyczyść”.
Ramka podglądu blokuje okienka alert, więc tu komunikat się nie pokaże - po otwarciu pliku w przeglądarce pojawi się po kliknięciu.
Krok 44: Skrypt 3: czyszczenie listy po zatwierdzeniu
Kryteria:
R.5.6 Po kliknięciu na przycisk Zatwierdź zawartość listy jest czyszczona
ok. 1 min
Polecenie z arkusza
Zawartość listy z lewej sekcji głównej jest czyszczona.
Czyszczenie to już gotowa funkcja clearOrder() - skrypt 3 jej używa, zamiast powtarzać tę samą linię. Kolejność ma znaczenie: alert wstrzymuje skrypt do kliknięcia OK, więc przy komunikacie zamówienie jest jeszcze widoczne, a znika dopiero po zamknięciu okienka (R.5.6).
Krok 45: Sprawdzenie: ponowne zamawianie po wyczyszczeniu
Kryteria:
R.5.7 Po wyczyszczeniu zawartości listy możliwe jest ponowne dodanie przynajmniej jednego elementu (do pustej listy)
ok. 1 min
Polecenie z arkusza
Dodaje nowy element do listy w lewej sekcji głównej.
Klucz osobno sprawdza, że po wyczyszczeniu listy można znowu dodawać potrawy (R.5.7). Działa bez dodatkowego kodu: replaceChildren() usuwa pozycje, a sam <ul> zostaje, więc orderList z początku pliku nadal wskazuje istniejący element. W podglądzie: dodaj potrawy, wyczyść, dodaj znowu.
Typowe błędy
orderList.remove() usuwa całą listę ze strony - zmienna nadal wskazuje element, ale już odłączony, więc kolejne potrawy „dodają się” poza stroną i nic nie widać.
Krok 46 · po tym etapie masz 35 z 35 kryteriów (pkt)
Krok 46: Co jest inaczej i którą wersję wybrać na egzaminie
ok. 2 min
Obie wersje dają komplet 35 punktów. Różnice:
wersja podstawowa
wersja nowoczesna
kolory
wpisane w każdej regule
zmienne --green, --page, --order
bloki potraw obok siebie
display: inline-block na bloku
display: grid + repeat(auto-fill, 220px) na sekcji
sekcje nagłówka i bloku głównego
display: flex
display: flex (szerokości procentowe sekcji)
skrypt
<script> na końcu <body>, 6 × onclick z nazwą potrawy
skrypt.js z defer, jeden nasłuchiwacz, nazwa z akapitu
treść pozycji
innerHTML
textContent
czyszczenie
innerHTML = "" w dwóch funkcjach
replaceChildren() w jednej funkcji, wołanej dwa razy
klawiatura
brak
tabindex, :focus-visible, Enter i spacja
zapytanie 3
DATE(dataZlozenia) = ...
przedział >= '2024-06-09' AND < '2024-06-10'
Na egzaminie wersja podstawowa trzyma się dosłownie tabeli 2 arkusza (onclick, getElementById, innerHTML) i jest szybsza do napisania. Nowoczesna wymaga pamiętania o defer i closest, ale nazwa potrawy nie może się już rozjechać między menu a zamówieniem. Wersja podstawowa w etapie „Dobre praktyki” pokazuje też blokadę pustego zamówienia - tu jej nie ma celowo: egzaminator może kliknąć „Zatwierdź” przy pustej liście i spodziewa się komunikatu z arkusza (R.5.5).
Krok 47 · po tym etapie masz 35 z 35 kryteriów (pkt)
Krok 47: 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 folderze z numerem zdającego: index.html, skrypt.js, styl.css, kwerendy.txt, import.png, kw1.png … kw5.png, zdjęcia potraw, logo.png i przeglądarka.txt. Bez skrypt.js potrawy nie trafiają do zamówienia. Płytę sprawdź po nagraniu.
Symulacja ekranu w przeglądarce - w Android Studio / Visual Studio wygląd może się nieco różnić.
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: Bartosz Bryniarski. 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.