Przejdź do głównej treści
EE.09-07-22.01-SGStyczeń 2022 · 21 kroków · ok. 61 min · 33 kryteria z klucza

Rozwiązanie krok po kroku: Galeria zdjęć z ciekawych miejsc (Nowoczesny kod (flex, addEventListener))

To drugi sposób rozwiązania tego samego arkusza. Wynik jest ten sam - baza podroze z czterema zapytaniami, zdjęcie Serengeti o szerokości 350 px oraz strona galeria.html, na której kliknięta miniatura pojawia się w dużym bloku, a serce „Polub nas” przełącza się między pustym a pełnym - i tak samo spełnia każde kryterium klucza. Inna jest droga:

  • znaczniki semantyczne: baner w <header>, treść w <main>, stopka w <footer>, a blok lewy i prawy w <section> wewnątrz wiersza na flex - bez float i bez clear,
  • zmienne CSS dla dwóch kolorów strony,
  • skrypt w osobnym pliku galeria.js, podpięty z atrybutem defer, z obsługą zdarzeń przez addEventListener zamiast atrybutów onclick w HTML-u,
  • jedna obsługa kliknięcia dla całego bloku lewego (delegowanie zdarzeń) zamiast onclick przy każdej miniaturze,
  • serce jako przycisk z atrybutem aria-pressed - działa też z klawiatury, a czytnik ekranu ogłasza, czy jest wciśnięte.

To arkusz EE.09 ze stycznia 2022 - kwalifikacji formuły 2017, którą zastąpiła INF.03. Baza i zdjęcia pochodzą z oryginalnego archiwum CKE pliki7 (załącznik na stronie arkusza), zapytania i zrzuty są policzone na MariaDB 10.4, a działanie skryptu sprawdzone w Chrome. Kroki bazy danych i grafiki są takie same jak w wersji podstawowej. Podgląd od kroku z HTML-em to działająca strona - miniatury i serce można klikać.

Jak liczą się punkty. Klucz ma 33 kryteria (R.1.1 - R.5.4), każde za 1 punkt. Próg zdania części praktycznej to 75%, czyli 25 punktów. Przy każdym kroku jest napisane, które kryteria spełnia.

  1. Etap 1: Baza danych

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

    Krok 1: Folder zdającego i archiwum pliki7

    ok. 2 min
    Polecenie z arkusza

    Należy utworzyć folder o nazwie odpowiadającej numerowi PESEL zdającego lub w przypadku jego braku innemu numerowi, którym został podpisany arkusz. Archiwum należy rozpakować do tego folderu. Wszystkie wykonane w czasie egzaminu pliki w tym zrzuty ekranu, pliki strony, stylów należy umieścić w tym folderze.

    Na pulpicie tworzysz folder nazwany numerem PESEL - w tym rozwiązaniu w jego miejscu stoi imię i nazwisko autora, Bartosz Bryniarski. Archiwum pliki7.zip rozpakowujesz do tego folderu, podając hasło {Ciekaw3Zdjecia} (z nawiasami klamrowymi i cyfrą 3 zamiast „e”). W środku są: podroze.sql, pięć zdjęć (lanzarotte.jpg, pekin.jpg, serengeti.jpg, tajlandia.jpg, wenecja.jpg) i dwie ikony serca: icon-off.png i icon-on.png.

  2. Krok 2: XAMPP i pusta baza podroze

    ok. 2 min
    Polecenie z arkusza

    Uruchom usługi MySQL i Apache za pomocą XAMPP Control Panel. Za pomocą narzędzia phpMyAdmin wykonaj podane operacje na bazie danych: Utwórz bazę danych o nazwie podroze

    W XAMPP Control Panel Start przy Apache i MySQL, potem http://localhost/phpmyadmin, Nowa, nazwa podroze (bez polskich liter), Utwórz. Strona tego zadania nie łączy się z bazą - baza służy tylko do czterech zapytań.

  3. Krok 3: Import pliku podroze.sql i zrzut egzamin.jpg

    Kryteria:

    R.1.1 Wykonano import tabel do bazy podroze , czynność udokumentowano plikiem o nazwie egzamin w formacie JPEG

    ok. 3 min
    Polecenie z arkusza

    Do bazy podroze zaimportuj plik podroze.sql z rozpakowanego archiwum. Wykonaj zrzut ekranu po imporcie. Zrzut zapisz w folderze z numerem PESEL lub w przypadku jego braku w folderze z innym numerem, którym został podpisany arkusz, w formacie JPEG o nazwie egzamin. 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

    Zaznacz bazę podroze, karta Import, Wybierz plik → podroze.sql, Wykonaj. Plik tworzy trzy tabele: samoloty (4 wiersze), odloty (10) i przyloty (8). Każdy lot ma kolumnę samoloty_id - numer samolotu, który go obsługuje. Na zrzucie widać zielony komunikat o sukcesie i trzy tabele w lewym panelu.

    Zrzut całego ekranu z paskiem zadań zapisujesz jako egzamin.jpg.

    Typowe błędy

    Zrzut importu ma być w JPEG, a zrzuty zapytań w PNG.

    Podgląd strony po tym kroku
    Podgląd strony po kroku 3
  4. Krok 4: Zapytanie 1: przyloty bez statusu lotu

    Kryteria: ,

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

    R.1.3 Utworzono zapytanie 1 wybierające pola kierunek i czas z tabeli przyloty dla lotów, które nie mają wpisu w polu status_lotu. W pliku z kwerendami lub na zrzucie istnieje zapis np.: SELECT kierunek, czas FROM przyloty WHERE status_lotu = ""; oraz wynik działania zapytania udokumentowano zrzutem, na którym widoczne są jedynie kolumny kierunek i czas, jedynie rekordy dla miast: Wiedeń, Berlin, Hamburg, Monachium, Zurych

    ok. 3 min
    Polecenie z arkusza

    Zapisz i wykonaj zapytania SQL działające na bazie podroze. Zapytania zapisz w pliku kwerendy.txt, w folderze z numerem PESEL lub w przypadku jego braku w folderze z innym numerem, którym został podpisany arkusz. Wykonaj zrzuty ekranu przedstawiające wyniki działania kwerend. Zrzuty zapisz w formacie PNG i nadaj im nazwy kw1, kw2, kw3, kw4. Zrzuty powinny obejmować cały ekran monitora z widocznym paskiem zadań. Zapytanie 1: wybierające pola kierunek i czas z tabeli przyloty dla lotów, które nie mają wpisu w polu status_lotu

    • SELECT kierunek, czas - tylko dwie kolumny,
    • FROM przyloty,
    • WHERE status_lotu = '' - pole z pustym napisem.

    „Brak wpisu” w tej bazie to pusty napis, a nie NULL - sprawdzone: żaden z 8 przylotów nie ma w tej kolumnie NULL, a pięć ma ''. Dlatego działa = '', a IS NULL zwróciłoby pusty wynik. Wynik: Wieden, Berlin, Hamburg, Monachium, Zurych z godzinami (w bazie „Wieden” bez „ń” - tabela ma kodowanie latin1). Zapytanie kopiujesz do nowego pliku kwerendy.txt, zrzut - do kw1.png.

    Typowe błędy

    Na egzaminie dobrze jest najpierw obejrzeć dane: SELECT * FROM przyloty pokaże, czy puste pola to NULL (phpMyAdmin pisze wtedy kursywą NULL), czy puste napisy. Bezpieczny warunek na oba przypadki: WHERE status_lotu = '' OR status_lotu IS NULL.

    kwerendy.txt Tekst nowy plik
    -- Zapytanie 1
    SELECT kierunek, czas FROM przyloty WHERE status_lotu = '';
    Podgląd strony po tym kroku
    Podgląd strony po kroku 4
  5. Krok 5: Zapytanie 2: odloty samolotów Boening 787

    Kryteria:

    R.1.4 Utworzono zapytanie 2 wybierające pola kierunek i dzien z tabeli odloty dla lotów obsługiwanych samolotem typu boening 787. Zapytanie wykorzystuje relację, w klauzuli warunku jest sprawdzany typ samolotu. W pliku z kwerendami lub na zrzucie istnieje zapis np.: SELECT kierunek, dzien FROM odloty JOIN samoloty ON odloty.samoloty_id = samoloty.id WHERE samoloty.typ = "boening 787"; możliwe również INNER JOIN lub przyrównanie kluczy w warunku oraz wynik działania zapytania udokumentowano zrzutem, na którym widoczne są jedynie kolumny kierunek i dzień dla: Neapol, ALICANTE, Londyn LT, Malta, Wiedeń

    ok. 4 min
    Polecenie z arkusza

    Zapytanie 2: wybierające pola kierunek i dzien z tabeli odloty dla lotów obsługiwanych samolotem typu Boening 787. Zapytanie wykorzystuje relację, w klauzuli warunku jest sprawdzany typ samolotu

    Typ samolotu jest w tabeli samoloty, a loty w odloty - łączy je relacja przez samoloty_id:

    • SELECT kierunek, dzien,
    • FROM odloty JOIN samoloty ON odloty.samoloty_id = samoloty.id - do każdego odlotu jego samolot,
    • WHERE samoloty.typ = 'Boening 787' - warunek na typie samolotu.

    Typ wpisujesz dokładnie tak, jak w bazie i w arkuszu: „Boening” (poprawnie producent nazywa się Boeing, ale zapytanie porównuje napisy, a w tabeli jest literówka). Boeingi 787 to samoloty nr 1 i 3, a ich odloty to Neapol, ALICANTE, Londyn LT, Malta, Wieden - wszystkie 25 lipca 2019. Zrzut: kw2.png.

    Typowe błędy

    WHERE typ = 'Boeing 787' (poprawna pisownia) zwróci pusty wynik - baza ma „Boening”.

    kwerendy.txt Tekst zmienione: 5 linii
    -- Zapytanie 1
    SELECT kierunek, czas FROM przyloty WHERE status_lotu = '';
    
    -- Zapytanie 2
    SELECT kierunek, dzien
    FROM odloty JOIN samoloty ON odloty.samoloty_id = samoloty.id
    WHERE samoloty.typ = 'Boening 787';
    Podgląd strony po tym kroku
    Podgląd strony po kroku 5
  6. Krok 6: Zapytanie 3: rejsy z „LX” w numerze

    Kryteria:

    R.1.5 Utworzono zapytanie 3 wybierające numer rejsu i kierunek z tabeli przyloty dla rejsów, których numer zawiera w dowolnym miejscu ciąg znaków LX. W pliku z kwerendami lub na zrzucie istnieje zapis np.: SELECT nr_rejsu, kierunek FROM przyloty WHERE nr_rejsu LIKE "%LX%"; oraz wynik działania zapytania udokumentowano zrzutem, na którym widoczne są jedynie kolumny nr_rejsu i kierunek, jedynie dla lotów: LX3447, LX5473, LX5728

    ok. 2 min
    Polecenie z arkusza

    Zapytanie 3: wybierające numer rejsu i kierunek z tabeli przyloty dla rejsów, których numer zawiera w dowolnym miejscu ciąg znaków LX

    • SELECT nr_rejsu, kierunek FROM przyloty,
    • WHERE nr_rejsu LIKE '%LX%' - LIKE porównuje z wzorcem, a % oznacza dowolny ciąg znaków (także pusty). %LX% to „LX gdziekolwiek”: na początku, w środku albo na końcu.

    Wynik: LX3447, LX5473, LX5728 (rejsy linii SWISS, której kod to LX). Zrzut: kw3.png.

    Typowe błędy

    LIKE 'LX%' szuka tylko numerów zaczynających się od LX - tu wynik byłby ten sam, ale arkusz każe szukać „w dowolnym miejscu”, a klucz ocenia zapytanie uniwersalne.

    kwerendy.txt Tekst zmienione: 3 linie
    -- Zapytanie 1
    SELECT kierunek, czas FROM przyloty WHERE status_lotu = '';
    
    -- Zapytanie 2
    SELECT kierunek, dzien
    FROM odloty JOIN samoloty ON odloty.samoloty_id = samoloty.id
    WHERE samoloty.typ = 'Boening 787';
    
    -- Zapytanie 3
    SELECT nr_rejsu, kierunek FROM przyloty WHERE nr_rejsu LIKE '%LX%';
    Podgląd strony po tym kroku
    Podgląd strony po kroku 6
  7. Krok 7: Zapytanie 4: linia SWISS zmienia nazwę na SWISS2

    Kryteria:

    R.1.6 Utworzono zapytanie 4 uaktualniające pole linie w tabeli samoloty . Firma SWISS zmieniła swoją nazwę na SWISS2. W pliku z kwerendami lub na zrzucie istnieje zapis np.: UPDATE samoloty SET linie="SWISS2" WHERE linie = "SWISS"; oraz wynik działania zapytania udokumentowano zrzutem, na którym widoczny jest efekt poprawnie wykonanego zapytania

    ok. 2 min
    Polecenie z arkusza

    Zapytanie 4: uaktualniające pole linie w tabeli samoloty. Firma SWISS zmieniła swoją nazwę na SWISS2

    • UPDATE samoloty - zmiana danych w tabeli,
    • SET linie = 'SWISS2' - nowa wartość kolumny,
    • WHERE linie = 'SWISS' - tylko w wierszach starej nazwy.

    phpMyAdmin odpowiada „Zmieniono rekordów: 1” - linie SWISS ma jeden samolot (nr 3). Zrzut: kw4.png; kwerendy.txt ma komplet czterech zapytań.

    Typowe błędy

    Bez WHERE zapytanie zmieni nazwę linii we wszystkich samolotach - patrz krok w etapie dobrych praktyk.

    kwerendy.txt Tekst zmienione: 3 linie
    -- Zapytanie 1
    SELECT kierunek, czas FROM przyloty WHERE status_lotu = '';
    
    -- Zapytanie 2
    SELECT kierunek, dzien
    FROM odloty JOIN samoloty ON odloty.samoloty_id = samoloty.id
    WHERE samoloty.typ = 'Boening 787';
    
    -- Zapytanie 3
    SELECT nr_rejsu, kierunek FROM przyloty WHERE nr_rejsu LIKE '%LX%';
    
    -- Zapytanie 4
    UPDATE samoloty SET linie = 'SWISS2' WHERE linie = 'SWISS';
    Podgląd strony po tym kroku
    Podgląd strony po kroku 7
  8. Etap 2: Grafika i strona HTML

    Kroki 8-12 · po tym etapie masz 18 z 33 kryteriów (pkt)

    Krok 8: Grafika: serengeti.jpg o szerokości 350 px

    Kryteria:

    R.2.1 Plik serengeti.jpg jest przeskalowany z zachowaniem proporcji do szerokości dokładnie 350 px odpowiadająca temu wysokość wynosi 233 px ±5 px

    ok. 3 min
    Polecenie z arkusza

    Plik serengeti.jpg, wypakowany z archiwum należy przeskalować z zachowaniem proporcji tak, aby szerokość wynosiła dokładnie 350 px i zapisać obraz pod tą samą nazwą. Pozostałych obrazów nie należy modyfikować.

    Oryginał ma 400 × 267 px, pozostałe zdjęcia - 350 px szerokości. W GIMP-ie Obraz → Skaluj obraz, łańcuch złączony, szerokość 350 - wysokość zmieni się sama na 234 px (267 × 350 / 400 = 233,6). Klucz przyjmuje 233 ± 5 px. Plik → Nadpisz serengeti.jpg.

    Po skalowaniu wszystkie miniatury mają tę samą szerokość, więc przy wspólnej wysokości z CSS układają się w równy pasek.

    Podgląd strony po tym kroku
    Podgląd strony po kroku 8
  9. Krok 9: Plik galeria.html: kodowanie, tytuł, arkusz stylów

    Kryteria: , , ,

    R.2.2 Witrynę internetową zapisano w pliku HTML o nazwie galeria

    R.2.3 Zastosowano właściwy standard kodowania polskich znaków dla witryny

    R.2.4 Nadano tytuł strony: "Galeria”

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

    ok. 3 min
    Polecenie z arkusza

    Składa się ze strony o nazwie galeria.html. Zastosowany właściwy standard kodowania polskich znaków. Tytuł strony widoczny na karcie przeglądarki: „Galeria”. Arkusz stylów w pliku o nazwie styl7.css prawidłowo połączony z kodem strony

    Plik galeria.html obok zdjęć (R.2.2), a w <head> od razu wszystko, co dotyczy całego dokumentu:

    • <meta charset="UTF-8"> - polskie litery (R.2.3),
    • viewport - telefon pokaże stronę w swojej szerokości (klucz tego nie ocenia),
    • <title>Galeria</title> (R.2.4),
    • <link> do styl7.css (R.3.4).
    galeria.html HTML nowy plik
    <!DOCTYPE html>
    <html lang="pl">
    <head>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, initial-scale=1">
        <title>Galeria</title>
        <link rel="stylesheet" href="styl7.css">
    </head>
    <body>
    </body>
    </html>
    Podgląd strony po tym kroku (galeria.html)
  10. Krok 10: Bloki strony: header, main z sekcjami, footer

    Kryteria:

    R.2.5 Wygląd strony zdefiniowano dzieląc ją na bloki: baner, główny, bloki lewy i prawy, stopka. Zastosowano znaczniki sekcji

    ok. 3 min
    Polecenie z arkusza

    Podział strony na bloki: baner, główny, poniżej obok siebie lewy i prawy, poniżej stopka. Podział zrealizowany za pomocą znaczników sekcji tak, aby wygląd układu bloków strony po uruchomieniu w przeglądarce, był zgodny z Obrazem 2. Zawartość banera: nagłówek drugiego stopnia o treści „Galeria miejsc ciekawych”. Zawartość stopki: napis o treści „Autor: ”, dalej wstawiony numer PESEL zdającego lub w przypadku jego braku inny numer, którym został podpisany arkusz

    Każdy blok dostaje znacznik, który mówi, czym jest:

    • baner to <header> z nagłówkiem <h2>,
    • treść strony - <main>: w nim blok główny (<section id="hero">) i wiersz .row z blokiem lewym (#browse) i prawym (#info) - oba to <section>, a .row jest tylko kontenerem układu, więc wystarczy <div>,
    • stopka - <footer> (na egzaminie po „Autor: ” numer PESEL; tu w jego miejscu imię i nazwisko: Bartosz Bryniarski).

    Identyfikatory nazywają zawartość bloku (browse - przeglądanie, info), a nie jego miejsce na ekranie: po zmianie układu na telefonie blok „lewy” stoi nad prawym i nazwa left przestałaby pasować. Podział na bloki znacznikami sekcji: R.2.5.

    galeria.html HTML zmienione: 16 linii
    <!DOCTYPE html>
    <html lang="pl">
    <head>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, initial-scale=1">
        <title>Galeria</title>
        <link rel="stylesheet" href="styl7.css">
    </head>
    <body>
        <header>
            <h2>Galeria miejsc ciekawych</h2>
        </header>
        <main>
            <section id="hero">
            </section>
            <div class="row">
                <section id="browse">
                </section>
                <section id="info">
                </section>
            </div>
        </main>
        <footer>
            Autor: Bartosz Bryniarski
        </footer>
    </body>
    </html>
    Podgląd strony po tym kroku (galeria.html)
  11. Krok 11: Blok główny i lewy: duże zdjęcie i pięć miniatur

    Kryteria:

    R.2.8 W bloku lewym umieszczono 5 zdjęć zgodnych z obrazem 2 w arkuszu egzaminacyjnym. Ich teksty alternatywne są takie same jak nazwa pliku (mogą być bez rozszerzenia lub z)

    ok. 3 min
    Polecenie z arkusza

    Zawartość bloku głównego: obraz lanzarotte.jpg z tekstem alternatywnym „galeria”. Zawartość bloku lewego: Nagłówek trzeciego stopnia o treści „Przeglądaj zdjęcia”. 5 zdjęć JPG o nazwach kolejno: lanzarotte, pekin, serengeti, wenecja, tajlandia oraz tekście alternatywnym takim jak nazwa zdjęcia

    Duże zdjęcie z identyfikatorem big - skrypt będzie podmieniał właśnie ten obraz. Pod nagłówkiem <h3> pięć miniatur w kolejności z arkusza, z tekstem alternatywnym równym nazwie zdjęcia (R.2.8) i wspólną klasą thumb (identyfikator musi być jednoznaczny, więc nie może się powtarzać).

    Miniatury nie mają żadnego onclick - całą obsługę kliknięć dostanie później blok #browse.

    galeria.html HTML zmienione: 7 linii
    <!DOCTYPE html>
    <html lang="pl">
    <head>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, initial-scale=1">
        <title>Galeria</title>
        <link rel="stylesheet" href="styl7.css">
    </head>
    <body>
        <header>
            <h2>Galeria miejsc ciekawych</h2>
        </header>
        <main>
            <section id="hero">
                <img src="lanzarotte.jpg" alt="galeria" id="big">
            </section>
            <div class="row">
                <section id="browse">
                    <h3>Przeglądaj zdjęcia</h3>
                    <img src="lanzarotte.jpg" alt="lanzarotte" class="thumb">
                    <img src="pekin.jpg" alt="pekin" class="thumb">
                    <img src="serengeti.jpg" alt="serengeti" class="thumb">
                    <img src="wenecja.jpg" alt="wenecja" class="thumb">
                    <img src="tajlandia.jpg" alt="tajlandia" class="thumb">
                </section>
                <section id="info">
                </section>
            </div>
        </main>
        <footer>
            Autor: Bartosz Bryniarski
        </footer>
    </body>
    </html>
    Podgląd strony po tym kroku (galeria.html)
  12. Krok 12: Blok prawy: tabela, serce jako przycisk, odnośnik

    Kryteria: , , , ,

    R.2.6 Zapisano: w banerze nagłówek h2: "Galeria miejsc ciekawych", w bloku lewym nagłówek h3: "Przeglądaj zdjęcia", w bloku prawym nagłówek h3: "Obrazy w naszej galerii" oraz paragraf

    R.2.7 W bloku głównym po uruchomieniu strony wstawiono zdjęcie lanzarotte.jpg z tekstem alternatywnym "galeria" oraz w bloku prawym umieszczono obraz icon-off.png

    R.2.9 W bloku prawym umieszczono tabelę o dwóch wierszach i trzech kolumnach, zastosowano znaczniki <table>, <tr>, <td> wraz z ich zamknięciami

    R.3.2 Wybranie odnośnika "Odkryj więcej zdjęć" inicjuje otwarcie strony https://pixabay.com

    R.3.3 Odnośnik otwiera się w osobnej karcie przeglądarki

    ok. 4 min
    Polecenie z arkusza

    Zawartość bloku prawego: Nagłówek trzeciego stopnia o treści „Obrazy w naszej galerii”. Tabela o dwóch wierszach i trzech kolumnach i wartościach: Wiersz pierwszy: Europa, Azja, Afryka. Wiersz drugi: 2, 2, 1. Paragraf (akapit) zawierający treść „Polub nas” i obraz icon-off.png. Odnośnik do adresu https://pixabay.com o treści „Odkryj więcej zdjęć”, odnośnik otwiera się w osobnej karcie przeglądarki

    • <h3> i tabela: dwa wiersze <tr> po trzy komórki <td> (R.2.9). Nagłówki h2, oba h3 i akapit: R.2.6.
    • Ikona serca icon-off.png stoi w akapicie z tekstem „Polub nas”, ale opakowana w <button type="button">. Obraz sam w sobie nie jest elementem, który można kliknąć klawiaturą - przycisk dostaje fokus klawiszem Tab i reaguje na Enter i spację. Atrybut aria-pressed mówi czytnikowi ekranu, czy przycisk jest wciśnięty; skrypt będzie go przełączał razem z ikoną. Obraz w bloku głównym i ikona: R.2.7.
    • Odnośnik z target="_blank" (nowa karta, R.3.2, R.3.3) i od razu z rel="noopener noreferrer": otwarta strona nie dostaje dostępu do karty galerii (window.opener) ani adresu, z którego przyszedł użytkownik.
    galeria.html HTML zmienione: 19 linii
    <!DOCTYPE html>
    <html lang="pl">
    <head>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, initial-scale=1">
        <title>Galeria</title>
        <link rel="stylesheet" href="styl7.css">
    </head>
    <body>
        <header>
            <h2>Galeria miejsc ciekawych</h2>
        </header>
        <main>
            <section id="hero">
                <img src="lanzarotte.jpg" alt="galeria" id="big">
            </section>
            <div class="row">
                <section id="browse">
                    <h3>Przeglądaj zdjęcia</h3>
                    <img src="lanzarotte.jpg" alt="lanzarotte" class="thumb">
                    <img src="pekin.jpg" alt="pekin" class="thumb">
                    <img src="serengeti.jpg" alt="serengeti" class="thumb">
                    <img src="wenecja.jpg" alt="wenecja" class="thumb">
                    <img src="tajlandia.jpg" alt="tajlandia" class="thumb">
                </section>
                <section id="info">
                    <h3>Obrazy w naszej galerii</h3>
                    <table>
                        <tr>
                            <td>Europa</td>
                            <td>Azja</td>
                            <td>Afryka</td>
                        </tr>
                        <tr>
                            <td>2</td>
                            <td>2</td>
                            <td>1</td>
                        </tr>
                    </table>
                    <p>Polub nas
                        <button type="button" id="like" aria-pressed="false">
                            <img src="icon-off.png" alt="Polub">
                        </button>
                    </p>
                    <a href="https://pixabay.com" target="_blank" rel="noopener noreferrer">Odkryj więcej zdjęć</a>
                </section>
            </div>
        </main>
        <footer>
            Autor: Bartosz Bryniarski
        </footer>
    </body>
    </html>
    Podgląd strony po tym kroku (galeria.html)
  13. Etap 3: Styl CSS

    Kroki 13-17 · po tym etapie masz 29 z 33 kryteriów (pkt)

    Krok 13: Plik styl7.css: zmienne kolorów i krój Helvetica

    Kryteria:

    R.4.1 Ustawiono domyślny krój czcionki dla całej strony na Helvetica (dla selektora * lub body lub html lub kontenera całej strony)

    ok. 2 min
    Polecenie z arkusza

    Cechy formatowania CSS: Są zawarte wyłącznie w zewnętrznym arkuszu stylów. Domyślne dla całej strony: krój czcionki Helvetica

    Na początku pliku dwie zmienne CSS (właściwości zaczynające się od --, zapisane w :root, czyli w elemencie <html>): kolor banera, stopki i bloków dolnych oraz jasny kolor bloku głównego. Reguły użyją ich przez var(--steel) - zmiana odcienia to jedna linia, nie cztery.

    Krój Helvetica dla body - dziedziczą go wszystkie elementy tekstowe strony (R.4.1). margin: 0 usuwa domyślny 8-pikselowy margines przeglądarki, więc bloki dochodzą do krawędzi okna.

    styl7.css CSS nowy plik
    :root {
        --steel: rgb(70, 130, 180);
        --light-steel: rgb(176, 196, 222);
    }
    
    body {
        margin: 0;
        font-family: Helvetica;
    }
    Podgląd strony po tym kroku (galeria.html)
  14. Krok 14: Baner i stopka

    ok. 2 min
    Polecenie z arkusza

    Dla banera i stopki: kolor RGB tła 70, 130, 180; biały kolor czcionki, wysokość 30 px, wyrównanie tekstu do środka

    Jedna reguła dla header i footer: tło ze zmiennej --steel, czyli rgb(70, 130, 180), biały tekst, 30 px wysokości, wyśrodkowanie. margin: 0 nagłówka - inaczej jego domyślne marginesy wypchnęłyby napis poza 30-pikselowy pasek.

    styl7.css CSS zmienione: 12 linii
    :root {
        --steel: rgb(70, 130, 180);
        --light-steel: rgb(176, 196, 222);
    }
    
    body {
        margin: 0;
        font-family: Helvetica;
    }
    
    header,
    footer {
        height: 30px;
        background-color: var(--steel);
        color: white;
        text-align: center;
    }
    
    header h2 {
        margin: 0;
    }
    Podgląd strony po tym kroku (galeria.html)
  15. Krok 15: Blok główny i duże zdjęcie

    Kryteria: , ,

    R.4.6 Ustawiono wyrównanie tekstu do środka dla banera, stopki i bloku głównego

    R.4.7 Ustawiono marginesy wewnętrzne (padding) 50px dla bloku głównego

    R.4.8 Ustawiono styl zdjęcia w bloku głównym: marginesy wewnętrzne (padding) 3px, obramowanie linią kreskowaną w kolorze niebieskim (dowolny odcień) grubości 1px, zaokrąglenie rogów obrazu o 10px

    ok. 2 min
    Polecenie z arkusza

    Dla bloku głównego: kolor RGB tła 176, 196, 222; marginesy wewnętrzne 50 px, wyrównanie tekstu do środka. Dla zdjęcia w bloku głównym: marginesy wewnętrzne 3 px, obramowanie linią kreskowaną w kolorze niebieskim grubości 1 px, zakrzywienie rogów obrazu o 10 px

    • #hero: tło rgb(176, 196, 222) ze zmiennej, padding: 50px (R.4.7) i wyśrodkowanie, które dotyczy też obrazu - wyrównanie banera, stopki i bloku głównego to R.4.6,
    • #big: 3 px odstępu, ramka kreskowana (dashed) niebieska 1 px i border-radius: 10px (R.4.8).
    styl7.css CSS zmienione: 12 linii
    :root {
        --steel: rgb(70, 130, 180);
        --light-steel: rgb(176, 196, 222);
    }
    
    body {
        margin: 0;
        font-family: Helvetica;
    }
    
    header,
    footer {
        height: 30px;
        background-color: var(--steel);
        color: white;
        text-align: center;
    }
    
    header h2 {
        margin: 0;
    }
    
    #hero {
        padding: 50px;
        background-color: var(--light-steel);
        text-align: center;
    }
    
    #big {
        padding: 3px;
        border: 1px dashed blue;
        border-radius: 10px;
    }
    Podgląd strony po tym kroku (galeria.html)
  16. Krok 16: Wiersz flex: blok lewy 80% i prawy 20%

    Kryteria: , , , ,

    R.3.1 Układ bloków po uruchomieniu strony w przeglądarce jest zgodny z Obrazem 2 w arkuszu egzaminacyjnym (prawidłowo zastosowano właściwości CSS układające bloki na stronie, np. float i clear albo display flex albo grid)

    R.4.2 Ustawiono kolor tła rgb(70, 130, 180) dla banera, stopki, bloku lewego i prawego oraz rgb(176, 196, 222) dla bloku głównego

    R.4.3 Ustawiono biały kolor czcionki dla bloków banera, lewego, prawego i stopki

    R.4.4 Ustawiono wysokość 30px dla banera i stopki oraz 300px dla bloku lewego i prawego

    R.4.5 Ustawiono szerokość bloku lewego 80% oraz prawego 20%

    ok. 3 min
    Polecenie z arkusza

    Dla bloku lewego: kolor RGB tła 70, 130, 180; biały kolor czcionki, wysokość 300 px, szerokość 80%. Dla bloku prawego: kolor RGB tła 70, 130, 180; biały kolor czcionki, wysokość 300 px, szerokość 20%

    display: flex na wierszu .row stawia obie sekcje obok siebie - bez float przy blokach i bez clear przy stopce, bo kontener flex ma wysokość swojej zawartości (R.3.1). Szerokości 80% i 20% stoją na samych blokach, tak jak wymaga arkusz i jak ocenia klucz.

    Wspólna reguła: wysokość 300 px, tło, biały tekst. Komplet: tła bloków (R.4.2), białe teksty (R.4.3), wysokości (R.4.4), szerokości (R.4.5).

    Typowe błędy

    grid-template-columns: 80% 20% na wierszu dałby ten sam wygląd, ale klucze z 2022 r. (sesja styczniowa) oceniały szerokość ustawioną na blokach - dlatego flex z width na sekcjach.

    styl7.css CSS zmienione: 19 linii
    :root {
        --steel: rgb(70, 130, 180);
        --light-steel: rgb(176, 196, 222);
    }
    
    body {
        margin: 0;
        font-family: Helvetica;
    }
    
    header,
    footer {
        height: 30px;
        background-color: var(--steel);
        color: white;
        text-align: center;
    }
    
    header h2 {
        margin: 0;
    }
    
    #hero {
        padding: 50px;
        background-color: var(--light-steel);
        text-align: center;
    }
    
    #big {
        padding: 3px;
        border: 1px dashed blue;
        border-radius: 10px;
    }
    
    .row {
        display: flex;
    }
    
    #browse,
    #info {
        height: 300px;
        background-color: var(--steel);
        color: white;
    }
    
    #browse {
        width: 80%;
    }
    
    #info {
        width: 20%;
    }
    Podgląd strony po tym kroku (galeria.html)
  17. Krok 17: Miniatury, ramka pod kursorem i przycisk serca

    Kryteria: ,

    R.4.9 Ustawiono styl dla wszystkich zdjęć w bloku lewym: wysokość 40% (np. za pomocą klasy, dodanie tego samego id do wszystkich zdjęć jest błędem)

    R.4.10 Gdy kursor myszy znajdzie się na obrazie miniatury pojawia się obramowanie linią ciągłą koloru białego i grubości 1px (np. za pomocą pseudoklasy hover)

    ok. 3 min
    Polecenie z arkusza

    Dla wszystkich zdjęć w bloku lewym: wysokość 40%, gdy mysz znajdzie się na obrazie pojawia się obramowanie linią ciągłą koloru białego i grubości 1px, co widać na Obrazie 2 (trzecia miniatura)

    • .thumb - wysokość 40% wysokości bloku (300 px, więc 120 px, R.4.9), cursor: pointer podpowiada, że miniaturę można kliknąć,
    • .thumb:hover - biała ciągła ramka 1 px pod kursorem (R.4.10),
    • #like - przycisk serca bez własnego tła, ramki i odstępów: wygląda jak sama ikona z arkusza, a zostaje przyciskiem. display: block ikony usuwa kilkupikselowy odstęp pod obrazem (obraz w linii tekstu stoi na linii bazowej), więc przycisk ma dokładnie 50 × 50 px.

    Nagłówki <h3> dostają odstęp jako padding-top zamiast domyślnego margin-top - margines nagłówka „wyciekałby” poza sekcję i przesuwał cały wiersz w dół.

    styl7.css CSS zmienione: 27 linii
    :root {
        --steel: rgb(70, 130, 180);
        --light-steel: rgb(176, 196, 222);
    }
    
    body {
        margin: 0;
        font-family: Helvetica;
    }
    
    header,
    footer {
        height: 30px;
        background-color: var(--steel);
        color: white;
        text-align: center;
    }
    
    header h2 {
        margin: 0;
    }
    
    #hero {
        padding: 50px;
        background-color: var(--light-steel);
        text-align: center;
    }
    
    #big {
        padding: 3px;
        border: 1px dashed blue;
        border-radius: 10px;
    }
    
    .row {
        display: flex;
    }
    
    #browse,
    #info {
        height: 300px;
        background-color: var(--steel);
        color: white;
    }
    
    #browse {
        width: 80%;
    }
    
    #info {
        width: 20%;
    }
    
    #browse h3,
    #info h3 {
        margin-top: 0;
        padding-top: 1em;
    }
    
    .thumb {
        height: 40%;
        cursor: pointer;
    }
    
    .thumb:hover {
        border: 1px solid white;
    }
    
    #like {
        padding: 0;
        border: 0;
        background: none;
        vertical-align: middle;
        cursor: pointer;
    }
    
    #like img {
        display: block;
    }
    Podgląd strony po tym kroku (galeria.html)
  18. Etap 4: Skrypt JavaScript

    Kroki 18-19 · po tym etapie masz 33 z 33 kryteriów (pkt)

    Krok 18: Plik galeria.js: jedna obsługa kliknięcia dla wszystkich miniatur

    Kryteria: , , ,

    R.5.1 Przynajmniej jeden skrypt napisano w języku JavaScript oraz zawiera on przynajmniej jedną instrukcję poprawną składniowo

    R.5.2 Dla przynajmniej jednego zdarzenia kliknięcia obrazu przypisano do niego funkcję JavaScript (może być pusta)

    R.5.3 Po kliknięciu na przynajmniej jednej miniaturze, odpowiadający jej obraz jest wyświetlany w bloku głównym

    R.5.4 Kliknięcie jest obsłużone zgodnie z R.5.3 dla każdej z pięciu miniatur

    ok. 4 min
    Polecenie z arkusza

    Skrypt: Obsługuje akcje wywoływane kliknięciem na zdjęciach z bloku lewego za pomocą języka JavaScript. Po kliknięciu na dowolnej miniaturze jest ona wyświetlona w bloku głównym (zamiast lanzarotte.jpg)

    Skrypt w osobnym pliku galeria.js, podpięty w <head> z atrybutem defer - przeglądarka uruchomi go dopiero po wczytaniu całego HTML-a, więc getElementById znajdzie elementy (R.5.1).

    Zamiast pięciu atrybutów onclick - jedna obsługa zdarzenia na bloku #browse (delegowanie zdarzeń). Kliknięcie miniatury „wędruje” w górę drzewa do bloku, a event.target.closest('.thumb') sprawdza, czy kliknięto miniaturę - przy kliknięciu w nagłówek albo tło bloku zwraca null i nic się nie dzieje. Adres klikniętej miniatury trafia do dużego zdjęcia (funkcja przypisana do kliknięcia - R.5.2, zmiana obrazu w bloku głównym - R.5.3, R.5.4).

    Sprawdzone w Chrome: każda z pięciu miniatur pojawia się w bloku głównym, kliknięcie nagłówka niczego nie zmienia. Szóste zdjęcie dodane do bloku działałoby bez zmiany skryptu.

    galeria.html HTML zmienione: 1 linia
    <!DOCTYPE html>
    <html lang="pl">
    <head>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, initial-scale=1">
        <title>Galeria</title>
        <link rel="stylesheet" href="styl7.css">
        <script src="galeria.js" defer></script>
    </head>
    <body>
        <header>
            <h2>Galeria miejsc ciekawych</h2>
        </header>
        <main>
            <section id="hero">
                <img src="lanzarotte.jpg" alt="galeria" id="big">
            </section>
            <div class="row">
                <section id="browse">
                    <h3>Przeglądaj zdjęcia</h3>
                    <img src="lanzarotte.jpg" alt="lanzarotte" class="thumb">
                    <img src="pekin.jpg" alt="pekin" class="thumb">
                    <img src="serengeti.jpg" alt="serengeti" class="thumb">
                    <img src="wenecja.jpg" alt="wenecja" class="thumb">
                    <img src="tajlandia.jpg" alt="tajlandia" class="thumb">
                </section>
                <section id="info">
                    <h3>Obrazy w naszej galerii</h3>
                    <table>
                        <tr>
                            <td>Europa</td>
                            <td>Azja</td>
                            <td>Afryka</td>
                        </tr>
                        <tr>
                            <td>2</td>
                            <td>2</td>
                            <td>1</td>
                        </tr>
                    </table>
                    <p>Polub nas
                        <button type="button" id="like" aria-pressed="false">
                            <img src="icon-off.png" alt="Polub">
                        </button>
                    </p>
                    <a href="https://pixabay.com" target="_blank" rel="noopener noreferrer">Odkryj więcej zdjęć</a>
                </section>
            </div>
        </main>
        <footer>
            Autor: Bartosz Bryniarski
        </footer>
    </body>
    </html>
    galeria.js JavaScript nowy plik
    const big = document.getElementById('big');
    
    document.getElementById('browse').addEventListener('click', (event) => {
        const thumbnail = event.target.closest('.thumb');
        if (thumbnail) {
            big.src = thumbnail.src;
        }
    });
    Podgląd strony po tym kroku (galeria.html)
  19. Krok 19: Serce: funkcja przełączająca stan przycisku

    ok. 3 min
    Polecenie z arkusza

    Po kliknięciu ikony icon-off.jpg jest ona podmieniana na ikonę icon-on.jpg. Po ponownym kliknięciu – powraca do icon-off.jpg i tak na zmianę – realizowane za pomocą funkcji.

    Funkcja toggleLike (arkusz wymaga funkcji) nie zgaduje stanu z nazwy pliku obrazka, tylko czyta go z atrybutu aria-pressed: odwraca go i na tej podstawie ustawia ikonę. Stan jest w jednym miejscu, a ten sam atrybut słyszy użytkownik czytnika ekranu („przycisk Polub, wciśnięty”).

    Funkcja jest przypięta przez addEventListener('click', toggleLike) - przycisk wywołuje click także klawiszem Enter i spacją. Sprawdzone w Chrome: kolejne kliknięcia dają icon-on, icon-off, icon-on, a aria-pressed zmienia się razem z ikoną. Klucz nie ma kryterium dla serca, ale arkusz go wymaga.

    ⚠️ Rozbieżność w arkuszu: część o skrypcie podaje nazwy icon-off.jpg i icon-on.jpg, a część o witrynie i archiwum pliki7 - icon-off.png i icon-on.png. W skrypcie są nazwy plików, które naprawdę są w archiwum: .png.

    galeria.html HTML zmienione: 0 linii
    <!DOCTYPE html>
    <html lang="pl">
    <head>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, initial-scale=1">
        <title>Galeria</title>
        <link rel="stylesheet" href="styl7.css">
        <script src="galeria.js" defer></script>
    </head>
    <body>
        <header>
            <h2>Galeria miejsc ciekawych</h2>
        </header>
        <main>
            <section id="hero">
                <img src="lanzarotte.jpg" alt="galeria" id="big">
            </section>
            <div class="row">
                <section id="browse">
                    <h3>Przeglądaj zdjęcia</h3>
                    <img src="lanzarotte.jpg" alt="lanzarotte" class="thumb">
                    <img src="pekin.jpg" alt="pekin" class="thumb">
                    <img src="serengeti.jpg" alt="serengeti" class="thumb">
                    <img src="wenecja.jpg" alt="wenecja" class="thumb">
                    <img src="tajlandia.jpg" alt="tajlandia" class="thumb">
                </section>
                <section id="info">
                    <h3>Obrazy w naszej galerii</h3>
                    <table>
                        <tr>
                            <td>Europa</td>
                            <td>Azja</td>
                            <td>Afryka</td>
                        </tr>
                        <tr>
                            <td>2</td>
                            <td>2</td>
                            <td>1</td>
                        </tr>
                    </table>
                    <p>Polub nas
                        <button type="button" id="like" aria-pressed="false">
                            <img src="icon-off.png" alt="Polub">
                        </button>
                    </p>
                    <a href="https://pixabay.com" target="_blank" rel="noopener noreferrer">Odkryj więcej zdjęć</a>
                </section>
            </div>
        </main>
        <footer>
            Autor: Bartosz Bryniarski
        </footer>
    </body>
    </html>
    galeria.js JavaScript zmienione: 10 linii
    const big = document.getElementById('big');
    
    document.getElementById('browse').addEventListener('click', (event) => {
        const thumbnail = event.target.closest('.thumb');
        if (thumbnail) {
            big.src = thumbnail.src;
        }
    });
    
    const like = document.getElementById('like');
    
    function toggleLike() {
        const pressed = like.getAttribute('aria-pressed') === 'true';
        like.setAttribute('aria-pressed', String(!pressed));
        like.querySelector('img').src = pressed ? 'icon-off.png' : 'icon-on.png';
    }
    
    like.addEventListener('click', toggleLike);
    Podgląd strony po tym kroku (galeria.html)
  20. Etap 5: Porównanie z wersją podstawową

    Krok 20 · po tym etapie masz 33 z 33 kryteriów (pkt)

    Krok 20: Co jest inaczej i którą wersję wybrać na egzaminie

    ok. 3 min

    Obie wersje dają komplet 33 punktów. Różnice:

    wersja podstawowawersja nowoczesna
    blokicztery <section> i <footer><header>, <main> z sekcjami, <footer>
    układ lewy/prawyfloat: left, clear stopkiwiersz .row z display: flex
    kolorywartości rgb() powtórzone w regułachzmienne CSS w :root
    gdzie jest skrypt<script> na końcu stronygaleria.js z defer
    kliknięcie miniaturonclick="show(this)" przy każdejjedna obsługa na bloku, closest('.thumb')
    serceobraz z onclick, stan odczytany z nazwy pliku (indexOf)<button> z aria-pressed, działa z klawiatury
    odnośnik w nowej karcietarget="_blank" (rel dopisany w dobrych praktykach)target="_blank" rel="noopener noreferrer" od początku

    Klucz oceniał skutek, nie sposób: funkcję przypisaną do kliknięcia (R.5.2) spełnia zarówno onclick="…", jak i addEventListener.

    Na egzaminie wersja podstawowa trzyma się pól i zdarzeń z tabeli 1 arkusza i łatwiej ją napisać z pamięci. Nowoczesna oddziela treść, wygląd i zachowanie: nowa miniatura nie wymaga zmian w skrypcie, kolor zmienia się w jednym miejscu, a serce obsłuży także osoba bez myszy.

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

  21. Etap 6: Oddanie pracy

    Krok 21 · po tym etapie masz 33 z 33 kryteriów (pkt)

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

    ok. 5 min
    Polecenie z arkusza

    Po zakończeniu pracy utwórz, w folderze z numerem PESEL lub w przypadku jego braku w folderze z innym numerem, którym został podpisany arkusz, plik tekstowy o nazwie przeglądarka.txt. Zapisz w nim nazwę przeglądarki internetowej, w której weryfikowałeś poprawność działania witryny. Nagraj płytę z rezultatami pracy.

    W przeglądarka.txt nazwa przeglądarki, w której sprawdzany był skrypt. W folderze z numerem zdającego: egzamin.jpg, galeria.html, galeria.js, icon-off.png, icon-on.png, kw1.png - kw4.png, kwerendy.txt, lanzarotte.jpg, pekin.jpg, przeglądarka.txt, serengeti.jpg, styl7.css, tajlandia.jpg i wenecja.jpg. Nagraj płytę, sprawdź jej odczyt i opisz ją numerem zdającego.

    przeglądarka.txt Tekst nowy plik
    Google Chrome

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

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.

Potwierdzenie

Informacja