Temat 19 · 3 × 45 minINF.03
Trening egzaminacyjny: część praktyczna
Masz już wszystkie klocki: odczyt kontrolek, obliczenia, zmiana stylów, tworzenie elementów, stan i walidacja. Ta lekcja składa je w to, co naprawdę zobaczysz na stanowisku: 150 minut, arkusz z pięcioma rezultatami, bez internetu, z jedną tabelą metod DOM jako pomocą. Najpierw poznasz zasady gry – jak czytać kryteria i gdzie zdający tracą punkty – a potem rozwiążesz trzy pełne zadania zbudowane z mechanizmów, które CKE stosuje od 2024 r.
Jak wygląda egzamin praktyczny
| Element | Jak jest naprawdę |
|---|---|
| Czas | 150 minut + 10 minut na zapoznanie się z arkuszem i stanowiskiem (nie wliczane) |
| Próg zdania | 75 % punktów |
| Stanowisko | komputer fizycznie odłączony od sieci, XAMPP (Apache, MySQL/MariaDB, PHP, phpMyAdmin), przeglądarka w aktualnej wersji, edytor z podświetlaniem składni bez WYSIWYG (VS Code, Notepad++…), GIMP/Inkscape, 7-Zip |
| Pomoce | tylko arkusz – w wariancie JS zawiera tabelę „Wybrane pola i metody modelu DOM języka JavaScript”; żadnej dokumentacji online |
| Rezultaty | 1. operacje na bazie danych (import, 4–5 kwerend, zrzuty), 2. zawartość witryny (HTML), 3. działanie witryny, 4. styl CSS, 5. skrypt – JS albo PHP |
| Skrypt | w 25–50 % wariantów sesji to JavaScript; nie wiesz, który wariant wylosujesz, więc ćwiczysz oba |
| Punkty za skrypt | 5–8 kryteriów zero-jedynkowych z 34–42 łącznie (13–20 %) |
| Oddanie pracy | folder o nazwie z numerem zdającego, plik przeglądarka.txt z nazwą użytej przeglądarki, zrzuty ekranu pełnoekranowe z paskiem zadań (wykadrowane nie są oceniane), nagranie na płytę i sprawdzenie, czy się otwiera |
Skrypt to zwykle jedna strona z formularzem lub kilkoma przyciskami i jedna–trzy funkcje. Arkusz nie wymaga osobnego pliku .js (możesz pisać w <script> na końcu body), nie określa wersji języka i nie zakazuje let, const, addEventListener czy template stringów – przeglądarka jest aktualna, więc wszystko działa. Liczy się efekt w przeglądarce, który egzaminator klika osobiście.
Budżet czasu
Egzaminator nie wie, ile czasu poświęciłeś na skrypt – ale ty musisz to zaplanować. Orientacyjny podział 150 minut (to szacunek z proporcji kryteriów, nie oficjalna zasada):
| Etap | Czas | Uwagi |
|---|---|---|
| Czytanie arkusza, rozpakowanie materiałów, folder wynikowy | 10 min | przeczytaj cały arkusz, zaznacz sformułowania „dokładnie”, „w akapicie”, „w kolorze” |
| Baza danych: import, kwerendy, zrzuty | 25 min | zrzuty rób od razu po każdej kwerendzie |
| HTML (zwykle 2–3 strony) | 40 min | szkielet pod skrypt: id kontrolek i pustego akapitu |
| CSS | 25 min | |
| Skrypt | 25 min | sekcja poniżej |
| Grafika / animacja | 10 min | |
Test całości w przeglądarce, przeglądarka.txt, płyta | 15 min | zostaw ten czas bezwzględnie |
Skrypt rób po HTML, ale nie na końcu – jeśli zabraknie czasu, lepiej mieć działający skrypt bez połowy CSS niż odwrotnie: skrypt to do 8 kryteriów, których nie da się nadrobić „w kodzie”, gdy strona nie działa.
Czytaj arkusz kryterium po kryterium
Oficjalne „Zasady oceniania” nie są dostępne w trakcie egzaminu, ale są przewidywalne: każde zdanie opisu skryptu to jedno kryterium. Przykładowy opis z arkusza (parafraza, styczeń 2025, INF.03-01-25.01): skrypt po kliknięciu „Oblicz” pobiera dane z kontrolek, ustala kwotę za zaznaczone kursy według cen z tabeli, dzieli ją przez liczbę rat i wyświetla pod przyciskiem w akapicie tekst „Kurs odbędzie się w <miasto>. Koszt całkowity: <kwota> zł. Płacisz <liczba> rat po <rata> zł”. Egzaminator sprawdzał to tak:
| Kryterium | Co sprawdza | Jak sprawdza |
|---|---|---|
| 5.1 | skrypt w JavaScript, co najmniej jedna instrukcja zgodna ze składnią | w kodzie |
| 5.2 | pobiera dane z co najmniej jednej kontrolki (np. document.getElementById) | w kodzie |
| 5.3 | liczy koszt zaznaczonych kursów, testując zaznaczenie każdego checkboxa | w kodzie |
| 5.4 | pobiera liczbę rat i dzieli przez nią koszt | w kodzie |
| 5.5 | wynik zawiera miasto z listy – dla dwóch różnych miast | w przeglądarce |
| 5.6 | wynik zawiera koszt całkowity | w przeglądarce |
| 5.7 | liczba rat i wysokość raty – dla dwóch różnych wartości | w przeglądarce |
| 5.8 | co najmniej jedna zmienna lub funkcja o znaczącej nazwie (PL/EN) | w kodzie |
Dwie rzeczy wynikają z tej tabeli. Po pierwsze: gdy skrypt nie uruchamia się (błąd składni, literówka w id), egzaminator sprawdza w kodzie tylko kryteria „kodowe” (język, pobranie, obliczenia, nazwy) – kryteria „wyjściowe” (tekst, miejsce, kolor) przepadają. Po drugie: „dla dwóch różnych wartości” oznacza, że egzaminator zmienia dane i klika ponownie – wynik zaszyty na sztywno, działający tylko dla jednego zestawu, nie dostanie punktu.
Zanim zaczniesz pisać, zrób z opisu własną listę kryteriów. Zdanie „wyświetla pod przyciskiem w akapicie tekst X w kolorze Y” rozbij na trzy: pod przyciskiem w akapicie, tekst dokładnie X, kolor Y. Każde z nich to osobny punkt do zdobycia – i osobny do stracenia.
Opis skryptu brzmi: „Po kliknięciu „Sprawdź” skrypt pobiera wagę i wzrost, oblicza BMI (waga / wzrost²) i wyświetla w akapicie pod przyciskiem tekst „Twoje BMI: <wynik>” zaokrąglony do jednego miejsca po przecinku”. Ile osobnych kryteriów wyjściowych (sprawdzanych w przeglądarce) najprawdopodobniej z tego wynika?
Lista kontrolna skryptu egzaminacyjnego
Przejdź ją przed oddaniem pracy. Każdy punkt odpowiada realnemu kryterium albo realnej przyczynie zera.
- Skrypt się uruchamia. Otwórz konsolę (F12) – zero czerwonych błędów po załadowaniu i po kliknięciu. Jeden błąd składni zatrzymuje cały skrypt.
- Zdarzenie zgodne z arkuszem: „po kliknięciu” →
click, „po najechaniu” →mouseover, „po opuszczeniu pola” →blur. Przycisk z arkusza ma dokładnie podany napis. <script>na końcubodyalbodefer– inaczejgetElementByIdzwracanull, bo elementów jeszcze nie ma.- Identyfikatory zgadzają się co do znaku z HTML (wielkość liter!). Wynik
nullw konsoli = literówka wid. - Konwersja na liczbę przy każdym obliczeniu:
parseFloat/parseInt/Number."5" + "3"to"53". - Każda kontrolka z opisu jest odczytana – każdy checkbox sprawdzony osobno, radio z
checked, select zvalue. - Tekst wyniku co do znaku: etykieta, dwukropek, spacje, „zł”, kropka na końcu, kolejność danych. Przepisz go z arkusza do kodu dosłownie, a wartości wstaw w miejsce nawiasów.
- Miejsce wyniku takie jak w arkuszu: akapit pod przyciskiem (
innerHTML/textContent), okno dialogowe (alert), konsola (console.log). Nie zamieniaj. - Kolor / styl, jeśli podany:
style.color = 'red','Navy'. - Zaokrąglenie zgodne z treścią: „do góry” →
Math.ceil, „do liczby całkowitej” →Math.round, „dwa miejsca” →toFixed(2). - Zawijanie, limity, stan początkowy: przetestuj galerię dookoła, pasek do 100 %, obliczenie przed jakimkolwiek kliknięciem.
- Test na dwóch zestawach danych – różne liczby, inna opcja listy, inne zaznaczenia – i na danych błędnych, jeśli arkusz wymaga walidacji.
- Znaczące nazwy zmiennych i funkcji (
obliczKoszt,liczbaRat), bez polskich znaków w identyfikatorach.a,x1,f1kosztują kryterium. - Nic ponad arkusz: nie dodawaj walidacji, gdy zadanie mówi „pominąć” – nie ma za to punktów, a może zablokować ścieżkę, którą egzaminator testuje.
- Plik zapisany w folderze wynikowym, strona otwarta ponownie z tego folderu i sprawdzona.
Gdzie uciekają punkty
| Objaw | Przyczyna | Kryterium, które przepada |
|---|---|---|
| nic się nie dzieje po kliknięciu | onclick="oblicz" bez nawiasów; addEventListener('click', oblicz()) z nawiasami; błąd składni gdziekolwiek | wszystkie wyjściowe |
Cannot read properties of null | literówka w id; skrypt w head bez defer | wszystkie wyjściowe |
| wynik „Koszt: 53 zł” zamiast 8 | brak parseFloat – konkatenacja napisów | obliczenie + tekst wyniku |
| wynik liczy tylko pierwszy kurs | sprawdzony jeden checkbox | „testując zaznaczenie każdego” |
| wynik w okienku | alert zamiast akapitu | miejsce wyświetlenia, kolor |
| „Koszt całkowity 300zł” | brak dwukropka / spacji z arkusza | tekst wyniku |
| 9,25 puszki farby | brak Math.ceil | zaokrąglenie |
| po 7. zdjęciu puste pole | brak zawijania | „po ostatnim pierwsze” |
| szerokość 112 % | brak Math.min/if | „nigdy ponad 100 %” |
| trzy zakładki widoczne naraz | brak ukrycia pozostałych | „pokazuje tylko wybraną” |
function f1(), var a, b, c | nazwy bez znaczenia | nazewnictwo (R.5.8) |
| strona „mruga” i wynik znika | <button> w <form> bez type="button" → wysłanie formularza | wyjściowe (wynik niewidoczny) |
Sprawdź, czy rozpoznasz błędy w kodzie – tak jak egzaminator, który czyta cudzy skrypt.
Zadanie: „skrypt sumuje ceny zaznaczonych zabiegów (peeling 45 zł, maska 30 zł) i wypisuje pod przyciskiem „Cena zabiegów: <suma>”. Które kryterium NIE zostanie spełnione przez ten kod?
function policz() {
var suma = 0;
if (document.getElementById('peeling').checked) {
suma = suma + 45;
suma = suma + 30;
}
document.getElementById('wynik').innerHTML = 'Cena zabiegów: ' + suma;
}Zadanie: „pod przyciskiem w akapicie wyświetla „Liczba puszek: <liczba>”, zaokrąglona w górę (1 puszka = 4 m²)”. Co straci ten skrypt?
function policzPuszki() {
var powierzchnia = document.getElementById('pow').value;
var puszki = powierzchnia / 4;
alert('Liczba puszek: ' + Math.ceil(puszki));
}Skrypt ma działać po kliknięciu przycisku. HTML: <button onclick='zmienKolor'>Zmień</button>. Co się stanie?
Jak pracować nad skryptem: 25 minut krok po kroku
- (2 min) Przeczytaj opis skryptu dwa razy i wypisz kryteria na kartce (z arkusza możesz korzystać jak z brudnopisu).
- (3 min) Szkielet, który już działa: funkcja, podpięcie do zdarzenia, wewnątrz
console.log('klik'). Kliknij. Jeśli w konsoli jest „klik”, połączenie HTML–JS jest poprawne i najgorszy scenariusz (zero kryteriów) masz z głowy. - (5 min) Pobranie danych: po jednej zmiennej na kontrolkę, od razu
parseFloattam, gdzie będziesz liczyć.console.logwszystkich zmiennych – sprawdź typy i wartości. - (5 min) Logika: obliczenie,
if/else, zawijanie, limity. Testuj w konsoli, zanim cokolwiek wypiszesz. - (5 min) Wyjście: tekst przepisany z arkusza, właściwe miejsce, kolor. Dopiero teraz patrzysz na stronę.
- (5 min) Testy: dwa zestawy danych, stan początkowy, ścieżka błędna (jeśli jest walidacja), konsola bez błędów. Usuń pomocnicze
console.logtylko wtedy, gdy arkusz czegoś nie wypisuje w konsoli celowo – inaczej mogą zostać, nie szkodzą. - (ostatnia minuta) Nazwy: przejrzyj identyfikatory – czy ktoś obcy zrozumie, co trzymają?
Nie zaczynaj od pisania całego skryptu „na raz”. Każdy etap kończy się działającym kodem, więc jeśli zabraknie czasu, oddajesz coś, co zdobywa kryteria kodowe.
Na egzaminie
Ściąga
Tabela z arkusza plus to, czego w niej nie ma, a czego używasz najczęściej:
| Składnia | Co robi | Przykład |
|---|---|---|
document.getElementById('id') | element o danym id (albo null) | const pole = document.getElementById('wiek') |
document.querySelector('sel') / querySelectorAll | element / lista wg selektora CSS | querySelectorAll('.miniatura') |
getElementsByClassName, getElementsByTagName | kolekcja (indeks, pętla) | elementy[i].style.color = 'red' |
el.value, el.checked, el.selectedIndex | odczyt kontrolek | parseFloat(pole.value) |
el.innerHTML, el.textContent | treść elementu | wynik.innerHTML = 'Koszt: ' + koszt + ' zł' |
el.style.wlasciwosc | styl inline (camelCase) | style.backgroundColor, style.display = 'none' |
el.setAttribute('atr', 'w'), el.src, el.title, el.alt | atrybuty | img.src = numer + '.jpg' |
document.createElement('tag'), rodzic.appendChild(el) | nowy element dołączony na koniec | lista.appendChild(li) |
rodzic.removeChild(el), el.remove() | usunięcie | |
el.classList.add/remove/toggle | klasy | classList.add('aktywny') |
el.addEventListener('click', f) / onclick="f()" | zdarzenia: click, mouseover, mouseout, blur, change, input, keyup | |
parseFloat, parseInt, Number, isNaN | konwersja | isNaN(parseFloat(x)) |
Math.ceil, Math.round, Math.floor, Math.random, toFixed(2) | zaokrąglenia i losowość | Math.floor(Math.random() * n) |
s.toUpperCase(), s.slice(a, b), s.lastIndexOf('x'), s.split(''), s.trim() | napisy | nazwa pliku: s.slice(s.lastIndexOf('\\') + 1) |
alert(t), console.log(t) | okno / konsola – tylko gdy arkusz tego żąda |
Zadania
Zapisy na obóz programistyczny: zakładki i pasek postępu
Strona zapisy.html ma gotową strukturę (HTML poniżej jest kompletny – twoim zadaniem jest wyłącznie skrypt). Trzy przyciski nawigacji i trzy sekcje-karty; na starcie widoczna jest tylko karta „Uczestnik” (pozostałe ukryte w CSS regułą display: none).
<nav>
<button id="btn-uczestnik" onclick="pokazKarte('uczestnik')">Uczestnik</button>
<button id="btn-szkola" onclick="pokazKarte('szkola')">Szkoła</button>
<button id="btn-kontakt" onclick="pokazKarte('kontakt')">Kontakt</button>
</nav>
<div id="pasek"><div id="postep"></div></div>
<section id="uczestnik" class="karta">
<label>Imię: <input id="imie"></label>
<label>Nazwisko: <input id="nazwisko"></label>
</section>
<section id="szkola" class="karta">
<label>Szkoła: <input id="nazwaSzkoly"></label>
<label>Klasa: <input id="klasa"></label>
</section>
<section id="kontakt" class="karta">
<label>E-mail: <input id="email"></label>
<label><input type="checkbox" id="rodo"> Zgoda na przetwarzanie danych</label>
<button type="button" onclick="zatwierdz()">Zatwierdź</button>
</section>.karta { display: none; }
#uczestnik { display: block; }
#pasek { width: 300px; height: 20px; background: #ddd; }
#postep { width: 0; height: 20px; background: green; }Skrypt wykonywany po stronie klienta:
- Kliknięcie przycisku nawigacji ukrywa wszystkie karty i pokazuje wybraną; kliknięty przycisk ma tło LightGreen, pozostałe – białe. Zrealizuj to jedną funkcją z parametrem
pokazKarte(idKarty). - Opuszczenie dowolnego z pięciu pól tekstowych (zdarzenie utraty fokusu) zwiększa szerokość paska
#postepo 20 % (20 %, 40 %, 60 %…). Zabezpiecz funkcję, aby szerokość nigdy nie przekroczyła 100 %. - Kliknięcie „Zatwierdź” wypisuje w konsoli przeglądarki jeden wiersz: „Zgłoszenie: Imię Nazwisko, Szkoła, kl. Klasa, e-mail; RODO: tak/nie” (wartości z pól; „tak” gdy checkbox zaznaczony). Dla uproszczenia walidację pomiń.
- Stosuj znaczące nazwy zmiennych i funkcji w języku polskim lub angielskim.
Kryteria (0/1):
- 5.1 Skrypt w JavaScript, co najmniej jedna poprawna składniowo instrukcja.
- 5.2 Kliknięcie przycisku nawigacji pokazuje wyłącznie wybraną kartę (sprawdzane dla dwóch różnych kart).
- 5.3 Kliknięty przycisk ma tło LightGreen, pozostałe białe.
- 5.4 Karty obsługuje jedna funkcja z parametrem.
- 5.5 Opuszczenie pola zwiększa szerokość paska o 20 %.
- 5.6 Szerokość paska nigdy nie przekracza 100 % (sprawdzane po 6 i więcej zdarzeniach).
- 5.7 „Zatwierdź” wypisuje w konsoli dane z pól w podanym formacie.
- 5.8 Znaczące nazewnictwo.
Pokaż rozwiązanie
<nav>
<button id="btn-uczestnik" onclick="pokazKarte('uczestnik')">Uczestnik</button>
<button id="btn-szkola" onclick="pokazKarte('szkola')">Szkoła</button>
<button id="btn-kontakt" onclick="pokazKarte('kontakt')">Kontakt</button>
</nav>
<div id="pasek"><div id="postep"></div></div>
<section id="uczestnik" class="karta">
<label>Imię: <input id="imie"></label>
<label>Nazwisko: <input id="nazwisko"></label>
</section>
<section id="szkola" class="karta">
<label>Szkoła: <input id="nazwaSzkoly"></label>
<label>Klasa: <input id="klasa"></label>
</section>
<section id="kontakt" class="karta">
<label>E-mail: <input id="email"></label>
<label><input type="checkbox" id="rodo"> Zgoda na przetwarzanie danych</label>
<button type="button" onclick="zatwierdz()">Zatwierdź</button>
</section>
<p><small>Wynik „Zatwierdź” pojawia się w konsoli pod podglądem.</small></p>.karta { display: none; padding: 10px 0; }
#uczestnik { display: block; }
#pasek { width: 300px; height: 20px; background: #ddd; margin: 8px 0; }
#postep { width: 0; height: 20px; background: green; }
nav button { background: white; border: 1px solid #999; padding: 6px 12px; }
input { width: 110px; }// 1. zakładki – jedna funkcja z parametrem
const NAZWY_KART = ['uczestnik', 'szkola', 'kontakt'];
function pokazKarte(idKarty) {
for (const nazwa of NAZWY_KART) {
document.getElementById(nazwa).style.display = 'none'; // ukryj każdą kartę
document.getElementById('btn-' + nazwa).style.backgroundColor = 'white'; // odznacz każdy przycisk
}
document.getElementById(idKarty).style.display = 'block';
document.getElementById('btn-' + idKarty).style.backgroundColor = 'LightGreen';
}
pokazKarte('uczestnik'); // stan początkowy: pierwszy przycisk podświetlony
// 2. pasek postępu – stan poza funkcją, limit 100
let szerokoscPaska = 0;
function zwiekszPostep() {
szerokoscPaska = Math.min(szerokoscPaska + 20, 100);
document.getElementById('postep').style.width = szerokoscPaska + '%';
}
const polaTekstowe = ['imie', 'nazwisko', 'nazwaSzkoly', 'klasa', 'email'];
for (const idPola of polaTekstowe) {
document.getElementById(idPola).addEventListener('blur', zwiekszPostep);
}
// 3. zatwierdzenie – wynik w konsoli, jak żąda arkusz
function zatwierdz() {
const imie = document.getElementById('imie').value;
const nazwisko = document.getElementById('nazwisko').value;
const szkola = document.getElementById('nazwaSzkoly').value;
const klasa = document.getElementById('klasa').value;
const email = document.getElementById('email').value;
const rodo = document.getElementById('rodo').checked ? 'tak' : 'nie';
console.log('Zgłoszenie: ' + imie + ' ' + nazwisko + ', ' + szkola + ', kl. ' + klasa + ', ' + email + '; RODO: ' + rodo);
}Samoocena: kliknij „Szkoła”, potem „Kontakt” (5.2, 5.3); co najmniej 6 razy wejdź w pole i je opuść (klik poza pole albo Tab) i sprawdź, czy pasek zatrzymał się na 100 % (5.5, 5.6); wypełnij pola i zatwierdź z zaznaczonym i niezaznaczonym checkboxem (5.7).
Drukarnia plakatów: koszyk z polem file
Strona zamowienie.html (HTML gotowy):
<label>Plik z projektem (PNG): <input type="file" id="plik" accept="image/png"></label>
<label>Liczba sztuk: <input type="number" id="sztuki" value="1" min="1"></label>
<label>Format:
<select id="format">
<option value="12">A3 – 12 zł</option>
<option value="20">A2 – 20 zł</option>
<option value="35">A1 – 35 zł</option>
</select>
</label>
<label><input type="checkbox" id="laminowanie"> Laminowanie (+3 zł/szt.)</label>
<button type="button" onclick="dodajDoKoszyka()">Dodaj do koszyka</button>
<section id="koszyk"><h2>Koszyk</h2></section>Skrypt po kliknięciu „Dodaj do koszyka”:
- Ustala nazwę pliku bez ścieżki dostępu z pola
file(przeglądarka zwraca wartość w postaciC:\fakepath\nazwa.png). - Oblicza cenę pozycji: liczba sztuk × cena formatu (z wartości opcji) + 3 zł za sztukę, jeśli zaznaczono laminowanie.
- Dokleja na końcu sekcji
#koszyknowy blokdivz klasąpozycja, zawierający: elementimgosrcialtrównych nazwie pliku oraz klasieminiatura, akapit „Plik: <nazwa>, format <A3/A2/A1>, <sztuki> szt.” oraz akapit „Cena: <cena> zł”. Kolejne kliknięcia dopisują kolejne pozycje; pozycje nie są usuwane. - Pod nagłówkiem koszyka akapit
<p id="suma">pokazuje „Razem: <suma> zł” – sumę wszystkich pozycji (utwórz go skryptem przy pierwszym dodaniu albo wpisz w HTML). - Znaczące nazwy zmiennych i funkcji.
Kryteria (0/1):
- 5.1 JavaScript, funkcja wywoływana przyciskiem.
- 5.2 Pobiera dane z co najmniej jednej kontrolki.
- 5.3 Nazwa pliku ustalona bez ścieżki dostępu.
- 5.4 Cena uwzględnia liczbę sztuk, format i laminowanie – sprawdzane dla dwóch różnych zestawów.
- 5.5 Nowa pozycja tworzona elementami DOM (
createElement/appendChild) i dołączana na końcu koszyka; kolejne kliknięcia dodają kolejne. - 5.6 Element
imgmasrc,altrówne nazwie pliku i klasęminiatura. - 5.7 Teksty pozycji i sumy zgodne z formatem.
- 5.8 Znaczące nazewnictwo.
Pokaż rozwiązanie
W placu zabaw obrazek się nie wyświetli (nie ma pliku), zobaczysz tekst alternatywny – na egzaminie plik leży w folderze strony i miniatura się pokaże.
<p><label>Plik z projektem (PNG): <input type="file" id="plik" accept="image/png"></label></p>
<p><label>Liczba sztuk: <input type="number" id="sztuki" value="1" min="1"></label>
<label>Format:
<select id="format">
<option value="12">A3 – 12 zł</option>
<option value="20">A2 – 20 zł</option>
<option value="35">A1 – 35 zł</option>
</select>
</label>
<label><input type="checkbox" id="laminowanie"> Laminowanie (+3 zł/szt.)</label></p>
<button type="button" onclick="dodajDoKoszyka()">Dodaj do koszyka</button>
<section id="koszyk"><h2>Koszyk</h2><p id="suma">Razem: 0 zł</p></section>.pozycja { border: 1px solid #ccc; padding: 6px; margin: 6px 0; display: flex; gap: 10px; align-items: center; }
.pozycja p { margin: 0; }
.miniatura { width: 60px; height: 40px; background: #eee; font-size: 11px; }
input[type=number] { width: 50px; }
h2 { font-size: 16px; margin: 8px 0 4px; }let sumaKoszyka = 0; // stan: suma wszystkich pozycji
function nazwaPlikuBezSciezki(sciezka) {
// 'C:\fakepath\plakat.png' → 'plakat.png'; pusta wartość → ''
return sciezka.slice(sciezka.lastIndexOf('\\') + 1);
}
function dodajDoKoszyka() {
const nazwaPliku = nazwaPlikuBezSciezki(document.getElementById('plik').value);
const sztuki = parseInt(document.getElementById('sztuki').value);
const listaFormatow = document.getElementById('format');
const cenaFormatu = parseFloat(listaFormatow.value); // np. 20
const nazwaFormatu = listaFormatow.options[listaFormatow.selectedIndex].text.slice(0, 2); // 'A2'
const laminowanie = document.getElementById('laminowanie').checked;
let cenaSztuki = cenaFormatu;
if (laminowanie) cenaSztuki += 3;
const cenaPozycji = sztuki * cenaSztuki;
// nowy blok pozycji – elementy DOM
const pozycja = document.createElement('div');
pozycja.className = 'pozycja';
const miniatura = document.createElement('img');
miniatura.src = nazwaPliku; // plik z folderu strony
miniatura.alt = nazwaPliku;
miniatura.className = 'miniatura';
const opis = document.createElement('p');
opis.textContent = 'Plik: ' + nazwaPliku + ', format ' + nazwaFormatu + ', ' + sztuki + ' szt.';
const cena = document.createElement('p');
cena.textContent = 'Cena: ' + cenaPozycji + ' zł';
pozycja.appendChild(miniatura);
pozycja.appendChild(opis);
pozycja.appendChild(cena);
document.getElementById('koszyk').appendChild(pozycja); // na końcu koszyka
sumaKoszyka += cenaPozycji;
document.getElementById('suma').textContent = 'Razem: ' + sumaKoszyka + ' zł';
}Dwa zestawy testowe: 2 szt. A2 bez laminowania → 40 zł; 3 szt. A3 z laminowaniem → 3 × 15 = 45 zł; suma 85 zł.
Wypożyczalnia rowerów: galeria z pętli i obliczenie wg stanu
Strona rowery.html (HTML gotowy, folder zawiera pliki rower1.jpg…rower6.jpg oraz rower1d.jpg…rower6d.jpg):
<div id="miniatury"></div>
<div id="galeria">
<button id="poprzedni"><</button>
<img id="duzy" src="rower1d.jpg" alt="Rower 1">
<button id="nastepny">></button>
</div>
<p id="opis">Rower 1 – miejski, 10 zł/h</p>
<label>Liczba godzin: <input type="number" id="godziny" value="1" min="1"></label>
<button id="oblicz">Oblicz</button>
<p id="koszt"></p>Skrypt wykonywany po stronie klienta:
- Pętla tworzy w bloku
#miniaturysześć obrazówrower1.jpg…rower6.jpg, każdy z klasąminiatura, tekstem alternatywnym „Rower N” i dymkiem (title) „Rower N” (N = numer). - Kliknięcie miniatury wyświetla w
#duzyplikrowerNd.jpgi aktualizuje akapit#opis: „Rower N – miejski, 10 zł/h” dla rowerów 1–3 albo „Rower N – górski, 16 zł/h” dla 4–6. - Przyciski „<” i „>” zmieniają duży obraz na poprzedni/następny z zawijaniem: po 6 → 1, przed 1 → 6 (z aktualizacją opisu).
- „Oblicz” pobiera liczbę godzin, sprawdza, który rower jest aktualnie wyświetlony, i wypisuje pod przyciskiem „Rower N, <godziny> h: <koszt> zł” wg stawki 10 lub 16 zł/h. Ma działać także dla stanu początkowego (rower 1).
- Znaczące nazwy.
Kryteria (0/1):
- 5.1 JavaScript, co najmniej jedna poprawna instrukcja.
- 5.2 Miniatury tworzone pętlą (
createElementw pętli), każda z klasą,altititlez numerem. - 5.3 Kliknięcie miniatury zmienia
srcdużego obrazu na właściwy plik i opis. - 5.4 „>” po ostatnim pokazuje pierwszy, „<” przed pierwszym – ostatni.
- 5.5 Skrypt pobiera liczbę godzin z pola.
- 5.6 Koszt zależy od wyświetlonego roweru – sprawdzane dla roweru miejskiego, górskiego i stanu początkowego.
- 5.7 Tekst wyniku pod przyciskiem w podanym formacie – dla dwóch liczb godzin.
- 5.8 Znaczące nazewnictwo.
Pokaż rozwiązanie
<div id="miniatury"></div>
<div id="galeria">
<button id="poprzedni"><</button>
<img id="duzy" alt="Rower 1">
<button id="nastepny">></button>
</div>
<p id="opis">Rower 1 – miejski, 10 zł/h</p>
<p><label>Liczba godzin: <input type="number" id="godziny" value="1" min="1"></label>
<button id="oblicz">Oblicz</button></p>
<p id="koszt"></p>.miniatura { width: 48px; height: 32px; margin-right: 4px; cursor: pointer; }
#galeria { display: flex; align-items: center; gap: 8px; margin-top: 6px; }
#duzy { width: 200px; height: 110px; }
input[type=number] { width: 50px; }
p { margin: 6px 0; }// Zamiennik plików rowerN.jpg / rowerNd.jpg – na egzaminie wpisujesz nazwy plików.
function obrazek(numer, szer, wys) {
const kolor = numer <= 3 ? 'SteelBlue' : 'DarkOliveGreen';
const svg = '<svg xmlns="http://www.w3.org/2000/svg" width="' + szer + '" height="' + wys + '">' +
'<rect width="' + szer + '" height="' + wys + '" fill="' + kolor + '"/>' +
'<text x="' + szer / 2 + '" y="' + (wys / 2 + 6) + '" font-size="' + wys / 3 + '" fill="white" text-anchor="middle" font-family="system-ui">rower' + numer + '</text></svg>';
return 'data:image/svg+xml;utf8,' + encodeURIComponent(svg);
}
function plikMiniatury(numer) { return obrazek(numer, 48, 32); } // egzamin: 'rower' + numer + '.jpg'
function plikDuzy(numer) { return obrazek(numer, 200, 110); } // egzamin: 'rower' + numer + 'd.jpg'
const LICZBA_ROWEROW = 6;
let numerRoweru = 1; // stan: który rower jest wyświetlony
const duzy = document.getElementById('duzy');
function stawka(numer) { return numer <= 3 ? 10 : 16; }
function typRoweru(numer) { return numer <= 3 ? 'miejski' : 'górski'; }
function pokazRower(numer) {
numerRoweru = numer;
duzy.src = plikDuzy(numer);
duzy.alt = 'Rower ' + numer;
document.getElementById('opis').textContent =
'Rower ' + numer + ' – ' + typRoweru(numer) + ', ' + stawka(numer) + ' zł/h';
}
// 1. miniatury generowane pętlą
const blokMiniatur = document.getElementById('miniatury');
for (let i = 1; i <= LICZBA_ROWEROW; i++) {
const miniatura = document.createElement('img');
miniatura.src = plikMiniatury(i);
miniatura.alt = 'Rower ' + i;
miniatura.title = 'Rower ' + i; // dymek
miniatura.className = 'miniatura';
miniatura.addEventListener('click', () => pokazRower(i)); // każda zna swój numer
blokMiniatur.appendChild(miniatura);
}
// 3. galeria z zawijaniem
document.getElementById('nastepny').addEventListener('click', () => {
let nowy = numerRoweru + 1;
if (nowy > LICZBA_ROWEROW) nowy = 1;
pokazRower(nowy);
});
document.getElementById('poprzedni').addEventListener('click', () => {
let nowy = numerRoweru - 1;
if (nowy < 1) nowy = LICZBA_ROWEROW;
pokazRower(nowy);
});
// 4. obliczenie zależne od stanu
document.getElementById('oblicz').addEventListener('click', () => {
const godziny = parseInt(document.getElementById('godziny').value);
const koszt = godziny * stawka(numerRoweru);
document.getElementById('koszt').textContent =
'Rower ' + numerRoweru + ', ' + godziny + ' h: ' + koszt + ' zł';
});
pokazRower(1); // stan początkowy zgodny z HTMLWersja bez zmiennej stanu, odczytująca numer z adresu obrazu (jak przy plikach rowerNd.jpg): const numer = parseInt(duzy.getAttribute('src').replace('rower', '')); – parseInt zatrzyma się na literze d. Obie wersje są poprawne; zmienna jest czytelniejsza.
Test powtórkowy
Test powtórkowy
Zasady egzaminu i czytanie kryteriów – sprawdź, czy wiesz, o co gra.
Ile trwa część praktyczna egzaminu INF.03 i jaki jest próg zdania?
Z czego możesz korzystać podczas pisania skryptu na stanowisku egzaminacyjnym?
Skrypt nie uruchamia się z powodu błędu składni. Które kryteria egzaminator może jeszcze przyznać na podstawie kodu źródłowego?
Kryterium brzmi: „wynik zawiera miasto wybrane z listy – sprawdzane dla dwóch różnych miast”. Który skrypt go NIE spełni?
Który zrzut ekranu z wykonanych kwerend zostanie oceniony?
Arkusz: „pasek rośnie o 12 % przy każdym opuszczeniu pola; szerokość nigdy nie może przekroczyć 100 %”. Który fragment spełnia oba wymagania?
// A
szer = szer + 12; pasek.style.width = szer + '%';
// B
szer = Math.min(szer + 12, 100); pasek.style.width = szer + '%';
// C
if (szer < 100) pasek.style.width = '100%';
// D
szer = szer + 12; if (szer == 100) szer = 100;HTML strony ma <p id='Wynik'></p>, a skrypt wykonuje document.getElementById('wynik').innerHTML = koszt;. Co zobaczy egzaminator?
W którym miejscu dokumentu należy umieścić <script>, aby document.getElementById znajdował elementy strony bez dodatkowych atrybutów?
Zadanie wymaga „znaczącego nazewnictwa zmiennych i funkcji w języku polskim lub angielskim”. Który zestaw nazw spełnia kryterium?
Arkusz mówi: „dla uproszczenia wszelką walidację należy pominąć”. Co powinieneś zrobić?