Semplice calcolatrice

Qui trovate tutti i codici utilizzati per la calcolatrice. Sono tutti ampiamente spiegati e commentati. Fate attenzione perchè i collegamenti ai file dipendono da dove sono collocati; Struttura che ho utilizzato io:

  •  calcolatrice
    •  bower_components
      •  base.reset
        •  reset.css
    •  css
      •  stile.css
    •  img
      •  Logo-Accademia.png
    •  index.html
    •  main.js

index.html

<!DOCTYPE html>
<html>
<!-- 
    ====================================================================
    LAYOUT DELL CALCOLATRICE
    ====================================================================
    Calcolatrice utilizza un layout di tipo flex annidato.
    1.  div.calcolatrice:
        Layout flex di tipo column dall'alto verso il basso. La 
        disposizione del contenuto è determinata dalla proprietà
        justify-content: space-between. Contiene tre elementi: 
        header.top-bar, div.carta e div.tastiera
    2.  header.top-bar
        Layout flex di tipo row orizzontale.  La disposizione 
        del contenuto è determinata dalla proprietà
        justify-content: space-between. Sono presenti due elementi: 
        img.logo e span.title.
    3.  div.carta 
        Layout flex di tipo column dall'alto verso il basso. 
        Contiene un solo elemento: div#userInput
    4.  div.tastiera
        Layout flex di tipo column dall'alto verso il basso.  Contiene 
        5 elementi div.riga ognino dei quali occupa il 20% dello spazio 
        (flex: 0 0 20%).
    5.  div.riga 
        Layout flex di tipo row orizzontale. Ogni riga contiene elementi 
        div.colonna-1, div.colonna-2 o div.colonna-3 rispettivamente 
        larghi 25%, 50% e 75% dello spazio a disposizione. 
    6.  div.colonna-1, div.colonna-2, div.colonna-3
        Elementi uguali son non per la larghezza (flex: 0 0 25%, 
        flex: 0 0 50%, flex: 0 0 75%) sono i contenitori dei tasti 
        (button.tasto). Il margine superiore e inferiore è dato 
        dal padding (margine interno) dell'elemento row che li contiene 
    7.  button.tasto
        button.tasto è alto e largo quanto l'elemento div.colonna che 
        lo contiene. Il margine tra un bottone e l'altro è dato dal 
        padding (margine interno) della div che contiene il bottone.
        Quando necessario al button.tasto viene aggiunta l'attributo 
        data-val che contiene il valore da utilizzare nell'espressione
        da valutare con javascript al posto del valore del button stesso.
        Ad esempio il taso "," ha data-val="." che è il separatore dei 
        decimali utilizzato in javascript.
 -->
<head>
    <title>Calcolatrice</title>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0, minimum-scale=1.0, maximum-scale=1.0">
    <link rel="stylesheet" href="bower_components/base.reset/reset.css" />
    <link rel="stylesheet" href="css/stile.css" />
</head>

<body>
    <div class="calcolatrice">
        <!-- Testata -->
        <header class="top-bar">
            <img class="logo" src="img/Logo-Accademia.png" />
            <span class="title">Calcolatrice</span>
        </header>
        <!-- CARTA -->
        <div class="carta">
            <div id="userInput" class="immissione">0</div>
        </div>

        <!-- Tastiera calcolatrice-->
        <div class="tastiera">
            <!-- RIGA -->
            <div class="riga">
                <!-- COLONNE -->
                <div class="colonna-1">
                    <button type="button" class="tasto">C</button>
                </div>
                <div class="colonna-1">
                    <button type="button" class="tasto">(</button>
                </div>
                <div class="colonna-1">
                    <button type="button" class="tasto">)</button>
                </div>
                <div class="colonna-1">
                    <button type="button" class="tasto">+</button>
                </div>
            </div>
            <!-- RIGA -->
            <div class="riga">
               <!-- COLONNE -->
               <div class="colonna-1">
                    <button type="button" class="tasto">1</button>
                </div>
                <div class="colonna-1">
                    <button type="button" class="tasto">2</button>
                </div>
                <div class="colonna-1">
                    <button type="button" class="tasto">3</button>
                </div>
                <div class="colonna-1">
                    <button type="button" data-val="-" class="tasto">&minus;</button>
                </div>
            </div>
            <!-- RIGA -->
            <div class="riga">
               <!-- COLONNE -->
               <div class="colonna-1">
                    <button type="button" class="tasto">4</button>
                </div>
                <div class="colonna-1">
                    <button type="button" class="tasto">5</button>
                </div>
                <div class="colonna-1">
                    <button type="button" class="tasto">6</button>
                </div>
                <div class="colonna-1">
                    <button type="button" data-val="*" class="tasto">&times;</button>
                </div>
            </div>
            <!-- RIGA -->
            <div class="riga">
               <!-- COLONNE -->
               <div class="colonna-1">
                    <button type="button" class="tasto">7</button>
                </div>
                <div class="colonna-1">
                    <button type="button" class="tasto">8</button>
                </div>
                <div class="colonna-1">
                    <button type="button" class="tasto">9</button>
                </div>
                <div class="colonna-1">
                    <button type="button" data-val="/" class="tasto">&divide;</button>
                </div>
            </div>
            <!-- RIGA -->
            <div class="riga">
                <!-- COLONNE -->
                <div class="colonna-2">
                    <button type="button" class="tasto">0</button>
                </div>
                <div class="colonna-1">
                    <button type="button" data-val="." class="tasto">,</button>
                </div>
                <div class="colonna-1">
                    <button type="button" class="tasto">=</button>
                </div>
            </div>
        </div>

    </div>

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

</html>

css/stile.css

Stili utilizzati nella calcolatrice. Ho incluso anche il foglio di stile bower_components/base.reset/reset.css  che le impostazione base che uniformano i browser senza creare alcuna classe.

body {
  font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Oxygen,
    Ubuntu, Cantarell, "Open Sans", "Helvetica Neue", sans-serif;
  font-size: 16px;
  font-weight: 300;
}

/*==================================================
  Contenitore della calcolatrice 
  ==================================================*/
.calcolatrice {
  height: 100vh;
  background-color: #666666;
  color: white;
  /* margine attorno alla calcolatrice */
  padding: 15px;
  /* Layout flex */
  display: -webkit-box;
    display: -ms-flexbox;
      display: flex;
  -webkit-box-orient: vertical;
  -webkit-box-direction: normal;
      -ms-flex-flow: column nowrap;
          flex-flow: column nowrap;
  /* disposizione degli elementi contenuti */
  -webkit-box-pack: justify;
      -ms-flex-pack: justify;
          justify-content: space-between;
}

/*==================================================
  Carta 
  ==================================================*/
.carta {
  background-color: #eeeeee;
  color: #333333;
  /* Layout flex */  
  -webkit-box-flex: 1;
    -ms-flex: 1 1 1%;
      flex: 1 1 1%;
}

/*==================================================
  Elemento che mostra l'espressione che l'utente
  sta componendo e, quando l'utente preme '=' il
  risultato
  ==================================================*/
.carta .immissione {
  font-size: 3em;
  text-align: right;
}

/*==================================================
  Testata con logo e titolo 
  ==================================================*/
.top-bar {
  max-height: 2.7em;
  width: 100%;
  padding-bottom: 5px;
  /* Impostazioni come CONTENUTO flex: non cresce, 
     non cala, ha un'altezza di 2.7em */
  -webkit-box-flex: 0;
    -ms-flex: 0 0 2.7em;
      flex: 0 0 2.7em;
  /* Impostazioni come CONTENITORE flex: flusso 
     orizzontale, contenuto disposto come 
     justify-content: space-between */
  display: -webkit-box;
    display: -ms-flexbox;
      display: flex;
  -webkit-box-orient: horizontal;
    -webkit-box-direction: normal;
      -ms-flex-flow: row nowrap;
        flex-flow: row nowrap;
  -webkit-box-pack: justify;
    -ms-flex-pack: justify;
      justify-content: space-between;
}

/*==================================================
  Logo barra superiore 
  ==================================================*/
.top-bar .logo {
  max-height: 100%;
  width: auto;
  /* Impostazioni come CONTENUTO flex: non cresce, 
     non cala, larghezza minima possibile*/
  -webkit-box-flex: 0;
    -ms-flex: 0 0 1%;
      flex: 0 0 1%;
}

/*==================================================
  Titolo barra superiore 
  ==================================================*/
.top-bar .title {
  font-size: 1.2em;
  font-weight: 700;
}

/*==================================================
  TASTIERA
  ==================================================*/
.tastiera {
  max-height: 70%;
  padding-top: 2px;
  /* Impostazioni come CONTENUTO flex: non cresce, 
     può calare, ha un'altezza di base del 70% */
  -webkit-box-flex: 0;
    -ms-flex: 0 1 70%;
      flex: 0 1 70%;
  /* Impostazioni come CONTENITORE flex con flusso 
     verticale */    
  display: -webkit-box;
    display: -ms-flexbox;
      display: flex;
  -webkit-box-orient: vertical;
    -webkit-box-direction: normal;
      -ms-flex-flow: column nowrap;
        flex-flow: column nowrap;
}

/*==================================================
  RIGA DI TASTI NELLA TASTIERA
  ==================================================*/
.riga {
  /* Impostazioni come CONTENUTO flex: non cresce, 
     non cala, ha un'altezza del 20% */
  -webkit-box-flex: 0;
    -ms-flex: 0 0 20%;
      flex: 0 0 20%;
  /* Impostazioni come CONTENITORE flex con flusso 
     orizzontale  */ 
  display: -webkit-box;
    display: -ms-flexbox;
      display: flex;
  -webkit-box-orient: horizontal;
    -webkit-box-direction: normal;
      -ms-flex-flow: row nowrap;
        flex-flow: row nowrap;
  /* I due margini esterni negativi servono a compensare 
     il padding degli elementi .colonna- contenuti 
     garantendo un corretto allineamento esterno dei 
     tasti*/
  margin-left: -2px;
  margin-right: -2px;
}

/*======================================================
  COLONNE
  Tre elementi identici in cui cambia solo la larghezza
  =====================================================*/
.colonna-1 {
  /* Impostazioni come CONTENUTO flex: non cresce, 
     non cala, ha una larghezza del 25% */
  -webkit-box-flex: 0;
    -ms-flex: 0 0 25%;
      flex: 0 0 25%;
  max-width: 25%;
  /* Margine interno che garantisce la distanza tra 
     i tasti */
  padding: 2px;
}

.colonna-2 {
  /* Impostazioni come CONTENUTO flex: non cresce, 
     non cala, ha una larghezza del 50% */ 
  -webkit-box-flex: 0;
    -ms-flex: 0 0 50%;
        flex: 0 0 50%;
  max-width: 50%;
  /* Margine interno che garantisce la distanza tra 
     i tasti */
  padding: 2px;
}

.colonna-3 {
  /* Impostazioni come CONTENUTO flex: non cresce, 
     non cala, ha una larghezza del 75% */ 
  -webkit-box-flex:0;
      -ms-flex:0 0 75%;
          flex:0 0 75%;
  max-width: 75%;
  /* Margine interno che garantisce la distanza tra 
     i tasti */
  padding: 2px;
}

/*==================================================
  TSTO DELLA CALCOLATRICE
  ==================================================*/
.tasto {
  /* Il tasto occupa l'intero spazio definito 
     dall'elemento .colonna- che lo contiene*/
  width: 100%;
  height: 100%;
  color: #333;
  background-color: #dddddd;
  border: 0;
  font-size: 1.5em;
}

/* Sugli schermi di larghezza superiore a tablet con 
   orientamento portrait la grandezza dei font dei 
   tasti viene postata a 2.5em */
@media screen and (min-width: 768px) {
  .tasto {
    font-size: 2.5em;
  }
}

main.js

/*==================================================
    CALCOLATRICE
    Il codice è molto semplificato. Possibili 
    miglioramenti:
    - Tenere traccia de calcoli effettuati in una 
      specie di history
    - Comporre l'espressione 'visibile' utilizzando 
      i segni che l'utente si aspetta (':' e non '/'
      per la divisione, ',' e non '.' come separatore 
      decimale, ecc.) e convertire l'espressione in 
      un espressione legale quando si effettua il 
      calcolo.
  ==================================================*/


// div che viene utilizzata per mostrare l'espressione 
// che viene composta usando i tasti della calcolatrice
var immissione = document.getElementById('userInput');

// nodeList che contiene tutti gli elemento con classe 
//'tasto' cioè tutti i tasti della calcolatrice
var tasti = document.getElementsByClassName('tasto');

/* ==================================================
    Con un ciclo 'for' scorro tutti gli elementi 
    contenuti nella nodeList tasti e a tutti 
    questi elementi (che sono tutti i tasti della mia 
    calcolatrice) aggiungo un gestore di eventi per 
    l'evento 'click'
   ==================================================*/
for(var i = 0; i < tasti.length; i++) {
    var tasto = tasti[i];
    /* -------- GESTORE DELL'EVENTO CLICK --------- 
        NOTA BENE: Nel gestore di evento la parola 
        riservata 'this' indica il tasto che riceve 
        l'evento 'click' che può essere provocato o
        dal click del mouse (bottone sinistro per 
        i mouse impostato per i destri, destro per i 
        mouse impostato per i mancini) o dal tocco su 
        un dispositivo touch.
    */
    tasto.addEventListener('click', function(){
        // La variabile 'valore' contiene il carattere 
        // corrispondente al tasto premuto 
        var valore;
        // 1. Determino il 'valore' del tasto 
        if (this.getAttribute('data-val') != null) {
            // Se il button.tasto ha un attributo 
            // data-val a valore è assegnato il valore 
            // dell'attributo data-val
            valore = this.getAttribute('data-val');
        } else {
            // Altrimenti a valore è assegnato 
            // il contenuto del button.tasto
            valore = this.innerHTML;
        }
        // 2. A secondo di cosa contiene valore eseguo
        //    l'azione conseguente.
        if (valore == "C") {
            // Se è stato premuto il tasto 'C' cancello
            // il contenuto di quanto immesso e lo 
            // sostituisco con '0'
            immissione.innerHTML = "0";
        } else if (valore == "=") {
            // Se è stato premuto il tasto '=' prendo
            // quanto immesso e calcolo il valore
            // dell'espressione che ho composto utilizzando
            // la funzione Javascript globale eval(). 
            // Inserisco il risultato in div#userInput
            var espressione = immissione.innerHTML;
            immissione.innerHTML = eval(espressione);
        } else {
            // Negli altri casi prendo il valore del tasto
            // premuto, lo aggiungo all'espressione da 
            // calcolare e visualizzo il risultato in
            // div#userInput
            var espressione = immissione.innerHTML;
            if (espressione == '0') {
                espressione = '';
            }
            espressione += valore;
            immissione.innerHTML = espressione;
        }
    });
}