Przejdź do głównej treści
INF.03-05-25.06-SGCzerwiec 2025 · 51 kroków · ok. 86 min · 41 kryteriów z klucza

Rozwiązanie krok po kroku: Salon fotograficzny online (Wersja podstawowa)

Rozwiązanie buduje aplikację salonu fotograficznego: baza fotografia z czterema operacjami (w tym obliczenie wartości zamówień przez złączenie i CREATE USER), grafika przeskalowana do 200 px wysokości, trzy podstrony (zamowienie.html z galerią dziesięciu obrazów, formularzem zamówienia i koszykiem oraz proste regulamin.html i uslugi.html), style w style.css (cień bloku, inline-block, float) i skrypt JavaScript, który liczy cenę i dokłada zamówienia do koszyka.

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ą. Kod JavaScript jest najpierw pisany najprościej, tak jak podpowiadają tabela 1 i klucz (atrybut onclick, lastIndexOf i substr), a na końcu zostaje przerobiony na wersję z prawdziwych projektów: nasłuchiwacz zdarzeń, File API zamiast parsowania ścieżki, walidacja i formatowanie ceny. W tym arkuszu nie ma PHP.

Obok jest druga wersja tego rozwiązania - zakładka Nowoczesny kod (grid): te same punkty, ale blok główny na siatce CSS, kolory w zmiennych i skrypt pisany od razu z nasłuchiwaczem zdarzeń, File API i mapą cen zamiast drabinki if.

Zdjęcia i baza pochodzą z prawdziwego archiwum pliki6 (załącznik do pobrania na stronie 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.

Jak liczą się punkty. Klucz ma 41 kryteriów (R.1.1 - R.5.9), każde za 1 punkt. Próg zdania części praktycznej to 75%, czyli 31 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-7 · po tym etapie masz 6 z 41 kryteriów (pkt)

    Krok 1: Baza danych fotografia

    Kryteria:

    R.1.1 Wykonany import bazy danych fotografia, czynność udokumentowana w pliku import.png

    ok. 2 min
    Polecenie z arkusza

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

    W przeglądarce otwierasz http://localhost/phpmyadmin, klikasz Nowa w lewym panelu, wpisujesz nazwę fotografia i z listy metod porównywania wybierasz utf8_unicode_ci (arkusz podaje ją jako przykład; utf8_polish_ci też jest poprawne). Polskie znaki są tu ważne - wartości kolumny rodzaj to „błyszczący” i „matowy”, a zapytania będą je porównywać - ale dba o nie sam plik SQL: tabele mają zestaw utf8 i porównywanie utf8_polish_ci zapisane we własnej definicji, więc wynik nie zależy od wyboru przy bazie (porównywanie bazy dziedziczą tylko tabele zakładane później bez własnego ustawienia).

    Typowe błędy

    Nazwa bazy musi być dokładnie fotografia. Przy złym zestawie znaków WHERE rodzaj = "błyszczący" może nie znaleźć żadnego wiersza, choć dane „wyglądają” dobrze.

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

    Kryteria:

    R.1.1 Wykonany import bazy danych fotografia, czynność udokumentowana w pliku import.png

    ok. 2 min
    Polecenie z arkusza

    Z rozpakowanego archiwum zaimportuj tabele z pliku fotografia.sql.

    Wejdź do bazy fotografia (musi być zaznaczona w lewym panelu), karta Import, Wybierz plik → fotografia.sql z rozpakowanego archiwum, Wykonaj.

    Po imporcie są dwie tabele z ilustracji 1: zamowienia (id_zam, plik, liczba_odbitek, nr_klienta, rodzaj - 81 wierszy) i zdjecia (rodzaj, cena, wysokosc, szerokosc - 2 wiersze: błyszczący 0,50 zł i matowy 0,70 zł). Arkusz mówi wprost, że kluczem relacji jest pole rodzaj - tekstowe, nie liczbowe. Po nim złączysz tabele w zapytaniu 2.

    Typowe błędy

    Import bez wcześniejszego wejścia do bazy fotografia tworzy tabele w innej bazie (np. test) - zapytania na zrzutach będą „działać na złej bazie”.

  3. Krok 3: Zrzut ekranu import.png

    Kryteria:

    R.1.1 Wykonany import bazy danych fotografia, czynność udokumentowana w pliku 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ń.

    Klawisz Print Screen (cały ekran, nie Alt+PrtScr, który łapie tylko aktywne okno), wklejasz do edytora grafiki i zapisujesz jako import.png w folderze z numerem zdającego. Na zrzucie ma być widać komunikat phpMyAdmin o pomyślnym imporcie albo obie tabele w bazie. W tym arkuszu wszystkie zrzuty są w PNG.

    Typowe błędy

    Wykadrowany zrzut (samo okno przeglądarki, bez paska zadań) nie jest oceniany - klucz mówi to wprost.

  4. Krok 4: Zapytanie 1: duże zamówienia na papierze matowym

    Kryteria: ,

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

    R.1.3 Wykonane zapytanie 1 wybierające jedynie pola plik, nr_klienta, liczba_odbitek dla zamówień na papierze matowym, z liczbą odbitek większą od 100. W pliku z kwerendami lub na zrzucie istnieje zapis np. SELECT plik, nr_klienta, liczba_odbitek FROM zamowienia WHERE liczba_odbitek > 100 AND rodzaj = "matowy"; oraz wynik działania zapytania udokumentowany zrzutem, na którym widocznych jest dokładnie 6 wierszy z numerami klienta: 2, 6, 5, 8, 2, 3

    ok. 3 min
    Polecenie z arkusza

    Zapytanie 1: wybierające jedynie pola plik, nr_klienta, liczba_odbitek dla zamówień na papierze matowym, z liczbą odbitek większą od 100.

    Zakładka SQL w phpMyAdmin (przy zaznaczonej bazie fotografia). Klauzula po klauzuli:

    • SELECT plik, nr_klienta, liczba_odbitek - dokładnie trzy kolumny z arkusza.
    • FROM zamowienia - wszystko jest w tabeli zamówień.
    • WHERE rodzaj = 'matowy' AND liczba_odbitek > 100 - dwa warunki naraz, połączone AND: rodzaj papieru (napis w apostrofach) i liczba odbitek większa od 100 (liczba bez apostrofów; „większa od” to >, bez =).

    Wynik: dokładnie 6 wierszy, numery klientów 2, 6, 5, 8, 2, 3. Zapytanie kopiujesz do pliku kwerendy.txt i robisz zrzut: kw1.png.

    Typowe błędy

    OR zamiast AND zwróci wszystkie matowe albo wszystkie duże zamówienia - kilkadziesiąt wierszy zamiast sześciu. Dwa warunki, które mają być spełnione jednocześnie, łączysz AND.

    kwerendy.txt Tekst nowy plik
    -- Zapytanie 1
    SELECT plik, nr_klienta, liczba_odbitek FROM zamowienia WHERE rodzaj = 'matowy' AND liczba_odbitek > 100;
    Podgląd strony po tym kroku
    Podgląd strony po kroku 4
  5. Krok 5: Zapytanie 2: wartość zamówień klienta 3

    Kryteria:

    R.1.4 Wykonane zapytanie 2 wybierające dla klienta o identyfikatorze 3 wartości jego zamówień obliczane na podstawie liczby odbitek i ceny, alias „Do zapłaty”. W pliku z kwerendami lub na zrzucie istnieje zapis np. SELECT (liczba_odbitek*cena) AS "Do zapłaty" FROM zamowienia JOIN zdjecia USING(rodzaj) WHERE nr_klienta = 3; (możliwe też porównanie kluczy po ON lub WHERE; dodatkowo AS opcjonalne, dozwolone dowolne kolumny po SELECT) oraz wynik działania zapytania udokumentowany zrzutem, na którym widocznych jest dokładnie 7 wierszy: 157, 157, 16.50, 157, 7, 15.40, 219.8

    ok. 4 min
    Polecenie z arkusza

    Zapytanie 2: wybierające dla klienta o identyfikatorze 3 wartości jego zamówień, obliczane na podstawie liczby odbitek i ceny, nazwa kolumny (alias) „Do zapłaty”. Należy posłużyć się relacją.

    Liczba odbitek jest w zamowienia, cena za odbitkę w zdjecia - „posłużyć się relacją” znaczy złączyć tabele po rodzaj.

    • SELECT liczba_odbitek * cena AS "Do zapłaty" - w SELECT można liczyć: mnożysz kolumny z dwóch tabel, a AS nadaje wynikowi nazwę. Alias ze spacją i polskimi znakami musi być w cudzysłowie.
    • FROM zamowienia JOIN zdjecia ON zdjecia.rodzaj = zamowienia.rodzaj - do każdego zamówienia dokładasz wiersz z ceną jego rodzaju papieru. Klucz to napis, więc złączenie porównuje napisy; klucz CKE pokazuje też skrót USING(rodzaj), który działa, gdy kolumna nazywa się tak samo w obu tabelach.
    • WHERE nr_klienta = 3 - tylko zamówienia klienta 3.

    Wynik: 7 wierszy - 157, 157, 16,50, 157, 7, 15,40, 219,8. Zrzut: kw2.png.

    Typowe błędy

    liczba_odbitek * cena bez JOIN to błąd „nieznana kolumna cena” - cena jest w drugiej tabeli. JOIN bez ON daje każdemu zamówieniu obie ceny (14 wierszy zamiast 7).

    kwerendy.txt Tekst zmienione: 3 linie
    -- Zapytanie 1
    SELECT plik, nr_klienta, liczba_odbitek FROM zamowienia WHERE rodzaj = 'matowy' AND liczba_odbitek > 100;
    
    -- Zapytanie 2
    SELECT liczba_odbitek * cena AS "Do zapłaty" FROM zamowienia JOIN zdjecia ON zdjecia.rodzaj = zamowienia.rodzaj WHERE nr_klienta = 3;
    Podgląd strony po tym kroku
    Podgląd strony po kroku 5
  6. Krok 6: Zapytanie 3: suma odbitek na papierze błyszczącym

    Kryteria:

    R.1.5 Wykonane zapytanie 3 zliczające sumę wszystkich odbitek na papierze błyszczącym. W pliku z kwerendami lub na zrzucie istnieje zapis np. SELECT SUM(liczba_odbitek) FROM zamowienia WHERE rodzaj = "błyszczący"; oraz wynik działania zapytania udokumentowany zrzutem, na którym jest widoczna wartość 4291

    ok. 2 min
    Polecenie z arkusza

    Zapytanie 3: zliczające sumę wszystkich odbitek na papierze błyszczącym.

    • SELECT SUM(liczba_odbitek) - funkcja grupująca SUM dodaje wartości kolumny ze wszystkich wybranych wierszy. Wynik to jedna liczba.
    • FROM zamowienia WHERE rodzaj = 'błyszczący' - tylko zamówienia na papierze błyszczącym; wartość przepisujesz dokładnie, z polskimi znakami.

    Wynik: dokładnie jedna wartość - 4291. Zrzut: kw3.png.

    Typowe błędy

    COUNT(liczba_odbitek) liczy wiersze (ile zamówień), nie sumę odbitek. „Suma wszystkich odbitek” to SUM.

    kwerendy.txt Tekst zmienione: 3 linie
    -- Zapytanie 1
    SELECT plik, nr_klienta, liczba_odbitek FROM zamowienia WHERE rodzaj = 'matowy' AND liczba_odbitek > 100;
    
    -- Zapytanie 2
    SELECT liczba_odbitek * cena AS "Do zapłaty" FROM zamowienia JOIN zdjecia ON zdjecia.rodzaj = zamowienia.rodzaj WHERE nr_klienta = 3;
    
    -- Zapytanie 3
    SELECT SUM(liczba_odbitek) FROM zamowienia WHERE rodzaj = 'błyszczący';
    Podgląd strony po tym kroku
    Podgląd strony po kroku 6
  7. Krok 7: Zapytanie 4: konto użytkownika Anna

    Kryteria:

    R.1.6 Wykonane zapytanie 4 tworzące konto użytkownika Anna na localhost z hasłem @NNa. W pliku z kwerendami lub na zrzucie istnieje zapis np. CREATE USER 'Anna'@'localhost' IDENTIFIED BY '@NNa'; oraz wynik działania zapytania udokumentowany zrzutem, na którym jest widoczny komunikat o poprawnie wykonanym zapytaniu (dopuszczalny jest błąd informujący o niewybraniu bazy)

    ok. 2 min
    Polecenie z arkusza

    Zapytanie 4: tworzące konto użytkownika Anna na localhost z hasłem @NNa.

    To nie jest zapytanie do tabeli, tylko polecenie administracyjne serwera: CREATE USER 'Anna'@'localhost' IDENTIFIED BY '@NNa'. Nazwa użytkownika i host w apostrofach, rozdzielone @ ('Anna'@'localhost' = Anna logująca się z tego komputera), hasło po IDENTIFIED BY. Wielkość liter w nazwie i haśle przepisujesz dokładnie z arkusza.

    Wynik: komunikat o pomyślnym wykonaniu - zrzut kw4.png. Klucz dopuszcza też komunikat o niewybraniu bazy, bo to polecenie nie dotyczy żadnej bazy. Plik kwerendy.txt ma komplet czterech zapytań.

    Typowe błędy

    CREATE USER Anna IDENTIFIED BY '@NNa' bez @'localhost' tworzy konto z hostem % (dowolny komputer) - arkusz mówi wyraźnie „na localhost”.

    kwerendy.txt Tekst zmienione: 3 linie
    -- Zapytanie 1
    SELECT plik, nr_klienta, liczba_odbitek FROM zamowienia WHERE rodzaj = 'matowy' AND liczba_odbitek > 100;
    
    -- Zapytanie 2
    SELECT liczba_odbitek * cena AS "Do zapłaty" FROM zamowienia JOIN zdjecia ON zdjecia.rodzaj = zamowienia.rodzaj WHERE nr_klienta = 3;
    
    -- Zapytanie 3
    SELECT SUM(liczba_odbitek) FROM zamowienia WHERE rodzaj = 'błyszczący';
    
    -- Zapytanie 4
    CREATE USER 'Anna'@'localhost' IDENTIFIED BY '@NNa';
    Podgląd strony po tym kroku
    Podgląd strony po kroku 7
  8. Etap 2: Grafika i strona HTML

    Kroki 8-27 · po tym etapie masz 20 z 41 kryteriów (pkt)

    Krok 8: Przeskalowanie grafiki 10.jpg

    Kryteria:

    R.2.1 Grafika 10.jpg została przeskalowana z zachowaniem proporcji do wysokości 200 px, odpowiadająca temu szerokość to 267 px (±5 px)

    ok. 3 min
    Polecenie z arkusza

    Cechy grafiki 10.jpg: grafikę należy przeskalować z zachowaniem proporcji do wysokości 200 px.

    Dziewięć zdjęć z archiwum ma już 267 × 200 px, tylko 10.jpg jest większe: 560 × 420 px. W edytorze grafiki rastrowej (np. GIMP: Obraz → Skaluj obraz) wpisujesz wysokość 200 px przy zamkniętym łańcuchu proporcji. Szerokość przeliczy się sama na 267 px (560 · 200 / 420 = 266,7) - i dokładnie to sprawdza egzaminator (267 ±5 px). Zapisz jako 10.jpg w folderze zdającego, obok pozostałych zdjęć.

    Typowe błędy

    Rozłączony łańcuch proporcji = obraz ściśnięty do 200 px wysokości przy starej szerokości 560 px. Wysokość się zgadza, punktu nie ma.

    Podgląd strony po tym kroku
    Podgląd strony po kroku 8
  9. Krok 9: Podstrony regulamin.html i uslugi.html

    Kryteria:

    R.3.3 Wybranie odnośnika "Regulamin" otwiera stronę regulamin.html, "Usługi" otwiera uslugi.html , „Zdjęcia” inicjuje otwarcie strony "https://pixabay.com"

    ok. 1 min
    Polecenie z arkusza

    Składa się z podstron o nazwach zamowienie.html, regulamin.html, uslugi.html. W pliku regulamin.html należy zapisać jedynie: „Regulamin”. W pliku uslugi.html należy zapisać jedynie: „Usługi”.

    Dwie najprostsze podstrony: w regulamin.html sam napis „Regulamin”, w uslugi.html sam napis „Usługi” - arkusz mówi „jedynie”, więc bez szkieletu HTML. Przeglądarka i tak je wyświetli. Istnieją po to, żeby odnośniki z nawigacji miały dokąd prowadzić (klucz R.3.3 sprawdza, czy się otwierają). Główną stronę zamowienie.html budujesz od następnego kroku.

    Typowe błędy

    Nazwa uslugi.html bez „ł” - tak jak w arkuszu. Plik usługi.html z polskim znakiem nie otworzy się z odnośnika uslugi.html.

    regulamin.html HTML nowy plik
    Regulamin
    uslugi.html HTML nowy plik
    Usługi
    Podgląd strony po tym kroku (regulamin.html)
  10. Krok 10: Plik zamowienie.html w HTML5

    Kryteria:

    R.2.2 W pliku zamowienie.html zapisana deklaracja HTML5 <!DOCTYPE HTML>, deklaracja języka zawartości: polski np. <html lang="pl">, w sekcji head znajduje się jawnie podany standard kodowania polskich znaków

    ok. 2 min
    Polecenie z arkusza

    Cechy strony zamowienie.html: zapisana w języku HTML5.

    W edytorze zaznaczającym składnię tworzysz plik zamowienie.html w folderze zdającego, obok zdjęć. Rozszerzenie .html, bo arkusz nie wymaga PHP - strona działa nawet otwarta prosto z dysku.

    Pierwsza linia <!DOCTYPE html> mówi przeglądarce, że dokument jest w HTML5. Dalej szkielet każdej strony: <html>, a w nim <head> (informacje o stronie) i <body> (to, co widać w oknie).

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

    Kryteria:

    R.2.2 W pliku zamowienie.html zapisana deklaracja HTML5 <!DOCTYPE HTML>, deklaracja języka zawartości: polski np. <html lang="pl">, w sekcji head znajduje się jawnie podany standard kodowania polskich znaków

    ok. 1 min
    Polecenie z arkusza

    Zadeklarowany polski język zawartości witryny.

    Atrybut lang="pl" w znaczniku <html>. Czytnik ekranu czyta wtedy tekst polską wymową, a przeglądarka dobiera słownik. Na stronie nic się nie zmienia - to informacja dla programów.

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

    Kryteria:

    R.2.2 W pliku zamowienie.html zapisana deklaracja HTML5 <!DOCTYPE HTML>, deklaracja języka zawartości: polski np. <html lang="pl">, w sekcji head znajduje się jawnie podany standard kodowania polskich znaków

    ok. 1 min
    Polecenie z arkusza

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

    <meta charset="UTF-8"> jako pierwsza rzecz w <head>. „Jawnie” znaczy: wpisane w kodzie, nie zdane na domysł przeglądarki. Bez tej linii „Papier błyszczący” mogłoby wyświetlić się jako krzaki. Plik trzeba też zapisać w UTF-8.

    zamowienie.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 (zamowienie.html)
  13. Krok 13: Tytuł strony

    Kryteria:

    R.2.3 Nadany tytuł stronie: "Fotografia"

    ok. 1 min
    Polecenie z arkusza

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

    <title> w <head> - napis na karcie przeglądarki, nie nagłówek na stronie. Klucz R.2.3 sprawdza tekst „Fotografia”.

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

    Kryteria:

    R.3.2 Strona zawiera działające połączenie z zewnętrznym arkuszem stylów o nazwie style.css formatowanie CSS pochodzi jedynie z tego arkusza

    ok. 1 min
    Polecenie z arkusza

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

    <link rel="stylesheet" href="style.css"> w <head>. Uwaga na nazwę: w tym arkuszu style.css (nie styl.css ani styles.css z innych arkuszy) - klucz R.3.2 sprawdza dokładnie tę nazwę. Plik napiszesz po HTML.

    Typowe błędy

    Zła nazwa pliku w href to brak stylów i cały rezultat R.4 przepada, bo „formatowanie CSS pochodzi jedynie z tego arkusza”.

    zamowienie.html HTML zmienione: 1 linia
    <!DOCTYPE html>
    <html lang="pl">
    <head>
        <meta charset="UTF-8">
        <title>Fotografia</title>
        <link rel="stylesheet" href="style.css">
    </head>
    <body>
    </body>
    </html>
    Podgląd strony po tym kroku (zamowienie.html)
  15. Krok 15: Bloki semantyczne

    Kryteria:

    R.2.4 W sekcji body zdefiniowany jest podział na bloki za pomocą semantycznych znaczników HTML 5: header, section (lub figure) , main-> section+nav+section, footer

    ok. 2 min
    Polecenie z arkusza

    Podział strony na bloki zrealizowany za pomocą semantycznych znaczników bloków języka HTML5 tak, aby po uruchomieniu w przeglądarce układ bloków na stronie był zgodny z ilustracją 3. Zawartość bloku głównego: bloki sekcji lewej, nawigacyjny i sekcji prawej.

    Z ilustracji 3: blok nagłówkowy, pod nim blok sekcji obrazów, potem blok główny, w którym po lewej jest sekcja lewa, a po prawej nad sobą blok nawigacyjny i sekcja prawa; na dole stopka. Klucz R.2.4 wymienia znaczniki wprost: <header>, <section> (albo <figure>) na obrazy, <main> z <section>, <nav> i <section>, <footer>.

    Kolejność w <main> ma znaczenie dla układu: sekcja lewa, potem nawigacja, potem sekcja prawa - tak popłyną w CSS. Sekcje dostają identyfikatory gallery, left, right. Nazwy identyfikatorów, klas i zmiennych piszesz w tym rozwiązaniu po angielsku (arkusz dopuszcza polski lub angielski, wymaga konsekwencji); wyjątkiem są nazwy narzucone przez arkusz (zamowienie.html, style.css, nazwy zdjęć).

    Typowe błędy

    Nawigacja poza <main> (np. pod nagłówkiem) nie spełnia R.2.4 - klucz mówi „main → section + nav + section”.

    zamowienie.html HTML zmienione: 14 linii
    <!DOCTYPE html>
    <html lang="pl">
    <head>
        <meta charset="UTF-8">
        <title>Fotografia</title>
        <link rel="stylesheet" href="style.css">
    </head>
    <body>
        <header>
        </header>
        <section id="gallery">
        </section>
        <main>
            <section id="left">
            </section>
            <nav>
            </nav>
            <section id="right">
            </section>
        </main>
        <footer>
        </footer>
    </body>
    </html>
    Podgląd strony po tym kroku (zamowienie.html)
  16. Krok 16: Nagłówek strony

    Kryteria:

    R.2.5 W bloku nagłówkowym umieszczony <h1> "Fotografia artystyczna", w sekcji lewej <h3> "Zamówienie", w prawej <h3> "Koszyk", w stopce paragraf z numerem zdającego

    ok. 1 min
    Polecenie z arkusza

    Zawartość bloku nagłówkowego: nagłówek pierwszego stopnia o treści „Fotografia artystyczna”.

    Pierwszego stopnia to <h1>. W sekcjach będą <h3>, więc nie mieszaj stopni (klucz R.2.5 wymienia je wszystkie).

    zamowienie.html HTML zmienione: 1 linia
    <!DOCTYPE html>
    <html lang="pl">
    <head>
        <meta charset="UTF-8">
        <title>Fotografia</title>
        <link rel="stylesheet" href="style.css">
    </head>
    <body>
        <header>
            <h1>Fotografia artystyczna</h1>
        </header>
        <section id="gallery">
        </section>
        <main>
            <section id="left">
            </section>
            <nav>
            </nav>
            <section id="right">
            </section>
        </main>
        <footer>
        </footer>
    </body>
    </html>
    Podgląd strony po tym kroku (zamowienie.html)
  17. Krok 17: Sekcja obrazów: pierwszy obraz

    Kryteria:

    R.2.6 Blok sekcji obrazów zawiera 10 obrazów od 1.jpg do 10.jpg. Wszystkie obrazy mają tekst alternatywny „obrazy do sprzedaży” oraz atrybut title, taki sam jak nazwa pliku, np. 1.jpg

    ok. 1 min
    Polecenie z arkusza

    Zawartość bloku sekcji obrazów: 10 obrazów od 1.jpg do 10.jpg. Wszystkie obrazy mają tekst alternatywny „obrazy do sprzedaży” oraz tekst dymka podpowiedzi taki sam jak nazwa pliku, np. 1.jpg.

    <img> z trzema atrybutami: src (plik), alt (tekst alternatywny - czyta go czytnik ekranu, pokazuje przeglądarka bez obrazu) i title - to właśnie „dymek podpowiedzi” po najechaniu kursorem, który ilustracja 2 pokazuje dla 7.jpg. Tekst alt jest ten sam dla wszystkich dziesięciu, title równa się nazwie pliku. Zacznij od jednego, sprawdź w podglądzie dymek, potem skopiuj.

    Typowe błędy

    Pomylenie alt z title (dymek z tekstem alternatywnym) to strata R.2.6 - arkusz mówi wprost, który tekst gdzie.

    zamowienie.html HTML zmienione: 1 linia
    <!DOCTYPE html>
    <html lang="pl">
    <head>
        <meta charset="UTF-8">
        <title>Fotografia</title>
        <link rel="stylesheet" href="style.css">
    </head>
    <body>
        <header>
            <h1>Fotografia artystyczna</h1>
        </header>
        <section id="gallery">
            <img src="1.jpg" alt="obrazy do sprzedaży" title="1.jpg">
        </section>
        <main>
            <section id="left">
            </section>
            <nav>
            </nav>
            <section id="right">
            </section>
        </main>
        <footer>
        </footer>
    </body>
    </html>
    Podgląd strony po tym kroku (zamowienie.html)
  18. Krok 18: Sekcja obrazów: pozostałe dziewięć

    Kryteria:

    R.2.6 Blok sekcji obrazów zawiera 10 obrazów od 1.jpg do 10.jpg. Wszystkie obrazy mają tekst alternatywny „obrazy do sprzedaży” oraz atrybut title, taki sam jak nazwa pliku, np. 1.jpg

    ok. 2 min
    Polecenie z arkusza

    Zawartość bloku sekcji obrazów: 10 obrazów od 1.jpg do 10.jpg.

    Dziewięć kolejnych <img> według tego samego wzoru - zmienia się tylko numer w src i w title. Klucz R.2.6 liczy: ma być dziesięć obrazów. W podglądzie stoją jeszcze w naturalnym rozmiarze, jeden pod drugim - rozmiar i ułożenie w rzędzie zrobi CSS.

    zamowienie.html HTML zmienione: 9 linii
    <!DOCTYPE html>
    <html lang="pl">
    <head>
        <meta charset="UTF-8">
        <title>Fotografia</title>
        <link rel="stylesheet" href="style.css">
    </head>
    <body>
        <header>
            <h1>Fotografia artystyczna</h1>
        </header>
        <section id="gallery">
            <img src="1.jpg" alt="obrazy do sprzedaży" title="1.jpg">
            <img src="2.jpg" alt="obrazy do sprzedaży" title="2.jpg">
            <img src="3.jpg" alt="obrazy do sprzedaży" title="3.jpg">
            <img src="4.jpg" alt="obrazy do sprzedaży" title="4.jpg">
            <img src="5.jpg" alt="obrazy do sprzedaży" title="5.jpg">
            <img src="6.jpg" alt="obrazy do sprzedaży" title="6.jpg">
            <img src="7.jpg" alt="obrazy do sprzedaży" title="7.jpg">
            <img src="8.jpg" alt="obrazy do sprzedaży" title="8.jpg">
            <img src="9.jpg" alt="obrazy do sprzedaży" title="9.jpg">
            <img src="10.jpg" alt="obrazy do sprzedaży" title="10.jpg">
        </section>
        <main>
            <section id="left">
            </section>
            <nav>
            </nav>
            <section id="right">
            </section>
        </main>
        <footer>
        </footer>
    </body>
    </html>
    Podgląd strony po tym kroku (zamowienie.html)
  19. Krok 19: Sekcja lewa: nagłówek „Zamówienie”

    Kryteria:

    R.2.5 W bloku nagłówkowym umieszczony <h1> "Fotografia artystyczna", w sekcji lewej <h3> "Zamówienie", w prawej <h3> "Koszyk", w stopce paragraf z numerem zdającego

    ok. 1 min
    Polecenie z arkusza

    Zawartość sekcji lewej: nagłówek trzeciego stopnia o treści „Zamówienie”.

    Trzeciego stopnia to <h3>, w sekcji left.

    zamowienie.html HTML zmienione: 1 linia
    <!DOCTYPE html>
    <html lang="pl">
    <head>
        <meta charset="UTF-8">
        <title>Fotografia</title>
        <link rel="stylesheet" href="style.css">
    </head>
    <body>
        <header>
            <h1>Fotografia artystyczna</h1>
        </header>
        <section id="gallery">
            <img src="1.jpg" alt="obrazy do sprzedaży" title="1.jpg">
            <img src="2.jpg" alt="obrazy do sprzedaży" title="2.jpg">
            <img src="3.jpg" alt="obrazy do sprzedaży" title="3.jpg">
            <img src="4.jpg" alt="obrazy do sprzedaży" title="4.jpg">
            <img src="5.jpg" alt="obrazy do sprzedaży" title="5.jpg">
            <img src="6.jpg" alt="obrazy do sprzedaży" title="6.jpg">
            <img src="7.jpg" alt="obrazy do sprzedaży" title="7.jpg">
            <img src="8.jpg" alt="obrazy do sprzedaży" title="8.jpg">
            <img src="9.jpg" alt="obrazy do sprzedaży" title="9.jpg">
            <img src="10.jpg" alt="obrazy do sprzedaży" title="10.jpg">
        </section>
        <main>
            <section id="left">
                <h3>Zamówienie</h3>
            </section>
            <nav>
            </nav>
            <section id="right">
            </section>
        </main>
        <footer>
        </footer>
    </body>
    </html>
    Podgląd strony po tym kroku (zamowienie.html)
  20. Krok 20: Sekcja lewa: pole wyboru pliku z etykietą

    Kryteria: ,

    R.2.7 W sekcji lewej umieszczone dwa pola edycyjne z powiązanymi etykietami, kolejno: "Wybierz obraz:" i "Liczba kopii:", dwa pola opcji: "Papier błyszczący" i "Papier matowy" oraz przycisk "Dodaj do koszyka"

    R.3.6 Pierwsze pole edycyjne jest typu file z atrybutem np. accept="image/jpeg" lub accept =".jpg, .jpeg", drugie pole edycyjne jest typu number

    ok. 2 min
    Polecenie z arkusza

    Etykieta „Wybierz obraz: ”, powiązana z polem edycyjnym znajdującym się obok. Pole edycyjne przeznaczone do wyboru pliku. Akceptuje tylko obrazy w formacie JPEG.

    Dwa zdania arkusza w dwóch liniach. Etykieta <label> jest „powiązana” z polem przez atrybut for równy id pola - kliknięcie w napis otwiera wybór pliku. Pole „do wyboru pliku” to <input type="file">; „akceptuje tylko JPEG” to atrybut accept="image/jpeg" (arkusz podaje przykład w ramce „File Input Type”; klucz R.3.6 przyjmuje też accept=".jpg, .jpeg"). Pole stoi obok etykiety w tej samej linii, <br> kończy wiersz.

    Pole nie ma formularza - arkusz go nie wymaga, dane odczyta JavaScript.

    Typowe błędy

    <label> bez for jest poprawnym HTML, ale nie jest „powiązana” z polem - klucz R.2.7 wymaga powiązanych etykiet.

    zamowienie.html HTML zmienione: 2 linie
    <!DOCTYPE html>
    <html lang="pl">
    <head>
        <meta charset="UTF-8">
        <title>Fotografia</title>
        <link rel="stylesheet" href="style.css">
    </head>
    <body>
        <header>
            <h1>Fotografia artystyczna</h1>
        </header>
        <section id="gallery">
            <img src="1.jpg" alt="obrazy do sprzedaży" title="1.jpg">
            <img src="2.jpg" alt="obrazy do sprzedaży" title="2.jpg">
            <img src="3.jpg" alt="obrazy do sprzedaży" title="3.jpg">
            <img src="4.jpg" alt="obrazy do sprzedaży" title="4.jpg">
            <img src="5.jpg" alt="obrazy do sprzedaży" title="5.jpg">
            <img src="6.jpg" alt="obrazy do sprzedaży" title="6.jpg">
            <img src="7.jpg" alt="obrazy do sprzedaży" title="7.jpg">
            <img src="8.jpg" alt="obrazy do sprzedaży" title="8.jpg">
            <img src="9.jpg" alt="obrazy do sprzedaży" title="9.jpg">
            <img src="10.jpg" alt="obrazy do sprzedaży" title="10.jpg">
        </section>
        <main>
            <section id="left">
                <h3>Zamówienie</h3>
                <label for="image">Wybierz obraz: </label>
                <input type="file" id="image" accept="image/jpeg"><br>
            </section>
            <nav>
            </nav>
            <section id="right">
            </section>
        </main>
        <footer>
        </footer>
    </body>
    </html>
    Podgląd strony po tym kroku (zamowienie.html)
  21. Krok 21: Sekcja lewa: pole liczby kopii z etykietą

    Kryteria: ,

    R.2.7 W sekcji lewej umieszczone dwa pola edycyjne z powiązanymi etykietami, kolejno: "Wybierz obraz:" i "Liczba kopii:", dwa pola opcji: "Papier błyszczący" i "Papier matowy" oraz przycisk "Dodaj do koszyka"

    R.3.6 Pierwsze pole edycyjne jest typu file z atrybutem np. accept="image/jpeg" lub accept =".jpg, .jpeg", drugie pole edycyjne jest typu number

    ok. 1 min
    Polecenie z arkusza

    Poniżej etykieta „Liczba Kopii: ”, powiązana z polem edycyjnym znajdującym się obok. Pole edycyjne przeznaczone do wpisywania jedynie liczb.

    Ten sam wzorzec: <label for="copies"> i pole z id="copies". „Przeznaczone do wpisywania jedynie liczb” to type="number" - przeglądarka nie pozwoli wpisać liter i doda strzałki do zmiany wartości. Klucz R.3.6 sprawdza ten typ wprost.

    zamowienie.html HTML zmienione: 2 linie
    <!DOCTYPE html>
    <html lang="pl">
    <head>
        <meta charset="UTF-8">
        <title>Fotografia</title>
        <link rel="stylesheet" href="style.css">
    </head>
    <body>
        <header>
            <h1>Fotografia artystyczna</h1>
        </header>
        <section id="gallery">
            <img src="1.jpg" alt="obrazy do sprzedaży" title="1.jpg">
            <img src="2.jpg" alt="obrazy do sprzedaży" title="2.jpg">
            <img src="3.jpg" alt="obrazy do sprzedaży" title="3.jpg">
            <img src="4.jpg" alt="obrazy do sprzedaży" title="4.jpg">
            <img src="5.jpg" alt="obrazy do sprzedaży" title="5.jpg">
            <img src="6.jpg" alt="obrazy do sprzedaży" title="6.jpg">
            <img src="7.jpg" alt="obrazy do sprzedaży" title="7.jpg">
            <img src="8.jpg" alt="obrazy do sprzedaży" title="8.jpg">
            <img src="9.jpg" alt="obrazy do sprzedaży" title="9.jpg">
            <img src="10.jpg" alt="obrazy do sprzedaży" title="10.jpg">
        </section>
        <main>
            <section id="left">
                <h3>Zamówienie</h3>
                <label for="image">Wybierz obraz: </label>
                <input type="file" id="image" accept="image/jpeg"><br>
                <label for="copies">Liczba Kopii: </label>
                <input type="number" id="copies"><br>
            </section>
            <nav>
            </nav>
            <section id="right">
            </section>
        </main>
        <footer>
        </footer>
    </body>
    </html>
    Podgląd strony po tym kroku (zamowienie.html)
  22. Krok 22: Sekcja lewa: pole opcji „Papier błyszczący”

    Kryteria: ,

    R.2.7 W sekcji lewej umieszczone dwa pola edycyjne z powiązanymi etykietami, kolejno: "Wybierz obraz:" i "Liczba kopii:", dwa pola opcji: "Papier błyszczący" i "Papier matowy" oraz przycisk "Dodaj do koszyka"

    R.3.5 Pierwsze pole opcji jest domyślnie zaznaczone. W jednym momencie można zaznaczyć tylko jedno pole opcji

    ok. 1 min
    Polecenie z arkusza

    Poniżej pole opcji „Papier błyszczący”, domyślnie zaznaczone.

    „Pole opcji” to <input type="radio"> (okrągłe, w odróżnieniu od kwadratowego checkbox). „Domyślnie zaznaczone” to atrybut checked bez wartości. Etykieta tym razem po polu - tak jak na ilustracji 2 (kółko, potem napis). Atrybut name="paper" jest potrzebny do następnego kroku.

    zamowienie.html HTML zmienione: 2 linie
    <!DOCTYPE html>
    <html lang="pl">
    <head>
        <meta charset="UTF-8">
        <title>Fotografia</title>
        <link rel="stylesheet" href="style.css">
    </head>
    <body>
        <header>
            <h1>Fotografia artystyczna</h1>
        </header>
        <section id="gallery">
            <img src="1.jpg" alt="obrazy do sprzedaży" title="1.jpg">
            <img src="2.jpg" alt="obrazy do sprzedaży" title="2.jpg">
            <img src="3.jpg" alt="obrazy do sprzedaży" title="3.jpg">
            <img src="4.jpg" alt="obrazy do sprzedaży" title="4.jpg">
            <img src="5.jpg" alt="obrazy do sprzedaży" title="5.jpg">
            <img src="6.jpg" alt="obrazy do sprzedaży" title="6.jpg">
            <img src="7.jpg" alt="obrazy do sprzedaży" title="7.jpg">
            <img src="8.jpg" alt="obrazy do sprzedaży" title="8.jpg">
            <img src="9.jpg" alt="obrazy do sprzedaży" title="9.jpg">
            <img src="10.jpg" alt="obrazy do sprzedaży" title="10.jpg">
        </section>
        <main>
            <section id="left">
                <h3>Zamówienie</h3>
                <label for="image">Wybierz obraz: </label>
                <input type="file" id="image" accept="image/jpeg"><br>
                <label for="copies">Liczba Kopii: </label>
                <input type="number" id="copies"><br>
                <input type="radio" id="glossy" name="paper" checked>
                <label for="glossy">Papier błyszczący</label><br>
            </section>
            <nav>
            </nav>
            <section id="right">
            </section>
        </main>
        <footer>
        </footer>
    </body>
    </html>
    Podgląd strony po tym kroku (zamowienie.html)
  23. Krok 23: Sekcja lewa: pole opcji „Papier matowy”

    Kryteria: ,

    R.2.7 W sekcji lewej umieszczone dwa pola edycyjne z powiązanymi etykietami, kolejno: "Wybierz obraz:" i "Liczba kopii:", dwa pola opcji: "Papier błyszczący" i "Papier matowy" oraz przycisk "Dodaj do koszyka"

    R.3.5 Pierwsze pole opcji jest domyślnie zaznaczone. W jednym momencie można zaznaczyć tylko jedno pole opcji

    ok. 1 min
    Polecenie z arkusza

    Poniżej pole opcji „Papier matowy”. W jednym momencie można zaznaczyć tylko jedno pole opcji.

    Drugie pole radio z id="matte". „Tylko jedno naraz” zapewnia wspólna wartość name - pola radio o tym samym name="paper" tworzą grupę, w której zaznaczenie jednego odznacza pozostałe (klucz R.3.5). Sprawdź w podglądzie: kliknięcie „Papier matowy” odznacza błyszczący.

    Typowe błędy

    Różne name (albo brak name) w dwóch polach radio pozwala zaznaczyć oba naraz - R.3.5 przepada. Pola checkbox zamiast radio też.

    zamowienie.html HTML zmienione: 2 linie
    <!DOCTYPE html>
    <html lang="pl">
    <head>
        <meta charset="UTF-8">
        <title>Fotografia</title>
        <link rel="stylesheet" href="style.css">
    </head>
    <body>
        <header>
            <h1>Fotografia artystyczna</h1>
        </header>
        <section id="gallery">
            <img src="1.jpg" alt="obrazy do sprzedaży" title="1.jpg">
            <img src="2.jpg" alt="obrazy do sprzedaży" title="2.jpg">
            <img src="3.jpg" alt="obrazy do sprzedaży" title="3.jpg">
            <img src="4.jpg" alt="obrazy do sprzedaży" title="4.jpg">
            <img src="5.jpg" alt="obrazy do sprzedaży" title="5.jpg">
            <img src="6.jpg" alt="obrazy do sprzedaży" title="6.jpg">
            <img src="7.jpg" alt="obrazy do sprzedaży" title="7.jpg">
            <img src="8.jpg" alt="obrazy do sprzedaży" title="8.jpg">
            <img src="9.jpg" alt="obrazy do sprzedaży" title="9.jpg">
            <img src="10.jpg" alt="obrazy do sprzedaży" title="10.jpg">
        </section>
        <main>
            <section id="left">
                <h3>Zamówienie</h3>
                <label for="image">Wybierz obraz: </label>
                <input type="file" id="image" accept="image/jpeg"><br>
                <label for="copies">Liczba Kopii: </label>
                <input type="number" id="copies"><br>
                <input type="radio" id="glossy" name="paper" checked>
                <label for="glossy">Papier błyszczący</label><br>
                <input type="radio" id="matte" name="paper">
                <label for="matte">Papier matowy</label><br>
            </section>
            <nav>
            </nav>
            <section id="right">
            </section>
        </main>
        <footer>
        </footer>
    </body>
    </html>
    Podgląd strony po tym kroku (zamowienie.html)
  24. Krok 24: Sekcja lewa: przycisk „Dodaj do koszyka”

    Kryteria:

    R.2.7 W sekcji lewej umieszczone dwa pola edycyjne z powiązanymi etykietami, kolejno: "Wybierz obraz:" i "Liczba kopii:", dwa pola opcji: "Papier błyszczący" i "Papier matowy" oraz przycisk "Dodaj do koszyka"

    ok. 1 min
    Polecenie z arkusza

    Przycisk „Dodaj do koszyka”, którego kliknięcie wywołuje skrypt.

    <button>Dodaj do koszyka</button>. Nie ma formularza, więc przycisk niczego nie wysyła - jego jedyną rolą będzie uruchomienie funkcji JavaScript. Wywołanie dopiszesz w etapie skryptu. Sekcja lewa jest kompletna.

    zamowienie.html HTML zmienione: 1 linia
    <!DOCTYPE html>
    <html lang="pl">
    <head>
        <meta charset="UTF-8">
        <title>Fotografia</title>
        <link rel="stylesheet" href="style.css">
    </head>
    <body>
        <header>
            <h1>Fotografia artystyczna</h1>
        </header>
        <section id="gallery">
            <img src="1.jpg" alt="obrazy do sprzedaży" title="1.jpg">
            <img src="2.jpg" alt="obrazy do sprzedaży" title="2.jpg">
            <img src="3.jpg" alt="obrazy do sprzedaży" title="3.jpg">
            <img src="4.jpg" alt="obrazy do sprzedaży" title="4.jpg">
            <img src="5.jpg" alt="obrazy do sprzedaży" title="5.jpg">
            <img src="6.jpg" alt="obrazy do sprzedaży" title="6.jpg">
            <img src="7.jpg" alt="obrazy do sprzedaży" title="7.jpg">
            <img src="8.jpg" alt="obrazy do sprzedaży" title="8.jpg">
            <img src="9.jpg" alt="obrazy do sprzedaży" title="9.jpg">
            <img src="10.jpg" alt="obrazy do sprzedaży" title="10.jpg">
        </section>
        <main>
            <section id="left">
                <h3>Zamówienie</h3>
                <label for="image">Wybierz obraz: </label>
                <input type="file" id="image" accept="image/jpeg"><br>
                <label for="copies">Liczba Kopii: </label>
                <input type="number" id="copies"><br>
                <input type="radio" id="glossy" name="paper" checked>
                <label for="glossy">Papier błyszczący</label><br>
                <input type="radio" id="matte" name="paper">
                <label for="matte">Papier matowy</label><br>
                <button>Dodaj do koszyka</button>
            </section>
            <nav>
            </nav>
            <section id="right">
            </section>
        </main>
        <footer>
        </footer>
    </body>
    </html>
    Podgląd strony po tym kroku (zamowienie.html)
  25. Krok 25: Blok nawigacyjny: lista odnośników

    Kryteria: ,

    R.2.8 W bloku nawigacyjnym umieszczona jedna lista punktowana z trzema elementami, zastosowane znaczniki <ul> i <li>

    R.3.3 Wybranie odnośnika "Regulamin" otwiera stronę regulamin.html, "Usługi" otwiera uslugi.html , „Zdjęcia” inicjuje otwarcie strony "https://pixabay.com"

    ok. 2 min
    Polecenie z arkusza

    Zawartość bloku nawigacyjnego: lista punktowana (nieuporządkowana) z elementami: odnośnik prowadzący do podstrony regulamin.html o treści „Regulamin”, odnośnik prowadzący do podstrony uslugi.html o treści „Usługi”, odnośnik prowadzący do strony internetowej https://pixabay.com o treści „Zdjęcia”.

    Lista <ul> z trzema <li>, w każdym odnośnik <a>. Dwa pierwsze prowadzą do podstron z folderu (ścieżka względna - sama nazwa pliku), trzeci do strony zewnętrznej - pełny adres z https://. Klucz R.2.8 liczy trzy elementy, R.3.3 sprawdza, czy każdy odnośnik otwiera właściwą stronę. W podglądzie kliknięcia są zablokowane. Kropki listy zdejmiesz w CSS.

    Typowe błędy

    href="pixabay.com" bez https:// to ścieżka względna - przeglądarka szuka pliku pixabay.com w folderze i dostaje 404.

    zamowienie.html HTML zmienione: 5 linii
    <!DOCTYPE html>
    <html lang="pl">
    <head>
        <meta charset="UTF-8">
        <title>Fotografia</title>
        <link rel="stylesheet" href="style.css">
    </head>
    <body>
        <header>
            <h1>Fotografia artystyczna</h1>
        </header>
        <section id="gallery">
            <img src="1.jpg" alt="obrazy do sprzedaży" title="1.jpg">
            <img src="2.jpg" alt="obrazy do sprzedaży" title="2.jpg">
            <img src="3.jpg" alt="obrazy do sprzedaży" title="3.jpg">
            <img src="4.jpg" alt="obrazy do sprzedaży" title="4.jpg">
            <img src="5.jpg" alt="obrazy do sprzedaży" title="5.jpg">
            <img src="6.jpg" alt="obrazy do sprzedaży" title="6.jpg">
            <img src="7.jpg" alt="obrazy do sprzedaży" title="7.jpg">
            <img src="8.jpg" alt="obrazy do sprzedaży" title="8.jpg">
            <img src="9.jpg" alt="obrazy do sprzedaży" title="9.jpg">
            <img src="10.jpg" alt="obrazy do sprzedaży" title="10.jpg">
        </section>
        <main>
            <section id="left">
                <h3>Zamówienie</h3>
                <label for="image">Wybierz obraz: </label>
                <input type="file" id="image" accept="image/jpeg"><br>
                <label for="copies">Liczba Kopii: </label>
                <input type="number" id="copies"><br>
                <input type="radio" id="glossy" name="paper" checked>
                <label for="glossy">Papier błyszczący</label><br>
                <input type="radio" id="matte" name="paper">
                <label for="matte">Papier matowy</label><br>
                <button>Dodaj do koszyka</button>
            </section>
            <nav>
                <ul>
                    <li><a href="regulamin.html">Regulamin</a></li>
                    <li><a href="uslugi.html">Usługi</a></li>
                    <li><a href="https://pixabay.com">Zdjęcia</a></li>
                </ul>
            </nav>
            <section id="right">
            </section>
        </main>
        <footer>
        </footer>
    </body>
    </html>
    Podgląd strony po tym kroku (zamowienie.html)
  26. Krok 26: Sekcja prawa: nagłówek „Koszyk” i blok na zamówienia

    Kryteria: ,

    R.2.5 W bloku nagłówkowym umieszczony <h1> "Fotografia artystyczna", w sekcji lewej <h3> "Zamówienie", w prawej <h3> "Koszyk", w stopce paragraf z numerem zdającego

    R.2.9 W sekcji prawej umieszczony element blokowy (np. <div> lub <section>)

    ok. 1 min
    Polecenie z arkusza

    Zawartość sekcji prawej: nagłówek trzeciego stopnia o treści „Koszyk”. Blok, w którym zostanie umieszczony efekt działania skryptu.

    <h3> z treścią z arkusza i pusty blok <div id="cart"> - do niego skrypt będzie dokładał obraz i dwa paragrafy dla każdego zamówienia. Identyfikator jest potrzebny, żeby skrypt znalazł blok. Klucz R.2.9 przyjmuje <div> albo <section>.

    zamowienie.html HTML zmienione: 3 linie
    <!DOCTYPE html>
    <html lang="pl">
    <head>
        <meta charset="UTF-8">
        <title>Fotografia</title>
        <link rel="stylesheet" href="style.css">
    </head>
    <body>
        <header>
            <h1>Fotografia artystyczna</h1>
        </header>
        <section id="gallery">
            <img src="1.jpg" alt="obrazy do sprzedaży" title="1.jpg">
            <img src="2.jpg" alt="obrazy do sprzedaży" title="2.jpg">
            <img src="3.jpg" alt="obrazy do sprzedaży" title="3.jpg">
            <img src="4.jpg" alt="obrazy do sprzedaży" title="4.jpg">
            <img src="5.jpg" alt="obrazy do sprzedaży" title="5.jpg">
            <img src="6.jpg" alt="obrazy do sprzedaży" title="6.jpg">
            <img src="7.jpg" alt="obrazy do sprzedaży" title="7.jpg">
            <img src="8.jpg" alt="obrazy do sprzedaży" title="8.jpg">
            <img src="9.jpg" alt="obrazy do sprzedaży" title="9.jpg">
            <img src="10.jpg" alt="obrazy do sprzedaży" title="10.jpg">
        </section>
        <main>
            <section id="left">
                <h3>Zamówienie</h3>
                <label for="image">Wybierz obraz: </label>
                <input type="file" id="image" accept="image/jpeg"><br>
                <label for="copies">Liczba Kopii: </label>
                <input type="number" id="copies"><br>
                <input type="radio" id="glossy" name="paper" checked>
                <label for="glossy">Papier błyszczący</label><br>
                <input type="radio" id="matte" name="paper">
                <label for="matte">Papier matowy</label><br>
                <button>Dodaj do koszyka</button>
            </section>
            <nav>
                <ul>
                    <li><a href="regulamin.html">Regulamin</a></li>
                    <li><a href="uslugi.html">Usługi</a></li>
                    <li><a href="https://pixabay.com">Zdjęcia</a></li>
                </ul>
            </nav>
            <section id="right">
                <h3>Koszyk</h3>
                <div id="cart">
                </div>
            </section>
        </main>
        <footer>
        </footer>
    </body>
    </html>
    Podgląd strony po tym kroku (zamowienie.html)
  27. Krok 27: Stopka z numerem zdającego

    Kryteria: ,

    R.2.5 W bloku nagłówkowym umieszczony <h1> "Fotografia artystyczna", w sekcji lewej <h3> "Zamówienie", w prawej <h3> "Koszyk", w stopce paragraf z numerem zdającego

    R.2.10 W stopce zastosowany dla numeru zdającego znacznik <em>

    ok. 1 min
    Polecenie z arkusza

    Zawartość stopki: paragraf o treści „Autor strony: ”, dalej wstawiony numer zdającego. Numer zdającego jest zapisany za pomocą znacznika semantycznego oznaczającego tekst uwypuklony, formatowany domyślnie jako pochylony.

    Paragraf <p> w <footer>. „Znacznik semantyczny oznaczający tekst uwypuklony, domyślnie pochylony” to <em> (emphasis) - nie <i>, które pochyla bez znaczenia semantycznego. Klucz R.2.10 sprawdza właśnie <em>. W tym rozwiązaniu w <em> stoi nazwisko autora - na egzaminie wpisujesz swój numer zdającego. Struktura HTML jest kompletna - dalej style.

    Typowe błędy

    <i> wygląda tak samo (kursywa), ale to znacznik prezentacyjny, nie semantyczny - klucz R.2.10 wymaga <em>.

    zamowienie.html HTML zmienione: 1 linia
    <!DOCTYPE html>
    <html lang="pl">
    <head>
        <meta charset="UTF-8">
        <title>Fotografia</title>
        <link rel="stylesheet" href="style.css">
    </head>
    <body>
        <header>
            <h1>Fotografia artystyczna</h1>
        </header>
        <section id="gallery">
            <img src="1.jpg" alt="obrazy do sprzedaży" title="1.jpg">
            <img src="2.jpg" alt="obrazy do sprzedaży" title="2.jpg">
            <img src="3.jpg" alt="obrazy do sprzedaży" title="3.jpg">
            <img src="4.jpg" alt="obrazy do sprzedaży" title="4.jpg">
            <img src="5.jpg" alt="obrazy do sprzedaży" title="5.jpg">
            <img src="6.jpg" alt="obrazy do sprzedaży" title="6.jpg">
            <img src="7.jpg" alt="obrazy do sprzedaży" title="7.jpg">
            <img src="8.jpg" alt="obrazy do sprzedaży" title="8.jpg">
            <img src="9.jpg" alt="obrazy do sprzedaży" title="9.jpg">
            <img src="10.jpg" alt="obrazy do sprzedaży" title="10.jpg">
        </section>
        <main>
            <section id="left">
                <h3>Zamówienie</h3>
                <label for="image">Wybierz obraz: </label>
                <input type="file" id="image" accept="image/jpeg"><br>
                <label for="copies">Liczba Kopii: </label>
                <input type="number" id="copies"><br>
                <input type="radio" id="glossy" name="paper" checked>
                <label for="glossy">Papier błyszczący</label><br>
                <input type="radio" id="matte" name="paper">
                <label for="matte">Papier matowy</label><br>
                <button>Dodaj do koszyka</button>
            </section>
            <nav>
                <ul>
                    <li><a href="regulamin.html">Regulamin</a></li>
                    <li><a href="uslugi.html">Usługi</a></li>
                    <li><a href="https://pixabay.com">Zdjęcia</a></li>
                </ul>
            </nav>
            <section id="right">
                <h3>Koszyk</h3>
                <div id="cart">
                </div>
            </section>
        </main>
        <footer>
            <p>Autor strony: <em>Bartosz Bryniarski</em></p>
        </footer>
    </body>
    </html>
    Podgląd strony po tym kroku (zamowienie.html)
  28. Etap 3: Styl CSS

    Kroki 28-39 · po tym etapie masz 31 z 41 kryteriów (pkt)

    Krok 28: Plik style.css: krój czcionki

    Kryteria:

    R.4.1 Ustawiony styl domyślny dla wszystkich selektorów (*): krój czcionki "Century Gothic", Arial (tylko taka kolejność)

    ok. 1 min
    Polecenie z arkusza

    Domyślnie, dla wszystkich selektorów: krój czcionki Century Gothic, w przypadku braku Arial.

    Utwórz plik style.css obok zamowienie.html. Selektor uniwersalny * obejmuje każdy element. font-family to lista krojów: nazwa z dwóch słów w cudzysłowie ("Century Gothic"), potem zapasowy Arial. Klucz R.4.1 mówi: tylko taka kolejność. W podglądzie zmienia się czcionka - znak, że <link> zadziałał.

    Typowe błędy

    font-family: Century Gothic, Arial bez cudzysłowu - nazwa ze spacją bez cudzysłowu bywa źle rozpoznana; dla pewności zawsze w cudzysłowie.

    style.css CSS nowy plik
    * {
        font-family: "Century Gothic", Arial;
    }
    Podgląd strony po tym kroku (zamowienie.html)
  29. Krok 29: Ciało strony: kolor tła

    Kryteria:

    R.4.2 Ustawiony kolor tła dla ciała strony BlanchedAlmond, dla bloku nagłówkowego i stopki Sienna, dla sekcji lewej NavajoWhite

    ok. 1 min
    Polecenie z arkusza

    Dla ciała strony: kolor tła BlanchedAlmond.

    Selektor znacznika body, kolor nazwany z arkusza. Tło całego okna robi się kremowe.

    style.css CSS zmienione: 3 linie
    * {
        font-family: "Century Gothic", Arial;
    }
    body {
        background-color: BlanchedAlmond;
    }
    Podgląd strony po tym kroku (zamowienie.html)
  30. Krok 30: Nagłówek i stopka: wspólne style

    Kryteria: , , , ,

    R.4.2 Ustawiony kolor tła dla ciała strony BlanchedAlmond, dla bloku nagłówkowego i stopki Sienna, dla sekcji lewej NavajoWhite

    R.4.3 Ustawiony biały kolor czcionki dla bloków nagłówkowego i stopki, oraz Sienna dla selektora a

    R.4.5 Ustawione wyrównanie tekstu do środka dla bloku nagłówkowego i stopki

    R.4.6 Ustawione marginesy wewnętrzne (padding ) dla bloku nagłówkowego i stopki 5px, dla sekcji lewej 20px oraz marginesy zewnętrzne (margin) dla sekcji lewej 10px , margin-top: 20px dla pola edycyjnego i przycisku, margin-right: 30px dla odnośnika (ustawione min. 6 właściwości)

    R.4.7 Ustawione dla bloku nagłówkowego i stopki rozmiar czcionki 130%, oraz dla sekcji prawej overflow: auto;

    ok. 2 min
    Polecenie z arkusza

    Dla bloku nagłówkowego i stopki: kolor tła Sienna, biały kolor czcionki, marginesy wewnętrzne 5 px, wyrównanie tekstu do środka, rozmiar czcionki 130%.

    Wspólne cechy dwóch bloków piszesz raz - selektory po przecinku header, footer. Pięć właściwości w jednej regule, w kolejności z arkusza: tło, kolor tekstu, padding (margines wewnętrzny), wyrównanie, rozmiar czcionki. Nagłówek i stopka stają się brązowymi pasami z białym, wyśrodkowanym tekstem.

    style.css CSS zmienione: 7 linii
    * {
        font-family: "Century Gothic", Arial;
    }
    body {
        background-color: BlanchedAlmond;
    }
    header, footer {
        background-color: Sienna;
        color: white;
        padding: 5px;
        text-align: center;
        font-size: 130%;
    }
    Podgląd strony po tym kroku (zamowienie.html)
  31. Krok 31: Sekcja lewa: tło, marginesy, wymiary, cień

    Kryteria: , , ,

    R.4.2 Ustawiony kolor tła dla ciała strony BlanchedAlmond, dla bloku nagłówkowego i stopki Sienna, dla sekcji lewej NavajoWhite

    R.4.4 Ustawiona szerokość dla sekcji lewej 35%, dla bloków nawigacyjnego i sekcji prawej 50% (width lub grid-template-columns lub flex) , dla selektora img 10%. Ustawione wysokości sekcji lewej 400px, bloku nawigacyjnego 50px, sekcji prawej 420px

    R.4.6 Ustawione marginesy wewnętrzne (padding ) dla bloku nagłówkowego i stopki 5px, dla sekcji lewej 20px oraz marginesy zewnętrzne (margin) dla sekcji lewej 10px , margin-top: 20px dla pola edycyjnego i przycisku, margin-right: 30px dla odnośnika (ustawione min. 6 właściwości)

    R.4.8 Ustawiony dla sekcji lewej styl box-shadow: 5px 5px 10px DimGray;

    ok. 2 min
    Polecenie z arkusza

    Dla sekcji lewej: kolor tła NavajoWhite, marginesy zewnętrzne 10 px, wewnętrzne 20 px, szerokość 35%, wysokość 400 px, cień o przesunięciu 5 px w obu osiach, rozmyciu 10 px i kolorze DimGray.

    Selektor #left. Zewnętrzne marginesy to margin, wewnętrzne padding - arkusz podaje oba. Cień bloku to box-shadow z czterema wartościami: przesunięcie w poziomie, w pionie, rozmycie, kolor - 5px 5px 10px DimGray (klucz R.4.8 podaje dokładnie ten zapis). To cień całego prostokąta, nie liter (text-shadow byłby błędem).

    Typowe błędy

    text-shadow zamiast box-shadow da cień literom w sekcji, a nie bloku - klucz R.4.8 sprawdza box-shadow.

    style.css CSS zmienione: 8 linii
    * {
        font-family: "Century Gothic", Arial;
    }
    body {
        background-color: BlanchedAlmond;
    }
    header, footer {
        background-color: Sienna;
        color: white;
        padding: 5px;
        text-align: center;
        font-size: 130%;
    }
    #left {
        background-color: NavajoWhite;
        margin: 10px;
        padding: 20px;
        width: 35%;
        height: 400px;
        box-shadow: 5px 5px 10px DimGray;
    }
    Podgląd strony po tym kroku (zamowienie.html)
  32. Krok 32: Blok nawigacyjny: wymiary

    Kryteria:

    R.4.4 Ustawiona szerokość dla sekcji lewej 35%, dla bloków nawigacyjnego i sekcji prawej 50% (width lub grid-template-columns lub flex) , dla selektora img 10%. Ustawione wysokości sekcji lewej 400px, bloku nawigacyjnego 50px, sekcji prawej 420px

    ok. 1 min
    Polecenie z arkusza

    Dla bloku nawigacyjnego: szerokość 50%, wysokość 50 px.

    Selektor nav, szerokość i wysokość z arkusza. Nawigacja stoi jeszcze pod sekcją lewą - obok niej ustawisz ją za dwa kroki.

    style.css CSS zmienione: 4 linie
    * {
        font-family: "Century Gothic", Arial;
    }
    body {
        background-color: BlanchedAlmond;
    }
    header, footer {
        background-color: Sienna;
        color: white;
        padding: 5px;
        text-align: center;
        font-size: 130%;
    }
    #left {
        background-color: NavajoWhite;
        margin: 10px;
        padding: 20px;
        width: 35%;
        height: 400px;
        box-shadow: 5px 5px 10px DimGray;
    }
    nav {
        width: 50%;
        height: 50px;
    }
    Podgląd strony po tym kroku (zamowienie.html)
  33. Krok 33: Sekcja prawa: wymiary i paski przewijania

    Kryteria: ,

    R.4.4 Ustawiona szerokość dla sekcji lewej 35%, dla bloków nawigacyjnego i sekcji prawej 50% (width lub grid-template-columns lub flex) , dla selektora img 10%. Ustawione wysokości sekcji lewej 400px, bloku nawigacyjnego 50px, sekcji prawej 420px

    R.4.7 Ustawione dla bloku nagłówkowego i stopki rozmiar czcionki 130%, oraz dla sekcji prawej overflow: auto;

    ok. 1 min
    Polecenie z arkusza

    Dla sekcji prawej: szerokość 50%, wysokość 420 px, paski przewijania pojawiające się tylko w przypadku przepełnienia bloku.

    Selektor #right. „Paski tylko przy przepełnieniu” to overflow: auto (klucz R.4.7). Koszyk z wieloma zamówieniami przekroczy 420 px i wtedy pojawi się pasek - zamiast rozciągać stronę.

    style.css CSS zmienione: 5 linii
    * {
        font-family: "Century Gothic", Arial;
    }
    body {
        background-color: BlanchedAlmond;
    }
    header, footer {
        background-color: Sienna;
        color: white;
        padding: 5px;
        text-align: center;
        font-size: 130%;
    }
    #left {
        background-color: NavajoWhite;
        margin: 10px;
        padding: 20px;
        width: 35%;
        height: 400px;
        box-shadow: 5px 5px 10px DimGray;
    }
    nav {
        width: 50%;
        height: 50px;
    }
    #right {
        width: 50%;
        height: 420px;
        overflow: auto;
    }
    Podgląd strony po tym kroku (zamowienie.html)
  34. Krok 34: Układ bloków: sekcja lewa obok nawigacji i sekcji prawej

    Kryteria:

    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)

    ok. 3 min
    Polecenie z arkusza

    Podział strony na bloki zrealizowany za pomocą semantycznych znaczników bloków języka HTML5 tak, aby po uruchomieniu w przeglądarce układ bloków na stronie był zgodny z ilustracją 3.

    Trzy bloki w <main> dostają float: left - pływają w lewo i układają się jak słowa w wierszu: sekcja lewa (35% plus marginesy), obok niej nawigacja (50%), a sekcja prawa (50%) nie mieści się już w tym wierszu, więc idzie niżej - ale wciąż na prawo od wysokiej sekcji lewej, czyli pod nawigacją. Dokładnie układ z ilustracji 3. Stopka dostaje clear: both, żeby wróciła pod wszystko (wspólna reguła header, footer zostaje).

    Klucz R.3.1 przyjmuje też display: flex albo grid.

    Typowe błędy

    Bez clear: both stopka wjeżdża obok pływających bloków, a <main> ma zerową wysokość - układ przestaje zgadzać się z ilustracją 3.

    style.css CSS zmienione: 6 linii
    * {
        font-family: "Century Gothic", Arial;
    }
    body {
        background-color: BlanchedAlmond;
    }
    header, footer {
        background-color: Sienna;
        color: white;
        padding: 5px;
        text-align: center;
        font-size: 130%;
    }
    #left {
        background-color: NavajoWhite;
        margin: 10px;
        padding: 20px;
        width: 35%;
        height: 400px;
        box-shadow: 5px 5px 10px DimGray;
        float: left;
    }
    nav {
        width: 50%;
        height: 50px;
        float: left;
    }
    #right {
        width: 50%;
        height: 420px;
        overflow: auto;
        float: left;
    }
    footer {
        clear: both;
    }
    Podgląd strony po tym kroku (zamowienie.html)
  35. Krok 35: Pole edycyjne i przycisk: górny margines zewnętrzny

    Kryteria:

    R.4.6 Ustawione marginesy wewnętrzne (padding ) dla bloku nagłówkowego i stopki 5px, dla sekcji lewej 20px oraz marginesy zewnętrzne (margin) dla sekcji lewej 10px , margin-top: 20px dla pola edycyjnego i przycisku, margin-right: 30px dla odnośnika (ustawione min. 6 właściwości)

    ok. 1 min
    Polecenie z arkusza

    Dla pola edycyjnego i przycisku: jedynie zewnętrzny margines górny 20 px.

    Selektory input, button, margin-top: 20px - margines tylko z góry, więc pola i przycisk rozsuwają się w pionie jak na ilustracji 2, bez odstępów bocznych. Reguła obejmuje też pola radio (to także <input>).

    Typowe błędy

    margin: 20px (ze wszystkich stron) odsunie pola także od etykiet w poziomie - arkusz mówi „jedynie górny”, a klucz R.4.6 sprawdza margin-top.

    style.css CSS zmienione: 3 linie
    * {
        font-family: "Century Gothic", Arial;
    }
    body {
        background-color: BlanchedAlmond;
    }
    header, footer {
        background-color: Sienna;
        color: white;
        padding: 5px;
        text-align: center;
        font-size: 130%;
    }
    #left {
        background-color: NavajoWhite;
        margin: 10px;
        padding: 20px;
        width: 35%;
        height: 400px;
        box-shadow: 5px 5px 10px DimGray;
        float: left;
    }
    nav {
        width: 50%;
        height: 50px;
        float: left;
    }
    #right {
        width: 50%;
        height: 420px;
        overflow: auto;
        float: left;
    }
    footer {
        clear: both;
    }
    input, button {
        margin-top: 20px;
    }
    Podgląd strony po tym kroku (zamowienie.html)
  36. Krok 36: Element listy: wyświetlanie liniowo-blokowe

    Kryteria:

    R.4.9 Ustawiony dla selektora li: display: inline-block; oraz dla obrazu: float: left

    ok. 1 min
    Polecenie z arkusza

    Dla selektora elementu listy: sposób wyświetlania liniowo-blokowy.

    Selektor znacznika li (arkusz tego wymaga). display: inline-block ustawia elementy listy obok siebie w jednej linii (jak tekst), zachowując wymiary bloku - trzy odnośniki stają w rzędzie jak na ilustracji 2, a kropki punktorów znikają, bo inline-block ich nie rysuje.

    style.css CSS zmienione: 3 linie
    * {
        font-family: "Century Gothic", Arial;
    }
    body {
        background-color: BlanchedAlmond;
    }
    header, footer {
        background-color: Sienna;
        color: white;
        padding: 5px;
        text-align: center;
        font-size: 130%;
    }
    #left {
        background-color: NavajoWhite;
        margin: 10px;
        padding: 20px;
        width: 35%;
        height: 400px;
        box-shadow: 5px 5px 10px DimGray;
        float: left;
    }
    nav {
        width: 50%;
        height: 50px;
        float: left;
    }
    #right {
        width: 50%;
        height: 420px;
        overflow: auto;
        float: left;
    }
    footer {
        clear: both;
    }
    input, button {
        margin-top: 20px;
    }
    li {
        display: inline-block;
    }
    Podgląd strony po tym kroku (zamowienie.html)
  37. Krok 37: Obraz: szerokość i opływanie

    Kryteria: ,

    R.4.4 Ustawiona szerokość dla sekcji lewej 35%, dla bloków nawigacyjnego i sekcji prawej 50% (width lub grid-template-columns lub flex) , dla selektora img 10%. Ustawione wysokości sekcji lewej 400px, bloku nawigacyjnego 50px, sekcji prawej 420px

    R.4.9 Ustawiony dla selektora li: display: inline-block; oraz dla obrazu: float: left

    ok. 2 min
    Polecenie z arkusza

    Dla selektora obrazu: szerokość 10%, opływanie po prawej stronie (obraz po lewej stronie).

    Selektor znacznika img (arkusz tego wymaga). width: 10% liczy się od szerokości rodzica - dziesięć obrazów galerii po 10% zajmuje dokładnie jeden rząd. „Opływanie po prawej stronie, obraz po lewej” to float: left: obraz stoi z lewej, a tekst obok niego - to zadziała w koszyku, gdzie paragrafy ustawią się obok miniatury (ilustracja 4).

    Typowe błędy

    float: right ustawia obraz po prawej - arkusz opisuje stronę, po której jest tekst („opływanie po prawej”), ale w nawiasie wyjaśnia: obraz po lewej. Klucz R.4.9: float: left.

    style.css CSS zmienione: 4 linie
    * {
        font-family: "Century Gothic", Arial;
    }
    body {
        background-color: BlanchedAlmond;
    }
    header, footer {
        background-color: Sienna;
        color: white;
        padding: 5px;
        text-align: center;
        font-size: 130%;
    }
    #left {
        background-color: NavajoWhite;
        margin: 10px;
        padding: 20px;
        width: 35%;
        height: 400px;
        box-shadow: 5px 5px 10px DimGray;
        float: left;
    }
    nav {
        width: 50%;
        height: 50px;
        float: left;
    }
    #right {
        width: 50%;
        height: 420px;
        overflow: auto;
        float: left;
    }
    footer {
        clear: both;
    }
    input, button {
        margin-top: 20px;
    }
    li {
        display: inline-block;
    }
    img {
        width: 10%;
        float: left;
    }
    Podgląd strony po tym kroku (zamowienie.html)
  38. Krok 38: Odnośniki: kolor i prawy margines

    Kryteria: ,

    R.4.3 Ustawiony biały kolor czcionki dla bloków nagłówkowego i stopki, oraz Sienna dla selektora a

    R.4.6 Ustawione marginesy wewnętrzne (padding ) dla bloku nagłówkowego i stopki 5px, dla sekcji lewej 20px oraz marginesy zewnętrzne (margin) dla sekcji lewej 10px , margin-top: 20px dla pola edycyjnego i przycisku, margin-right: 30px dla odnośnika (ustawione min. 6 właściwości)

    ok. 1 min
    Polecenie z arkusza

    Dla selektora odnośnika: kolor czcionki Sienna, jedynie zewnętrzny margines prawy 30 px.

    Selektor znacznika a (arkusz tego wymaga). color: Sienna i margin-right: 30px - margines tylko z prawej, więc odnośniki w nawigacji rozsuwają się od siebie.

    style.css CSS zmienione: 4 linie
    * {
        font-family: "Century Gothic", Arial;
    }
    body {
        background-color: BlanchedAlmond;
    }
    header, footer {
        background-color: Sienna;
        color: white;
        padding: 5px;
        text-align: center;
        font-size: 130%;
    }
    #left {
        background-color: NavajoWhite;
        margin: 10px;
        padding: 20px;
        width: 35%;
        height: 400px;
        box-shadow: 5px 5px 10px DimGray;
        float: left;
    }
    nav {
        width: 50%;
        height: 50px;
        float: left;
    }
    #right {
        width: 50%;
        height: 420px;
        overflow: auto;
        float: left;
    }
    footer {
        clear: both;
    }
    input, button {
        margin-top: 20px;
    }
    li {
        display: inline-block;
    }
    img {
        width: 10%;
        float: left;
    }
    a {
        color: Sienna;
        margin-right: 30px;
    }
    Podgląd strony po tym kroku (zamowienie.html)
  39. Krok 39: Odnośnik pod kursorem

    Kryteria:

    R.4.10 Gdy kursor znajdzie się na odnośniku jego kolor czcionki zamienia się na #4C1900

    ok. 1 min
    Polecenie z arkusza

    W momencie, gdy kursor znajdzie się na odnośniku jego kolor czcionki zamienia się na #4C1900.

    Pseudoklasa :hover na a z kolorem szesnastkowym z arkusza (ciemny brąz). Najedź w podglądzie na „Regulamin”. Arkusz stylów jest kompletny.

    style.css CSS zmienione: 3 linie
    * {
        font-family: "Century Gothic", Arial;
    }
    body {
        background-color: BlanchedAlmond;
    }
    header, footer {
        background-color: Sienna;
        color: white;
        padding: 5px;
        text-align: center;
        font-size: 130%;
    }
    #left {
        background-color: NavajoWhite;
        margin: 10px;
        padding: 20px;
        width: 35%;
        height: 400px;
        box-shadow: 5px 5px 10px DimGray;
        float: left;
    }
    nav {
        width: 50%;
        height: 50px;
        float: left;
    }
    #right {
        width: 50%;
        height: 420px;
        overflow: auto;
        float: left;
    }
    footer {
        clear: both;
    }
    input, button {
        margin-top: 20px;
    }
    li {
        display: inline-block;
    }
    img {
        width: 10%;
        float: left;
    }
    a {
        color: Sienna;
        margin-right: 30px;
    }
    a:hover {
        color: #4C1900;
    }
    Podgląd strony po tym kroku (zamowienie.html)
  40. Etap 4: JavaScript

    Kroki 40-47 · po tym etapie masz 41 z 41 kryteriów (pkt)

    Krok 40: Plik script.js i funkcja wywoływana przyciskiem

    Kryteria: , ,

    R.3.4 Zdefiniowane dla przycisku zdarzenie związane z jego wciśnięciem, które uruchamia funkcję skryptu (obsługa zdarzenia zdefiniowana w HTML np. onClick lub w skrypcie np.addEventListener zmienna.onClick = …)

    R.5.1 Skrypt napisany w języku JavaScript i zawiera on przynajmniej jedną poprawną składniowo instrukcję wynikającą z treści zadania

    R.5.9 W skryptach zastosowana przynajmniej jedna zmienna lub funkcja oraz nazwy wszystkich funkcji i zmiennych są w języku polskim lub angielskim i odzwierciedlają cel zastosowania

    ok. 2 min
    Polecenie z arkusza

    Wykonywany po stronie klienta, po kliknięciu przycisku. Przycisk „Dodaj do koszyka”, którego kliknięcie wywołuje skrypt.

    „Po stronie klienta” to JavaScript - wykonuje go przeglądarka, nie serwer. Utwórz plik script.js i podepnij go na końcu <body> przez <script src="script.js"></script> - na końcu, żeby pola i koszyk już istniały, gdy skrypt zacznie działać.

    Funkcja addToCart() na razie pusta; przycisk dostaje onclick="addToCart()" - najprostszy sposób z tabeli 1 arkusza (klucz R.3.4 przyjmuje onclick w HTML albo addEventListener w skrypcie - ten drugi pokażesz w refaktorze). Nazwa funkcji po angielsku, znacząca (R.5.9).

    Typowe błędy

    Skrypt podpięty w <head> wykona się, zanim powstanie koszyk - dla onclick to jeszcze nie problem, ale przy nasłuchiwaczach z refaktoru getElementById zwróci null.

    script.js JavaScript nowy plik
    function addToCart() {
    }
    zamowienie.html HTML zmienione: 2 linie
    <!DOCTYPE html>
    <html lang="pl">
    <head>
        <meta charset="UTF-8">
        <title>Fotografia</title>
        <link rel="stylesheet" href="style.css">
    </head>
    <body>
        <header>
            <h1>Fotografia artystyczna</h1>
        </header>
        <section id="gallery">
            <img src="1.jpg" alt="obrazy do sprzedaży" title="1.jpg">
            <img src="2.jpg" alt="obrazy do sprzedaży" title="2.jpg">
            <img src="3.jpg" alt="obrazy do sprzedaży" title="3.jpg">
            <img src="4.jpg" alt="obrazy do sprzedaży" title="4.jpg">
            <img src="5.jpg" alt="obrazy do sprzedaży" title="5.jpg">
            <img src="6.jpg" alt="obrazy do sprzedaży" title="6.jpg">
            <img src="7.jpg" alt="obrazy do sprzedaży" title="7.jpg">
            <img src="8.jpg" alt="obrazy do sprzedaży" title="8.jpg">
            <img src="9.jpg" alt="obrazy do sprzedaży" title="9.jpg">
            <img src="10.jpg" alt="obrazy do sprzedaży" title="10.jpg">
        </section>
        <main>
            <section id="left">
                <h3>Zamówienie</h3>
                <label for="image">Wybierz obraz: </label>
                <input type="file" id="image" accept="image/jpeg"><br>
                <label for="copies">Liczba Kopii: </label>
                <input type="number" id="copies"><br>
                <input type="radio" id="glossy" name="paper" checked>
                <label for="glossy">Papier błyszczący</label><br>
                <input type="radio" id="matte" name="paper">
                <label for="matte">Papier matowy</label><br>
                <button onclick="addToCart()">Dodaj do koszyka</button>
            </section>
            <nav>
                <ul>
                    <li><a href="regulamin.html">Regulamin</a></li>
                    <li><a href="uslugi.html">Usługi</a></li>
                    <li><a href="https://pixabay.com">Zdjęcia</a></li>
                </ul>
            </nav>
            <section id="right">
                <h3>Koszyk</h3>
                <div id="cart">
                </div>
            </section>
        </main>
        <footer>
            <p>Autor strony: <em>Bartosz Bryniarski</em></p>
        </footer>
        <script src="script.js"></script>
    </body>
    </html>
    Podgląd strony po tym kroku (zamowienie.html)
  41. Krok 41: Odczyt liczby kopii

    Kryteria:

    R.5.2 Skrypt pobiera dane z przynajmniej jednej kontrolki, np. zastosowana funkcja document.getElementById z parametrem, który zdefiniowany w kontrolce jako id

    ok. 1 min
    Polecenie z arkusza

    Pobiera dane z kontrolek.

    document.getElementById('copies') (tabela 1) znajduje pole liczby kopii po identyfikatorze, a .value to wpisana wartość. Zapisz ją w stałej copies. Klucz R.5.2 sprawdza właśnie getElementById z parametrem równym id kontrolki.

    Typowe błędy

    getElementById('copies').innerText dla pola <input> daje pusty napis - wpisana wartość jest w value.

    script.js JavaScript zmienione: 1 linia
    function addToCart() {
        const copies = document.getElementById('copies').value;
    }
    Podgląd strony po tym kroku (zamowienie.html)
  42. Krok 42: Odczyt rodzaju papieru

    Kryteria:

    R.5.2 Skrypt pobiera dane z przynajmniej jednej kontrolki, np. zastosowana funkcja document.getElementById z parametrem, który zdefiniowany w kontrolce jako id

    ok. 1 min
    Polecenie z arkusza

    Pobiera dane z kontrolek.

    Dla pola radio liczy się nie value, tylko checked - true, gdy pole jest zaznaczone. Wystarczy sprawdzić jedno: jeśli „Papier błyszczący” nie jest zaznaczony, to zaznaczony jest matowy (grupa name="paper" gwarantuje dokładnie jedno). Stała glossy jest wartością logiczną.

    script.js JavaScript zmienione: 1 linia
    function addToCart() {
        const copies = document.getElementById('copies').value;
        const glossy = document.getElementById('glossy').checked;
    }
    Podgląd strony po tym kroku (zamowienie.html)
  43. Krok 43: Obliczenie ceny

    Kryteria:

    R.5.3 Skrypt oblicza cenę na podstawie liczby kopii pobranej z kontrolki i rodzaju papieru: błyszczący 1.5 zł, matowy 2 zł

    ok. 2 min
    Polecenie z arkusza

    Oblicza cenę na podstawie liczby kopii i rodzaju papieru. Dla papieru błyszczącego cena jednostkowa wynosi 1,5 zł, dla papieru matowego - 2 zł.

    Instrukcja warunkowa if (glossy) { ... } else { ... }: dla błyszczącego cena to copies * 1.5, dla matowego copies * 2. Zmienna price jest deklarowana przez let, bo dostaje wartość dopiero w jednej z gałęzi. Uwaga na kropkę dziesiętną - w JavaScript 1.5, nie 1,5 (przecinek rozdziela argumenty).

    copies jest napisem z pola, ale mnożenie * samo zamienia go na liczbę - w refaktorze zrobisz to jawnie.

    Typowe błędy

    copies * 1,5 to błąd składni (przecinek). if (glossy = true) z jednym = to przypisanie, zawsze prawdziwe - porównanie to == albo ===, a dla wartości logicznej wystarczy samo if (glossy).

    script.js JavaScript zmienione: 6 linii
    function addToCart() {
        const copies = document.getElementById('copies').value;
        const glossy = document.getElementById('glossy').checked;
        let price;
        if (glossy) {
            price = copies * 1.5;
        } else {
            price = copies * 2;
        }
    }
    Podgląd strony po tym kroku (zamowienie.html)
  44. Krok 44: Ustalenie nazwy pliku

    Kryteria:

    R.5.4 Skrypt ustala nazwę pliku np.: indeks = plik.lastIndexOf('\\'); nazwaPliku = plik.substr(indeks+1);

    ok. 3 min
    Polecenie z arkusza

    Ustala nazwę pliku z wartości pobranej z pierwszego pola edycyjnego.

    value pola wyboru pliku to nie sama nazwa, tylko ścieżka w rodzaju C:\fakepath\7.jpg (przeglądarka ukrywa prawdziwy folder, zostawia nazwę). Nazwę wycinasz po ostatnim ukośniku: lastIndexOf('\\') (tabela 1 - metody obiektu string) daje pozycję ostatniego \, a substr(index + 1) bierze wszystko za nim. Backslash w napisie JavaScript trzeba podwoić ('\\'), bo pojedynczy rozpoczyna znak specjalny.

    Klucz R.5.4 podaje dokładnie ten sposób. Dla C:\fakepath\7.jpg wynik to 7.jpg.

    Typowe błędy

    lastIndexOf('\') z pojedynczym backslashem to błąd składni - napis nie ma końca, bo \' to „apostrof jako znak”. Zawsze '\\'.

    script.js JavaScript zmienione: 3 linie
    function addToCart() {
        const copies = document.getElementById('copies').value;
        const glossy = document.getElementById('glossy').checked;
        let price;
        if (glossy) {
            price = copies * 1.5;
        } else {
            price = copies * 2;
        }
        const filePath = document.getElementById('image').value;
        const index = filePath.lastIndexOf('\\');
        const fileName = filePath.substr(index + 1);
    }
    Podgląd strony po tym kroku (zamowienie.html)
  45. Krok 45: Element obrazu w koszyku

    Kryteria:

    R.5.5 Skrypt tworzy element img z ustaloną nazwą pliku i dodaje go do bloku w sekcji prawej

    ok. 2 min
    Polecenie z arkusza

    Tworzy elementy i dodaje je do bloku z sekcji prawej (ilustracja 4): element DOM dla obrazu z ustaloną nazwą pliku.

    Blok koszyka znajdujesz po id. document.createElement('img') (tabela 1) tworzy nowy element obrazu w pamięci, image.src = fileName ustawia atrybut (element.attribute_name = "wartość" z tabeli 1), a cart.appendChild(image) wstawia go na koniec bloku. Obraz dostaje styl img z CSS: 10% szerokości i float: left, więc stanie z lewej jak na ilustracji 4.

    Podgląd działa: wybierz zdjęcie z folderu (dowolny JPEG o nazwie od 1 do 10), kliknij przycisk - miniatura pojawia się w koszyku.

    Typowe błędy

    image.src = filePath (cała ścieżka z fakepath) nie wczyta obrazu - przeglądarka nie ma dostępu do tej ścieżki. Dlatego najpierw wycinasz samą nazwę.

    script.js JavaScript zmienione: 4 linie
    function addToCart() {
        const copies = document.getElementById('copies').value;
        const glossy = document.getElementById('glossy').checked;
        let price;
        if (glossy) {
            price = copies * 1.5;
        } else {
            price = copies * 2;
        }
        const filePath = document.getElementById('image').value;
        const index = filePath.lastIndexOf('\\');
        const fileName = filePath.substr(index + 1);
        const cart = document.getElementById('cart');
        const image = document.createElement('img');
        image.src = fileName;
        cart.appendChild(image);
    }
    Podgląd strony po tym kroku (zamowienie.html)
  46. Krok 46: Paragraf z liczbą kopii

    Kryteria: ,

    R.5.6 Skrypt tworzy 2 elementy p z treścią i dodaje je do bloku w sekcji prawej

    R.5.7 Skrypt wyświetla napisy: „Liczba kopii: <kopie>”, gdzie pole <> jest pobrane z kontrolki, „Cena: <cena>”, gdzie pole <> jest wyliczoną ceną

    ok. 1 min
    Polecenie z arkusza

    Element DOM dla paragrafu z treścią Liczba kopii: <kopie>, gdzie pole <> jest pobrane z kontrolki.

    Nowy paragraf <p> przez createElement('p'), treść przez innerText - napis „Liczba kopii: ” sklejony plusem z wartością z pola (copies). appendChild dokłada go pod obrazem. Dzięki float: left obrazu paragraf staje obok miniatury, jak na ilustracji 4.

    script.js JavaScript zmienione: 3 linie
    function addToCart() {
        const copies = document.getElementById('copies').value;
        const glossy = document.getElementById('glossy').checked;
        let price;
        if (glossy) {
            price = copies * 1.5;
        } else {
            price = copies * 2;
        }
        const filePath = document.getElementById('image').value;
        const index = filePath.lastIndexOf('\\');
        const fileName = filePath.substr(index + 1);
        const cart = document.getElementById('cart');
        const image = document.createElement('img');
        image.src = fileName;
        cart.appendChild(image);
        const copiesParagraph = document.createElement('p');
        copiesParagraph.innerText = 'Liczba kopii: ' + copies;
        cart.appendChild(copiesParagraph);
    }
    Podgląd strony po tym kroku (zamowienie.html)
  47. Krok 47: Paragraf z ceną

    Kryteria: , ,

    R.5.6 Skrypt tworzy 2 elementy p z treścią i dodaje je do bloku w sekcji prawej

    R.5.7 Skrypt wyświetla napisy: „Liczba kopii: <kopie>”, gdzie pole <> jest pobrane z kontrolki, „Cena: <cena>”, gdzie pole <> jest wyliczoną ceną

    R.5.8 Po ponownym wypełnieniu kontrolek i kliknięciu przycisku poprzednie zamówienie nie znika, następne jest dodawane pod nim

    ok. 1 min
    Polecenie z arkusza

    Element DOM dla paragrafu z treścią Cena: <cena>, gdzie pole <> jest wyliczoną ceną.

    Drugi paragraf tak samo, z wyliczoną wcześniej price. Dla 10 kopii na błyszczącym wyjdzie „Cena: 15”, a na matowym „Cena: 20”. Ilustracja 4 pokazuje trzy zamówienia: 10 kopii na matowym (20), 7 na matowym (14) i 20 na błyszczącym (30).

    Podgląd działa jak na ilustracji 4: wypełnij kontrolki i kliknij trzy razy - kolejne zamówienia dokładają się pod poprzednimi, bo appendChild nigdy nie kasuje tego, co już jest w bloku (klucz R.5.8). Skrypt spełnia wszystkie kryteria - dalej refaktor.

    Typowe błędy

    cart.innerHTML = '...' zamiast appendChild zastępuje zawartość koszyka - poprzednie zamówienie znika i R.5.8 przepada.

    script.js JavaScript zmienione: 3 linie
    function addToCart() {
        const copies = document.getElementById('copies').value;
        const glossy = document.getElementById('glossy').checked;
        let price;
        if (glossy) {
            price = copies * 1.5;
        } else {
            price = copies * 2;
        }
        const filePath = document.getElementById('image').value;
        const index = filePath.lastIndexOf('\\');
        const fileName = filePath.substr(index + 1);
        const cart = document.getElementById('cart');
        const image = document.createElement('img');
        image.src = fileName;
        cart.appendChild(image);
        const copiesParagraph = document.createElement('p');
        copiesParagraph.innerText = 'Liczba kopii: ' + copies;
        cart.appendChild(copiesParagraph);
        const priceParagraph = document.createElement('p');
        priceParagraph.innerText = 'Cena: ' + price;
        cart.appendChild(priceParagraph);
    }
    Podgląd strony po tym kroku (zamowienie.html)
  48. Etap 5: Dobre praktyki (poza kluczem)

    Kroki 48-50 · po tym etapie masz 41 z 41 kryteriów (pkt)

    Krok 48: Refaktor: nasłuchiwacz zamiast atrybutu onclick

    Kryteria:

    R.3.4 Zdefiniowane dla przycisku zdarzenie związane z jego wciśnięciem, które uruchamia funkcję skryptu (obsługa zdarzenia zdefiniowana w HTML np. onClick lub w skrypcie np.addEventListener zmienna.onClick = …)

    ok. 2 min
    Polecenie z arkusza

    Zdefiniowane dla przycisku zdarzenie związane z jego wciśnięciem, które uruchamia funkcję skryptu (obsługa zdarzenia zdefiniowana w HTML np. onClick lub w skrypcie np. addEventListener).

    Klucz R.3.4 sam wymienia dwie drogi. W prawdziwych projektach zachowanie trzyma się w skrypcie, a HTML opisuje tylko strukturę. Stara linia przycisku zostaje w komentarzu <!-- -->, nowa ma id="add-button" zamiast onclick. W skrypcie, na końcu pliku: addEventListener('click', addToCart) - funkcja bez nawiasów (przekazujesz ją, nie wywołujesz). Skrypt jest na końcu <body>, więc przycisk już istnieje. Podgląd działa jak wcześniej.

    Typowe błędy

    addEventListener('click', addToCart()) z nawiasami wywołuje funkcję od razu przy wczytaniu i jako nasłuchiwacz przekazuje jej wynik (undefined) - kliknięcie nic nie zrobi.

    script.js JavaScript zmienione: 2 linie
    function addToCart() {
        const copies = document.getElementById('copies').value;
        const glossy = document.getElementById('glossy').checked;
        let price;
        if (glossy) {
            price = copies * 1.5;
        } else {
            price = copies * 2;
        }
        const filePath = document.getElementById('image').value;
        const index = filePath.lastIndexOf('\\');
        const fileName = filePath.substr(index + 1);
        const cart = document.getElementById('cart');
        const image = document.createElement('img');
        image.src = fileName;
        cart.appendChild(image);
        const copiesParagraph = document.createElement('p');
        copiesParagraph.innerText = 'Liczba kopii: ' + copies;
        cart.appendChild(copiesParagraph);
        const priceParagraph = document.createElement('p');
        priceParagraph.innerText = 'Cena: ' + price;
        cart.appendChild(priceParagraph);
    }
    
    document.getElementById('add-button').addEventListener('click', addToCart);
    zamowienie.html HTML zmienione: 2 linie
    <!DOCTYPE html>
    <html lang="pl">
    <head>
        <meta charset="UTF-8">
        <title>Fotografia</title>
        <link rel="stylesheet" href="style.css">
    </head>
    <body>
        <header>
            <h1>Fotografia artystyczna</h1>
        </header>
        <section id="gallery">
            <img src="1.jpg" alt="obrazy do sprzedaży" title="1.jpg">
            <img src="2.jpg" alt="obrazy do sprzedaży" title="2.jpg">
            <img src="3.jpg" alt="obrazy do sprzedaży" title="3.jpg">
            <img src="4.jpg" alt="obrazy do sprzedaży" title="4.jpg">
            <img src="5.jpg" alt="obrazy do sprzedaży" title="5.jpg">
            <img src="6.jpg" alt="obrazy do sprzedaży" title="6.jpg">
            <img src="7.jpg" alt="obrazy do sprzedaży" title="7.jpg">
            <img src="8.jpg" alt="obrazy do sprzedaży" title="8.jpg">
            <img src="9.jpg" alt="obrazy do sprzedaży" title="9.jpg">
            <img src="10.jpg" alt="obrazy do sprzedaży" title="10.jpg">
        </section>
        <main>
            <section id="left">
                <h3>Zamówienie</h3>
                <label for="image">Wybierz obraz: </label>
                <input type="file" id="image" accept="image/jpeg"><br>
                <label for="copies">Liczba Kopii: </label>
                <input type="number" id="copies"><br>
                <input type="radio" id="glossy" name="paper" checked>
                <label for="glossy">Papier błyszczący</label><br>
                <input type="radio" id="matte" name="paper">
                <label for="matte">Papier matowy</label><br>
                <!-- <button onclick="addToCart()">Dodaj do koszyka</button> -->
                <button id="add-button">Dodaj do koszyka</button>
            </section>
            <nav>
                <ul>
                    <li><a href="regulamin.html">Regulamin</a></li>
                    <li><a href="uslugi.html">Usługi</a></li>
                    <li><a href="https://pixabay.com">Zdjęcia</a></li>
                </ul>
            </nav>
            <section id="right">
                <h3>Koszyk</h3>
                <div id="cart">
                </div>
            </section>
        </main>
        <footer>
            <p>Autor strony: <em>Bartosz Bryniarski</em></p>
        </footer>
        <script src="script.js"></script>
    </body>
    </html>
    Podgląd strony po tym kroku (zamowienie.html)
  49. Krok 49: Refaktor: File API i walidacja

    Kryteria:

    R.5.4 Skrypt ustala nazwę pliku np.: indeks = plik.lastIndexOf('\\'); nazwaPliku = plik.substr(indeks+1);

    ok. 3 min
    Polecenie z arkusza

    Ustala nazwę pliku z wartości pobranej z pierwszego pola edycyjnego.

    Wycinanie nazwy z C:\fakepath\… działa, ale opiera się na sztuczce przeglądarki, a substr jest w JavaScript oznaczone jako przestarzałe. Pole type="file" ma File API (ramka w arkuszu o nim wspomina): fileInput.files to lista wybranych plików, a files[0].name to po prostu nazwa pierwszego - bez żadnego cięcia napisów.

    Przy okazji walidacja: jeśli nie wybrano pliku (files.length === 0) albo liczba kopii jest mniejsza niż 1, funkcja kończy się return - bez tego kliknięcie z pustymi polami dodawało do koszyka obraz bez nazwy i „Cena: 0”. Stare linie zostają w komentarzu.

    Typowe błędy

    Walidacja to dodatek, nie wymaganie - klucz R.5.4 sprawdza tylko ustalenie nazwy pliku. Nie trać na to czasu, dopóki nie masz wszystkich kryteriów.

    script.js JavaScript zmienione: 8 linii
    function addToCart() {
        const copies = document.getElementById('copies').value;
        const glossy = document.getElementById('glossy').checked;
        let price;
        if (glossy) {
            price = copies * 1.5;
        } else {
            price = copies * 2;
        }
        // const filePath = document.getElementById('image').value;
        // const index = filePath.lastIndexOf('\\');
        // const fileName = filePath.substr(index + 1);
        const fileInput = document.getElementById('image');
        if (fileInput.files.length === 0 || copies < 1) {
            return;
        }
        const fileName = fileInput.files[0].name;
        const cart = document.getElementById('cart');
        const image = document.createElement('img');
        image.src = fileName;
        cart.appendChild(image);
        const copiesParagraph = document.createElement('p');
        copiesParagraph.innerText = 'Liczba kopii: ' + copies;
        cart.appendChild(copiesParagraph);
        const priceParagraph = document.createElement('p');
        priceParagraph.innerText = 'Cena: ' + price;
        cart.appendChild(priceParagraph);
    }
    
    document.getElementById('add-button').addEventListener('click', addToCart);
    Podgląd strony po tym kroku (zamowienie.html)
  50. Krok 50: Refaktor: liczba zamiast napisu i formatowanie ceny

    ok. 2 min
    Polecenie z arkusza

    Oblicza cenę na podstawie liczby kopii i rodzaju papieru.

    Dwie drobne rzeczy, które w prawdziwym kodzie robią różnicę:

    • Number(...) przy odczycie pola - value jest zawsze napisem; mnożenie zamieniało go na liczbę po cichu, ale porównanie copies < 1 z walidacji i ewentualne dodawanie (copies + 1 sklejałoby napisy!) wymagają prawdziwej liczby,
    • price.toFixed(2) + ' zł' - cena zawsze z dwoma miejscami po przecinku i walutą: „Cena: 15.00 zł” zamiast „Cena: 15”. toFixed zwraca napis, więc wywołujesz go na końcu, po obliczeniach.

    Na egzaminie wystarczy goła liczba - klucz R.5.7 sprawdza Cena: <cena>. To już wersja gotowa do prawdziwego użycia.

    Typowe błędy

    toFixed przed mnożeniem (copies.toFixed(2) * 1.5) działa przypadkiem, bo JavaScript znów zamieni napis na liczbę - ale to prosi się o błąd. Formatuj dopiero wynik.

    script.js JavaScript zmienione: 2 linie
    function addToCart() {
        const copies = Number(document.getElementById('copies').value);
        const glossy = document.getElementById('glossy').checked;
        let price;
        if (glossy) {
            price = copies * 1.5;
        } else {
            price = copies * 2;
        }
        // const filePath = document.getElementById('image').value;
        // const index = filePath.lastIndexOf('\\');
        // const fileName = filePath.substr(index + 1);
        const fileInput = document.getElementById('image');
        if (fileInput.files.length === 0 || copies < 1) {
            return;
        }
        const fileName = fileInput.files[0].name;
        const cart = document.getElementById('cart');
        const image = document.createElement('img');
        image.src = fileName;
        cart.appendChild(image);
        const copiesParagraph = document.createElement('p');
        copiesParagraph.innerText = 'Liczba kopii: ' + copies;
        cart.appendChild(copiesParagraph);
        const priceParagraph = document.createElement('p');
        priceParagraph.innerText = 'Cena: ' + price.toFixed(2) + ' zł';
        cart.appendChild(priceParagraph);
    }
    
    document.getElementById('add-button').addEventListener('click', addToCart);
    Podgląd strony po tym kroku (zamowienie.html)
  51. Etap 6: Oddanie pracy

    Krok 51 · po tym etapie masz 41 z 41 kryteriów (pkt)

    Krok 51: 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. Nagraj płytę z rezultatami pracy.

    W przeglądarka.txt wpisujesz nazwę przeglądarki, w której sprawdzasz stronę.

    W folderze z numerem zdającego muszą być: zdjęcia 1.jpg … 10.jpg, import.png, kw1.png … kw4.png, kwerendy.txt, przeglądarka.txt, regulamin.html, uslugi.html, zamowienie.html, style.css oraz script.js. Nagraj płytę, sprawdź jej odczyt i opisz numerem zdającego. Pusta lub nieczytelna płyta to zero punktów za wszystkie pięć rezultatów.

    przeglądarka.txt Tekst nowy plik
    Google Chrome

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

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.