INF.03-02-24.06-SGCzerwiec 2024 · 54 kroki · ok. 92 min · 40 kryteriów z klucza
Rozwiązanie krok po kroku: Prototyp front-endu chatu (Wersja podstawowa)
Prototyp chatu to baza chat (uczestnicy i dane logowania) z pięcioma zapytaniami - INSERT z identyfikatorem wziętym z relacji, średnia AVG zaokrąglona w dół FLOOR z aliasem, JOIN z LIKE, a na koniec CREATE USER i GRANT - oraz zdjęcie przycięte w edytorze grafiki i strona chat.html z oknem rozmowy. Skrypt JavaScript dokłada do okna wiadomość wpisaną w pole (jako wypowiedź Jolanty) albo losową odpowiedź Krzysztofa z tablicy dziewięciu tekstów i przewija okno do nowej wypowiedzi.
Kroki idą zdanie po zdaniu za treścią arkusza - przy każdym jest polecenie z arkusza, a kod pokazuje dokładnie te linie, które je spełniają. Skrypt jest najpierw napisany najprościej, funkcjami z tabel 1 i 2 arkusza (createElement, classList.add, innerText, appendChild, scrollIntoView, zdarzenie onclick), a na końcu przerobiony na wersję z prawdziwych projektów: jedna wspólna funkcja zamiast dwóch kopii, pomijanie pustych wiadomości, wysyłanie klawiszem Enter i nasłuchiwacze zdarzeń.
To jest wersja podstawowa. W zakładce „Nowoczesny kod (grid, addEventListener)” jest drugi sposób rozwiązania tego samego arkusza: bloki na siatce CSS, formularz z obsługą klawisza Enter i jedna funkcja tworząca wypowiedź od początku, zdarzenia podpięte przez addEventListener - obie wersje są zgodne z kluczem.
Baza, zdjęcia i teksty odpowiedzi pochodzą z prawdziwego archiwum pliki2 (załącznik do arkusza, hasło w treści zadania). Zrzuty wyników zapytań są odtworzone z tej bazy - na egzaminie robisz je sam, z całego ekranu. Działanie skryptu jest sprawdzone w prawdziwej przeglądarce Chrome.
Jak liczą się punkty. Klucz ma 40 kryteriów (R.1.1 - R.5.9), każde za 1 punkt. Próg zdania części praktycznej to 75%, czyli 30 punktów - można stracić 10 kryteriów i nadal zdać. Przy każdym kroku jest napisane, które kryteria spełnia; egzaminator ocenia spełnienie kryteriów z klucza, nie zgodność z tym kodem.
Suwak i strzałki obok niego - albo ←→ na klawiaturze - przechodzą krok po kroku; wyjaśnienie, pliki i podgląd zmieniają się razem z krokiem.
Lista „Etap” przenosi od razu do wybranego etapu.
„Rozwiązuję samodzielnie” chowa rozwiązanie kroku - najpierw własna próba, potem odsłonięcie.
„Tryb prezentacji” pokazuje same kroki, bez menu strony - na rzutnik.
Etap 1: Baza danych
Kroki 1-8 · po tym etapie masz 7 z 40 kryteriów (pkt)
Krok 1: Baza danych chat
ok. 2 min
Polecenie z arkusza
Utwórz bazę danych o nazwie chat, z zestawem polskich znaków (np. utf8_unicode_ci)
Najpierw archiwum pliki2.zip z pulpitu (hasło ChaT_Ch@t, wielkość liter ma znaczenie) i folder z numerem zdającego - arkusz każe umieścić w nim rozpakowane pliki. W phpMyAdmin: Nowa, nazwa chat, porównywanie utf8_unicode_ci.
Krok 2: Import tabel z pliku baza.sql
ok. 2 min
Polecenie z arkusza
Do bazy zaimportuj tabele z pliku baza.sql z rozpakowanego archiwum
Zaznaczona baza chat, potem Import → baza.sql → Wykonaj. Powstają dwie tabele z obrazu 1: logowanie (nick i hasło, na razie 2 wiersze) i uczestnicy (3 osoby). Pole logowanie_id uczestnika wskazuje jego wiersz w tabeli logowanie - Jeremi Kowalski ma już logowanie_id = 3, choć wiersza o tym identyfikatorze jeszcze nie ma.
Krok 3: Zrzut ekranu import.png
Kryteria:
R.1.1 Wykonano import tabel do bazy danych chat czynność udokumentowano plikiem o nazwie import w formacie PNG
ok. 2 min
Polecenie z arkusza
Wykonaj zrzut ekranu po imporcie. Zrzut zapisz w formacie PNG i nazwij import. Nie kadruj zrzutu. Powinien on obejmować cały ekran monitora, z widocznym paskiem zadań. Na zrzucie powinny być widoczne elementy wskazujące na poprawnie wykonany import tabel.
Print Screen, wklejenie do edytora grafiki i zapis jako import.png. Uwaga na formaty: import idzie do PNG, a zrzuty zapytań do JPEG.
Typowe błędy
Wykadrowany zrzut albo zrzut bez paska zadań nie jest oceniany (uwaga w kluczu przy R.1).
Krok 4: Zapytanie 1: dane logowania Jeremiego
Kryteria: ,
R.1.2 Zapisano plik kwerendy.txt zawierający co najmniej jedno zapytanie SQL, wynikające z treści zadania
R.1.3 Wykonano zapytanie 1 wstawiające do tabeli logowanie nick "Jeremi" z hasłem „Jer123” o id=3. W pliku z kwerendami lub na zrzucie istnieje zapis np.: INSERT INTO `logowanie`(`id`, `nick`, `haslo`) VALUES (3, 'Jeremi','Jer123'); oraz wynik działania udokumentowano zrzutem, na którym jest widoczne pomyślnie wykonane zapytanie lub tabela ze wstawionym wierszem o id=3
ok. 2 min
Polecenie z arkusza
Zapytanie 1: wstawiające do tabeli logowanie nick „Jeremi” z hasłem „Jer123”. Wstawianemu wierszowi należy nadać identyfikator, odpowiadający wartości klucza obcego dla wiersza z danymi „Jeremi Kowalski” z tabeli uczestnicy
INSERT INTO logowanie (id, nick, haslo) - tym razem identyfikator podaje się sam, bo musi pasować do relacji,
VALUES (3, 'Jeremi', 'Jer123') - trójka to wartość logowanie_id w wierszu Jeremiego Kowalskiego w tabeli uczestnicy (wystarczy ją odczytać w phpMyAdmin).
Tabela logowanie nie ma w tym dumpie AUTO_INCREMENT, więc bez podanego id wiersz dostałby zero. Zapytania trafiają do kwerendy.txt, zrzut z komunikatem albo z wstawionym wierszem do kw1.jpg.
Krok 5: Zapytanie 2: średni rok urodzenia zaokrąglony w dół
Kryteria:
R.1.4 Wykonano zapytanie 2 obliczające średni rok urodzenia uczestników. Wybrana kolumna powinna nosić nazwę "Średni rok urodzenia", a obliczony wynik powinien być zaokrąglony do najbliższej mniejszej liczby całkowitej. W pliku z kwerendami lub na zrzucie istnieje zapis np.: SELECT FLOOR(AVG(rokUr)) AS "Średni rok urodzenia" FROM uczestnicy; oraz wynik działania udokumentowano zrzutem, na którym jest widoczna wartość całkowita 2001, nazwa kolumny (alias) "Średni rok urodzenia"
ok. 2 min
Polecenie z arkusza
Zapytanie 2: obliczające średni rok urodzenia uczestników. Wybrana kolumna powinna mieć nazwę (alias) „Średni rok urodzenia”, a obliczony wynik powinien być zaokrąglony w dół do liczby całkowitej
AVG(rokUr) - średnia z kolumny rokUr wszystkich uczestników,
FLOOR(AVG(rokUr)) - zaokrąglenie średniej w dół do liczby całkowitej (tabela 3 arkusza; ROUND zaokrągla do najbliższej, CEIL w górę),
AS `Średni rok urodzenia` - alias ze spacjami trzeba ująć w lewe apostrofy albo w cudzysłów.
Wynik: 2001. Zrzut: kw2.jpg.
Typowe błędy
Alias bez cudzysłowu (AS Średni rok urodzenia) to błąd składni - po pierwszym słowie MySQL oczekuje słowa FROM.
kwerendy.txtTekstzmienione: 3 linie
-- Zapytanie 1INSERT INTO logowanie (id, nick, haslo) VALUES (3, 'Jeremi', 'Jer123');-- Zapytanie 2SELECT FLOOR(AVG(rokUr)) AS `Średni rok urodzenia` FROM uczestnicy;
Podgląd strony po tym kroku
Krok 6: Zapytanie 3: uczestnicy na J z danymi logowania
Kryteria:
R.1.5 Wykonano zapytanie 3 wybierające jedynie imię i nazwisko uczestnika oraz odpowiadające mu nick i hasło dla imion rozpoczynających się literą J. W pliku z kwerendami lub na zrzucie istnieje zapis np.: SELECT imie, nazwisko, nick, haslo FROM uczestnicy JOIN logowanie ON logowanie_id = logowanie.id WHERE imie LIKE "J%"; (możliwe również INNER JOIN lub bez JOIN i porównanie kluczy po WHERE) oraz wynik działania udokumentowano zrzutem, na którym są widoczne dokładnie 2 rekordy: Jolanta Nowak Jolka Jol123; Jeremi Kowalski Jeremi Jer123. Jeżeli nie wykonano R.1.3 jest widoczny dokładnie 1 rekord dla Jolanty
ok. 2 min
Polecenie z arkusza
Zapytanie 3: wybierające jedynie imię i nazwisko uczestnika oraz odpowiadające mu nick i hasło dla imion rozpoczynających się literą J. Należy posłużyć się relacją
SELECT imie, nazwisko, nick, haslo - dwa pola z uczestnicy, dwa z logowanie,
FROM uczestnicy JOIN logowanie - złączenie,
ON uczestnicy.logowanie_id = logowanie.id - relacja z obrazu 1,
WHERE imie LIKE 'J%' - % zastępuje dowolny ciąg znaków, więc wzorzec łapie każde imię zaczynające się od „J”.
Wynik: Jolanta Nowak Jolka Jol123 i Jeremi Kowalski Jeremi Jer123 - Jeremi jest w wyniku tylko dzięki zapytaniu 1 (bez niego złączenie nie znalazłoby pary). Zrzut: kw3.jpg.
kwerendy.txtTekstzmienione: 3 linie
-- Zapytanie 1INSERT INTO logowanie (id, nick, haslo) VALUES (3, 'Jeremi', 'Jer123');-- Zapytanie 2SELECT FLOOR(AVG(rokUr)) AS `Średni rok urodzenia` FROM uczestnicy;-- Zapytanie 3SELECT imie, nazwisko, nick, haslo FROM uczestnicy JOIN logowanie ON uczestnicy.logowanie_id = logowanie.id WHERE imie LIKE 'J%';
Podgląd strony po tym kroku
Krok 7: Zapytanie 4: użytkownik uczestnik
Kryteria:
R.1.6 Wykonano zapytanie 4 tworzące użytkownika uczestnik na localhost z hasłem Ucz123& W pliku z kwerendami lub na zrzucie istnieje zapis np.: CREATE USER uczestnik@localhost IDENTIFIED BY "Ucz123&" oraz wynik działania udokumentowano zrzutem, na którym widoczne jest poprawnie wykonane zapytanie
ok. 2 min
Polecenie z arkusza
Zapytanie 4: tworzące użytkownika uczestnik na localhost z hasłem Ucz123&
CREATE USER 'uczestnik'@'localhost' - konto serwera MySQL (nie wiersz tabeli): nazwa i host, z którego wolno się logować,
IDENTIFIED BY 'Ucz123&' - hasło w apostrofach.
Zapytanie nie zwraca wierszy - na zrzucie kw4.jpg widać komunikat o poprawnym wykonaniu. Zapytania 4 i 5 wpisuje się w zakładce SQL serwera albo bazy - działają w obu miejscach.
kwerendy.txtTekstzmienione: 3 linie
-- Zapytanie 1INSERT INTO logowanie (id, nick, haslo) VALUES (3, 'Jeremi', 'Jer123');-- Zapytanie 2SELECT FLOOR(AVG(rokUr)) AS `Średni rok urodzenia` FROM uczestnicy;-- Zapytanie 3SELECT imie, nazwisko, nick, haslo FROM uczestnicy JOIN logowanie ON uczestnicy.logowanie_id = logowanie.id WHERE imie LIKE 'J%';-- Zapytanie 4CREATE USER 'uczestnik'@'localhost' IDENTIFIED BY 'Ucz123&';
Podgląd strony po tym kroku
Krok 8: Zapytanie 5: prawa SELECT i UPDATE do tabeli uczestnicy
Kryteria:
R.1.7 Wykonano zapytanie 5 nadające utworzonemu użytkownikowi prawa do wybierania i aktualizacji danych jedynie dla tabeli uczestnicy . W pliku z kwerendami lub na zrzucie istnieje zapis np.: GRANT SELECT, UPDATE ON chat.uczestnicy TO uczestnik@localhost; oraz wynik działania udokumentowano zrzutem, na którym widoczne jest poprawnie wykonane zapytanie lub użytkownik z przydzielonymi prawami SELECT, UPDATE
ok. 2 min
Polecenie z arkusza
Zapytanie 5: nadające utworzonemu użytkownikowi prawa do wybierania i aktualizacji danych jedynie dla tabeli uczestnicy
GRANT SELECT, UPDATE - wybieranie i aktualizacja danych,
ON chat.uczestnicy - tylko ta jedna tabela tej bazy (chat.* dałoby prawa do wszystkich tabel),
TO 'uczestnik'@'localhost'.
Sprawdzone: SHOW GRANTS pokazuje GRANT SELECT, UPDATE ON chat.uczestnicy, a po zalogowaniu jako uczestnik zapytanie do tabeli uczestnicy działa, a do logowanie kończy się odmową („SELECT command denied”). Zrzut: kw5.jpg.
kwerendy.txtTekstzmienione: 3 linie
-- Zapytanie 1INSERT INTO logowanie (id, nick, haslo) VALUES (3, 'Jeremi', 'Jer123');-- Zapytanie 2SELECT FLOOR(AVG(rokUr)) AS `Średni rok urodzenia` FROM uczestnicy;-- Zapytanie 3SELECT imie, nazwisko, nick, haslo FROM uczestnicy JOIN logowanie ON uczestnicy.logowanie_id = logowanie.id WHERE imie LIKE 'J%';-- Zapytanie 4CREATE USER 'uczestnik'@'localhost' IDENTIFIED BY 'Ucz123&';-- Zapytanie 5GRANT SELECT, UPDATE ON chat.uczestnicy TO 'uczestnik'@'localhost';
Podgląd strony po tym kroku
Etap 2: Grafika i strona HTML
Kroki 9-30 · po tym etapie masz 19 z 40 kryteriów (pkt)
Krok 9: Jolka.jpg: kadr do kwadratu z całą twarzą
ok. 3 min
Polecenie z arkusza
Grafika Jolka.jpg przygotowana, podobnie jak Krzysiek.jpg. Grafikę Jolka.jpg należy wykadrować do kwadratu tak, aby była widoczna tylko cała twarz. Następnie należy przeskalować dokładnie do rozmiaru 70 px na 70 px.
Wzorem jest Krzysiek.jpg z archiwum: sama twarz, 70 × 70 pikseli. Oryginał Jolka.jpg ma 640 × 427 i pokazuje całą postać na tle drzew. W GIMP-ie: narzędzie Zaznaczanie prostokątne z opcją Stałe: Proporcje 1:1 (zaznaczenie zawsze kwadratowe), obrys od czoła do brody i od policzka do policzka, potem Obraz → Przytnij do zaznaczenia. W tym rozwiązaniu kwadrat ma 180 × 180 pikseli i zaczyna się w punkcie (165, 70) - widać całą twarz, a tło prawie znika.
Podgląd strony po tym kroku
Krok 10: Jolka.jpg: skala do 70 × 70 px
Kryteria:
R.2.1 Plik Jolka.jpg wykadrowano do kwadratu, tak, aby była widoczna cała twarz. Wymiary grafiki to 70 px na 70 px
ok. 2 min
Polecenie z arkusza
Grafika Jolka.jpg przygotowana, podobnie jak Krzysiek.jpg. Grafikę Jolka.jpg należy wykadrować do kwadratu tak, aby była widoczna tylko cała twarz. Następnie należy przeskalować dokładnie do rozmiaru 70 px na 70 px.
Obraz → Skaluj obraz, szerokość i wysokość 70 px. Kadr jest kwadratem, więc proporcje się nie zmieniają i twarz nie jest spłaszczona. Eksport pod tą samą nazwą: Plik → Nadpisz Jolka.jpg (albo Wyeksportuj jako). Teraz oba zdjęcia mają ten sam rozmiar, co przyda się w blokach wypowiedzi wysokich na 70 px.
Typowe błędy
Skalowanie całego zdjęcia 640 × 427 do 70 × 70 bez kadrowania spłaszcza postać i nie pokazuje „tylko twarzy”.
Podgląd strony po tym kroku
Krok 11: Plik chat.html w HTML5
ok. 1 min
Polecenie z arkusza
Składa się ze strony o nazwie chat.html zapisanej w języku HTML5
Deklaracja <!DOCTYPE html>, sekcje head i body. Strona nie ma skryptów PHP, więc wystarczy rozszerzenie .html - plik otwiera się w przeglądarce prosto z folderu.
R.2.2 Witrynę internetową zapisano w pliku chat.html oraz zapisano jawnie standard kodowania polskich znaków i deklarację HTML5 <!DOCTYPE HTML> i zadeklarowano język witryny polski np.<HTML lang="pl">. Strona zawiera sekcje head i body
ok. 1 min
Polecenie z arkusza
Jawnie zastosowany właściwy standard kodowania polskich znaków
<meta charset="UTF-8"> jako pierwszy element <head>. Ten krok zamyka kryterium R.2.2: nazwa pliku, deklaracja HTML5, język i kodowanie.
R.3.5 Strona zawiera działające połączenie z zewnętrznym arkuszem stylów o nazwie styl.css , formatowanie CSS pochodzi jedynie z tego arkusza Uwaga: kryterium to nie jest spełnione również, gdy zdający źle przypisał co najmniej jeden selektor do bloku (np. kropka zamiast #)
ok. 1 min
Polecenie z arkusza
Arkusz stylów w pliku o nazwie styl.css prawidłowo połączony z kodem strony
Nazwa pliku: styl.css (nie style.css). Klucz przypomina, że R.3.5 przepada także wtedy, gdy któryś selektor jest źle zapisany, np. kropka zamiast # przy identyfikatorze.
R.2.4 Układ strony zdefiniowano dzieląc ją na bloki: banera, boczny, główny oraz stopkę. Zastosowano semantyczne znaczniki sekcji HTML5 zgodnie z ich znaczeniem, w tym do części nagłówkowej - header, stopki - footer, dopuszcza się zagnieżdżenie bloków div w znacznikach semantycznych
ok. 2 min
Polecenie z arkusza
Podział strony na baner i pod nim blok główny, obok obu bloków blok boczny oraz na dole stopka. Podział zrealizowany wyłącznie za pomocą semantycznych znaczników sekcji języka HTML5 tak, aby po uruchomieniu w przeglądarce wygląd układu bloków był zgodny z obrazem 2
Baner to header, stopka footer (klucz wymienia je wprost), blok boczny aside, główny main (R.2.4). Kolejność w kodzie - baner, boczny, główny, stopka - jest taka jak kolejność opisu zawartości bloków w arkuszu i ułatwi ułożenie bloków w CSS: blok boczny musi stanąć obok banera, więc w kodzie stoi tuż za nim.
Krok 20: Lista numerowana zagnieżdżona w drugim elemencie
Kryteria:
R.2.8 W bloku bocznym umieszczono jedną listę punktowaną o dwóch elementach, z czego drugi zagnieżdża jedną listę numerowaną o czterech elementach. Zastosowano znaczniki <ul>, <ol>, <li>, zagnieżdżenie wewnątrz znacznika <li>
ok. 2 min
Polecenie z arkusza
Drugi element zagnieżdża listę numerowaną z elementami „Turystyczny”, „Żeglarski”, „Filatelistyczny”, „Hodowla zwierzątek domowych”
„Zagnieżdża” znaczy: lista <ol> stoi wewnątrz elementu <li> z tekstem „Tematyczne”, przed jego zamykającym znacznikiem </li> - klucz sprawdza to wprost (R.2.8). Lista numerowana obok <ul> (po </li>) byłaby błędem składni HTML, bo w <ul> mogą stać tylko elementy <li>.
Obraz Jolka.jpg z tekstem alternatywnym "Jolanta Nowak"
Przycięte i przeskalowane zdjęcie z etapu grafiki. Nazwa pliku z wielką literą, jak w archiwum - na serwerze wielkość liter w nazwach plików ma znaczenie.
Zawartość bloku głównego: Blok chatu zawierający: Jeden blok z wypowiedzią Jolanty: Obraz Jolka.jpg i paragraf: „Cześć idziesz jutro do kina?”
Blok chatu to <div id="chat"> - jeden na stronie, więc identyfikator (po nim skrypt znajdzie okno rozmowy). Wypowiedź to <div> z dwiema klasami naraz, rozdzielonymi spacją: message (wspólny wygląd wszystkich wypowiedzi) i jolanta (kolor tła i obraz po lewej). Klucz wymaga, żeby wspólny styl był nadany klasą - identyfikator byłby błędem (R.4.9), bo wypowiedzi będzie wiele.
R.3.2 W bloku głównym zdefiniowano blok okna chatu zawierający dwa bloki
R.2.6 W oknie chatu oraz bloku bocznym umieszczono dwa obrazy Jolka.jpg i Krzysiek.jpg
ok. 1 min
Polecenie z arkusza
Jeden blok z wypowiedzią Krzysztofa: Obraz Krzysiek.jpg i paragraf: „Tak! A ty?”
Ta sama budowa z klasą krzysztof. Obraz stoi w kodzie przed paragrafem także tutaj - na prawą stronę przeniesie go CSS. Okno chatu zawiera teraz dwa bloki (R.3.2), a zdjęcia obojga uczestników są i w oknie chatu, i w bloku bocznym (R.2.6).
R.3.4 Dla dowolnego przycisku zdefiniowano zdarzenie związane z jego kliknięciem, które odwołuje się do funkcji w skrypcie (atrybut onClick lub słuchacz zdarzenia click lub właściwość onclick obiektu DOM)
ok. 2 min
Polecenie z arkusza
Obok siebie: napis „Wpisz wiadomość:”, pole edycyjne, przycisk o treści „Wyślij”. Kliknięcie przycisku powoduje wywołanie funkcji skryptu
Napis to <label> powiązany z polem przez for/id - kliknięcie w niego ustawia kursor w polu. Etykieta, pole i przycisk są elementami liniowymi, więc stoją obok siebie bez żadnego CSS. Atrybut onclick wywołuje funkcję sendMessage, którą napisze etap JavaScript. <br> przenosi kolejny przycisk do nowej linii („poniżej”).
R.2.5 W bloku banera zapisano nagłówek h2 "Chat", w bloku bocznym h3: "Chaty" i "Uczestnicy", poniżej dwa paragrafy, w bloku stopki nagłówek h5: "Chat wykonał: " z numerem zdającego. W oknie chatu zapisano dwa paragrafy
ok. 1 min
Polecenie z arkusza
Zawartość stopki: nagłówek piątego stopnia o treści: „Chat wykonał: ”, dalej wstawiony numer zdającego.
Tym razem nie paragraf, a nagłówek <h5>. Na egzaminie w miejscu imienia i nazwiska wpisuje się numer zdającego, czyli PESEL; w tym rozwiązaniu stoi tam „Bartosz Bryniarski”. Strona ma już wszystkie nagłówki i paragrafy z klucza (R.2.5).
R.3.1 Układ bloków po uruchomieniu strony w przeglądarce jest zgodny z obrazem 2 w arkuszu egzaminacyjnym, nie należy brać pod uwagę zawartości bloku głównego (prawidłowo zastosowano właściwości CSS decydujące o układzie strony, np. float i clear albo display flex albo grid)
ok. 3 min
Polecenie z arkusza
Podział strony na baner i pod nim blok główny, obok obu bloków blok boczny oraz na dole stopka. Podział zrealizowany wyłącznie za pomocą semantycznych znaczników sekcji języka HTML5 tak, aby po uruchomieniu w przeglądarce wygląd układu bloków był zgodny z obrazem 2
Baner float: left staje w lewym górnym rogu, blok boczny float: right - w prawym, obok niego (80% + 20%). Blok główny też płynie w lewo, ale obok banera nie ma już miejsca, więc schodzi pod niego - a blok boczny sięga po prawej przez całą wysokość obu bloków. Stopka z clear: both zaczyna się pod pływającymi blokami. Dlatego aside stoi w kodzie przed main: pływający blok nie może zacząć się wyżej niż blok wcześniejszy w kodzie, więc blok boczny zapisany po bloku głównym spadłby pod baner.
Dla selektora obrazu: zaokrąglenie rogów 50%, marginesy wewnętrzne lewy i prawy 10 px
border-radius: 50% robi z kwadratowego zdjęcia koło. Skrót padding: 0 10px - górny i dolny 0, lewy i prawy 10 px. Zgodnie z uwagą arkusza selektor to sam znacznik img (klasa nie spełniłaby R.4.6).
R.4.3 Ustawiono wysokość bloków banera 80px, głównego 600px i bocznego 680px oraz bloku chatu 470px
ok. 2 min
Polecenie z arkusza
Dla bloku chatu: obramowanie linią ciągłą o szerokości 1 px i kolorze Tomato, marginesy zewnętrzne 15 px, wysokość 470 px, paski przewijania zawsze widoczne na stronie
Skrót border: 1px solid Tomato - grubość, styl (solid - linia ciągła), kolor. „Paski przewijania zawsze widoczne” to overflow: scroll: paski są od początku, choć dwie wypowiedzi mieszczą się w oknie (obraz 2). Okno ma stałą wysokość 470 px, więc kolejne wypowiedzi nie rozciągną strony - pojawi się przewijanie. Ustawione są już wszystkie wysokości z klucza (R.4.3).
R.4.9 Ustawiono styl dla obu bloków z wypowiedziami: zaokrąglenie rogów 5px, szerokość 90%, wysokość 70px, marginesy zewnętrzne 2%, marginesy wewnętrzne 3px (np. za pomocą klasy, id jest błędem)
ok. 1 min
Polecenie z arkusza
Wspólne dla bloków z wypowiedziami: zaokrąglenie rogów 5 px, szerokość 90%, wysokość 70 px, marginesy zewnętrzne 2%, marginesy wewnętrzne 3 px
Klasa message jest przy każdej wypowiedzi, także dokładanej przez skrypt. Wysokość 70 px to dokładnie wysokość zdjęć.
Dodatkowo dla bloków z wypowiedziami Jolanty: kolor tła #EEE, obraz opływany tekstem z prawej strony (obraz po lewej stronie)
#EEE to skrót od #EEEEEE - jasnoszary. Obraz z float: left przesuwa się do lewej krawędzi bloku, a tekst paragrafu opływa go z prawej. Selektor .jolanta img wskazuje tylko zdjęcia wewnątrz wypowiedzi Jolanty - zdjęcia w bloku bocznym nie zmieniają ułożenia.
Krok 41: Wypowiedź Krzysztofa: tło, tekst do prawej, obraz po prawej
Kryteria: ,
R.3.3 W bloku z wypowiedziami Jolanty obraz jest opływany tekstem po prawej stronie a z wypowiedziami Krzysztofa po stronie lewej
R.4.10 Ustawiono kolor tła bloku wypowiedzi Jolanty #EEE oraz wypowiedzi Krzysztofa #CCC, wypowiedzi Krzysztofa są wyrównane do prawej strony
ok. 2 min
Polecenie z arkusza
Dodatkowo dla bloków z wypowiedziami Krzysztofa: kolor tła #CCC, wyrównanie tekstu do prawej strony, obraz opływany tekstem z lewej strony (obraz po prawej stronie)
Ciemniejsze tło, tekst dosunięty do prawej i obraz z float: right - tekst opływa go z lewej. Okno chatu wygląda już jak na obrazie 2: wypowiedzi na zmianę z lewej i z prawej (R.3.3, R.4.10).
R.4.2 Ustawiono kolor tła Tomato dla bloków banera, stopki i przycisków; Coral dla bloku bocznego oraz biały kolor czcionki dla banera i stopki
R.4.5 Ustawiono wyrównanie tekstu do środka dla banera i stopki oraz czcionkę pogrubioną dla przycisków
R.4.6 Ustawiono marginesy wewnętrzne (padding) lewy i prawy 10px dla selektora img, 5px dla przycisków oraz marginesy zewnętrzne (margin) dla bloku chatu 15px
R.4.7 Ustawiono obramowanie linią ciągłą o szerokości 1px i kolorze Tomato dla bloku chatu oraz obramowanie linią ciągłą o szerokości 1px i kolorze DarkRed dla przycisków oraz paski przewijania zawsze widoczne na stronie (overflow: scroll;) dla bloku chatu
ok. 2 min
Polecenie z arkusza
Dla obu przycisków: kolor tła Tomato, obramowanie linią ciągłą o szerokości 1 px i kolorze DarkRed, marginesy wewnętrzne 5 px, czcionka pogrubiona
Selektor button obejmuje oba przyciski. Ta reguła domyka kilka kryteriów naraz: kolory tła (R.4.2), pogrubienie obok wyśrodkowania banera i stopki (R.4.5), marginesy wewnętrzne i zewnętrzne (R.4.6) oraz obramowania razem z przewijaniem chatu (R.4.7).
Kroki 44-50 · po tym etapie masz 40 z 40 kryteriów (pkt)
Krok 44: Wyślij: tekst z pola na końcu okna chatu
Kryteria: , ,
R.5.1 Skrypt zapisano w języku JavaScript i zawiera on przynajmniej jedną instrukcję zapisaną zgodnie ze składnią
R.5.2 Funkcja wywoływana przyciskiem Wyślij pobiera dane z pola edycyjnego
R.5.3 Dane z pola edycyjnego są wyświetlane w oknie chatu
ok. 2 min
Polecenie z arkusza
Działanie funkcji wywoływanej po kliknięciu przycisku Wyślij: Pobierany jest tekst z pola edycyjnego i umieszczany w oknie chatu jako ostatni
Skrypt w znaczniku <script> na końcu <body>. Funkcja sendMessage (tę nazwę wywołuje onclick) odczytuje pole przez getElementById("text").value, tworzy nowy paragraf (createElement("p") z tabeli 2), wpisuje do niego tekst przez innerText i dokłada go na koniec okna chatu - appendChild zawsze wstawia element jako ostatni. Na razie tekst pojawia się bez tła i zdjęcia; wygląd wypowiedzi dojdzie w następnym kroku.
R.5.4 Dane z funkcji związanej z przyciskiem Wyślij są formatowane jako wypowiedzi Jolanty (tak samo jak pierwsza wypowiedź w chacie)
ok. 3 min
Polecenie z arkusza
Tekst jest formatowany jako wypowiedź Jolanty, zgodnie z obrazem 3, czyli utworzony jest blok z wypowiedzią zawierający obraz Jolka.jpg i paragraf zgodny z tekstem wpisanym do pola edycyjnego
Skrypt buduje dokładnie taki sam kawałek drzewa dokumentu jak pierwsza wypowiedź w HTML-u: div z klasami message i jolanta (classList.add z tabeli 2), a w nim obraz i paragraf. Kolejność appendChild ma znaczenie - obraz przed paragrafem, jak w kodzie HTML, bo float działa na tekst stojący za obrazem. Do okna chatu trafia dopiero gotowy blok. Sprawdzone w Chrome: wiadomość „Ok, cieszę się” dostaje ten sam wygląd co „Cześć idziesz jutro do kina?” (obraz 3).
R.5.5 Po zapełnieniu bloku chatu następuje przewinięcie do nowo wstawionej wypowiedzi dla przynajmniej jednej funkcji.
ok. 1 min
Polecenie z arkusza
Jeśli blok chatu jest cały wypełniony, powinien być przewinięty do nowo wstawionej wypowiedzi
scrollIntoView() (tabela 2) przewija okno chatu tak, żeby nowy blok był widoczny. Gdy okno nie jest jeszcze pełne, nic się nie dzieje - warunek „jeśli wypełniony” spełnia się sam. Sprawdzone w Chrome: po kilkunastu wiadomościach okno jest przewinięte do ostatniej.
R.5.6 W kodzie zdefiniowano tablicę z dziewięcioma wypowiedziami Krzysztofa
ok. 2 min
Polecenie z arkusza
Losowana jest wypowiedź Krzysztofa z wcześniej zadeklarowanej tablicy. Tablica zawiera 9 elementów, którymi są wypowiedzi. Należy je skopiować z pliku pomocniczego tekstyDoChatu.txt rozpakowanego z archiwum
Plik tekstyDoChatu.txt jest przygotowany do wklejenia: każdy tekst w cudzysłowie, z przecinkiem na końcu linii. Wystarczy go objąć nawiasami kwadratowymi i nazwać tablicę - replies. Tablica stoi poza funkcją, więc powstaje raz, przy wczytaniu strony („wcześniej zadeklarowana”), a nie przy każdym kliknięciu.
chat.htmlHTMLzmienione: 12 linii
<!DOCTYPE html><htmllang="pl"><head> <metacharset="UTF-8"> <title>Chat</title> <linkrel="stylesheet"href="styl.css"></head><body> <header> <h2>Chat</h2> </header> <aside> <h3>Chaty</h3> <ul> <li>Ogólny</li> <li>Tematyczne <ol> <li>Turystyczny</li> <li>Żeglarski</li> <li>Filatelistyczny</li> <li>Hodowla zwierzątek domowych</li> </ol> </li> </ul> <h3>Uczestnicy</h3> <p>Jolanta Nowak</p> <imgsrc="Jolka.jpg"alt="Jolanta Nowak"> <p>Krzysztof Łukasiński</p> <imgsrc="Krzysiek.jpg"alt="Krzysztof Łukasiński"> </aside> <main> <divid="chat"> <divclass="message jolanta"> <imgsrc="Jolka.jpg"alt="Jolanta Nowak"> <p>Cześć idziesz jutro do kina?</p> </div> <divclass="message krzysztof"> <imgsrc="Krzysiek.jpg"alt="Krzysztof Łukasiński"> <p>Tak! A ty?</p> </div> </div> <labelfor="text">Wpisz wiadomość:</label> <inputtype="text"id="text"> <buttononclick="sendMessage()">Wyślij</button><br> <buttononclick="generateReply()">Generuj losową odpowiedź</button> </main> <footer> <h5>Chat wykonał: Bartosz Bryniarski</h5> </footer> <script>let replies = ["Świetnie!","Kto gra główną rolę?","Lubisz filmy Tego reżysera?","Będę 10 minut wcześniej","Może kupimy sobie popcorn?","Ja wolę Colę","Zaproszę jeszcze Grześka","Tydzień temu też byłem w kinie na Diunie","Ja funduję bilety" ];function sendMessage() {let text = document.getElementById("text").value;let block = document.createElement("div"); block.classList.add("message"); block.classList.add("jolanta");let image = document.createElement("img"); image.src = "Jolka.jpg"; image.alt = "Jolanta Nowak";let paragraph = document.createElement("p"); paragraph.innerText = text; block.appendChild(image); block.appendChild(paragraph);document.getElementById("chat").appendChild(block); block.scrollIntoView(); } </script></body></html>
Podgląd strony po tym kroku (chat.html)
Krok 48: Generuj: losowy indeks 0-8 i tekst na końcu chatu
Kryteria:
R.5.7 Funkcja wywoływana przyciskiem Generuj… losuje index tablicy z wypowiedziami Krzysztofa (liczba od 0 do 8), wypowiedź o tym indeksie jest wyświetlana w oknie chatu (sprawdzić w kodzie i w przeglądarce)
ok. 2 min
Polecenie z arkusza
Losowana liczba z przedziału od 0 do 8 jest indeksem tablicy. Wypowiedź jest umieszczana w oknie chatu jako ostatnia
Math.random() zwraca ułamek od 0 (włącznie) do 1 (bez jedynki), po pomnożeniu przez 9 - od 0 do prawie 9, a Math.floor obcina część ułamkową: wychodzi liczba całkowita od 0 do 8, czyli poprawny indeks tablicy dziewięcioelementowej. replies[index] to wylosowany tekst; trafia na koniec okna tak samo jak wiadomość z pola.
chat.htmlHTMLzmienione: 7 linii
<!DOCTYPE html><htmllang="pl"><head> <metacharset="UTF-8"> <title>Chat</title> <linkrel="stylesheet"href="styl.css"></head><body> <header> <h2>Chat</h2> </header> <aside> <h3>Chaty</h3> <ul> <li>Ogólny</li> <li>Tematyczne <ol> <li>Turystyczny</li> <li>Żeglarski</li> <li>Filatelistyczny</li> <li>Hodowla zwierzątek domowych</li> </ol> </li> </ul> <h3>Uczestnicy</h3> <p>Jolanta Nowak</p> <imgsrc="Jolka.jpg"alt="Jolanta Nowak"> <p>Krzysztof Łukasiński</p> <imgsrc="Krzysiek.jpg"alt="Krzysztof Łukasiński"> </aside> <main> <divid="chat"> <divclass="message jolanta"> <imgsrc="Jolka.jpg"alt="Jolanta Nowak"> <p>Cześć idziesz jutro do kina?</p> </div> <divclass="message krzysztof"> <imgsrc="Krzysiek.jpg"alt="Krzysztof Łukasiński"> <p>Tak! A ty?</p> </div> </div> <labelfor="text">Wpisz wiadomość:</label> <inputtype="text"id="text"> <buttononclick="sendMessage()">Wyślij</button><br> <buttononclick="generateReply()">Generuj losową odpowiedź</button> </main> <footer> <h5>Chat wykonał: Bartosz Bryniarski</h5> </footer> <script>let replies = ["Świetnie!","Kto gra główną rolę?","Lubisz filmy Tego reżysera?","Będę 10 minut wcześniej","Może kupimy sobie popcorn?","Ja wolę Colę","Zaproszę jeszcze Grześka","Tydzień temu też byłem w kinie na Diunie","Ja funduję bilety" ];function sendMessage() {let text = document.getElementById("text").value;let block = document.createElement("div"); block.classList.add("message"); block.classList.add("jolanta");let image = document.createElement("img"); image.src = "Jolka.jpg"; image.alt = "Jolanta Nowak";let paragraph = document.createElement("p"); paragraph.innerText = text; block.appendChild(image); block.appendChild(paragraph);document.getElementById("chat").appendChild(block); block.scrollIntoView(); }function generateReply() {let index = Math.floor(Math.random() * 9);let paragraph = document.createElement("p"); paragraph.innerText = replies[index];document.getElementById("chat").appendChild(paragraph); } </script></body></html>
Podgląd strony po tym kroku (chat.html)
Krok 49: Generuj: blok wypowiedzi Krzysztofa
Kryteria:
R.5.8 Dane z funkcji związanej z przyciskiem Generuj... są formatowane jako wypowiedzi Krzysztofa (tak samo jak druga wypowiedź w chacie)
ok. 2 min
Polecenie z arkusza
Tekst jest formatowany jako wypowiedź Krzysztofa, zgodnie z obrazem 4, czyli utworzony jest blok z wypowiedzią zawierający obraz Krzysiek.jpg i paragraf zgodny z wylosowanym tekstem
Ta sama budowa co w sendMessage, ale z klasą krzysztof i zdjęciem Krzysiek.jpg - odpowiedź ląduje po prawej, na ciemniejszym tle (obraz 4).
Krok 50: Generuj: przewinięcie do nowej wypowiedzi
Kryteria:
R.5.9 Zastosowano znaczące nazewnictwo dla wszystkich zmiennych i funkcji w języku polskim lub angielskim. Nazwy odzwierciedlają cel zastosowania.
ok. 1 min
Polecenie z arkusza
Jeśli blok chatu jest cały wypełniony, powinien być przewinięty do nowo wstawionej wypowiedzi
To samo scrollIntoView() na końcu drugiej funkcji. Wszystkie nazwy mówią, do czego służą: sendMessage, generateReply, replies, text, index, block, image, paragraph (R.5.9).
Kroki 51-53 · po tym etapie masz 40 z 40 kryteriów (pkt)
Krok 51: Jedna funkcja addMessage zamiast dwóch kopii
ok. 4 min
Polecenie z arkusza
Należy stosować znaczące nazewnictwo wszystkich zmiennych i funkcji
Obie funkcje egzaminacyjne różnią się tylko czterema wartościami: tekstem, plikiem zdjęcia, podpisem i klasą. W prawdziwym projekcie tworzenie bloku wypowiedzi jest jedną funkcją addMessage z czterema parametrami, a sendMessage i generateReply tylko ją wywołują - poprawka wyglądu wypowiedzi jest wtedy w jednym miejscu. Przy okazji: classList.add przyjmuje kilka klas naraz, append - kilka elementów, liczba odpowiedzi bierze się z replies.length (dopisanie dziesiątego tekstu nie wymaga zmiany losowania), a okno przewija scrollTop = scrollHeight. Sprawdzone w Chrome: scrollIntoView przewijało nie tylko okno chatu, ale i całą stronę (na niskim ekranie strona „podskakiwała” o 257 px), a scrollTop przewija tylko okno chatu. Na egzaminie wystarczy wersja wcześniejsza - klucz tego nie sprawdza.
Krok 52: Pusta wiadomość pominięta, pole czyszczone po wysłaniu
ok. 3 min
Polecenie z arkusza
Pobierany jest tekst z pola edycyjnego i umieszczany w oknie chatu jako ostatni
Wersja egzaminacyjna sprawdzona w Chrome z pustym polem: kliknięcie „Wyślij” dokłada pustą wypowiedź - samo zdjęcie Jolanty w szarym prostokącie. Tak samo przy tekście złożonym z samych spacji. Poprawka: trim() obcina spacje z początku i końca, a dla pustego napisu funkcja kończy się od razu (return). Po wysłaniu pole jest czyszczone i dostaje kursor (focus()) - można pisać kolejną wiadomość bez klikania w pole. Na egzaminie wystarczy wersja wcześniejsza - klucz tego nie sprawdza.
Krok 53: Nasłuchiwacze zdarzeń i wysyłanie klawiszem Enter
ok. 3 min
Polecenie z arkusza
Działanie funkcji wywoływanej po kliknięciu przycisku Wyślij
Przyciski dostają identyfikatory, a zdarzenia podpina skrypt przez addEventListener - HTML zostaje bez kodu JavaScript. W każdym komunikatorze wiadomość wysyła się też klawiszem Enter: nasłuchiwacz zdarzenia keydown na polu sprawdza, który klawisz naciśnięto (event.key), i dla Entera wywołuje tę samą funkcję co przycisk. Na egzaminie wystarczy wersja wcześniejsza - klucz uznaje oba sposoby podpięcia zdarzenia (R.3.4).
Krok 54 · po tym etapie masz 40 z 40 kryteriów (pkt)
Krok 54: Plik przeglądarka.txt i nagranie płyty
ok. 5 min
Polecenie z arkusza
Po zakończeniu pracy utwórz plik tekstowy o nazwie przeglądarka.txt. Zapisz w nim nazwę przeglądarki internetowej, w której weryfikowana była poprawność działania witryny. Umieść go w folderze z numerem zdającego. Nagraj płytę z rezultatami pracy.
W przeglądarka.txt wystarczy nazwa przeglądarki, w której była sprawdzana strona.
W folderze z numerem zdającego: rozpakowane pliki z archiwum (baza.sql, Jolka.jpg - już przycięta, Krzysiek.jpg, tekstyDoChatu.txt), chat.html, import.png, kw1.jpg - kw5.jpg, kwerendy.txt, przeglądarka.txt i styl.css. Po nagraniu płyty trzeba sprawdzić jej odczyt i opisać ją numerem zdającego.
Symulacja ekranu w przeglądarce - w Android Studio / Visual Studio wygląd może się nieco różnić.
To jedno z możliwych rozwiązań. Egzaminator ocenia spełnienie kryteriów z klucza odpowiedzi, a nie zgodność z tym kodem - inna, poprawna droga też daje punkty.
Autor rozwiązania: Bartosz Bryniarski. Licencja CC BY-NC 4.0 - kopiowanie i przeróbki do celów niekomercyjnych, z podaniem autora i źródła (link do tej strony) (zasady wykorzystania). Treść arkusza i klucza oceniania pochodzi z CKE.