Interaktywny Konwerter Systemów Liczbowych

HTML
Priorytet: Normalny Szkic

Zadanie 200: Interaktywny Konwerter Systemów Liczbowych

Wstęp

W powiązanym zadaniu JavaScript 200 dowiedziałeś się, jak wbudowane w JS metody toString(radix) i parseInt(string, radix) pozwalają w łatwy sposób konwertować liczby ze standardowego systemu dziesiętnego na dwójkowy (binarny), ósemkowy (oktalny) czy szesnastkowy (heksadecymalny) i z powrotem.

Jako programista Front-End, nie powinieneś jednak zostawiać swoich skryptów jedynie w konsoli. W tym zadaniu połączymy świat HTML, CSS i wyżej wymienionego skryptu JS, budując estetyczny i responsywny kalkulator działający u użytkownika na żywo z poziomu okna przeglądarki!

Cel zadania

Stwórz stronę zawierającą formularz, w którym użytkownik będzie mógł wpisać dowolną liczbę w systemie dziesiętnym, następnie z rozwijanej listy (select) wybrać docelowy system liczbowy (np. Binarny (2), Oktalny (8), Heksadecymalny (16)), po czym w trzecim, zablokowanym polu (readonly) natychmiast zobaczy sformatowany wynik. Kalkulator ma przeliczać wartości dynamicznie, w momencie ich wpisywania (bez konieczności klikania "Oblicz").

Wymagania techniczne

  1. Podstawowa znajomość struktury dokumentu HTML5.
  2. Zastosowanie formularza z etykietami (label), wejściem na tekst (input type="text" lub type="number"), listą wyboru (select) z opcjami (option) oraz polem tylko do odczytu (readonly).
  3. Ostylowanie kalkulatora w CSS.
  4. Podpięcie zewnętrznego skryptu .js, wyszukanie elementów w DOM przy pomocy document.getElementById lub document.querySelector.
  5. Użycie nasłuchiwaczy zdarzeń (addEventListener) na akcje wejścia typu input lub zmiany wyselekcjonowanej opcji typu change.
  6. Zabezpieczenie skryptu przed "NaN", czyli odpowiednia reakcja w sytuacji gdy użytkownik wpisze coś, co nie jest poprawną liczbą.

Kroki do wykonania

1. Struktura plików i dokument HTML

Utwórz folder na projekt, a w nim stwórz:

  • index.html
  • style.css
  • script.js

W pliku index.html utwórz szkielet HTML5 i podepnij arkusz stylów oraz skrypt zgodny ze strukturą:

<!DOCTYPE html>
<html lang="pl">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Konwerter Systemów Liczbowych</title>
    <link rel="stylesheet" href="style.css">
</head>
<body>

<main class="kalkulator-container">
    <h1>Kalkulator Systemów Liczbowych</h1>
    <p>Wpisz liczbę dziesiętną, przelicz na wybrany system.</p>

    <div class="form-group">
        <label for="input-dziesietny">Wartość dziesiętna:</label>
        <input type="number" id="input-dziesietny" placeholder="np. 255" autocomplete="off">
    </div>

    <div class="form-group">
        <label for="select-system">Zamień na system:</label>
        <select id="select-system">
            <option value="2">Binarny (podstawa 2)</option>
            <option value="8">Oktalny (podstawa 8)</option>
            <option value="16">Heksadecymalny (podstawa 16)</option>
        </select>
    </div>

    <div class="form-group">
        <label for="output-wynik">Wynik konwersji:</label>
        <input type="text" id="output-wynik" readonly placeholder="Wynik pojawi się tutaj">
    </div>
</main>

<script src="script.js"></script>
</body>
</html>

2. Estetyczny wygląd - CSS Layout

Twój kalkulator musi dobrze wyglądać i zachęcać do użytkowania. Przejdź do style.css i wycentruj kontener np. za pomocą Flexbox.

* {
    box-sizing: border-box;
    margin: 0;
    padding: 0;
    font-family: Arial, sans-serif;
}

body {
    background-color: #f0f2f5;
    display: flex;
    justify-content: center;
    align-items: center;
    min-height: 100vh;
}

.kalkulator-container {
    background-color: #fff;
    padding: 30px;
    border-radius: 12px;
    box-shadow: 0 4px 15px rgba(0,0,0,0.1);
    width: 100%;
    max-width: 400px;
}

.kalkulator-container h1 {
    font-size: 20px;
    margin-bottom: 10px;
    text-align: center;
    color: #333;
}

.kalkulator-container p {
    font-size: 14px;
    color: #666;
    text-align: center;
    margin-bottom: 25px;
}

.form-group {
    margin-bottom: 20px;
}

.form-group label {
    display: block;
    margin-bottom: 8px;
    font-weight: bold;
    color: #444;
}

.form-group input, 
.form-group select {
    width: 100%;
    padding: 10px;
    border: 1px solid #ccc;
    border-radius: 6px;
    font-size: 16px;
    outline: none;
}

.form-group input:focus, 
.form-group select:focus {
    border-color: #007bff;
    box-shadow: 0 0 5px rgba(0, 123, 255, 0.3);
}

.form-group input[readonly] {
    background-color: #e9ecef;
    cursor: not-allowed;
    color: #0d6efd;
    font-weight: bold;
}

3. Logika konwertera - plik script.js

Mając gotowy interfejs, nadeszła pora na "ożywienie" go przy pomocy logiki operującej na drzewie DOM. W klasycznym powiązaniu JS, musimy zlokalizować 3 utworzone elementy HTML (wejście liczbowe, wybierak select, i wyjście readonly), i nasłuchiwać ich interakcji.

// 1. Odszukaj elementy w drzewie DOM przy pomocy ID
const inputDziesietny = document.getElementById('input-dziesietny');
const selectSystem = document.getElementById('select-system');
const outputWynik = document.getElementById('output-wynik');

// 2. Skonstruuj funkcję konwertującą
function przelicz() {
    // a) Pobierz wejściowy napis i sprawdź parsując w formę inta o bazie 10
    const wartoscLiczbowa = parseInt(inputDziesietny.value, 10);
    
    // b) Zabezpiecz NaN
    if (isNaN(wartoscLiczbowa)) {
        outputWynik.value = '';
        return;
    }
    
    // c) Sprawdź podstawę na co zmieniamy
    const systemDocelowy = parseInt(selectSystem.value, 10);
    
    // d) Zamień bazową formę
    let wynik = wartoscLiczbowa.toString(systemDocelowy);
    if (systemDocelowy === 16) {
        wynik = wynik.toUpperCase();
    }
    
    // e) Przepisz jako odpowiedź
    outputWynik.value = wynik;
}

// 3. Nasłuchuj eventów użytkowania. Jeżeli w inpucie zajdzie event "input" wypuść trigger funkcji natychmiast
inputDziesietny.addEventListener('input', przelicz);

// Jeżeli użytkownik zmieni docelowy ustrój z listy rozwijalnej
selectSystem.addEventListener('change', przelicz);

4. Testy i weryfikacja

W przeglądarce podaj np. 255. Wynik heksadecymalny pokaże dumnie FF, binarny pokaże 11111111, zaś oktalny udowodni, że 377 ma swoją matematyczną historię.


Zadania dla chętnych

Poszerz wiedzę i postaraj się o implementację zaawansowanych zagadnień:

  1. Przycisk "Kopiuj do schowka": Korzystając z interfejsu przeglądarki (navigator.clipboard.writeText) dodaj mniejszy przycisk obok wyniku, po naciśnięciu którego wynik zostaje skopiowany cicho do zwykłego systemowego schowka, wyświetlając krótki alert() lub toast UI z komunikatem.
  2. Pełna obustronność konwersji: Dodaj po lewej select dla wejścia z którego wchodzimy, czyniąc go nie tylko "Dziesiętnym z urzędu", ale umożliwiając np wybór "Binarnego na start" a pod spodem "Heksadecymalnego". Twoja uniwersalna metoda z parseInt musi zaczerpnąć const zSystemu = select1.value; parseInt(wartosc, zSystemu) a poniżej wynik potraktować toString(select2.value).
  3. Fiksacja Hex-ów o U2 (Ujemne): Jeśli liczysz dziesiętne liczby do 2 bez maskowania systemem ujemnym - pozostanie na swoim wbudowanym standardzie JS. Poszukaj na StackOverflow jak zbudować odpowiednią bramkę bitową wypisując bezmyślnie "zera po lewej", lub w prostszym przypadku obsłuż ujemne liczby do formatu u2 jeśli użytkownik z listy rozwijanej chciał by to uaktywnić odpowiednim Checkboxem.